LOR contest:Python - dim13/lor GitHub Wiki
Так же, как и для Ocaml, программа состоит из четырех файлов -- advworld.py, advserver.py, hclient.py, roboclient.py.
[advworld.py]
from copy import deepcopy
class World:
def __init__(self, world_file):
self.map = []
self.items = []
f = open(world_file)
row = 0
while True:
l = f.readline().rstrip()
if l == '':
break
map_line = str(l).replace('$', ' ').replace('.', ' ')
self.map.append(list(map_line))
for col in xrange(len(l)):
if l[col] == '$':
self.items.append((row, col))
if l[col] == '.':
self.entry = (row, col)
row += 1
self.height = len(self.map)
self.width = max(len(r) for r in self.map)
self.hands_empty = True
self.position = self.entry
def gameWon(self):
ok = True
for item in self.items:
if item != self.entry:
ok = False
break
return ok and self.hands_empty
def move(self, dx, dy):
new_col = self.position[1] + dx
new_row = self.position[0] + dy
try:
new_place = self.map[new_row][new_col]
if new_place == ' ':
self.position = (new_row, new_col)
except IndexError:
pass
def action_north(self):
self.move(0, -1)
def action_south(self):
self.move(0, 1)
def action_east(self):
self.move(1, 0)
def action_west(self):
self.move(-1, 0)
def action_pickup(self):
if self.position in self.items:
self.items.remove(self.position)
self.hands_empty = False
def action_drop(self):
if not self.hands_empty:
self.hands_empty = True
self.items.append(self.position)
def performActions(self, actions):
states = []
for action in actions:
try:
getattr(self, 'action_'+action)()
states.append(deepcopy(self))
except KeyError:
pass
return states
def __str__(self):
s = []
for row in xrange(self.height):
line = ''
for col in xrange(self.width):
pos = (row, col)
try:
char = self.map[row][col]
if pos == self.position:
char = '@'
elif pos == self.entry:
char = '.'
elif pos in self.items:
char = '$'
line += char
except IndexError:
pass
s.append(line)
if self.gameWon():
s.append('You won!')
else:
s.append('Game is in progress')
if self.hands_empty:
s.append('Your hands are empty')
else:
s.append('You carry an item')
s.append('Here lie(s) %d item(s)' % (self.items.count(self.position)))
return '\n'.join(s)
[advserver.py]
from sys import argv
from Pyro.core import Daemon, initServer, ObjBase
from advworld import World
class Server(ObjBase):
def init(self, fname):
self.world = World(fname)
def read_world(self):
return self.world
def perform_actions(self, actions):
return self.world.performActions(actions)
if __name__ == '__main__':
server = Server()
server.init(argv[1])
initServer()
daemon = Daemon(port=int(argv[2]))
daemon.connect(server, 'adventure_server')
daemon.requestLoop()
[hclient.py]
from sys import stdin, stdout, argv
import Pyro.core
from roboclient import Robot
if __name__ == '__main__':
server = Pyro.core.getProxyForURI(
'PYROLOC://%s:%s/adventure_server' % (argv[1], argv[2]))
print server.read_world()
while True:
stdout.write('> ')
commands = stdin.readline().strip().lower().split()
for cmd in commands:
if cmd == 'autocollect':
robot = Robot(server)
robot.collect(server.read_world().position)
else:
print server.perform_actions([cmd])[0]
[roboclient.py]
from sys import argv
from copy import deepcopy
from time import sleep
from Pyro.core import getProxyForURI
class RoutingError(Exception):
pass
class Robot:
def __init__(self, server):
self.server = server
def findPath(self, world, target_position):
map = deepcopy(world.map)
map[world.position[0]][world.position[1]] = [world.position]
def propagate(pos):
deltas = [(0, 1), (0, -1), (1, 0), (-1, 0)]
new_positions = []
current_path = map[pos[0]][pos[1]]
for d in deltas:
new_pos = (pos[0] + d[0], pos[1] + d[1])
new_path = list(current_path) + [new_pos]
try:
location = map[new_pos[0]][new_pos[1]]
except IndexError:
location = '#'
if location != '#':
if location == ' ' or (len(location) > len(new_path)):
map[new_pos[0]][new_pos[1]] = new_path
new_positions.append(new_pos)
return list(set(new_positions))
positions = [world.position]
while True:
new_positions = []
for pos in positions:
new_positions += propagate(pos)
positions = new_positions
if not positions:
raise RoutingError()
path = map[target_position[0]][target_position[1]]
if isinstance(path, list):
break
return path
def moveTo(self, position):
world = self.server.read_world()
path = self.findPath(world, position)[1:]
return [self.stepTo(pos) for pos in path]
def stepTo(self, pos):
world = self.server.read_world()
dr = pos[0] - world.position[0]
dc = pos[1] - world.position[1]
directions = {
(0, -1): 'west',
(0, 1): 'east',
(1, 0): 'south',
(-1, 0): 'north'}
action = directions.get((dr, dc), None)
if action is None:
raise RoutingError()
return self.performAction(action)
def performAction(self, action):
print self.server.read_world()
print 'Robot action:', action
sleep(1)
self.server.perform_actions([action])
def collect(self, position):
while True:
world = self.server.read_world()
items = [i for i in world.items if i != position]
if not items:
break
self.moveTo(items[0])
self.performAction('pickup')
self.moveTo(position)
self.performAction('drop')
print world
def play(self):
self.collect(self.server.read_world().entry)
if __name__ == '__main__':
server = getProxyForURI(
'PYROLOC://%s:%s/adventure_server' % (argv[1], argv[2]))
Robot(server).play()