X-Git-Url: https://plomlompom.com/repos/foo.html?a=blobdiff_plain;f=server.py;h=121e22906377985100bb099759eb52f36574fdbf;hb=d7ef942b11fcd51bd82c9ffb5f133d9202a73804;hp=e9b519db5d92af4c74f34b50c5fd8df0bffdb419;hpb=43e1de9a436affa7c081fe7bb4e51ba3a1947a1e;p=plomrogue2-experiments
diff --git a/server.py b/server.py
index e9b519d..121e229 100755
--- a/server.py
+++ b/server.py
@@ -81,6 +81,13 @@ class IO_Handler(socketserver.BaseRequestHandler):
class World:
turn = 0
+ map_size = (5, 5)
+ map_ = 'xxxxx\n'+\
+ 'x...x\n'+\
+ 'x.X.x\n'+\
+ 'x...x\n'+\
+ 'xxxxx'
+ player_pos = [3, 3]
def fib(n):
@@ -91,11 +98,18 @@ def fib(n):
return fib(n-1) + fib(n-2)
+class ArgumentError(Exception):
+ pass
+
+
class CommandHandler:
- def __init__(self, world, queues_out):
- self.world = world
+ def __init__(self, queues_out):
+ from multiprocessing import Pool
self.queues_out = queues_out
+ self.pool = Pool()
+ self.world = World()
+ self.pool_result = None
def send_to(self, connection_id, msg):
"""Send msg to client of connection_id."""
@@ -106,40 +120,62 @@ class CommandHandler:
for connection_id in self.queues_out:
self.send_to(connection_id, msg)
+ def stringify_yx(self, tuple_):
+ """Transform tuple (y,x) into string 'Y:'+str(y)+',X:'+str(x)."""
+ return 'Y:' + str(tuple_[0]) + ',X:' + str(tuple_[1])
+
def cmd_fib(self, tokens, connection_id):
"""Reply with n-th Fibonacci numbers, n taken from tokens[1:].
Numbers are calculated in parallel as far as possible, using fib().
A 'CALCULATING â¦' message is sent to caller before the result.
"""
- from multiprocessing import Pool
- fib_fail = 'MALFORMED FIB REQUEST'
if len(tokens) < 2:
- self.send_to(connection_id, fib_fail)
- return
+ raise ArgumentError('FIB NEEDS AT LEAST ONE ARGUMENT')
numbers = []
for token in tokens[1:]:
- if token != '0' and token.isdigit():
- numbers += [int(token)]
- else:
- self.send_to(connection_id, fib_fail)
- return
+ if token == '0' or not token.isdigit():
+ raise ArgumentError('FIB ARGUMENTS MUST BE INTEGERS > 0')
+ numbers += [int(token)]
self.send_to(connection_id, 'CALCULATING â¦')
- with Pool(len(numbers)) as p:
- results = p.map(fib, numbers)
+ results = self.pool.map(fib, numbers)
reply = ' '.join([str(r) for r in results])
self.send_to(connection_id, reply)
def cmd_inc(self, connection_id):
- """Increment world.turn, send TURN_FINISHED, NEW_TURN to everyone."""
+ """Increment world.turn, send game turn data to everyone.
+
+ To simulate game processing waiting times, a one second delay between
+ TURN_FINISHED and NEW_TURN occurs; after NEW_TURN, some expensive
+ calculations are started as pool processes that need to be finished
+ until a further INC finishes the turn.
+ """
+ from time import sleep
+ if self.pool_result is not None:
+ self.pool_result.wait()
self.send_all('TURN_FINISHED ' + str(self.world.turn))
+ sleep(1)
self.world.turn += 1
self.send_all('NEW_TURN ' + str(self.world.turn))
+ self.send_all('MAP_SIZE ' + self.stringify_yx(self.world.map_size))
+ self.send_all('TERRAIN\n' + self.world.map_)
+ self.send_all('POSITION ' + self.stringify_yx(self.world.player_pos))
+ self.pool_result = self.pool.map_async(fib, (35, 35))
def cmd_get_turn(self, connection_id):
"""Send world.turn to caller."""
self.send_to(connection_id, str(self.world.turn))
+ def cmd_move(self, direction):
+ """Move player 'UP' or 'DOWN' depending on direction string."""
+ if not direction in {'UP', 'DOWN'}:
+ raise ArgumentError('MOVE ARGUMENT MUST BE "UP" or "DOWN"')
+ if direction == 'UP':
+ self.world.player_pos[0] -= 1
+ else:
+ self.world.player_pos[0] += 1
+ self.send_all('POSITION ' + self.stringify_yx(self.world.player_pos))
+
def cmd_echo(self, tokens, input_, connection_id):
"""Send message in input_ beyond tokens[0] to caller."""
msg = input_[len(tokens[0]) + 1:]
@@ -153,21 +189,26 @@ class CommandHandler:
def handle_input(self, input_, connection_id):
"""Process input_ to command grammar, call command handler if found."""
tokens = [token for token in input_.split(' ') if len(token) > 0]
- if len(tokens) == 0:
- self.send_to(connection_id, 'EMPTY COMMAND')
- elif len(tokens) == 1 and tokens[0] == 'INC':
- self.cmd_inc(connection_id)
- elif len(tokens) == 1 and tokens[0] == 'GET_TURN':
- self.cmd_get_turn(connection_id)
- elif len(tokens) >= 1 and tokens[0] == 'ECHO':
- self.cmd_echo(tokens, input_, connection_id)
- elif len(tokens) >= 1 and tokens[0] == 'ALL':
- self.cmd_all(tokens, input_)
- elif len(tokens) >= 1 and tokens[0] == 'FIB':
- # TODO: Should this really block the whole loop?
- self.cmd_fib(tokens, connection_id)
- else:
- self.send_to(connection_id, 'UNKNOWN COMMAND')
+ try:
+ if len(tokens) == 0:
+ self.send_to(connection_id, 'EMPTY COMMAND')
+ elif len(tokens) == 1 and tokens[0] == 'INC':
+ self.cmd_inc(connection_id)
+ elif len(tokens) == 1 and tokens[0] == 'GET_TURN':
+ self.cmd_get_turn(connection_id)
+ elif len(tokens) == 2 and tokens[0] == 'MOVE':
+ self.cmd_move(tokens[1])
+ elif len(tokens) >= 1 and tokens[0] == 'ECHO':
+ self.cmd_echo(tokens, input_, connection_id)
+ elif len(tokens) >= 1 and tokens[0] == 'ALL':
+ self.cmd_all(tokens, input_)
+ elif len(tokens) >= 1 and tokens[0] == 'FIB':
+ # TODO: Should this really block the whole loop?
+ self.cmd_fib(tokens, connection_id)
+ else:
+ self.send_to(connection_id, 'UNKNOWN COMMAND')
+ except ArgumentError as e:
+ self.send_to(connection_id, 'ARGUMENT ERROR: ' + str(e))
def io_loop(q):
@@ -188,8 +229,7 @@ def io_loop(q):
sending out replies.
"""
queues_out = {}
- world = World()
- command_handler = CommandHandler(world, queues_out)
+ command_handler = CommandHandler(queues_out)
while True:
x = q.get()
command_type = x[0]