예제 #1
0
파일: proto.py 프로젝트: peterrecore/plyus
class ProtoPlayer(db.Model):
    """This class will link player objects to a user object, without the player object having
    to know anything about Users. This is an extra level of indirection, but without it,
     player objects, and therefore the whole game engine would need to know about Users"""
    __tablename__ = "proto_players"
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey(User.id))
    user = db.relationship("User")
    player_id = db.Column(db.Integer, db.ForeignKey(Player.id))
    player = db.relationship("Player", uselist=False)
    proto_game_id = db.Column(db.Integer,
                              db.ForeignKey(ProtoGame.id),
                              nullable=False)

    def __init__(self, u):
        self.user_id = u.id

    #        self.proto_game_id = pg_id

    def __repr__(self):
        return "ProtoPlayer(user_id=%s)" % self.user_id
예제 #2
0
파일: user.py 프로젝트: peterrecore/plyus
class User(db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True)
    nickname = db.Column(db.String(64), unique=True)
    email = db.Column(db.String(120), unique=True)

    proto_players = db.relationship("ProtoPlayer")

    def is_authenticated(self):
        return True

    def is_active(self):
        return True

    def is_anonymous(self):
        return False

    def get_id(self):
        return str(self.id)

    def __repr__(self):
        return '<User %r>' % (self.nickname)
예제 #3
0
파일: misc.py 프로젝트: peterrecore/plyus
class BuildingDeck(db.Model):
    __tablename__ = "buildingdecks"
    id = db.Column(db.Integer, primary_key=True)
    game_state_id = db.Column(db.Integer, db.ForeignKey("gamestates.id"))
    template = db.Column(db.String)
    cards = db.Column(MutableList.as_mutable(JSONEncoded))
    card_map = None
    full_cards = None

    def __init__(self, template):
        """ template is a file name for now.  Might be a database id later """
        self.template = template
        self._construct_card_map()
        self.cards = list(self.card_map.keys())

    def _construct_card_map(self):

        if self.full_cards is None:
            self.full_cards = self._create_deck_from_csv(self.template)

        if self.card_map is None:
            self.card_map = dict([(c.id, c) for c in self.full_cards])

    def card_for_id(self, card_id):
        if self.card_map is None:
            self._construct_card_map()
        return self.card_map[card_id]

    def _create_deck_from_csv(self, filename):

        def card_from_line(line):
            return Building(int(line[0]), line[1], int(line[2]), line[3])

        with open(filename, 'r') as myfile:
            lines = csv.reader(myfile)
            return [card_from_line(line) for line in lines]
예제 #4
0
파일: misc.py 프로젝트: peterrecore/plyus
class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    num = db.Column(db.Integer)
예제 #5
0
파일: proto.py 프로젝트: peterrecore/plyus
class ProtoGame(db.Model):
    WAITING_FOR_PLAYERS = 1
    WAITING_TO_START = 2
    PLAYING = 3
    FINISHED = 4
    _status_descriptions = {(WAITING_FOR_PLAYERS, "Waiting For Players"),
                            (WAITING_TO_START, "Waiting To Start"),
                            (FINISHED, "Finished"), (PLAYING, "In Progress")}

    __tablename__ = "proto_games"
    id = db.Column(db.Integer, primary_key=True)

    status = db.Column(db.String)
    num_players = db.Column(db.Integer)
    real_game = db.Column(db.Integer, db.ForeignKey(GameState.id))
    proto_players = db.relationship("ProtoPlayer")

    owner_id = db.Column(db.Integer, db.ForeignKey(User.id))

    def __init__(self, n, owner):
        self.owner_id = owner.id
        self.num_players = n
        pp = ProtoPlayer(owner)
        self.proto_players = [pp]
        self.status = self.WAITING_FOR_PLAYERS

    def can_user_join(self, user):
        if self.is_full():
            return False
            #TODO: Should this be done via a sql query or a for loop like this?
        for pp in self.proto_players:
            if user.id == pp.user_id:
                return False
        return True

    def join_user(self, user):
        if self.can_user_join(user):
            pp = ProtoPlayer(user)
            self.proto_players.append(pp)
            if self.is_full():
                self.status = self.WAITING_TO_START
            logging.info(
                "user %s has been added as protoplayer %s to protogame %s",
                user, pp, self)
        else:
            logging.warn("user %s can't join protogame %s but was trying to.",
                         user, self)
            raise FatalPlyusError(
                "Can't join this game. maybe because game is full?")

    def can_user_start(self, user):
        if self.is_full() and user.id == self.owner_id:
            return True
        return False

    def is_full(self):
        return len(self.proto_players) >= self.num_players

    def get_status_desc(self):
        return self._status_descriptions[self.status]

    def num_joined_players(self):
        return len(self.proto_players)
예제 #6
0
class GameState(db.Model):
    __tablename__ = 'gamestates'
    id = db.Column(db.Integer, primary_key=True)
    stage = db.Column(db.String)
    step = db.Column(db.String)
    phase = db.Column(db.String)
    players = db.relationship("Player", order_by="Player.position")
    base_seed = db.Column(db.Integer)
    building_card_deck = db.relationship(BuildingDeck, uselist=False)
    num_players = db.Column(db.Integer)
    round_num = db.Column(db.Integer)
    cur_player_index = db.Column(db.Integer)
    player_with_crown_token = db.Column(db.Integer)
    winner = db.Column(db.Integer)
    round = db.relationship("Round", uselist=False, backref="game_state")
    created_by = db.relationship("Player", uselist=False)

    def __init__(self, base_seed, created_by, num_players, deck_template=None):
        self.stage = Stage.PRE_GAME
        self.step = Step.NO_STEP
        self.base_seed = base_seed
        if deck_template is None:
            deck_template = 'decks/deck_test_60.csv'
        self.building_card_deck = BuildingDeck(deck_template)
        self.round_num = -1

        self.num_players = num_players

        self.players = [created_by]
        self.winner = None
        self.cur_player_index = 0

    def add_player(self, player):
        if self.stage != Stage.PRE_GAME:
            raise FatalPlyusError("Can't add players except in stage PRE_GAME")
        if len(self.players) >= self.num_players:
            raise FatalPlyusError("Game already has %s players." %
                                  self.num_players)

        self.players.append(player)

    def start_game(self):

        if len(self.players) < self.num_players:
            logging.error(
                "trying to start game %s with only %s players, but expecting %s players"
                % (self.id, len(self.players), self.num_players))
            raise FatalPlyusError("Not all players have joined yet")
        if self.stage != Stage.PRE_GAME:
            raise FatalPlyusError(
                "Can't start game except from stage PRE_GAME  (in stage %s now)"
                % (self.stage, ))

        rand_gen = self.get_random_gen()
        rand_gen.shuffle(self.players)
        rand_gen.shuffle(self.building_card_deck.cards)

        for i, p in enumerate(self.players):
            p.set_position(i)
            #TODO:  replace magic number with actual number of cards in starting hand.
            p.buildings_in_hand.extend(
                util.draw_n(self.building_card_deck.cards, 4))

        self.round = Round(self)
        self.player_with_crown_token = 0  #this player gets to go first when picking a role
        self.stage = Stage.PLAYING
        self.start_new_round()

    def to_dict_for_public(self):
        d = {}
        fields_to_copy = [
            'round_num', 'player_with_crown_token', 'stage', 'phase', 'step',
            'cur_player_index', 'num_players', 'winner'
        ]
        for k in fields_to_copy:
            if k in self.__dict__:
                d[k] = self.__dict__[k]

        if self.id:
            d['id'] = self.id

        d['players'] = [
            p.to_dict_for_public(self.building_card_deck) for p in self.players
        ]
        d['building_card_deck_len'] = len(self.building_card_deck.cards)

        r = {}
        if self.round:
            r = self.round.to_dict_for_public()
        d['round'] = r

        return d

    def to_dict_for_player(self, player):
        d = self.to_dict_for_public()

        r = self.round.to_dict_for_public()
        logging.debug("in todictforplayer %s" % (player))
        if player.position == self.cur_player_index and self.phase == Phase.PICK_ROLES:
            logging.debug("assigning role_draw_pile now")
            r['role_draw_pile'] = self.round.role_draw_pile
        else:
            logging.debug(" %s not equal %s" %
                          (player.position, self.cur_player_index))
            logging.debug("or  %s not equal %s" %
                          (self.phase, Phase.PICK_ROLES))
        d['round'] = r
        return d

    def advance_cur_player_index(self):
        self.cur_player_index = (self.cur_player_index + 1) % self.num_players

    def __repr__(self):
        return ("phase=%s, step=%s, cur_player_index: %s, round=%s" %
                (self.phase, self.step, self.cur_player_index, self.round))

    def finish_round(self):
        logging.debug("made it to finish_round with stage as %s" % self.stage)
        #TODO: announce dead player if any

        # if we are in the end_game (someone built 8 things)
        # and we are done with the round, game is over
        if self.stage == Stage.END_GAME:
            self.do_game_over_calculations()
            self.stage = Stage.GAME_OVER
        logging.info("after end game check, stage is %s" % self.stage)
        #if the konig was around, give that player the crown
        m = self.round.gen_role_to_plyr_map()
        if 4 in m:
            #TODO:  announce which player now has the crown
            self.player_with_crown_token = m[4]

    def start_new_round(self):
        logging.info("starting new round")
        self.round = Round(self)
        self.cur_player_index = self.player_with_crown_token
        self.phase = Phase.PICK_ROLES
        self.step = Step.PICK_ROLE
        self.round_num += 1

        for p in self.players:
            p.revealed_roles = []

    def get_cur_plyr(self):
        return self.players[self.cur_player_index]

    # this should only be called at the end of a round, after
    # all players have taken their turn and we are in the
    # END_GAME stage
    def do_game_over_calculations(self):

        rankings = []
        for p in self.players:

            basic_points = 0
            bonus_points = 0
            colors = {}
            buildings = map(self.building_card_deck.card_for_id,
                            p.buildings_on_table)
            for d in buildings:
                basic_points += d.points
                colors[d.color] = True

            if len(colors.keys()) == 5:
                p.rainbow_bonus = True
                bonus_points += 3

            if len(p.buildings_on_table) >= 8:
                bonus_points += 2

            if p.first_to_eight_buildings:
                bonus_points += 2

            p.points = basic_points + bonus_points
            p.ranking = (p.points, p.gold, basic_points)
            #TODO:  implement official tiebreaker
        ranked_players = sorted(self.players,
                                key=lambda p: p.ranking,
                                reverse=True)
        self.winner = ranked_players[0].name

    def get_random_gen(self):
        cur_plyr = self.get_cur_plyr()
        seed = str(self.base_seed) + str(self.round_num * 117) + str(
            self.cur_player_index * 13)

        seed = seed + self.step
        str(cur_plyr.name) + str(cur_plyr.buildings_in_hand)
        return random.Random(seed)
예제 #7
0
파일: round.py 프로젝트: peterrecore/plyus
class Round(db.Model):
    __tablename__ = 'rounds'
    id = db.Column(db.Integer, primary_key=True)
    game_state_id = db.Column(db.Integer, db.ForeignKey('gamestates.id'))
    has_used_power = db.Column(MutableList.as_mutable(JSONEncoded))
    has_taken_bonus = db.Column(MutableList.as_mutable(JSONEncoded))
    num_seven_builds_left = db.Column(db.Integer)
    dead_role = db.Column(db.Integer)
    mugged_role = db.Column(db.Integer)

    role_draw_pile = db.Column(MutableList.as_mutable(JSONEncoded))
    face_up_roles = db.Column(MutableList.as_mutable(JSONEncoded))
    face_down_roles = db.Column(MutableList.as_mutable(JSONEncoded))

    def gen_plyr_to_role_map(self):
        m = {}
        for p in self.game_state.players:
            l = []
            l.extend(p.roles)
            m[p.position] = l
        return m

    def gen_role_to_plyr_map(self):
        m = {}
        for p in self.game_state.players:
            for r in p.roles:
                m[r] = p.position
        return m


    def __init__(self, game_state):
        self.game_state = game_state

        self.has_used_power = []
        self.has_taken_bonus = []
        self.num_seven_builds_left = 3
        self.dead_role = None
        self.mugged_role = None

        players = game_state.players

        for p in players:
            self.has_used_power.append(False)
            self.has_taken_bonus.append(False)
            p.roles = []
            p.cur_role = None

        face_up_num, face_down_num = self.role_setup_for_n_players(len(players))
        self.role_draw_pile = [1, 2, 3, 4, 5, 6, 7, 8]
        game_state.get_random_gen().shuffle(self.role_draw_pile)
        self.face_up_roles = util.draw_n(self.role_draw_pile, face_up_num)
        self.face_down_roles = util.draw_n(self.role_draw_pile, face_down_num)

    def mark_role_picked(self, role, player_id):
        if player_id not in range(0, self.game_state.num_players):
            raise FatalPlyusError("bad player-id")

        logging.info("marking %s as picked by %s" % (role, player_id))

        # logging.info("before appending, plyr_to_role_map is %s" % (repr(self.plyr_to_role_map)))
        # self.plyr_to_role_map[player_id].append(role)
        # logging.info("after appending, plyr_to_role_map is %s" % (repr(self.plyr_to_role_map)))
        # self.role_to_plyr_map[role] = player_id
        self.role_draw_pile.remove(role)

    def role_setup_for_n_players(self, n):
        # return (num_face_up, num_face_down)
        if n == 2: return (0, 1)
        if n == 3: return (0, 1)
        if n == 4: return (2, 1)
        if n == 5: return (1, 1)
        if n == 6: return (0, 1)
        raise FatalPlyusError("Wrong number of players: %s" % n)

    def done_picking(self):
        #if no player still needs to choose, we're done picking
        # easy case - if everyone has picked one role we're done

        roles_picked = util.flatten(self.gen_plyr_to_role_map().values())
        logging.info("roles_picked is %s" % roles_picked)
        num_roles_picked = len(roles_picked)
        num_players = len(self.game_state.players)

        num_roles_per_player = 1

        if num_players <= 3:
            num_roles_per_player = 2

        return num_roles_picked >= num_players * num_roles_per_player

    def __repr__(self):
        return "Round(draw:%s, up:%s, down:%s\n    plyr_to_role:%s  role_to_plyr:%s" % (self.role_draw_pile,
                                                                                        self.face_up_roles,
                                                                                        self.face_down_roles,
                                                                                        self.gen_plyr_to_role_map(),
                                                                                        self.gen_role_to_plyr_map())

    def to_dict_for_public(self):
        d = {}
        fields_to_copy = ['face_up_roles', 'has_used_power', 'has_taken_bonus', 'num_seven_builds_left']

        for k in fields_to_copy:
            d[k] = self.__dict__[k]

        return d
예제 #8
0
파일: player.py 프로젝트: peterrecore/plyus
class Player(db.Model):
    __tablename__ = 'players'

    id = db.Column(db.Integer, primary_key=True)
    gamestate_id = db.Column(db.Integer,
                             db.ForeignKey(GameState.id),
                             nullable=False)
    name = db.Column(db.String)
    position = db.Column(db.Integer)
    gold = db.Column(db.Integer)
    buildings_on_table = db.Column(MutableList.as_mutable(JSONEncoded))
    buildings_in_hand = db.Column(MutableList.as_mutable(JSONEncoded))
    buildings_buffer = db.Column(MutableList.as_mutable(JSONEncoded))
    cur_role = db.Column(db.Integer)
    roles = db.Column(MutableList.as_mutable(JSONEncoded))
    revealed_roles = db.Column(MutableList.as_mutable(JSONEncoded))
    rainbow_bonus = db.Column(db.Boolean)
    first_to_eight_buildings = db.Column(db.Boolean)
    points = db.Column(db.Integer)

    def __init__(self, n):
        self.name = n
        self.position = None
        self.gold = 2
        self.buildings_on_table = []
        self.buildings_in_hand = []
        self.buildings_buffer = []
        self.cur_role = None
        self.roles = []
        self.revealed_roles = []
        self.rainbow_bonus = False
        self.first_to_eight_buildings = False
        self.points = None

    #current player chooses to get gold
    def take_gold(self):
        self.gold += 2

    #when current player chooses to draw cards
    def take_cards(self, cards):
        if len(cards) < 2:
            #TODO: figure out and implement rule on reshuffling building cards
            raise FatalPlyusError("Building deck is out of cards.")
        self.buildings_buffer = draw_n(cards, 2)

    def set_position(self, i):
        self.position = i

    def __repr__(self):
        return "Player(name=%s, pos=%s, cur_role= %s, roles=%s, gold=%s, hand=%r, dists=%s)" % (
            self.name, self.position, self.cur_role, self.roles, self.gold,
            self.buildings_in_hand, self.buildings_on_table)

    def to_dict_for_public(self, deck):
        d = {}
        fields_to_copy = [
            'name', 'position', 'gold', 'points', 'revealed_roles'
        ]

        for k in fields_to_copy:
            d[k] = self.__dict__[k]

        d['buildings_on_table'] = [
            deck.card_for_id(i) for i in self.buildings_on_table
        ]
        d['num_cards_in_hand'] = len(self.buildings_in_hand)

        return d

    def to_dict_for_private(self, deck):
        d = self.to_dict_for_public(deck)

        fields_to_copy = ['cur_role', 'roles']
        for k in fields_to_copy:
            d[k] = self.__dict__[k]

        d['buildings_in_hand'] = [
            deck.card_for_id(i) for i in self.buildings_in_hand
        ]
        d['buildings_buffer'] = [
            deck.card_for_id(i) for i in self.buildings_buffer
        ]
        return d