NB. 2048.ijs - http://codegolf.stackexchange.com/a/24207/5138
NB. code golf: play a game of 2048
'you ',>lose`win{~$:@".@('o b=:2 t}^:(1-b-:])s ',' b',~1!:1@1:)`w@.((w=:2048 e.,)+(s d-:s u=:l d=:r(&.|:))*s r-:(s=:[:p(2(=/(0,+/^:)@{.,}.),)/@p=:\:=&0)l=:&.|.r=:"1)(o=:[2:1!:2~4<@":"0])b=:2(t=:(?&#{])[:I.0=,)}4 4$0
NB. we're going to explain the action of the above expression by breaking it up
NB. and naming every little bit, degolfing a little as we go
NB. push: filters any zeroes to the left, by sorting by equality to 0
p =: \: =&0
NB. slide: perform a slide to the right
NB. first we push, then we try merging each pair of columns by folding a merge
NB. verb over the row, then one more push for good measure
s =: [: p m/ @ p
m =: 2 (=/(0,+/^:)@{. , }.) ,
NB. m works over the whole row by induction, taking a new element of the row at
NB. a time and trying to merge it with what's already done
NB. the 2 in m controls how many columns to work over
NB. =/(0,+/^:) is golfed-J for (0,+/)^:(=/) meaning "sum and prepend 0 if equal"
NB. directional modifiers: change how s is applied, to allow all four directions
NB. e.g. s l will make the board move left, s u up, and so on
r =: "1 NB. apply on rows, so that left-slides work
l =: &.|.r NB. flip each row before and after working on it
d =: r (&.|:) NB. transpose the whole board before and after
u =: l d NB. transpose board and flip rows (stacking r is harmless)
NB. output: print out the board, and then return it
NB. three options here, with varying levels of shortness and spec-following
o =: [ 1!:2&2 @ ": NB. this lets j output it the way it wants to
o =: [ 2: 1!:2~ 5 ": ] NB. this just makes the spaces 5-wide always
o =: [ 2: 1!:2~ 4 <@":"0 ] NB. this puts the above into little boxes
o =: [ 2: 1!:2~ ' ' ,:"1~ 5 ": ] NB. this makes square tiles with lots of space
NB. new-random-tile: place a new tile in an empty space on the board
NB. left argument is the tile contents, right is the board
t =: (?&# { ]) [: I. 0 = ,
NB. [:I.0=, -> list of all the indices where there is an empty space
NB. (?&#{]) -> a random selection out of those indices, for each value to insert
NB. board: the global variable holding the game state
b =: 2 t} 4 4 $ 0 NB. insert a 2 at a location in a 4x4 array of zeroes given by t
NB. now we can make a full step of the game!
step =: ". @ ('o b=:2 t}^:(1-b-:])s ' , ' b' ,~ 1!:1@1:)
NB. we read in a line of input with 1!:1@1: then slip it into the string
NB. 'o b=:2 t}^:(1-b-:])s b' and call it with ".
NB. the intent is to have the ulrd bits that act as modifiers on s be read from
NB. input, because that's the shortest way to take that input. since ulrd are
NB. modifiers for verbs, they are at the highest level of absraction j is able
NB. to handle: hence we need this level of indirection.
NB. is the game over? 0 if no, 1 if yes
over =: w + (s d -: s u) * (s r -: s l)
NB. note that if moving left and right give the same result, neither was valid
NB. -: is called Match and returns 1 if the arguments are the same, and 0 if not
NB. hence, the product of the matches will be 1 only if all four moves fail
w =: 2048 e. , NB. also this will be 1 if 2048 is anywhere on the board
NB. these conditions can never both happen under normal conditions, so just add
NB. now with the definitions, this is what the game really looks like:
main =: $:@step ` w @. over o b
NB. first we output b, so that the player can see the board at game start,
NB. then we run this weird $: and @. expression, which is actually a loop:
NB. $: is the recursion verb, and for arcane and mystical reasons is equal to
NB. $:@step`w@.over
NB. if over returns 0, then we take a step and recur$:e
NB. if over returns 1, we stop looping and check whether the game is won with w
NB. then the junk on the left is just the win/lose notifier
'you ' , > lose`win {~ main
NB. once more, sans comments:
p =: \: =&0 NB. push
m =: 2 (=/(0,+/^:)@{. , }.) , NB. merge
s =: [: p m/ @ p NB. slide
r =: "1 NB. right
l =: &.|.r NB. left
d =: r (&.|:) NB. down
u =: l d NB. up
o =: [ 2: 1!:2~ 4 <@":"0 ] NB. output
t =: (?&# { ]) [: I. 0 = , NB. random tile
b =: 2 t} 4 4 $ 0 NB. board
step =: ". @ ('o b=:2 t}^:(1-b-:])s ' , ' b' ,~ 1!:1@1:)
w =: 2048 e. , NB. won?
over =: w + (s u -: s d) * (s l -: s r)
main =: $:@step ` w @. over o b
'you ' , > lose`win {~ main