diff options
-rw-r--r-- | board.cpp | 101 | ||||
-rw-r--r-- | board.h | 55 | ||||
-rw-r--r-- | cards.cpp | 62 | ||||
-rw-r--r-- | cards.h | 53 | ||||
-rw-r--r-- | client.cpp | 40 | ||||
-rw-r--r-- | client.h | 40 | ||||
-rw-r--r-- | game.cpp | 285 | ||||
-rw-r--r-- | game.h | 89 | ||||
-rw-r--r-- | player.cpp | 50 | ||||
-rw-r--r-- | player.h | 51 |
10 files changed, 826 insertions, 0 deletions
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 <olivier.gayot@sigexec.com> + * + * 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<const cards::card *, player *> 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(); + } +}; @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 Olivier Gayot <olivier.gayot@sigexec.com> + * + * 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<cards::deck, cards::deck> _black_decks; + std::pair<cards::deck, cards::deck> _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 <olivier.gayot@sigexec.com> + * + * 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 <fstream> +#include <cerrno> +#include <cstring> +#include <algorithm> + +#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()); + } + + }; +}; @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 Olivier Gayot <olivier.gayot@sigexec.com> + * + * 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 <string> +#include <deque> +#include <vector> +#include <map> + +namespace cao { + class player; + + namespace cards { + typedef std::string card; + + class deck : public std::deque<const card *> { + public: + deck() : deque() {}; + deck(const std::string &dict_file); + + void shuffle(); + const card *pick(); + }; + + class flop : public std::vector<std::pair<const card *, player *> > { + public: + flop() : vector() {}; + + void shuffle(); + }; + + typedef std::map<int, const card *> 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 <olivier.gayot@sigexec.com> + * + * 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 <iostream> +#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 <olivier.gayot@sigexec.com> + * + * 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 <string> +#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 <olivier.gayot@sigexec.com> + * + * 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 <iostream> +#include <vector> +#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<const cards::card *> 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 cards::card *>::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<player *>::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<const std::string, game *>::iterator it = _games.find(game_name); + + if (it != _games.end()) + return it->second; + + return _games[game_name] = new game(black_deck, white_deck); + } + + /* }}} */ +}; @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2016 Olivier Gayot <olivier.gayot@sigexec.com> + * + * 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 <string> +#include <map> +#include <vector> + +#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<player *> _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<const std::string, game *> _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 <olivier.gayot@sigexec.com> + * + * 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 <olivier.gayot@sigexec.com> + * + * 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 */ |