Skip to content

Instantly share code, notes, and snippets.

@pachacamac
Last active August 29, 2015 13:57
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pachacamac/9925102 to your computer and use it in GitHub Desktop.
Save pachacamac/9925102 to your computer and use it in GitHub Desktop.
2048 game in concise but not golfed Ruby
def rgb(r, g, b)16+(r.to_i*36)+(g.to_i*6)+b.to_i end
def colorize(s, fg, bg = nil) "#{fg ? "\x1b[38;5;#{fg}m" : ''}#{bg ? "\x1b[48;5;#{bg}m" : ''}#{s}\x1b[0m" end
def rainbow(n)f,w,o=5.0/n,3,3; (0...n).map{|i| rgb(Math.sin(f*i+0)*o+w, Math.sin(f*i+2)*o+w, Math.sin(f*i+4)*o+w)} end
def display(board, goal=2048)
@palette ||= rainbow(Math.log2(goal))
puts board.map{|r| r.map{|c| colorize((c==0 ? ?. : c).to_s.center(6), @palette[Math.log2(c+1)])}.join}.join("\n\n")
end
def compress(board, direction)
t=->(a){z=0;a.reduce([]){|s,e| z+=e==s[-1]? (s[-1]+=e;1): e>0? (s<<e;0): 1;s}+Array.new(z,0)} # trivial case: 1D array to the left
case direction
when :l; board.map{|e| t[e]} # 2D array to the left
when :r; board.map{|e| t[e.reverse].reverse} # 2D array to the right
when :u; board.transpose.map{|e| t[e]}.transpose # 2D array upwards
when :d; board.transpose.map{|e| t[e.reverse].reverse}.transpose # 2D array downwards
else board
end
end
def add(board)
free = board.each_with_index.reduce([]){|s,(e,i)| s+e.each_with_index.select{|d,j| d==0}.map{|k| [i,k[1]]}}.sample
(puts 'Game over!'; exit) unless free
board[free[0]][free[1]] = rand > 0.8 ? 4 : 2
board
end
def won?(board, goal=2048)board.flatten.any?{|e| e==goal}end
def key
state = `stty -g`.chomp
system 'stty raw -echo'
char = STDIN.getc
char << STDIN.getc << STDIN.getc if char==0x1b.chr
char[-1]
rescue; warn $!.message, $!.backtrace
ensure; system 'stty', state
end
# optional args are -w,-h for board size, -g for goal. defaults are 4,4,2048
args = Hash[ARGV.each_slice(2).to_a.map{|k,v| [k[1..-1].downcase.to_sym,v.to_i]}]
board = Array.new(args[:h]||4){Array.new(args[:w]||4, 0)}
board = add(board)
STDIN.reopen('/dev/tty')
loop do
system 'clear'
display(board,args[:g]||2048)
(puts 'You won!';exit) if won?(board, args[:g]||2048)
direction = case key
when ?D,?a,?h; :l # use either arrow keys or wsad or hjkl
when ?B,?s,?j; :d
when ?A,?w,?k; :u
when ?C,?d,?l; :r
when ?\C-c,?\C-x,?x,?q; exit
else next
end
board = add(compress(board, direction))
end
@pachacamac
Copy link
Author

Tested in: ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]

@jcsrb
Copy link

jcsrb commented Apr 2, 2014

works ok on ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-linux]

@mevdschee
Copy link

Does not work on: ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]

This is the version of Ruby included in Ubuntu 12.04 LTS

@pachacamac
Copy link
Author

@mevdschee: That's probably because it doesn't understand the new lambda syntax in line 10? You could replace the "->" with "lambda". And I don't know if in 1.8.7 it can be called usind "[ ]", maybe you need to say t.call(...).
Anyways. 1.8.7 is ancient history :) I suggest you use RVM or RBENV and get yourself something modern :)

@williamtguerra
Copy link

When there are no moves in one direction (left, for example), the original game locks up, while yours creates a new piece every time. Its hard to explain, but when there are no pieces to be combined when moving left, left is therefore not supposed to be a valid move.

@pachacamac
Copy link
Author

@williamtguerra fixed that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment