Skip to content

Instantly share code, notes, and snippets.

@mxrnx
Created June 23, 2018 12:51
Show Gist options
  • Save mxrnx/06a628eafafdfffdc34e80984c6cdc6a to your computer and use it in GitHub Desktop.
Save mxrnx/06a628eafafdfffdc34e80984c6cdc6a to your computer and use it in GitHub Desktop.
A tiny, self-sustained implementation of Sokoban
require 'io/console'
# minimal Sokoban implementation
# by knarka
# released into the public domain
class Sokoban
def initialize
@levels = DATA.readlines.map { |r| Level.new r }
main
end
private
def main
loop do
win if @level.nil? && @levels.empty?
@level = @levels.shift if @level.nil?
@level.draw
@level.handle STDIN.getch
@level = nil if @level.done?
end
end
def win
puts 'you win!'
exit
end
class Level
def initialize(raw)
i = -1
@map = raw.split('-').map do |l|
i += 1
width ||= l.length
raise 'uneven level' unless l.length == width
l.chars.map do |c|
@pos = [i, l.index('@')] if ['@', '+'].include?(c) && @pos.nil?
c
end
end
end
def done?
@map.each { |l| l.each { |c| return false if c == 'o' } }
true
end
def draw
@map.each { |l| puts l.join }
puts
end
def handle(key)
case key
when 'j' then move 0, :+
when 'k' then move 0, :-
when 'l' then move 1, :+
when 'h' then move 1, :-
when 'q' then abort 'you lose'
end
end
private
def move(index, operator)
dpos = @pos.clone
dpos[index] = dpos[index].public_send(operator, 1)
case get_field(dpos)
when '.', ' '
move_player @pos, dpos
@pos = dpos
when 'o'
dcube = @pos.clone
dcube[index] = dcube[index].public_send(operator, 2)
if ['.', ' '].include? get_field(dcube)
move_cube dpos, dcube
move_player @pos, dpos
@pos = dpos
end
end
end
def get_field(pos)
@map[pos[0]][pos[1]]
end
def set_field(pos, value)
@map[pos[0]][pos[1]] = value
end
def move_player(old, new)
set_field(old, get_field(old) == '@' ? ' ' : '.')
set_field(new, get_field(new) == ' ' ? '@' : '+')
end
def move_cube(old, new)
set_field(old, ' ')
set_field(new, get_field(new) == '.' ? '*' : 'o')
end
end
end
Sokoban.new
__END__
#####-#.o@#-#####
#####-#. #-#o@o#-# .#-#####
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment