def __init__(self): super(GameController, self).__init__() self.players = [] self.state = GameState() self.shutdown_event = threading.Event() self.id = None self.lock_start = threading.Lock()
def _reset(self): """ Reset the game. """ logging.info('Resetting') self._stop_players() self.players = [] self.state = GameState()
def parse_header(header): game_state = GameState() base_featureset = FeatureSet() for line in header.split("\n"): line = line.strip() if line.startswith("info,"): try: _, key, value = csv_split(line) except Exception: logging.error("Choked on line: %s" % line) raise if key in ["visteam", "hometeam"]: setattr(GameState, key, value) fs_key = "game_%s" % key if fs_key in FeatureSet.__slots__: setattr(FeatureSet, fs_key, value) return game_state, base_featureset
class XMLRPCCliPlayer(players.CliPlayer): """ XML-RPC command line interface human player. """ def __init__(self, player_name): players.CliPlayer.__init__(self, player_name) self.game_state = GameState() self.hand = None def handle_event(self, event): if isinstance(event, CardPlayedEvent): self.card_played(event.player, event.card, event.game_state) elif isinstance(event, MessageEvent): self.send_message(event.sender, event.message) elif isinstance(event, TrickPlayedEvent): self.trick_played(event.player, event.game_state) elif isinstance(event, TurnEvent): self.game_state.update(event.game_state) state = self.controller.get_state(self.id) self.hand = state['hand'] self.game_state.update(state['game_state']) elif isinstance(event, StateChangedEvent): self.game_state.update(event.game_state) else: print "unknown event: %s" % event def wait_for_turn(self): """ Wait for this player's turn. """ while True: time.sleep(0.5) if self.controller is not None: events = self.controller.get_events(self.id) for event in events: self.handle_event(event) if self.game_state.turn_id == self.id: break
def main(): input_queue = queue.Queue() input_thread = threading.Thread(target=add_input, args=(input_queue, )) input_thread.daemon = True input_thread.start() outs, ins = [], [] turn = 0 total_turns = 0 prev_turn = -1 pygame.key.set_repeat(500, 30) if len(sys.argv) > 1 and sys.argv[1] == '-s': d = os.path.dirname(os.path.realpath(__file__)) fname = os.path.join(d, "logs", "commands_{:.0f}".format(time.time())) cf = open(fname, "w") else: cf = None global sz while True: while not input_queue.empty(): line = input_queue.get() if line.startswith("->"): if cf is not None: cf.write(line) outs.append(parse_line(line[3:].strip())) if line.startswith("<-"): if cf is not None: cf.write(line) ins.append(parse_line(line[3:].strip())) for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_1: sz += 1 if event.key == pygame.K_2 and sz > 1: sz -= 1 if event.key == pygame.K_o: if turn > 1: turn -= 1 if event.key == pygame.K_p: if turn + 1 < total_turns: turn += 1 total_turns = min(len(ins), len(outs)) if total_turns == 0: continue try: gs = GameState(ins[turn]) except: if turn == 0 and total_turns > 1: turn += 1 gs = GameState(ins[turn]) screen.fill(0) if turn != prev_turn: print("=" * 20) print("turn {}/{}".format(turn, total_turns)) print("sent -> {}".format(outs[turn])) print("got <- {}".format(ins[turn])) prev_turn = turn last_text_pos_y = 40 for sh in gs.ships: if sh.player_type == gs.my_type: color = (0, 192, 0) else: color = (192, 0, 0) screen_pos = to_screen(sh.pos) if sh.player_type == DEFENDER_ID: pygame.draw.circle(screen, color, screen_pos, 15, 2) else: pygame.draw.rect( screen, color, (screen_pos[0] - 15, screen_pos[1] - 15, 30, 30), 2) pygame.draw.line(screen, color, screen_pos, to_screen(sh.pos + sh.speed), 2) screen.blit(font.render(str(sh.ship_id), 1, color), (screen_pos[0] - 35, screen_pos[1] - 12)) screen.blit( small_font.render( "{}+{}".format(sh.pos, sh.speed).replace(" ", ""), 1, color), (screen_pos[0] + 20, screen_pos[1] - 6)) text = '(id:{}, energy:{}, shoot_energy:{}, rest:{}, health:{}, tired:{}/{})'.format( sh.ship_id, sh.energy, sh.shoot_energy, sh.rest, sh.health, sh.tiredness, sh.tiredness_limit) for m in sh.prev_moves: text += " " + str(m) if m.move_type == 2: target_pos = to_screen(m.pos()) pygame.draw.line(screen, color, screen_pos, target_pos, 1 + m.args[2] // 10) text_info = font_ship_info.render(text, 1, color) screen.blit(text_info, (10, last_text_pos_y)) last_text_pos_y += 24 border_color = (200, 200, 200) draw_centered_rect(border_color, gs.world_size, 2) draw_centered_rect(border_color, gs.planet_size, 0) # fill tt = font.render( 'turn {}/{}; sz = {}; finished = {}'.format( turn, total_turns, sz, gs.game_finished), 1, (192, 192, 192)) # print(dir(tt.get_rect())) screen.blit(tt, (10, 5)) pygame.display.update()
def __init__(self, player_name): players.CliPlayer.__init__(self, player_name) self.game_state = GameState() self.hand = None
class GameController(object): """ The controller class that runs everything. """ def __init__(self): super(GameController, self).__init__() self.players = [] self.state = GameState() self.shutdown_event = threading.Event() self.id = None self.lock_start = threading.Lock() def register_player(self, player): """ Register a new Player. """ if player.id in [pl.id for pl in self.players]: raise GameError('Player already registered to game') if len(self.players) == 4: raise GameError('Already 4 players registered') self.players.append(player) # TODO: should we generate UUIDs instead? if player.id == None: player.id = str(self.players.index(player)) player.team = self.players.index(player) % 2 def player_leave(self, player_id): """ Player leaves the game. """ self._send_msg('Player %s quit' % player_id) plr = self.get_player(player_id) if plr: self.players.remove(plr) plr.hand.clear() plr.stop() # stops the thread in case of ThreadedPlayer # reset the game unless we are still in OPEN state if self.state.state != GameState.OPEN: self._reset() def player_quit(self, player_id): """ Leave and quit the game. """ self.player_leave(player_id) self.shutdown_event.set() def get_player(self, player_id): """ Get player by id. """ for plr in self.players: if plr.id == player_id: return plr return None def _get_player_in_turn(self, turn): """ Get player who is in turn. """ if turn >= 0: return self.players[turn % 4] return None def _next_in_turn(self, thenext=None): """ Set the next player in turn. """ self.state.next_in_turn(thenext) self.state.turn_id = self._get_player_in_turn(self.state.turn).id def _set_state(self, new_state): """ Change the game state. """ self.state.state = new_state for player in self.players: player.state_changed(self.state) def _stop_players(self): """ Stop all running players. """ self._set_state(GameState.STOPPED) for player in self.players: if player: player.act(self, self.state) for player in self.players: if player and isinstance(player, players.ThreadedPlayer): if player.is_alive() and player.thread is not threading.current_thread(): player.join() def _reset(self): """ Reset the game. """ logging.info('Resetting') self._stop_players() self.players = [] self.state = GameState() def _get_team_players(self, team): """ Get players in a team. """ return [player for player in self.players if player.team == team] def _get_team_str(self, team): """ Get team string representation. """ plrs = self._get_team_players(team) return '%d (%s)' % (team + 1, ', '.join([pl.player_name for pl in plrs])) def _send_msg(self, msg): """ Send a message to all players. """ logging.debug(msg) for player in self.players: player.send_message('', msg) @synchronized_method('lock_start') def start_game(self): """ Start the game. """ if self.state.state != GameState.OPEN: raise GameError('Game already started') if len(self.players) < 4: raise GameError('Not enough players') for player in self.players: player.start() self._start_new_hand() def wait_for_shutdown(self): """ Wait for shutdown event and shut down after it. """ self.shutdown_event.wait() self.shutdown() def _signal_act(self): """ Tell the player who is in turn to act. """ self._get_player_in_turn(self.state.turn).act(self, self.state) def _start_new_hand(self): """ Start a new hand. """ logging.info('New hand') self.state.tricks = [0, 0] # create a full deck deck = CardSet.new_full_deck() logging.debug('deck is %s', str(deck)) deck.shuffle() logging.debug('shuffled deck %s', str(deck)) deck.deal([player.hand for player in self.players]) for player in self.players: player.hand.sort() logging.debug("%s's hand: %s", player.player_name, str(player.hand)) # voting self.state.mode = NOLO self.state.rami_chosen_by = None self._set_state(GameState.VOTING) # uncomment following to skip voting #self._set_state(GameState.ONGOING) # start the game self._next_in_turn(self.state.dealer + 1) self._signal_act() def _trick_played(self): """ A trick (4 cards) has been played. """ table = self.state.table high = table.get_cards(suit=table[0].suit).get_highest() high_played_by = self.get_player(high.played_by) team = high_played_by.team self._send_msg('Team %s takes this trick' % (self._get_team_str(team))) self.state.tricks[team] += 1 self._send_msg('Tricks: %s' % self.state.tricks) # send signals for plr in self.players: plr.trick_played(high_played_by, self.state) self.state.table.clear() # do we have a winner? if self.state.tricks[0] + self.state.tricks[1] == 13: self._hand_played() else: self._next_in_turn(self.players.index(high_played_by)) self._signal_act() def _hand_played(self): """ A hand has been played. """ if self.state.mode == NOLO: if self.state.tricks[0] < self.state.tricks[1]: winner = 0 loser = 1 else: winner = 1 loser = 0 score = (7 - self.state.tricks[winner]) * 4 else: if self.state.tricks[0] > self.state.tricks[1]: winner = 0 loser = 1 else: winner = 1 loser = 0 if self.state.rami_chosen_by.team != winner: self._send_msg("Double points for taking opponent's rami!") score = (self.state.tricks[winner] - 6) * 8 else: score = (self.state.tricks[winner] - 6) * 4 self._send_msg('Team %s won this hand with %d tricks' % (self._get_team_str(winner), self.state.tricks[winner])) if self.state.score[loser] > 0: self._send_msg('Team %s fell down' % (self._get_team_str(loser))) self.state.score = [0, 0] else: self.state.score[winner] += score if self.state.score[winner] > 52: self._send_msg('Team %s won with score %d!' % (self._get_team_str(winner), self.state.score[winner])) self.shutdown_event.set() return else: self._send_msg('Team %s is at %d' % (self._get_team_str(winner), self.state.score[winner])) self.state.dealer = (self.state.dealer + 1) % 4 self._start_new_hand() def shutdown(self): """ Shutdown the game. """ self._stop_players() sys.exit(0) def _vote_card(self, player, card): """ Player votes with a card. """ table = self.state.table card = copy.copy(card) card.played_by = player.id table.append(card) # fire signals for plr in self.players: plr.card_played(player, card, self.state) if card.suit == common.DIAMOND or card.suit == common.HEART: self.state.mode = RAMI self.state.rami_chosen_by = player self._next_in_turn(self.players.index(player) - 1) self._begin_game() elif len(table) == 4: self.state.mode = NOLO self._next_in_turn() self._begin_game() else: self._next_in_turn() self._signal_act() def _begin_game(self): if self.state.mode == RAMI: self._send_msg('Rami it is') else: self._send_msg('Nolo it is') self._send_msg('Game on, %s begins!' % self._get_player_in_turn(self.state.turn)) self.state.table.clear() self._set_state(GameState.ONGOING) def play_card(self, player, card): """ Play one card on the table. """ if self._get_player_in_turn(self.state.turn).id != player.id: raise RuleError('Not your turn') table = self.state.table if self.state.state == GameState.VOTING: self._vote_card(player, card) elif self.state.state == GameState.ONGOING: # make sure that suit is followed if len(table) > 0 and card.suit != table[0].suit: if len(player.hand.get_cards(suit=table[0].suit)) > 0: raise RuleError('Suit must be followed') # make sure that the player actually has the card try: table.append(player.hand.take(card)) card.played_by = player.id except ValueError: raise RuleError('Invalid card') if len(table) == 4: # TODO: there must be a better way for this turn_backup = self.state.turn self.state.turn = TURN_NONE # fire signals with temporary state # this is to let clients know that all four cards have been played # and it's nobody's turn yet for plr in self.players: plr.card_played(player, card, self.state) self.state.turn = turn_backup self._trick_played() else: self._next_in_turn() # fire signals for plr in self.players: plr.card_played(player, card, self.state) self._signal_act()