It's really, really neat. Even to those of us who know little or nothing about the game, from the nested Englishy descriptors piled up into short conditions for things-the-bot-might-want-to-do, the basic strategies can be discerned...
It's really, really neat. Even to those of us who know little or nothing about the game, from the nested Englishy descriptors piled up into short conditions for things-the-bot-might-want-to-do, the basic strategies can be discerned...
(def desired-shirt
(ordered-set "T-shirt" "Hawaiian shirt"))Absolutely cannot tell if you're fucking with me, or if this is an actual game mechanic - and if so, why this shirt would be desirable.
Welcome to the world of nethack! The amount of special case situations that have been programmed into this game over the last few decades are truly amazing. (Mostly because it somehow still works.)
I still remember the first time I ran into a kitchen sink.
http://tvtropes.org/pmwiki/pmwiki.php/TheDevTeamThinksOfEver...
> Additionally, throwing a cockatrice corpse up (<) will result in it hitting you on the head and, unless you're wearing a helmet, petrifying you instantly. Cause of death? "Petrified By Elementary Physics"
Some of these I knew, most I did not. Thanks for sharing that.
The Quantum Mechanic monster is basically one big physics joke.
Its attack will randomly teleport you, and eating a Quantum
Mechanic corpse will give you the intrinsic speed ability (or
remove intrinsic speed from you if you were already fast). Upon
death, the Quantum Mechanic also has a small chance to drop a
box. When you open the box, a cat named Schrodingers Cat will be
found inside. 50% of the time, the cat will be alive, and 50% of
the time, the cat will be dead.
What brings this into The Dev Team Thinks of Everything territory
is that if you look at the game's source code, you discover that
unlike every other box in the game, the state of the box's
contents (whether the cat is alive or dead) is not determined
until you open the box and look. (or (if (and (weak? player)
If it is a player or a weak player?Or this probably simple function(?):
(defn- want-protection? [game]
(and (< (:protection (:player game)) 3) (> 15 (:xplvl (:player game)))))
It makes zero intuitive sense to me.The second function is easier for me to understand: it says that the player wants protection if the player has less than 3 intrinsic protection and has an experience level higher than 15. (In NetHack, gods grant intrinsic protection under some circumstances, which causes one to become better armored even without wearing additional physical armor. It's basically like a kind of magical armor on one's body that's independent of any physical object.) The idea seems to be that a player with at least experience level 15 ought to have 3 or more points of protection, and if the player doesn't, the player should try to go and get them.
If you're not used to reading parenthesized prefix notation, you might have a look at
https://en.wikipedia.org/wiki/Polish_notation
https://en.wikipedia.org/wiki/S-expression
https://en.wikipedia.org/wiki/Lisp_%28programming_language%2...
[1] In another example of NetHack's complexity, it's also possible in some circumstances to eat objects other than food, by turning into a monster that's able to eat the objects in question.
def want-protection(game) =
game.player.protection < 3 &&
game.player.xplvl < 15The first one is missing a whole bunch of context. But here's a start: The first thing inside parentheses is the operator/function, the rest are arguments/operands. This one is best viewed from the inside out, so... a method ending in a question mark is most likely a predicate, i.e. a true/false test returning a boolean. So we're testing for a weak player. Outside from there is an 'and', so we're looking to combine that test with another one (further to the right, that you didn't show). Maybe checking if the player is both weak and hungry, as that may mean he'll croak soon.
Every paren pair ('S-expression') in Lisp (err, Clojure) returns a value, so the "if" is not so much a control-flow construct as it's like C's ternary op: [ cond ? iftrue : iffalse ]. Its first argument will be a test, like that weak-hunger thing. Then you will have one or maybe two other arguments. The first is returned if the condition is true, the second one if false. There may not be a second argument, in which case the return value will be 'nil' or maybe 'false' - they're sorta equivalent anyway.
Finally, the "or" will evaluate and return its first subexpression if it's true, or also evaluate the second one if not and return that. You can actually have as many arguments to an "or" as you like - they will be short-circuit-evaluated until one of the arguments is true, or if you hit the right paren without finding a true, you'll get a 'false' ('nil' ?).
------------------------------------
The second example is a function definition. By convention, 'want-protection?' will be the name of a predicate, i.e. something that tests and returns true/false.
'game' is the single argument to that function. From usage later on, it looks to be a map, or you might think of it as an associative array, or a key-value mapping.
The first half tests whether the 'protection' value of the player, which itself is the 'player' value of the game (in C: game.player.protection, except those components are keys rather than fields) is less than (see the '<' operator on the left?) 3. The second half tests whether (I'm guessing) his experience level is greater than 15. The 'and' combines those, i.e. if he's at least a lvl 16 player and his prot value sucks at less than 3, he'll want protection (so return 'true').