From 9cba7e2d3ff647d3ade46cefba24451ce837a5f1 Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Fri, 29 Jan 2016 22:18:02 +0100 Subject: game rewritten in C++ Signed-off-by: Olivier Gayot --- board.cpp | 101 ++++++++++++++++++++++ board.h | 55 ++++++++++++ cards.cpp | 62 ++++++++++++++ cards.h | 53 ++++++++++++ client.cpp | 40 +++++++++ client.h | 40 +++++++++ game.cpp | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ game.h | 89 +++++++++++++++++++ player.cpp | 50 +++++++++++ player.h | 51 +++++++++++ 10 files changed, 826 insertions(+) create mode 100644 board.cpp create mode 100644 board.h create mode 100644 cards.cpp create mode 100644 cards.h create mode 100644 client.cpp create mode 100644 client.h create mode 100644 game.cpp create mode 100644 game.h create mode 100644 player.cpp create mode 100644 player.h diff --git a/board.cpp b/board.cpp new file mode 100644 index 0000000..b11ecad --- /dev/null +++ b/board.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "board.h" + +namespace cao { + board::board(const cards::deck &black_deck, const cards::deck &white_deck) + : _black_decks(black_deck, cards::deck()), + _white_decks(white_deck, cards::deck()), + _black_pick(&_black_decks.first), _white_pick(&_white_decks.first), + _black_recycl(&_black_decks.second), _white_recycl(&_white_decks.second), + _flop(), _current_black_card(NULL) + { + _black_pick->shuffle(); + _white_pick->shuffle(); + } + + void board::reveal_black_card() + { + /* + * if we do not have enough cards in the pick, then we exchange the + * decks with the recycling deck. + */ + if (_black_pick->empty()) + { + cards::deck *d = _black_pick; + + _black_pick = _black_recycl; + _black_recycl = d; + + _black_pick->shuffle(); + } + + _current_black_card = _black_pick->pick(); + } + + void board::recycle_black_card() + { + _black_recycl->push_front(_current_black_card); + + _current_black_card = NULL; + } + + const cards::card *board::pick_white_card() + { + if (_white_pick->empty()) + { + cards::deck *d = _white_pick; + + _white_pick = _white_recycl; + _white_recycl = d; + + _white_pick->shuffle(); + } + + return _white_pick->pick(); + } + + void board::play_card(const cards::card *card, player *p) + { + std::pair pair; + + pair.first = card; + pair.second = p; + + _flop.push_back(pair); + } + + void board::shuffle_flop() + { + _flop.shuffle(); + } + + void board::recycle_flop() + { + for (cards::flop::const_iterator it = _flop.begin(); + it != _flop.end(); ++it) + { + const cards::card *card = (*it).first; + + _white_recycl->push_front(card); + } + + _flop.clear(); + } +}; diff --git a/board.h b/board.h new file mode 100644 index 0000000..c0af7a7 --- /dev/null +++ b/board.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef BOARD_H +#define BOARD_H + +#include "cards.h" + +namespace cao { + class board { + public: + board(const cards::deck &black_deck, const cards::deck &white_deck); + + void reveal_black_card(); + void recycle_black_card(); + const cards::card *pick_white_card(); + void play_card(const cards::card *, player *); + void shuffle_flop(); + void recycle_flop(); + + const cards::flop &get_flop() const { return _flop; }; + const cards::card *get_current_black_card() const { return _current_black_card; }; + + private: + std::pair _black_decks; + std::pair _white_decks; + + cards::deck *_black_pick; + cards::deck *_white_pick; + + cards::deck *_black_recycl; + cards::deck *_white_recycl; + + cards::flop _flop; + + const cards::card *_current_black_card; + }; +}; + +#endif /* BOARD_H */ diff --git a/cards.cpp b/cards.cpp new file mode 100644 index 0000000..cec65db --- /dev/null +++ b/cards.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include + +#include "cards.h" + +namespace cao { + namespace cards { + deck::deck(const std::string &dict_file) + { + std::string line; + std::ifstream ifile(dict_file.c_str(), std::ios_base::in); + + if (!ifile.good()) { + throw std::runtime_error(dict_file + ": " + strerror(errno)); + } + + while (std::getline(ifile, line)) { + push_back(new card(line)); + } + } + + void deck::shuffle() + { + std::random_shuffle(begin(), end()); + } + + const card *deck::pick() + { + const card *c = front(); + + pop_front(); + + return c; + } + + void flop::shuffle() + { + std::random_shuffle(begin(), end()); + } + + }; +}; diff --git a/cards.h b/cards.h new file mode 100644 index 0000000..cbe013f --- /dev/null +++ b/cards.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef CARDS_H +#define CARDS_H + +#include +#include +#include +#include + +namespace cao { + class player; + + namespace cards { + typedef std::string card; + + class deck : public std::deque { + public: + deck() : deque() {}; + deck(const std::string &dict_file); + + void shuffle(); + const card *pick(); + }; + + class flop : public std::vector > { + public: + flop() : vector() {}; + + void shuffle(); + }; + + typedef std::map hand; + }; +}; + +#endif /* CARDS_H */ diff --git a/client.cpp b/client.cpp new file mode 100644 index 0000000..c4486d1 --- /dev/null +++ b/client.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include "client.h" + +namespace cao { + client::client(int sock, void *handler) + : _sock(sock), _handler(handler), _player(NULL) + { + std::clog << "creating a new client" << std::endl; + } + + void client::join_game(const std::string &name) + { + if (_player) { + std::clog << "hey you already are in a game" << std::endl; + return; + } + + game *game = game_manager::get_instance()->find_game_by_name(name); + + _player = game->try_join(this); + } +}; diff --git a/client.h b/client.h new file mode 100644 index 0000000..ee64055 --- /dev/null +++ b/client.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2016 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef CLIENT_H +#define CLIENT_H + +#include +#include "game.h" + +namespace cao { + class client { + public: + client(int, void *); + + void join_game(const std::string &name); + + private: + int _sock; + void *_handler; + + player *_player; + }; +}; + +#endif /* CLIENT_H */ diff --git a/game.cpp b/game.cpp new file mode 100644 index 0000000..7d87e2b --- /dev/null +++ b/game.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2016 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include "game.h" + +#define CARDS_PER_PLAYER 10 + +namespace cao { + /* game {{{ */ + + game::game(const cards::deck &black_deck, const cards::deck &white_deck) + : _board(black_deck, white_deck), _state(WAITING_NEW_JUDGE), + _players(), _judge() + { + std::clog << "creating new game" << std::endl; + } + + player *game::try_join(client *client) + { + if (_players.size() >= CARDS_PER_PLAYER) { + std::clog << "too many players in this game" << std::endl; + /* TODO send error */ + return NULL; + } + + /* pick 10 cards */ + std::vector cards; + + try { + for (int i = 0; i < CARDS_PER_PLAYER; ++i) { + cards.push_back(_board.pick_white_card()); + } + } catch (std::string index_error) { + std::clog << "not enough white cards for player" << std::endl; + /* TODO send error */ + + /* TODO put the cards back in the pick */ + + return NULL; + } + + player *p = new player(client); + + for (std::vector::const_iterator it = cards.begin(); + it != cards.end(); ++it) + { + p->receive_card(*it); + } + + _players.push_back(p); + + /* TODO send notification to other players */ + + /* TODO send cards and game state to player */ + + return p; + } + + void game::try_become_judge(player *p) + { + if (_state != WAITING_NEW_JUDGE) { + std::clog << "someone is judge already" << std::endl; + /* TODO send error */ + return; + } + + _judge = p; + _board.reveal_black_card(); + + _state = WAITING_COLLECTION; + + /* TODO send notification "judge designed" to other players */ + + /* TODO send black card back to player */ + } + + void game::try_play_card(player *p, int idx) + { + if (_state != WAITING_COLLECTION) { + std::clog << "Who asked you to play now ?!" << std::endl; + /* TODO send error */ + return; + } + + if (_judge == p) { + std::clog << "You're the judge, you silly" << std::endl; + /* TODO send error */ + return; + } + + if (p->has_played()) { + std::clog << "You already played, dumb ass" << std::endl; + /* TODO send error */ + return; + } + + const cards::card *c; + + try { + c = p->pop_card(idx); + } catch (std::string idnex_error) { + std::clog << "Invalid card idx" << std::endl; + /* TODO send error */ + return; + } + + p->has_played(true); + + _board.play_card(c, p); + + /* TODO send notification to judge */ + + /* TODO return card id back to the plaeyr */ + return; + } + + void game::try_collect_cards(player *p) + { + if (_state != WAITING_COLLECTION) { + std::clog << "Do you think it's the moment for collection !?" << std::endl; + /* TODO send error */ + return; + } + + if (_judge != p) { + std::clog << "You are not the judge, you fool !" << std::endl; + /* TODO send error */ + return; + } + + _board.shuffle_flop(); + + /* we prevent the others to play */ + _state = WAITING_DESIGNATION; + + /* TODO send notification cards collected to the others */ + + /* TODO send the flop back to the player */ + } + + /* TODO handle when no cards are on the board */ + void game::try_designate_card(player *p, int idx) + { + if (_state != WAITING_DESIGNATION) { + std::clog << "not now, moron !" << std::endl; + /* TODO send error */ + + return; + } + + if (_judge != p) { + std::clog << "who do you think you are !?" << std::endl; + /* TODO send error */ + + return; + } + + if ((idx == -1) && (!_board.get_flop().empty())) { + std::clog << "there are cards on the board, so pick one !" << std::endl; + /* TODO send error */ + return; + } + + if ((idx >= 0) && (!_board.get_flop().empty())) { + /* TODO apparently, there's an exception to check */ + /* there are cards on the board */ + + player *winner; + + try { + winner = _board.get_flop()[idx].second; + } catch (std::string index_error) { + std::clog << "invalid card" << std::endl; + /* TODO send error */ + return; + } + + winner->inc_score(); + + /* put the cards back in the deck */ + _board.recycle_flop(); + + /* reset the state of the players */ + for (std::vector::iterator it = _players.begin(); + it != _players.end(); ++it) + { + player *target = (*it); + + if (target->has_played()) { + target->receive_card(_board.pick_white_card()); + + /* TODO send notification to the player */ + + target->has_played(false); + } + } + } + + _board.recycle_black_card(); + _judge = NULL; + _state = WAITING_NEW_JUDGE; + + /* TODO send notification judge needed to the other players */ + } + + void game::try_view_player_cards(const player *p) const + { + (void) p; + /* TODO return the cards along with their index */ + } + + void game::try_view_flop() const + { + if (_state != WAITING_DESIGNATION) { + std::clog << "not now, moron !" << std::endl; + /* TODO send error */ + return; + + } + + /* TODO return the cards */ + } + + void game::try_view_black_card() const + { + const cards::card *c = _board.get_current_black_card(); + + if (c) { + /* TODO return the black card to the player */ + return; + } + + std::clog << "The black card has not been revealed yet" << std::endl; + /* TODO send error */ + } + + /* }}} */ + /* game_manager {{{ */ + + game_manager *game_manager::_instance = NULL; + + game_manager *game_manager::get_instance() + { + if (!_instance) { + _instance = new game_manager(); + } + + return _instance; + } + + game_manager::game_manager() + : _games(), + black_deck("usr/share/cao/lang/en/cards/black"), + white_deck("usr/share/cao/lang/en/cards/white") + { } + + game *game_manager::find_game_by_name(const std::string &game_name) + { + std::map::iterator it = _games.find(game_name); + + if (it != _games.end()) + return it->second; + + return _games[game_name] = new game(black_deck, white_deck); + } + + /* }}} */ +}; diff --git a/game.h b/game.h new file mode 100644 index 0000000..b76127c --- /dev/null +++ b/game.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2016 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef GAME_H +#define GAME_H + +#include +#include +#include + +#include "game.h" +#include "cards.h" +#include "board.h" +#include "player.h" +#include "client.h" + +class client; + +namespace cao { + /* game {{{ */ + + class game { + public: + game(const cards::deck &black_deck, const cards::deck &white_deck); + + enum state { + WAITING_NEW_JUDGE, /* we need a new judge */ + WAITING_COLLECTION, /* the judge should collect the cards */ + WAITING_DESIGNATION, /* the judge should pick the best card */ + }; + + player *try_join(client *); + void try_become_judge(player *); + void try_play_card(player *, int idx); + void try_collect_cards(player *); + void try_designate_card(player *, int idx); + void try_view_player_cards(const player *) const; + void try_view_flop() const; + void try_view_black_card() const; + + private: + board _board; + + state _state; + + std::vector _players; + player *_judge; + + }; + + /* }}} */ + /* game_manager {{{ */ + + class game_manager { + public: + static game_manager *get_instance(); + + game *find_game_by_name(const std::string &game_name); + + private: + game_manager(); + + std::map _games; + + cards::deck black_deck; + cards::deck white_deck; + + static game_manager *_instance; + }; + + /* }}} */ +}; + +#endif /* GAME_H */ diff --git a/player.cpp b/player.cpp new file mode 100644 index 0000000..e2e3ed3 --- /dev/null +++ b/player.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "player.h" + +namespace cao { + player::player(client *client) + : _client(client), _name("default"), _score(0), _hand(), _next_idx(0), + _has_played(false) + { + } + + void player::inc_score() + { + ++_score; + + /* TODO send notification */ + } + + const cards::card *player::pop_card(int idx) + { + const cards::card *c = _hand[idx]; + + _hand.erase(idx); + + return c; + } + + int player::receive_card(const cards::card *card) + { + _hand[_next_idx++] = card; + + return _next_idx - 1; + } +}; diff --git a/player.h b/player.h new file mode 100644 index 0000000..a870e5e --- /dev/null +++ b/player.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 Olivier Gayot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef PLAYER_H +#define PLAYER_H + +#include "cards.h" +#include "client.h" + +namespace cao { + class client; + + class player { + public: + player(client *); + + bool has_played() const { return _has_played; }; + void has_played(bool has) { _has_played = has; }; + void inc_score(); + const cards::card *pop_card(int idx); + int receive_card(const cards::card *); + private: + client *_client; + std::string _name; + + int _score; + + cards::hand _hand; + + int _next_idx; + + bool _has_played; + }; +}; + +#endif /* PLAYER_H */ -- cgit v1.2.3