async def end_game_with_reason(self, our_ctrl: GameController, other_ctrl: GameController, our_reason: EndGameReason, other_reason: EndGameReason): our_ctrl.cancel_timeout() other_ctrl.cancel_timeout() del self.games[our_ctrl.game_id] del self.user_game_ctrl[our_ctrl.username] del self.user_game_ctrl[other_ctrl.username] del self.user_gid[our_ctrl.username] del self.user_gid[other_ctrl.username] # if this was called from logout, the user no longer exists if our_ctrl.username in self.users: self.users[ our_ctrl.username].state = ClientConnectionState.GAME_SELECTION # if this was called from logout, the user no longer exists if other_ctrl.username in self.users: self.users[other_ctrl. username].state = ClientConnectionState.GAME_SELECTION await self.send( other_ctrl.client, ProtocolMessage.create_single(ProtocolMessageType.ENDGAME, {"reason": other_reason})) await self.send( our_ctrl.client, ProtocolMessage.create_single(ProtocolMessageType.ENDGAME, {"reason": our_reason})) self.print_stats()
async def handle_shoot(self, client: Client, msg: ProtocolMessage): our_ctrl: GameController = self.user_game_ctrl[client.username] other_ctrl: GameController = self.user_game_ctrl[ our_ctrl.opponent_name] try: hit: bool = other_ctrl.run(msg) except BattleshipError as e: answer = ProtocolMessage.create_error(e.error_code) await self.send(client, answer) return except Exception as e: raise e our_ctrl.timeout_counter = 0 our_ctrl.cancel_timeout() if hit: sunk: bool = other_ctrl.ship_sunk_at_pos( msg.parameters["position"].horizontal, msg.parameters["position"].vertical) msg_hit: ProtocolMessage = ProtocolMessage.create_single( ProtocolMessageType.HIT, { "sunk": sunk, "position": msg.parameters["position"] }) await self.send(other_ctrl.client, msg_hit) await self.send(our_ctrl.client, msg_hit) our_ctrl.run(msg_hit) other_ctrl.run(msg_hit) our_ctrl.start_timeout(self.handle_timeout_wrapper) if other_ctrl.all_ships_sunk(): await self.end_game_with_reason(our_ctrl, other_ctrl, EndGameReason.YOU_WON, EndGameReason.OPPONENT_WON) else: msg_fail: ProtocolMessage = ProtocolMessage.create_single( ProtocolMessageType.FAIL, {"position": msg.parameters["position"]}) await self.send(other_ctrl.client, msg_fail) await self.send(our_ctrl.client, msg_fail) our_ctrl.run(msg_fail) other_ctrl.run(msg_fail) other_ctrl.start_timeout(self.handle_timeout_wrapper)
async def handle_timeout(self, client: Client): if not client.username in self.user_game_ctrl: # This happened once when a timeout came almost exactly when the game ended return our_ctrl: GameController = self.user_game_ctrl[client.username] if not our_ctrl.opponent_name in self.user_game_ctrl: # This happened once when a timeout came almost exactly when the game ended return other_ctrl: GameController = self.user_game_ctrl[ our_ctrl.opponent_name] our_ctrl.timeout_counter += 1 if our_ctrl.timeout_counter >= 3: # TODO: really send OPPONENT_WON? await self.end_game_with_reason(our_ctrl, other_ctrl, EndGameReason.OPPONENT_WON, EndGameReason.OPPONENT_TIMEOUT) return msg_timeout: ProtocolMessage = ProtocolMessage.create_single( ProtocolMessageType.TIMEOUT) await self.send(our_ctrl.client, msg_timeout) await self.send(other_ctrl.client, msg_timeout) our_ctrl.run(msg_timeout) other_ctrl.run(msg_timeout) other_ctrl.start_timeout(self.handle_timeout_wrapper)
async def handle_move(self, client: Client, msg: ProtocolMessage): our_ctrl: GameController = self.user_game_ctrl[client.username] other_ctrl: GameController = self.user_game_ctrl[ our_ctrl.opponent_name] try: positions: Positions = our_ctrl.run(msg) except BattleshipError as e: answer: ProtocolMessage = ProtocolMessage.create_error( e.error_code) await self.send(client, answer) return except Exception as e: raise e our_ctrl.timeout_counter = 0 our_ctrl.cancel_timeout() # notify params = {} if not len(positions.positions) == 0: params["positions"] = positions msg_moved: ProtocolMessage = ProtocolMessage.create_single( ProtocolMessageType.MOVED, params) await self.send(other_ctrl.client, msg_moved) await self.send(our_ctrl.client, msg_moved) our_ctrl.run(msg_moved) other_ctrl.run(msg_moved) other_ctrl.start_timeout(self.handle_timeout_wrapper)
async def send_cancel(self): msg = ProtocolMessage.create_single(ProtocolMessageType.CANCEL) await self.client.send_and_wait_for_answer(msg) # TODO: timeouts if self.client.last_msg_was_error: raise BattleshipError(self.client.last_error)
async def handle_place(self, client: Client, msg: ProtocolMessage): our_ctrl: GameController = self.user_game_ctrl[client.username] other_ctrl: GameController = self.user_game_ctrl[ our_ctrl.opponent_name] try: our_ctrl.run(msg) except BattleshipError as e: # TODO: maybe check if it's not an internal error answer: ProtocolMessage = ProtocolMessage.create_error( e.error_code) await self.send(client, answer) return except Exception as e: raise e # notify the other msg_placed: ProtocolMessage = ProtocolMessage.create_single( ProtocolMessageType.PLACED) await self.send(other_ctrl.client, msg_placed) # if both are on waiting, the game can start if our_ctrl.state == GameState.WAITING and other_ctrl.state == GameState.WAITING: # who starts? starting_ctrl: GameController waiting_ctrl: GameController (starting_ctrl, waiting_ctrl) = ( our_ctrl, other_ctrl) if randrange(2) == 1 else (other_ctrl, our_ctrl) youstart: ProtocolMessage = ProtocolMessage.create_single( ProtocolMessageType.YOUSTART) await self.send(starting_ctrl.client, youstart) starting_ctrl.run(youstart) starting_ctrl.timeout_counter = 0 starting_ctrl.start_timeout(self.handle_timeout_wrapper) youwait: ProtocolMessage = ProtocolMessage.create_single( ProtocolMessageType.WAIT) await self.send(waiting_ctrl.client, youwait) waiting_ctrl.run(youwait) # TODO: fix this, should be merged with state, is this even used anymore? starting_ctrl._game_started = True waiting_ctrl._game_started = True
async def handle_chat_send(self, client: Client, msg: ProtocolMessage): params: Dict[str, Any] = msg.parameters answer: Optional[ProtocolMessage] = None forward: ProtocolMessage text: str = params["text"] recipient: str = params["username"] if len(text) > ProtocolConfig.CHAT_MAX_TEXT_LENGTH: answer = ProtocolMessage.create_error( ErrorCode.SYNTAX_MESSAGE_TEXT_TOO_LONG) # check if the message is for all users elif recipient == "": forward = ProtocolMessage.create_single( ProtocolMessageType.CHAT_RECV, { "sender": client.username, "recipient": "", "text": text }) await self.msg_to_all_but_one(forward, client.username) self.print_client( client, "Forwarding chat message to all logged in users but {}".format( client.username)) elif recipient not in self.users: answer = ProtocolMessage.create_error( ErrorCode.PARAMETER_USERNAME_DOES_NOT_EXIST) else: forward = ProtocolMessage.create_single( ProtocolMessageType.CHAT_RECV, { "sender": client.username, "recipient": recipient, "text": text }) await self.msg_to_user(forward, recipient) self.print_client( client, "Forwarding chat message to '{}'".format(recipient)) if answer is not None: await self.send(client, answer)
async def client(client_id: int): async def msg_callback(msg: ProtocolMessage): print("< [{}] {}".format(client_id, msg)) def closed_callback(): print("< [{}] server closed connection".format(client_id)) async def _send_and_wait(msg: ProtocolMessage, seconds_to_wait: float = 0.0): print("> [{}] {}".format(client_id, msg)) await battleship_client.send(msg) if seconds_to_wait > 0: await asyncio.sleep(seconds_to_wait) battleship_client = BattleshipClient(loop, msg_callback, closed_callback) await battleship_client.connect(Constants.SERVER_IP, Constants.SERVER_PORT) # the following messages are just to test # normally you can just call `await battleship_client.send(msg)` # await is necessary because it's asynchronous await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.LOGIN, {"username": "******".format(client_id)})) if client_id % 2 == 0: await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.CREATE_GAME, {"board_size": 10, "num_ships": NumShips([1, 1, 1, 1, 1]), "round_time": 25, "options": GameOptions.PASSWORD, "password": "******" })) #await do_join.wait() await asyncio.sleep(10) if client_id % 2 == 1: await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.JOIN, {"game_id": int((client_id+1)/2), "password": "******"})) #await finished.wait() await asyncio.sleep(10) battleship_client.close()
async def send_join(self, game_id: int, password: str = ""): params: Dict[str, Any] = {"game_id": game_id} if not password == "": params["password"] = password msg: ProtocolMessage = ProtocolMessage.create_single( ProtocolMessageType.JOIN, params) await self.client.send_and_wait_for_answer(msg) # TODO: timeouts if self.client.last_msg_was_error: raise BattleshipError(self.client.last_error)
async def send_chat(self, username, text): if len(text) > ProtocolConfig.CHAT_MAX_TEXT_LENGTH: offset = 0 while offset < len(text): next_text = text[offset:offset + ProtocolConfig.CHAT_MAX_TEXT_LENGTH] offset += ProtocolConfig.CHAT_MAX_TEXT_LENGTH msg = ProtocolMessage.create_single( ProtocolMessageType.CHAT_SEND, { "username": username, "text": next_text }) await self.client.send(msg) else: msg = ProtocolMessage.create_single(ProtocolMessageType.CHAT_SEND, { "username": username, "text": text }) await self.client.send(msg)
async def send_get_games(self): try: msg = ProtocolMessage.create_single(ProtocolMessageType.GET_GAMES) self.games = {} await self.client.send_and_wait_for_answer(msg) except Exception as e: logging.debug("send_get_games-->".format(str(e))) # TODO: timeouts if self.client.last_msg_was_error: raise BattleshipError(self.client.last_error)
async def try_login(self, server, port, username): if not self.client.connected: await self.client.connect(server, port) if username.strip() == "": raise BattleshipError(ErrorCode.PARAMETER_INVALID_USERNAME) elif len(username) > ProtocolConfig.USERNAME_MAX_LENGTH: raise BattleshipError(ErrorCode.SYNTAX_USERNAME_TOO_LONG) msg = ProtocolMessage.create_single(ProtocolMessageType.LOGIN, {"username": username}) await self.client.send_and_wait_for_answer(msg) # TODO: timeouts if self.client.last_msg_was_error: raise BattleshipError(self.client.last_error)
async def send_delete_game(self, game_id: int): del_msg: ProtocolMessage = ProtocolMessage.create_single( ProtocolMessageType.DELETE_GAME, {"game_id": game_id}) await self.msg_to_all(del_msg)
async def send_abort(self): msg = ProtocolMessage.create_single(ProtocolMessageType.ABORT) await self.client.send_and_wait_for_answer(msg)
async def client(client_id: int): async def msg_callback(msg: ProtocolMessage): print("< [{}] {}".format(client_id, msg)) def closed_callback(): print("< [{}] server closed connection".format(client_id)) async def _send_and_wait(msg: ProtocolMessage, seconds_to_wait: float = 1.0): print("> [{}] {}".format(client_id, msg)) await battleship_client.send(msg) if seconds_to_wait > 0: await asyncio.sleep(seconds_to_wait) battleship_client = BattleshipClient(loop, msg_callback, closed_callback) await battleship_client.connect(Constants.SERVER_IP, Constants.SERVER_PORT) # the following messages are just to test # normally you can just call `await battleship_client.send(msg)` # await is necessary because it's asynchronous await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.LOGIN, {"username": "******".format(client_id)})) # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.CREATE_GAME, # {"board_size": 5, # "num_ships": NumShips([1, 2, 3, 4, 5]), # "round_time": 25, # "options": GameOptions.PASSWORD, # "password": "******" # })) # # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.CREATE_GAME, # {"board_size": 5, # "num_ships": NumShips([1, 2, 3, 4, 5]), # "round_time": 25, # "options": 0 # })) await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.CHAT_SEND, {"username": "******".format((client_id + 1) % 2), "text": "hurz from client {}".format(client_id)})) await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.CHAT_SEND, {"username": "", "text": "z"})) # # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.MOVE, {"turn_counter": 2, "ship_id": 146579, "direction": Orientation.EAST})) # # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.GAME, { # "game_id": 60000, "username": "******", "board_size": 7, "num_ships": NumShips([1, 2, 3, 4, 5]), "round_time": 25, "options": GameOptions.PASSWORD})) # # await _send_and_wait(ProtocolMessage.create_repeating(ProtocolMessageType.GAMES, [ # {"game_id": 60000, "username": "******", "board_size": 7, "num_ships": NumShips([1, 2, 3, 4, 5]), # "round_time": 25, "options": GameOptions.PASSWORD}, # {"game_id": 60001, "username": "******", "board_size": 8, "num_ships": NumShips([1, 2, 3, 4, 6]), # "round_time": 30, "options": 0}, # {"game_id": 60002, "username": "******", "board_size": 9, "num_ships": NumShips([1, 2, 3, 4, 7]), # "round_time": 35, "options": GameOptions.PASSWORD}])) # # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.JOIN, {"game_id": 60000, "password": "******"})) # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.JOIN, {"game_id": 60001})) await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.LOGOUT)) battleship_client.close()
async def client(client_id: int): async def msg_callback(msg: ProtocolMessage): print("< [{}] {}".format(client_id, msg)) def closed_callback(): print("< [{}] server closed connection".format(client_id)) async def _send_and_wait(msg: ProtocolMessage, seconds_to_wait: float = 0.5): print("> [{}] {}".format(client_id, msg)) await battleship_client.send(msg) if seconds_to_wait > 0: await asyncio.sleep(seconds_to_wait) # Ding was die Verbindung managed zum Server battleship_client = BattleshipClient(loop, msg_callback, closed_callback) await battleship_client.connect(Constants.SERVER_IP, Constants.SERVER_PORT) #await battleship_client.connect("192.168.0.1", "4242") # the following messages are just to test # normally you can just call `await battleship_client.send(msg)` # await is necessary because it's asynchronous await _send_and_wait( ProtocolMessage.create_single( ProtocolMessageType.LOGIN, {"username": "******".format(client_id)})) # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.CREATE_GAME, # {"board_size": 5, # "num_ships": NumShips([1, 2, 3, 4, 5]), # "round_time": 25, # "options": GameOptions.PASSWORD, # "password": "******" # })) # # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.CREATE_GAME, # {"board_size": 5, # "num_ships": NumShips([1, 2, 3, 4, 5]), # "round_time": 25, # "options": 0 # })) input("PUSH THE BUTTON for chatting") await _send_and_wait( ProtocolMessage.create_single( ProtocolMessageType.CHAT_SEND, { "username": "******".format((client_id + 1) % 2), "text": "client {} schießt den server ab :P".format(client_id) })) input("PUSH THE BUTTON to create a game") #await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.CHAT_SEND, {"username": "", "text": "z"})) await _send_and_wait( ProtocolMessage.create_single( ProtocolMessageType.CREATE_GAME, { "board_size": 10, "num_ships": NumShips([1, 0, 0, 0, 2]), "round_time": 25, "options": 0 })) input("PUSH THE BUTTON to place a game") msg = ProtocolMessage.create_single( ProtocolMessageType.PLACE, { "ship_positions": ShipPositions([ ShipPosition(Position(0, 0), Orientation.EAST), ShipPosition(Position(3, 0), Orientation.EAST) ]) }) await _send_and_wait(msg) #################################################################################################################### # Start Playing # #################################################################################################################### end = input("x=exit, m=move, s=shoot:_") while end is not "x": if end == "s": turn_counter = int(input("insert turn_counter to shoot: ")) x_pos = int(input("shot x_pos: ")) y_pos = int(input("shoot y_pos: ")) msg = ProtocolMessage.create_single( ProtocolMessageType.SHOOT, { "position": Position(y_pos, x_pos), "turn_counter": turn_counter }) if end == "m": turn_counter = int(input("insert turn_counter to move: ")) move_direction = int(input("insert move direction: ")) msg = ProtocolMessage.create_single( ProtocolMessageType.MOVE, { "ship_id": 0, "direction": move_direction, "turn_counter": turn_counter }) await _send_and_wait(msg) end = input("x=exit, m=move, s=shoot:_") #ABORT input("PUSH THE BOTTEN for abort") msg = ProtocolMessage.create_single(ProtocolMessageType.ABORT) await _send_and_wait(msg) # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.MOVE, {"turn_counter": 2, "ship_id": 146579, "direction": Orientation.EAST})) # # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.GAME, { # "game_id": 60000, "username": "******", "board_size": 7, "num_ships": NumShips([1, 2, 3, 4, 5]), "round_time": 25, "options": GameOptions.PASSWORD})) # # await _send_and_wait(ProtocolMessage.create_repeating(ProtocolMessageType.GAMES, [ # {"game_id": 60000, "username": "******", "board_size": 7, "num_ships": NumShips([1, 2, 3, 4, 5]), # "round_time": 25, "options": GameOptions.PASSWORD}, # {"game_id": 60001, "username": "******", "board_size": 8, "num_ships": NumShips([1, 2, 3, 4, 6]), # "round_time": 30, "options": 0}, # {"game_id": 60002, "username": "******", "board_size": 9, "num_ships": NumShips([1, 2, 3, 4, 7]), # "round_time": 35, "options": GameOptions.PASSWORD}])) # # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.JOIN, {"game_id": 60000, "password": "******"})) # await _send_and_wait(ProtocolMessage.create_single(ProtocolMessageType.JOIN, {"game_id": 60001})) #################################################################################################################### # Logout # #################################################################################################################### input("PUSH THE BUTTON to logout") await _send_and_wait( ProtocolMessage.create_single(ProtocolMessageType.LOGOUT)) battleship_client.close()