Created
March 30, 2012 10:13
-
-
Save simon2k/2250576 to your computer and use it in GitHub Desktop.
sokoban
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# http://www.rubyquiz.com/quiz5.html | |
# SOKOBAN | |
# gem install highline | |
require 'highline/system_extensions' | |
include HighLine::SystemExtensions | |
class String | |
# define methods: | |
# crate? garage? wall? man? | |
{ 'crate?' => /o|\*/, 'garage?' => /\.|\*/,'man?' => /@|\+/, 'wall?' => /#/ }. | |
each_pair { |name, regex| define_method(name) { match(regex) } } | |
def empty? | |
!wall? && !crate? | |
end | |
def colorize(colour) | |
"\e[#{colour}m#{self}\e[0m" | |
end | |
end | |
class Array | |
def colorize | |
colours = { '.' => 31, '#' => 35, '*' => 32, 'o' => 33, '@' => 34, '+' => 34 } | |
map { |e| colours[e] ? e.colorize(colours[e]) : e } | |
end | |
def clone | |
map(&:clone) | |
end | |
end | |
class Board | |
def initialize(filename) | |
@original_board = parse_boards(filename).shuffle.first | |
@board = @original_board.clone | |
@all_points = count_char '.' | |
@arrow | |
end | |
def display | |
system('clear') | |
puts 'SOKOBAN'.colorize(2) | |
puts '------------------------' | |
puts "Points: #{count_char('*')}/#{@all_points}".colorize(97) | |
puts '------------------------' | |
@board.each { |line| puts line.colorize.join } | |
end | |
def running? | |
@all_points != current_points | |
end | |
def wait_for_move | |
@arrow = Game::Arrows[get_character.chr.to_sym] | |
if @arrow && !next_field.wall? | |
move_crate if can_move_crate? | |
move_man if next_field.empty? | |
end | |
end | |
private | |
# define methods: | |
# move_man move_crate | |
{ :crate => %w{* o}, :man => %w{+ @} }.each_pair do |name, val| | |
define_method("move_#{name}") do | |
px, py = name.eql?(:crate) ? next_coordinaties : [x, y] | |
x, y = next_coordinaties(px, py) | |
@board[y][x] = @original_board[y][x].garage? ? val[0] : val[1] | |
@board[py][px] = @original_board[py][px].garage? ? '.' : ' ' | |
end | |
end | |
def can_move_crate? | |
x, y = next_coordinaties | |
next_field.crate? && next_field(x, y).empty? | |
end | |
def count_char(chr) | |
@board.join.scan(chr).count | |
end | |
def current_points | |
count_char '*' | |
end | |
def next_coordinaties(x = x, y = y) | |
case @arrow | |
when :right then x += 1 | |
when :left then x -= 1 | |
when :down then y += 1 | |
when :up then y -= 1 | |
end | |
[x, y] | |
end | |
def next_field(x = x, y = y) | |
x, y = next_coordinaties(x, y) | |
@board[y][x].to_s | |
end | |
def parse_boards(filename) | |
File.open(filename).read.split("\n\n"). | |
each.inject([]) do |all_boards, b| | |
all_boards << b.split("\n").each.inject([]) do |lines, line| | |
lines << line.scan(/./) | |
end | |
end | |
end | |
def x | |
@board[y].index { |e| e.man? } | |
end | |
def y | |
line = @board.detect { |r| r.include?('@') || r.include?('+') } | |
@board.index(line) | |
end | |
end | |
module Game | |
Arrows = { :j => :left, | |
:l => :right, | |
:k => :down, | |
:i => :up } | |
def self.start | |
board = Board.new('sokoban_levels.txt') | |
while board.running? | |
board.display | |
board.wait_for_move | |
end | |
board.display | |
puts 'Good job! :-)' | |
end | |
end | |
Game.start |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment