Skip to content

Instantly share code, notes, and snippets.

@SonOfLilit
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SonOfLilit/1c7c20e3bbfd01c780c1 to your computer and use it in GitHub Desktop.
Save SonOfLilit/1c7c20e3bbfd01c780c1 to your computer and use it in GitHub Desktop.
Pythonists, I challenge you to a game of Sokoban Golf!
'''
Sokoban Golf by Aur Saraf
At line 145 you will find a very naive solution for level 1.
You can easily learn the API from it.
How few lines do you need for solutions to levels 1, 2, and 3?
Do not modify the game or the levels in any way. Just remove the
level 1 solution and uncomment the level 2 and level 3 boards,
and try to solve all three in as few characters as possible.
The challenge is intentionally on ALL THREE LEVELS TOGETHER. You
should be writing utility functions that help with more than one
level.
Good luck, and have fun!
'''
WALL = '#'
EMPTY = ' '
PLAYER = '@'
CRATE = '*'
EMPTY_DESTINATION = 'X'
CRATE_IN_DESTINATION = 'V'
EMPTY_SYMBOLS = (EMPTY, EMPTY_DESTINATION)
CRATE_SYMBOLS = (CRATE, CRATE_IN_DESTINATION)
DIRECTIONS = SOUTH, WEST, NORTH, EAST = 'SWNE'
_dirs = lambda values: dict(zip(DIRECTIONS, values))
DIRECTION_VECTOR = _dirs((
(1, 0),
(0, -1),
(-1, 0),
(0, 1),
))
LEFT = _dirs((DIRECTIONS[(i - 1) % 4] for i in xrange(4)))
RIGHT = _dirs((DIRECTIONS[(i + 1) % 4] for i in xrange(4)))
class QuietBoard(object):
def __init__(self, level):
self.board = [list(row) for row in level.splitlines()]
self.crates_at_large = level.count(CRATE)
self.player = self._player_position(self.board)
self.orientation = SOUTH
self.on_destination = False
def _player_position(self, board):
for i, row in enumerate(board):
if PLAYER in row:
return (i, row.index(PLAYER))
assert False
def __str__(self):
return '\n'.join(''.join(row) for row in self.board) + '\n' + str(self.orientation)
def is_win(self):
return self.crates_at_large == 0
def at(self, (row, column)):
return self.board[row][column]
def forward(self):
in_front = self._in_front(self.player)
if self._is_movable_crate(in_front):
self._slide_crate(in_front)
if self._is_empty(in_front):
self._slide_player()
def left(self):
self.orientation = LEFT[self.orientation]
def right(self):
self.orientation = RIGHT[self.orientation]
def _is_movable_crate(self, position):
return self._is_crate(position) and self._is_empty(self._in_front(position))
def _in_front(self, (row, column)):
drow, dcolumn = DIRECTION_VECTOR[self.orientation]
return row + drow, column + dcolumn
def _is_empty(self, position):
return self.at(position) in EMPTY_SYMBOLS
def _is_crate(self, position):
return self.at(position) in CRATE_SYMBOLS
def _slide_crate(self, position):
if self.at(position) == CRATE_IN_DESTINATION:
empty = EMPTY_DESTINATION
self.crates_at_large += 1
else:
empty = EMPTY
self._put(empty, position)
destination = self._in_front(position)
if self.at(destination) == EMPTY_DESTINATION:
crate = CRATE_IN_DESTINATION
self.crates_at_large -= 1
else:
crate = CRATE
self._put(crate, destination)
def _slide_player(self):
destination = self._in_front(self.player)
empty = EMPTY_DESTINATION if self.on_destination else EMPTY
self.on_destination = self.at(destination) == EMPTY_DESTINATION
self._put(empty, self.player)
self._put(PLAYER, destination)
self.player = destination
def _put(self, symbol, (row, column)):
assert (symbol in EMPTY_SYMBOLS) != self._is_empty((row, column))
self.board[row][column] = symbol
class Board(QuietBoard):
def __init__(self, level):
super(Board, self).__init__(level)
print self
print 'Start!'
def forward(self):
super(Board, self).forward()
print self
if self.is_win():
print 'You beat this level!'
print
LEVEL0 = '''\
#############
#@ * X#
#############'''
b = QuietBoard(LEVEL0)
b.left()
for _ in range(10): b.forward()
assert b.is_win()
LEVEL1 = '''\
#############
#@ X#
# ##*########
# ########
#############'''
b = Board(LEVEL1)
b.forward()
b.forward()
b.left()
b.forward()
b.forward()
b.forward()
b.left()
b.forward()
b.left()
b.left()
b.forward()
b.right()
b.forward()
b.forward()
b.forward()
b.right()
b.forward()
b.forward()
b.right()
for _ in range(9): b.forward()
LEVEL2 = '''\
#############
# ###### #
#@ #
##*#*# ####X#
## ####X#
#############'''
#b = Board(LEVEL2)
# Mini Cosmos 01 (c) Aymeric Du Peloux
LEVEL3 = '''\
#####
### #
# * # ##
# # X #
# # #
## # #
#@ ###
##### '''
#b = Board(LEVEL3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment