separate game logic from bot interface,

introduce exceptions instead of boolean returns,
remove repetitive code,
begin unit tests,
improve docstrings,
update to python-telegram-bot==4.1.1,
add ponyorm settings classes (unused)
This commit is contained in:
Jannes Höke
2016-05-19 20:52:50 +02:00
parent a6f2c07403
commit 6204868a18
14 changed files with 755 additions and 339 deletions

View File

@ -21,6 +21,8 @@ import logging
from game import Game
from player import Player
from errors import (AlreadyJoinedError, LobbyClosedError, NoGameInChatError,
NotEnoughPlayersError)
class GameManager(object):
@ -38,7 +40,7 @@ class GameManager(object):
"""
chat_id = chat.id
self.logger.info("Creating new game with id " + str(chat_id))
self.logger.debug("Creating new game in chat " + str(chat_id))
game = Game(chat)
if chat_id not in self.chatid_games:
@ -47,13 +49,17 @@ class GameManager(object):
self.chatid_games[chat_id].append(game)
return game
def join_game(self, chat_id, user):
def join_game(self, user, chat):
""" Create a player from the Telegram user and add it to the game """
self.logger.info("Joining game with id " + str(chat_id))
self.logger.info("Joining game with id " + str(chat.id))
try:
game = self.chatid_games[chat_id][-1]
game = self.chatid_games[chat.id][-1]
except (KeyError, IndexError):
return None
raise NoGameInChatError()
if not game.open:
raise LobbyClosedError()
if user.id not in self.userid_players:
self.userid_players[user.id] = list()
@ -61,76 +67,81 @@ class GameManager(object):
players = self.userid_players[user.id]
# Don not re-add a player and remove the player from previous games in
# this chat
# this chat, if he is in one of them
for player in players:
if player in game.players:
return False
raise AlreadyJoinedError()
else:
self.leave_game(user, chat_id)
try:
self.leave_game(user, chat)
except NoGameInChatError:
pass
player = Player(game, user)
players.append(player)
self.userid_current[user.id] = player
return True
def leave_game(self, user, chat_id):
def leave_game(self, user, chat):
""" Remove a player from its current game """
try:
players = self.userid_players[user.id]
games = self.chatid_games[chat_id]
for player in players:
for game in games:
if player in game.players:
if player is game.current_player:
game.turn()
player = self.player_for_user_in_chat(user, chat)
players = self.userid_players.get(user.id, list())
player.leave()
players.remove(player)
if not player:
raise NoGameInChatError
# If this is the selected game, switch to another
if self.userid_current[user.id] is player:
if len(players):
self.userid_current[user.id] = players[0]
else:
del self.userid_current[user.id]
return True
game = player.game
if len(game.players) < 3:
raise NotEnoughPlayersError()
if player is game.current_player:
game.turn()
player.leave()
players.remove(player)
# If this is the selected game, switch to another
if self.userid_current.get(user.id, None) is player:
if players:
self.userid_current[user.id] = players[0]
else:
return False
del self.userid_current[user.id]
del self.userid_players[user.id]
except KeyError:
return False
def end_game(self, chat_id, user):
def end_game(self, chat, user):
"""
End a game
"""
self.logger.info("Game in chat " + str(chat_id) + " ended")
players = self.userid_players[user.id]
games = self.chatid_games[chat_id]
the_game = None
self.logger.info("Game in chat " + str(chat.id) + " ended")
# Find the correct game instance to end
for player in players:
for game in games:
if player in game.players:
the_game = game
break
if the_game:
break
else:
return
player = self.player_for_user_in_chat(user, chat)
for player in the_game.players:
if not player:
raise NoGameInChatError
game = player.game
# Clear game
for player_in_game in game.players:
this_users_players = self.userid_players[player.user.id]
this_users_players.remove(player)
if len(this_users_players) is 0:
this_users_players.remove(player_in_game)
if this_users_players:
self.userid_current[player.user.id] = this_users_players[0]
else:
del self.userid_players[player.user.id]
del self.userid_current[player.user.id]
else:
self.userid_current[player.user.id] = this_users_players[0]
self.chatid_games[chat_id].remove(the_game)
return
self.chatid_games[chat.id].remove(game)
def player_for_user_in_chat(self, user, chat):
players = self.userid_players.get(user.id, list())
for player in players:
if player.game.chat.id == chat.id:
return player
else:
return None