class Sokoban::Level
Constants
- DIRECTIONS
Attributes
lnum[R]
pushes[R]
Public Class Methods
new(lnum = 1)
click to toggle source
# File lib/sokoban.rb, line 131 def initialize(lnum = 1) unless lnum.between?(1, 50) raise RangeError, "Level out of range. Choose 1-50" end @lnum = lnum @moves = [] @level = LEVELS[@lnum - 1].ljust(19 * 16) @state = [@level.dup] @pushes = 0 end
Public Instance Methods
free_boxes()
click to toggle source
# File lib/sokoban.rb, line 180 def free_boxes @level.scan(/o/).size end
inspect()
click to toggle source
# File lib/sokoban.rb, line 193 def inspect s = "Level: #{@lnum} Moves: #{moves} Pushes: #{@pushes} " s << @moves.join end
load_game()
click to toggle source
# File lib/sokoban.rb, line 205 def load_game file = Zlib::GzipReader.open(SAV_FILE) {|f| f.read } initialize(file.slice!(/\d+/).to_i) # Init @lnum file.each_char {|c| move(c.to_sym) } # Rebuild @moves end
moves()
click to toggle source
# File lib/sokoban.rb, line 184 def moves @moves.size end
parse_move(input)
click to toggle source
# File lib/sokoban.rb, line 164 def parse_move(input) # Handle multiple moves input.each_char {|c| parse_move(c) } if input.size > 1 case input.downcase when 'b'; $batch = ! $batch when 'w', 'k', '8'; move(:W) # up when 'a', 'h', '4'; move(:A) # left when 's', 'j', '2'; move(:S) # down when 'd', 'l', '6'; move(:D) # right when 'r'; initialize(@lnum) when 'u'; undo when 'q'; quit when "\u0003"; puts; exit # ^C - Quit without save end end
play()
click to toggle source
# File lib/sokoban.rb, line 142 def play while free_boxes > 0 print self if $batch # Input a string terminated by newline parse_move(gets.strip) else # Handle single key press parse_move(STDIN.getch) end if $hax break if @moves.size > 3 # Hax end end print self print "Level #{@lnum} complete! " unless @lnum == 50 print "Congratulations, on to level #{@lnum + 1}. " end STDIN.getch end
restart(lnum)
click to toggle source
The public interface to initialize()
# File lib/sokoban.rb, line 189 def restart(lnum) initialize(lnum) end
to_s()
click to toggle source
# File lib/sokoban.rb, line 198 def to_s clear_screen s = "Level: #{@lnum}\n\n" s << (0...16).map {|i| @level[i * 19, 19] }.join("\n") s << "\nMoves: #{moves} Pushes: #{@pushes}\n> " end
Private Instance Methods
[](x, y)
click to toggle source
# File lib/sokoban.rb, line 258 def [](x, y) @level[x + y * 19] end
[]=(x, y, v)
click to toggle source
# File lib/sokoban.rb, line 262 def []=(x, y, v) @level[x + y * 19] = v end
box_moved?()
click to toggle source
# File lib/sokoban.rb, line 231 def box_moved? @level.split(//).each_with_index do |char, i| if char =~ /o|\*/ return true if @state.last[i] != char end end return false end
clear_screen()
click to toggle source
# File lib/sokoban.rb, line 218 def clear_screen 30.times { puts } end
find_player()
click to toggle source
# File lib/sokoban.rb, line 253 def find_player pos = @level.index(/@|\+/) return pos % 19, pos / 19 end
move(direction)
click to toggle source
# File lib/sokoban.rb, line 273 def move(direction) x, y = find_player dx = DIRECTIONS[direction][:x] dy = DIRECTIONS[direction][:y] dest = self[x + dx, y + dy] case dest when '#' # This is a wall, no move return when 'o', '*' # Check dest2 behind box, same direction times 2 dest2 = self[x + dx * 2, y + dy * 2] if dest2 == ' ' self[x + dx * 2, y + dy * 2] = 'o' elsif dest2 == '.' self[x + dx * 2, y + dy * 2] = '*' else # Destination is blocked, no move return end # Update previous box position dest = (dest == 'o') ? ' ' : '.' @pushes += 1 end # Update player position self[x + dx, y + dy] = (dest == ' ') ? '@' : '+' # Update previous position self[x, y] = (self[x, y] == '@') ? ' ' : '.' @moves << direction.to_s # Save a copy of the level in case of undo @state << @level.dup end
quit()
click to toggle source
# File lib/sokoban.rb, line 240 def quit print "Save game? [y/n] " puts c = STDIN.getch case c when 'y', 'Y' print "Saving... " save_game end puts "Goodbye" # rescue RuntimeError in Game class raise RuntimeError end
save_game()
click to toggle source
# File lib/sokoban.rb, line 213 def save_game file = ([@lnum] << @moves).flatten.join Zlib::GzipWriter.open(SAV_FILE) {|f| f.write(file) } end
undo()
click to toggle source
# File lib/sokoban.rb, line 222 def undo if @moves.size > 0 @moves.pop @state.pop @pushes -= 1 if box_moved? @level = @state.last.dup end end