#!/usr/bin/ruby require 'zlib' # 0 = conceal and shuffle # 1 = reveal state = 1 # 1 = left # 2 = middle # 4 = right ball_position = 2 eval $common_code = %{ # Determine ball's final position, and then animate toward this # position (as opposed to determining final position after animation). # This is so that users can copy&paste either the initial or the final # frame and still get the same outcome. new_position = [1, 2, 4][rand(3)] # Sprites: horizontal offset + run length pairs $cup_sprite = [ [2, 16], # xxxxxxxxxxxxxxxx [2, 16], # xxxxxxxxxxxxxxxx [1, 18], # xxxxxxxxxxxxxxxxxx [1, 18], # xxxxxxxxxxxxxxxxxx [1, 18], # xxxxxxxxxxxxxxxxxx [1, 18], # xxxxxxxxxxxxxxxxxx [1, 18], # xxxxxxxxxxxxxxxxxx [0, 20], # xxxxxxxxxxxxxxxxxxxx [0, 20], # xxxxxxxxxxxxxxxxxxxx [0, 20], # xxxxxxxxxxxxxxxxxxxx [0, 20], # xxxxxxxxxxxxxxxxxxxx [0, 20], # xxxxxxxxxxxxxxxxxxxx [0, 20] # xxxxxxxxxxxxxxxxxxxx ] $ball_sprite = [ [1, 4], # xxxx [0, 6], # xxxxxx [0, 6], # xxxxxx [0, 6], # xxxxxx [1, 4] # xxxx ] # Predefined paths (x, y) vertical = [2, 3, 4, 5, 6, 7, 8, 9] if state > 0 then vertical = vertical.reverse end cup_left = [ vertical.map{|y| [2, y]}, 8.times.map{[30, 9]}, 8.times.map{[58, 9]}, 8.times.map{[9, 17]} ] cup_middle = [ 8.times.map{[2, 9]}, vertical.map{|y| [30, y]}, 8.times.map{[58, 9]}, 8.times.map{[37, 17]} ] cup_right = [ 8.times.map{[2, 9]}, 8.times.map{[30, 9]}, vertical.map{|y| [58, y]}, 8.times.map{[65, 17]} ] swap_left_middle = [ [[ 8, 8], [14, 7], [18, 7], [24, 8], [30, 9]], [[24, 10], [19, 11], [13, 11], [ 8, 10], [ 2, 9]], 5.times.map{[58, 9]}, 5.times.map{[65, 17]} ] swap_middle_right = [ 5.times.map{[2, 9]}, swap_left_middle[0].map{|x, y| [x + 28, y]}, swap_left_middle[1].map{|x, y| [x + 28, y]}, 5.times.map{[9, 17]} ] swap_left_right = [ swap_left_middle[0].map{|x, y| [x * 2 - 2, y]}, 5.times.map{[30, 9]}, swap_left_middle[1].map{|x, y| [x * 2 - 2, y]}, 5.times.map{[37, 17]} ] swap_data = [ [3, swap_left_middle], [6, swap_middle_right], [5, swap_left_right] ] # Set after first call to render() $clear = "" # Build code string for everything except the last 5 characters $data = 'salt = ' + rand.to_s + ';state = ' + (state ^ 1).to_s + ';ball_position = ' + new_position.to_s + ';eval $common_code = %{' + $common_code + '}' $data = [Zlib::Deflate.deflate($data)].pack('m').gsub("\n", '') $data = 'eval(%w{' + "require'zlib';eval(Zlib::Inflate.inflate('" + $data + "'.unpack('m')[0]))#" + $data def render_sprite(pos, spr) r = pos[1] spr.each{|p, q| (0..(q-1)).each{|c| $buffer[r][pos[0] + c + p] = 'x' } r += 1 } end def render(c1, c2, c3, ball) $buffer = 24.times.map{79.times.map{" "}.join("")} render_sprite(ball, $ball_sprite) render_sprite(c1, $cup_sprite) render_sprite(c2, $cup_sprite) render_sprite(c3, $cup_sprite) print $clear $clear = "#" + 27.chr + "[24A" + 13.chr template = $buffer.join("\n") $tdata = $data[0, template.count('x') - 5] + '}*"")' $tindex = -1 $output = '' template.each_char{|c| $output += (c == 'x' ? $tdata[$tindex += 1] : c)} puts $output $stdout.flush sleep 0.05 end # Initial cup motion for i in 0..(vertical.length - 1) path = [ [], cup_left, cup_middle, [], cup_right ][ball_position] render(path[0][i], path[1][i], path[2][i], path[3][i]) end # Swap cups if state == 0 s = 0 while s < 20 || ball_position != new_position op = swap_data[rand(3)] ball_position ^= op[0] s += 1 path = op[1] for i in 0..4 render(path[0][i], path[1][i], path[2][i], path[3][i]) end end end exit }