#!/usr/bin/ruby palette = ["\e[0m", "\e[1m"] + "#,'h_(e(#kek#df/)de/`(f)f.#j".scan(/../).map{|x| "\e[#{x.ord-5};#{x[1].ord}m" } + "## []()@@OO%%XX++".scan(/../) COLOR_SPACE = palette[2] # Black on dark blue. COLOR_WALL = palette[3] # Dark blue on bright blue. COLOR_BLACK0 = palette[4] # Dark gray on black. COLOR_BLACK1 = palette[5] # Bright cyan on black. COLOR_WHITE0 = palette[6] # Black on white. COLOR_WHITE1 = palette[7] # Bright cyan on white. COLOR_BLACK_TAIL = palette[8] # Black on dark gray. COLOR_WHITE_TAIL = palette[9] # White on light gray. COLOR_BLACK_TAIL1 = palette[10] # Cyan on dark gray. COLOR_WHITE_TAIL1 = palette[11] # Bright cyan on light gray. COLOR_BLACK_TOMBSTONE = palette[12] # Bright red on black. COLOR_WHITE_TOMBSTONE = palette[13] # Bright white on dark red. COLOR_SHORT_CHAIN = palette[14] # Bright white on dark cyan. COLOR_MAX_CHAIN = palette[15] # Black on bright cyan. SPRITES = # Chain images: # - First index (*2) is chain length (0..3), +2 for blinking max. # - Second index is last item color (0 or 1). ["\e[0m "] * 2 + [COLOR_BLACK0 + "[]\e[0m ", COLOR_WHITE0 + "()\e[0m "] + [COLOR_BLACK0 + "[][]\e[0m ", COLOR_WHITE0 + "()()\e[0m "] + [COLOR_BLACK1 + "[][][]\e[0m", COLOR_WHITE1 + "()()()\e[0m"] + [COLOR_BLACK0 + "[][][]\e[0m", COLOR_WHITE0 + "()()()\e[0m"] + # Tile images: # - First index (*2) is grid cell value (matches tile indices constants). # - Second index is player color (0 or 1). # # We use to make these blink by refreshing the entire screen at a very # high frame rate, which eats up a lot of bandwidth, and the blinking # isn't always consistent since the framerate isn't consistent, so we # stopped doing that. [COLOR_WALL + "##"] * 2 + [COLOR_SPACE + " "] * 2 + # Highlight items when they match player's current color. [COLOR_BLACK1 + "[]", COLOR_BLACK0 + "[]"] + [COLOR_WHITE0 + "()", COLOR_WHITE1 + "()"] + # Draw player with current color. [COLOR_BLACK1 + "@@", COLOR_WHITE1 + "OO"] + # Draw player tail with a slightly different color from the items, # otherwise it's difficult to tell the player apart from the items. # # We used to also use different tiles for different turn directions, # but that honestly did not improve the visuals by much. It might # have been useful if we use unicode line drawing characters, but for # compatibility reasons we don't use those. # # It is helpful to have different characters for different segment # of the player's tail, so that they can gauge which direction of # an enclosed area is more likely to open up soon. 3 color/character # combinations are used below for that purpose. [COLOR_BLACK_TAIL1 + "%%", COLOR_WHITE_TAIL1 + "##"] + [COLOR_BLACK_TAIL + "%%", COLOR_WHITE_TAIL + "##"] + [COLOR_BLACK_TAIL + "XX", COLOR_WHITE_TAIL + "++"] + # Highlight where player died. [COLOR_BLACK_TOMBSTONE + "@@", COLOR_WHITE_TOMBSTONE + "OO"] + # Debugging hint for when we have entered endgame. [COLOR_WALL + "[]"] * 2 + [COLOR_WALL + "()"] * 2 separator = ('a'.ord + palette.size).chr print "separator = #{separator}\n" encoded = "" last_token = nil SPRITES.each{|input| print "#{input}\e[0m -> " output = "" while input != "" palette.size.times{|i| replacement = palette[i] if input[0, replacement.size] == replacement output += ('a'.ord + i).chr input = input[replacement.size, input.size] end } end print output, "\e[0m\n" if output == last_token encoded += separator else encoded += output + separator last_token = output end } # Need to append an extra non-separator at the end, otherwise split() # will drop the trailing elements. encoded += "a" print encoded, "\n" last_token = "" decoded = encoded.split(/z/).map{|x| x == "" ? last_token : last_token = x.bytes.map{|y| palette[y - 'a'.ord]} * "" } print decoded, "\e[0m\n"