#!/usr/bin/ruby require "io/console" # Decode LZW encoded sprites lzw_data = %w{ """""##..#))#90;;KCX2;;K>U5z2k0MF[:$$$..#)+]1;;K=%$%%$X1;;K?##//1.91j.m.#+z2K:q3i5%x./.%#)n/;;K;"#$%)++)%$8/;;K=#[.$..#++i2y/*.K.;;K.$#k0;;K:"#$z.*%$80;;K=##'-#].[.%]0;.*o/s.z0K8#%%y.%..%$#m12.#'##9.;;KAL.j180;2*;9L.K4#'-*#$$%/.k0;/('#;8$K.$>.x.#%%%..;/n0###*-'o0K/l/;;K3#[2$%*y.W0[0;.<.j/[5k1'k0(h0j.'###l/0/m0#(L.Y.L2"#*'&''83)y.#h.M.)L3(''?.#i2';.&&'(#..k0F.l.z3[/*(&R.&&l/#[5:0A.'J.*[2q/L.'&##'L0"#;.8/i0l0'&(>/[1#'&''[.'<2o/(*##Z2w.##*(=/'(^2&=/Y4o.*'#(&U/i0[391a.&(#'*[3J.(*v.##'[1k.9.84l0G.&&l3'#7.r.K4&(*&#&h3##&'(('Z.z3H.*(K3[/&x.&#('n1[3x1'([/M/Z3,Y.#k.#=4L0K2#70(&&,,n1#'*#*q.[4l/,h4;1=/<5M1K4v0&k8[5B.H.M/h3Z.##(O.m3g.,L3x0w/1/k1('#''n.<2N1g3^1&I.=9M6v/,##;5[:F.M0X2x.w.##&]3k.#m.@.Y1J/q021S.(..L.D1>/52k2;/==M4u.,[9v.=;M4###v0#,l3=.,,,;6E1L0#v.&##''(&5.^2Z.g3;2m.=:M7[<&#..[Dz/o/z6##..o451;1F2M2# } * "" skip_next_byte = false flat_data = "" lzw_data.size.times{|i| if skip_next_byte skip_next_byte = false elsif lzw_data[i] < "." # Literal flat_data += lzw_data[i] else # Backreference # ord = OFFSET_BASE + index - offset - MIN_MATCH # = 46 + index - offset - 3 # offset = 46 + index - 3 - ord offset = 43 + flat_data.size - lzw_data[i].ord # ord = OFFSET_BASE + length - MIN_MATCH # = 46 + length - 3 # length = ord - 34 + 3 length = lzw_data[i + 1].ord - 43 skip_next_byte = true flat_data += flat_data[offset, length] end } # Split decompressed data to individual sprites sprites = [] 5.times{|i| sprites.push([]) 4.times{sprites[i].push("")} } 24.times{|y| 3.times{|frame| 3.times{|direction| sprites[direction][frame] += flat_data[y * 160 + direction * 16 * 3 + frame * 16, 16] + "\n" } sprites[3][frame] += sprites[2][frame][y * 17, 16].reverse + "\n" sprites[4][frame] += flat_data[y * 160 + 9 * 16, 16] + "\n" } } 5.times{|direction| sprites[direction][3] = sprites[direction][1] } # Convert sprites to ANSI coded string palette = [0, 233, 23, 108, 88, 222, 173, 98, 230, 177, 136, 17].map{ |c| "\e[48;5;#{c}m" } sprites = sprites.map{|i| i.map{|input| output = palette[0] + "\e[24A\e[1G" current_color = "" input.each_byte{|c| if c == "\n".ord current_color = "" output += palette[0] + "\e[1B\e[1G" else if current_color != palette[c - 34] current_color = palette[c - 34] output += current_color end # Using 2 spaces to make a square pixel, assuming 1:2 aspect ratio output += " " end } output } } # Hide cursor and prepare a set of blank lines print palette[0] + "\n" * 24, "\e[?25l" # Spawn thread to read input key_map = { "A" => 1, "k" => 1, # Up "B" => 0, "j" => 0, # Down "C" => 3, "l" => 3, # Right "D" => 2, "h" => 2, # Left "\3" => 4, "q" => 4 } direction = 0 frame = 0 input_thread = Thread.new{ while direction != 4 key = STDIN.getch() direction = key_map[key] || direction end } while direction != 4 print sprites[direction][frame] frame = (frame + 1) % 4 sleep 0.14 end print sprites[4][0] # Show cursor and reset colors print "\e[?25h\e[0m\n" input_thread.join