From e979d4bb2bef45238f011b93cedfaec0392de0ba Mon Sep 17 00:00:00 2001 From: r3w0p Date: Thu, 23 May 2024 20:24:21 +0100 Subject: [PATCH] what to do with model/game? --- include/caravan/controller/controller.h | 2 +- include/caravan/controller/controller_tui.h | 1 + include/caravan/core/common.h | 4 +- include/caravan/core/exceptions.h | 17 ++ include/caravan/model/caravan.h | 14 +- include/caravan/model/game.h | 32 +- include/caravan/model/player.h | 17 +- include/caravan/model/table.h | 3 + src/caravan/controller/controller_tui.cpp | 308 +++++++++++--------- src/caravan/main.cpp | 2 +- src/caravan/model/caravan.cpp | 87 +++++- src/caravan/model/deck.cpp | 5 + src/caravan/model/game.cpp | 68 +++-- src/caravan/model/player.cpp | 39 ++- src/caravan/model/table.cpp | 59 +++- src/caravan/view/view_tui.cpp | 173 +++++++---- test/caravan/model/test_caravan.cpp | 61 ++-- test/caravan/model/test_game.cpp | 21 -- 18 files changed, 566 insertions(+), 347 deletions(-) diff --git a/include/caravan/controller/controller.h b/include/caravan/controller/controller.h index 5f49ba7..2f95c37 100644 --- a/include/caravan/controller/controller.h +++ b/include/caravan/controller/controller.h @@ -24,7 +24,7 @@ class Controller : public ViewSubscriber, public Publisher explicit Controller() : closed(false) {}; void subscribe(ControllerSubscriber *sub) override; - void close() { closed = true; }; + virtual void close() = 0; }; #endif //CARAVAN_CONTROLLER_H diff --git a/include/caravan/controller/controller_tui.h b/include/caravan/controller/controller_tui.h index 0a50dce..7673ada 100644 --- a/include/caravan/controller/controller_tui.h +++ b/include/caravan/controller/controller_tui.h @@ -12,6 +12,7 @@ class ControllerTUI : public Controller { explicit ControllerTUI() = default; void on_view_user_input(std::string input, bool confirmed) override; // from ViewSubscriber + void close() override; }; #endif //CARAVAN_CONTROLLER_TUI_H diff --git a/include/caravan/core/common.h b/include/caravan/core/common.h index dbd614b..8a2f0c8 100644 --- a/include/caravan/core/common.h +++ b/include/caravan/core/common.h @@ -15,8 +15,8 @@ */ const uint8_t TRACK_NUMERIC_MIN = 1; -const uint8_t TRACK_NUMERIC_MAX = 10; -const uint8_t TRACK_FACE_MAX = 5; +const uint8_t TRACK_NUMERIC_MAX = 8; +const uint8_t TRACK_FACE_MAX = 3; const uint8_t CARAVAN_SOLD_MIN = 21; const uint8_t CARAVAN_SOLD_MAX = 26; const uint8_t DECK_STANDARD_MAX = 52; diff --git a/include/caravan/core/exceptions.h b/include/caravan/core/exceptions.h index d8c7f49..2d4ccb3 100644 --- a/include/caravan/core/exceptions.h +++ b/include/caravan/core/exceptions.h @@ -7,6 +7,10 @@ #include +/* + * BASE + */ + class CaravanException : public std::exception { private: std::string message; @@ -16,6 +20,10 @@ class CaravanException : public std::exception { std::string what(); }; +/* + * GENERAL + */ + class CaravanFatalException : public CaravanException { public: explicit CaravanFatalException(std::string msg) : CaravanException(msg) {} @@ -26,4 +34,13 @@ class CaravanGameException : public CaravanException { explicit CaravanGameException(std::string msg) : CaravanException(msg) {} }; +/* + * CONTROLLER + */ + +class CaravanInputException : public CaravanException { +public: + explicit CaravanInputException(std::string msg) : CaravanException(msg) {} +}; + #endif //CARAVAN_CORE_EXCEPTIONS_H diff --git a/include/caravan/model/caravan.h b/include/caravan/model/caravan.h index ee08602..2ecc804 100644 --- a/include/caravan/model/caravan.h +++ b/include/caravan/model/caravan.h @@ -17,13 +17,21 @@ class Caravan { CaravanName name; Track track; uint8_t i_track; + bool closed; static uint8_t numeral_rank_to_uint8_t(Rank rank); - void remove_numeral_card(uint8_t index); public: - explicit Caravan(CaravanName cvname); + /** + * A caravan that contains all of the information for a given track of numeral + * cards and any face cards attached to them, including: the total caravan bid, + * its direction, and its suit. + * + * @param cvname The caravan name. + */ + explicit Caravan(CaravanName cvname) : + name(cvname), track({}), i_track(0), closed(false) {}; void clear(); @@ -46,6 +54,8 @@ class Caravan { void remove_rank(Rank rank, uint8_t pos_exclude); void remove_suit(Suit suit, uint8_t pos_exclude); + + void close(); }; #endif //CARAVAN_MODEL_CARAVAN_H diff --git a/include/caravan/model/game.h b/include/caravan/model/game.h index 243f80e..d441272 100644 --- a/include/caravan/model/game.h +++ b/include/caravan/model/game.h @@ -13,47 +13,19 @@ class Game { protected: Table *table_ptr{}; - Deck *deck_pa_ptr{}; - Deck *deck_pb_ptr{}; Player *pa_ptr{}; Player *pb_ptr{}; - bool closed; Player *p_turn; + bool closed; int8_t compare_bids(CaravanName cvname1, CaravanName cvname2); - bool has_sold(CaravanName cvname); - void option_clear(Player *pptr, GameOption* go); - void option_discard(Player *pptr, GameOption* go); - void option_play(Player *pptr, GameOption* go); public: - explicit Game(GameConfig gc) { - if (gc.pn_first == NO_PLAYER) - throw CaravanFatalException( - "Invalid player name for first player in " - "game configuration."); - - deck_pa_ptr = DeckBuilder::build_caravan_deck( - gc.pa_num_cards, - gc.pa_num_sample_decks, - gc.pa_balanced_sample); - - deck_pb_ptr = DeckBuilder::build_caravan_deck( - gc.pb_num_cards, - gc.pb_num_sample_decks, - gc.pb_balanced_sample); - - table_ptr = new Table(); - pa_ptr = new Player(PLAYER_BOTTOM, deck_pa_ptr); - pb_ptr = new Player(PLAYER_TOP, deck_pb_ptr); - - closed = false; - p_turn = gc.pn_first == pa_ptr->get_name() ? pa_ptr : pb_ptr; - } + explicit Game(GameConfig gc); void close(); diff --git a/include/caravan/model/player.h b/include/caravan/model/player.h index 2dbad09..038b6c2 100644 --- a/include/caravan/model/player.h +++ b/include/caravan/model/player.h @@ -16,21 +16,12 @@ class Player { Hand hand; uint8_t i_hand; uint16_t moves; + bool closed; public: - explicit Player(PlayerName pn, Deck *d) { - name = pn; - deck = d; - hand = {}; - i_hand = 0; - moves = 0; - - while (i_hand < HAND_SIZE_MAX_START) { - hand[i_hand] = deck->back(); - deck->pop_back(); - i_hand += 1; - } - } + explicit Player(PlayerName pn, Deck *d); + + void close(); Card get_from_hand_at(uint8_t pos); diff --git a/include/caravan/model/table.h b/include/caravan/model/table.h index 1a56473..49d9eb3 100644 --- a/include/caravan/model/table.h +++ b/include/caravan/model/table.h @@ -20,12 +20,15 @@ class Table { Caravan* f = new Caravan(CARAVAN_F); std::array caravans = { a, b, c, d, e, f }; + bool closed; uint8_t caravan_name_to_uint8_t_index(CaravanName cvname); public: explicit Table(); + void close(); + void clear_caravan(CaravanName cvname); uint16_t get_caravan_bid(CaravanName cvname); diff --git a/src/caravan/controller/controller_tui.cpp b/src/caravan/controller/controller_tui.cpp index 46f23dd..0c55ca4 100644 --- a/src/caravan/controller/controller_tui.cpp +++ b/src/caravan/controller/controller_tui.cpp @@ -3,42 +3,16 @@ // modified under the terms of the GPL-3.0 License. #include "caravan/controller/controller_tui.h" +#include "caravan/core/exceptions.h" -void ControllerTUI::on_view_user_input(std::string input, bool confirmed) { - if(closed) return; - - // TODO A future feature that highlights parts of the board as a command is typed, - // so that the user has a better idea of what their command will do. - if(!confirmed) return; - - // Decipher input - GameCommand command; - - /* - * EXIT - */ - if( - input.size() == 4 and - (input.at(0) == 'E' or input.at(0) == 'e') and - (input.at(1) == 'X' or input.at(1) == 'x') and - (input.at(2) == 'I' or input.at(2) == 'i') and - (input.at(3) == 'T' or input.at(3) == 't') - ) { - command.type = OPTION_EXIT; - } - /* - * FIRST - * - OPTION TYPE - */ +void process_first(std::string input, GameCommand *command) { + char c = input.at(0); // minimum input size already checked elsewhere - if (input.size() < 1) - throw CaravanFatalException("A command type has not been entered."); - - switch (input.at(0)) { + switch (c) { case 'P': case 'p': - command.type = OPTION_PLAY; + command->type = OPTION_PLAY; /* * P2F * "Play numeral card at hand pos 2 onto caravan F" @@ -47,184 +21,240 @@ void ControllerTUI::on_view_user_input(std::string input, bool confirmed) { * "Play face card at hand pos 4 onto caravan F, slot 8" */ break; + case 'D': case 'd': - command.type = OPTION_DISCARD; + command->type = OPTION_DISCARD; /* * D3 * "Discard card at hand pos 3" */ break; + case 'C': case 'c': /* * CE * "Clear caravan E" */ - command.type = OPTION_CLEAR; + command->type = OPTION_CLEAR; break; + default: - throw CaravanGameException("Invalid option '" + std::to_string(input.at(0)) + "', must be one of: (P)lay, (D)iscard, (C)lear."); + throw CaravanInputException("Invalid option '" + std::string(1, c) + "', must be one of: (P)lay, (D)iscard, (C)lear."); } +} - /* - * SECOND - * - HAND POSITION or - * - CARAVAN NAME - */ - - if (command.type == OPTION_PLAY or command.type == OPTION_DISCARD) { +void process_second(std::string input, GameCommand *command) { + if (command->type == OPTION_PLAY or command->type == OPTION_DISCARD) { if (input.size() < 2) - throw CaravanFatalException("A hand position has not been entered."); + throw CaravanInputException("A hand position has not been entered."); - switch (input.at(1)) { + char c = input.at(1); + + switch (c) { case '1': - command.pos_hand = 1; + command->pos_hand = 1; break; case '2': - command.pos_hand = 2; + command->pos_hand = 2; break; case '3': - command.pos_hand = 3; + command->pos_hand = 3; break; case '4': - command.pos_hand = 4; + command->pos_hand = 4; break; case '5': - command.pos_hand = 5; + command->pos_hand = 5; break; case '6': - command.pos_hand = 6; + command->pos_hand = 6; break; case '7': - command.pos_hand = 7; + command->pos_hand = 7; break; case '8': - command.pos_hand = 8; + command->pos_hand = 8; break; default: - throw CaravanGameException("Invalid hand position '" + std::to_string(input.at(1)) + "'."); + throw CaravanInputException("Invalid hand position '" + std::string(1, c) + "'."); } - } else if (command.type == OPTION_CLEAR) { + } else if (command->type == OPTION_CLEAR) { if (input.size() < 2) - throw CaravanFatalException("A caravan name has not been entered."); + throw CaravanInputException("A caravan name has not been entered."); + + char c = input.at(1); - switch (input.at(1)) { + switch (c) { case 'A': case 'a': - command.caravan_name = CARAVAN_A; + command->caravan_name = CARAVAN_A; break; case 'B': case 'b': - command.caravan_name = CARAVAN_B; + command->caravan_name = CARAVAN_B; break; case 'C': case 'c': - command.caravan_name = CARAVAN_C; + command->caravan_name = CARAVAN_C; break; case 'D': case 'd': - command.caravan_name = CARAVAN_D; + command->caravan_name = CARAVAN_D; break; case 'E': case 'e': - command.caravan_name = CARAVAN_E; + command->caravan_name = CARAVAN_E; break; case 'F': case 'f': - command.caravan_name = CARAVAN_F; + command->caravan_name = CARAVAN_F; break; default: - throw CaravanGameException("Invalid caravan name '" + std::to_string(input.at(1)) + "', must be between: A-F."); + throw CaravanInputException("Invalid caravan name '" + std::string(1, c) + "', must be between: A-F."); + } + + } // else invalid command type, handled during parse of first character +} + +void process_third(std::string input, GameCommand *command) { + if (command->type == OPTION_PLAY) { + + if (input.size() < 3) + throw CaravanInputException("A caravan name has not been entered."); + + char c = input.at(2); + + switch (c) { + case 'A': + case 'a': + command->caravan_name = CARAVAN_A; + break; + case 'B': + case 'b': + command->caravan_name = CARAVAN_B; + break; + case 'C': + case 'c': + command->caravan_name = CARAVAN_C; + break; + case 'D': + case 'd': + command->caravan_name = CARAVAN_D; + break; + case 'E': + case 'e': + command->caravan_name = CARAVAN_E; + break; + case 'F': + case 'f': + command->caravan_name = CARAVAN_F; + break; + default: + throw CaravanInputException("Invalid caravan name '" + std::string(1, c) + "', must be between: A-F."); } } +} - // Discard/clear does not require caravan name/pos - if (command.type == OPTION_DISCARD or command.type == OPTION_CLEAR) - return command; // TODO fix +void process_fourth(std::string input, GameCommand *command) { + if (command->type == OPTION_PLAY) { - /* - * THIRD - * - CARAVAN NAME - */ + if (input.size() < 4) return; // optional, not an error - if (input.size() < 3) - throw CaravanFatalException("A caravan name has not been entered."); + char c = input.at(3); - switch (input.at(2)) { - case 'A': - case 'a': - command.caravan_name = CARAVAN_A; - break; - case 'B': - case 'b': - command.caravan_name = CARAVAN_B; - break; - case 'C': - case 'c': - command.caravan_name = CARAVAN_C; - break; - case 'D': - case 'd': - command.caravan_name = CARAVAN_D; - break; - case 'E': - case 'e': - command.caravan_name = CARAVAN_E; - break; - case 'F': - case 'f': - command.caravan_name = CARAVAN_F; - break; - default: - throw CaravanGameException( - "Invalid caravan name '" + std::to_string(input.at(2)) + "', must be between: A-F."); + switch (c) { + case '1': + command->pos_caravan = 1; + break; + case '2': + command->pos_caravan = 2; + break; + case '3': + command->pos_caravan = 3; + break; + case '4': + command->pos_caravan = 4; + break; + case '5': + command->pos_caravan = 5; + break; + case '6': + command->pos_caravan = 6; + break; + case '7': + command->pos_caravan = 7; + break; + case '8': + command->pos_caravan = 8; + break; + default: + throw CaravanInputException("Invalid caravan position '" + std::string(1, c) + "'."); + } + } +} + +bool process_exit(std::string input, GameCommand *command) { + if( + input.size() == 4 and + (input.at(0) == 'E' or input.at(0) == 'e') and + (input.at(1) == 'X' or input.at(1) == 'x') and + (input.at(2) == 'I' or input.at(2) == 'i') and + (input.at(3) == 'T' or input.at(3) == 't') + ) { + command->type = OPTION_EXIT; + return true; } + return false; +} + +void ControllerTUI::on_view_user_input(std::string input, bool confirmed) { + if(closed) return; + + if(input.empty()) return; + + // TODO A future feature that highlights parts of the board as a command is typed, + // so that the user has a better idea of what their command will do. + if(!confirmed) return; + + GameCommand command; + bool is_exit; + /* - * FOURTH - * - CARAVAN POSITION (used when selecting Face card only) + * EXIT */ + is_exit = process_exit(input, &command); - // Caravan position only specified here when playing a face card - if ((char) input.at(3) == '\0') { - command.pos_caravan = 0; - return command; // TODO fix - } + if(!is_exit) { + /* + * FIRST + * - COMMAND TYPE + */ + process_first(input, &command); - switch (input.at(3)) { - case '1': - command.pos_caravan = 1; - break; - case '2': - command.pos_caravan = 2; - break; - case '3': - command.pos_caravan = 3; - break; - case '4': - command.pos_caravan = 4; - break; - case '5': - command.pos_caravan = 5; - break; - case '6': - command.pos_caravan = 6; - break; - case '7': - command.pos_caravan = 7; - break; - case '8': - command.pos_caravan = 8; - break; - case '9': - command.pos_caravan = 9; - break; - default: - throw CaravanGameException("Invalid caravan position '" + std::to_string(input.at(3)) + "'."); + /* + * SECOND + * - HAND POSITION or + * - CARAVAN NAME + */ + process_second(input, &command); + + /* + * THIRD + * - CARAVAN NAME + */ + process_third(input, &command); + + /* + * FOURTH + * - CARAVAN POSITION (used when selecting Face card only) + */ + process_fourth(input, &command); } // Pass to subscribers (i.e., Model) @@ -232,3 +262,9 @@ void ControllerTUI::on_view_user_input(std::string input, bool confirmed) { s->on_controller_command(command); } } + +void ControllerTUI::close() { + if(!closed) { + closed = true; + } +} \ No newline at end of file diff --git a/src/caravan/main.cpp b/src/caravan/main.cpp index 57d5cea..c821b28 100644 --- a/src/caravan/main.cpp +++ b/src/caravan/main.cpp @@ -34,7 +34,7 @@ int main() { v->close(); c->close(); - // TODO m->close(); + // m->close(); delete v; delete c; diff --git a/src/caravan/model/caravan.cpp b/src/caravan/model/caravan.cpp index 791d898..42df9e6 100644 --- a/src/caravan/model/caravan.cpp +++ b/src/caravan/model/caravan.cpp @@ -5,34 +5,31 @@ #include "caravan/model/caravan.h" #include "caravan/core/exceptions.h" -/** - * A caravan that contains all of the information for a given track of numeral - * cards and any face cards attached to them, including: the total caravan bid, - * its direction, and its suit. - * - * @param cvname The caravan name. - */ -Caravan::Caravan(CaravanName cvname) { - name = cvname; - track = {}; - i_track = 0; -} +const std::string EXC_CLOSED = "Caravan is closed."; /** * Remove all cards from the caravan. + * + * @throws CaravanGameException Caravan track is empty. + * @throws CaravanFatalException Caravan is closed. */ void Caravan::clear() { + if(closed) throw CaravanFatalException(EXC_CLOSED); + if (i_track == 0) - throw CaravanGameException( - "Cannot clear empty caravan."); + throw CaravanGameException("Cannot clear empty caravan."); i_track = 0; } /** * @return Current bid. + * + * @throws CaravanFatalException Caravan is closed. */ uint16_t Caravan::get_bid() { + if(closed) throw CaravanFatalException(EXC_CLOSED); + uint16_t bid; uint8_t value; uint8_t value_final; @@ -56,8 +53,13 @@ uint16_t Caravan::get_bid() { /** * @param pos Caravan position. * @return Slot at position. + * + * @throws CaravanGameException Chosen card position is out of range. + * @throws CaravanFatalException Caravan is closed. */ Slot Caravan::get_slot(uint8_t pos) { + if(closed) throw CaravanFatalException(EXC_CLOSED); + if (pos < TRACK_NUMERIC_MIN or pos > i_track) throw CaravanGameException( "The chosen card position is out of range."); @@ -67,8 +69,12 @@ Slot Caravan::get_slot(uint8_t pos) { /** * @return Current caravan direction. + * + * @throws CaravanFatalException Caravan is closed. */ Direction Caravan::get_direction() { + if(closed) throw CaravanFatalException(EXC_CLOSED); + Direction dir; int t_latest; int t_pen; @@ -112,22 +118,34 @@ Direction Caravan::get_direction() { /** * @return Caravan name. + * + * @throws CaravanFatalException Caravan is closed. */ CaravanName Caravan::get_name() { + if(closed) throw CaravanFatalException(EXC_CLOSED); + return name; } /** * @return Current number of numeral cards in caravan. + * + * @throws CaravanFatalException Caravan is closed. */ uint8_t Caravan::get_size() { + if(closed) throw CaravanFatalException(EXC_CLOSED); + return i_track; } /** * @return Current caravan suit. + * + * @throws CaravanFatalException Caravan is closed. */ Suit Caravan::get_suit() { + if(closed) throw CaravanFatalException(EXC_CLOSED); + Suit last; int t; int f; @@ -156,8 +174,16 @@ Suit Caravan::get_suit() { /** * @param card Numeral card to put into caravan. + * + * @throws CaravanGameException Card is not a numeral. + * @throws CaravanGameException Caravan is at maximum numeral card capacity. + * @throws CaravanGameException Numeral card has same rank as most recent card in caravan. + * @throws CaravanGameException Numeral card does not follow direction of caravan. + * @throws CaravanFatalException Caravan is closed. */ void Caravan::put_numeral_card(Card card) { + if(closed) throw CaravanFatalException(EXC_CLOSED); + Direction dir; Suit suit; bool ascends; @@ -202,8 +228,16 @@ void Caravan::put_numeral_card(Card card) { * @param card Face card to put into caravan. * @param pos Position of numeral card on which to put the face card. * @return The numeral card on which the face card was placed. + * + * @throws CaravanGameException Caravan position not entered. + * @throws CaravanGameException No numeral card at chosen position. + * @throws CaravanGameException Chosen card is not a face card. + * @throws CaravanGameException Numeral card is at maximum face card capacity. + * @throws CaravanFatalException Caravan is closed. */ Card Caravan::put_face_card(Card card, uint8_t pos) { + if(closed) throw CaravanFatalException(EXC_CLOSED); + uint8_t i; Card c_on; @@ -230,8 +264,7 @@ Card Caravan::put_face_card(Card card, uint8_t pos) { } else { if (track[i].i_faces == TRACK_FACE_MAX) throw CaravanGameException( - "The numeral card is at its maximum face card " - "capacity."); + "The numeral card is at its maximum face card capacity."); track[i].faces[track[i].i_faces] = card; track[i].i_faces += 1; @@ -246,8 +279,13 @@ Card Caravan::put_face_card(Card card, uint8_t pos) { * @param rank The rank to remove. * @param pos_exclude The numeral card at the position will be excluded from * removal. If 0, no card is excluded. + * + * @throws CaravanFatalException Exclude position is out of range. + * @throws CaravanFatalException Caravan is closed. */ void Caravan::remove_rank(Rank rank, uint8_t pos_exclude) { + if(closed) throw CaravanFatalException(EXC_CLOSED); + uint8_t i_track_original; if (i_track == 0) @@ -274,8 +312,13 @@ void Caravan::remove_rank(Rank rank, uint8_t pos_exclude) { * @param suit The suit to remove. * @param pos_exclude The numeral card at the position will be excluded from * removal. If 0, no card is excluded. + * + * @throws CaravanFatalException Exclude position is out of range. + * @throws CaravanFatalException Caravan is closed. */ void Caravan::remove_suit(Suit suit, uint8_t pos_exclude) { + if(closed) throw CaravanFatalException(EXC_CLOSED); + uint8_t i_track_original; if (i_track == 0) @@ -296,6 +339,17 @@ void Caravan::remove_suit(Suit suit, uint8_t pos_exclude) { } } +/** + * Closes the caravan. + * + * @throws CaravanFatalException Caravan is closed. + */ +void Caravan::close() { + if(!closed) { + closed = true; + } +} + /* * PROTECTED */ @@ -305,6 +359,7 @@ void Caravan::remove_suit(Suit suit, uint8_t pos_exclude) { * @return An integer equivalent of the numeral, range: 1-10. * * @throws CaravanFatalException If a non-numeral rank is provided. + * @throws CaravanFatalException Caravan is closed. */ uint8_t Caravan::numeral_rank_to_uint8_t(Rank rank) { switch (rank) { diff --git a/src/caravan/model/deck.cpp b/src/caravan/model/deck.cpp index 2a38a07..327cfed 100644 --- a/src/caravan/model/deck.cpp +++ b/src/caravan/model/deck.cpp @@ -20,7 +20,12 @@ * fashion e.g. a random card from deck 1, then deck 2, then 3, then * 1, 2, 3, and so on. * If false, then standard decks are sampled randomly. + * * @return A caravan deck. + * + * @throws CaravanFatalException Requested number of cards outside of acceptable range. + * @throws CaravanFatalException Requested number of sample decks outside of acceptable range. + * @throws CaravanFatalException Insufficient cards to sample in order to build deck. */ Deck *DeckBuilder::build_caravan_deck( uint8_t num_cards, diff --git a/src/caravan/model/game.cpp b/src/caravan/model/game.cpp index c11da81..96cb535 100644 --- a/src/caravan/model/game.cpp +++ b/src/caravan/model/game.cpp @@ -4,23 +4,51 @@ #include "caravan/model/game.h" +const std::string EXC_CLOSED = "Game is closed."; + +/** + * @param gc Game configuration. + * + * @throws CaravanFatalException Invalid player names. + */ +Game::Game(GameConfig gc) { + if (gc.pn_first == NO_PLAYER) + throw CaravanFatalException("Invalid player name for first player in game configuration."); + + Deck *deck_top = DeckBuilder::build_caravan_deck( + gc.pa_num_cards, + gc.pa_num_sample_decks, + gc.pa_balanced_sample); + + Deck *deck_bottom = DeckBuilder::build_caravan_deck( + gc.pb_num_cards, + gc.pb_num_sample_decks, + gc.pb_balanced_sample); + + table_ptr = new Table(); + pa_ptr = new Player(PLAYER_BOTTOM, deck_bottom); + pb_ptr = new Player(PLAYER_TOP, deck_top); + + closed = false; + p_turn = gc.pn_first == pa_ptr->get_name() ? pa_ptr : pb_ptr; +} void Game::close() { - if (closed) - throw CaravanFatalException("The game has already closed."); + if (!closed) { + table_ptr->close(); + pa_ptr->close(); + pb_ptr->close(); - delete table_ptr; - delete deck_pa_ptr; - delete deck_pb_ptr; - delete pa_ptr; - delete pb_ptr; + delete table_ptr; + delete pa_ptr; + delete pb_ptr; - closed = true; + closed = true; + } } Player *Game::get_player(PlayerName pname) { - if (closed) - throw CaravanFatalException("The game has already closed."); + if (closed) throw CaravanFatalException(EXC_CLOSED); if (pa_ptr->get_name() == pname) return pa_ptr; @@ -32,8 +60,7 @@ Player *Game::get_player(PlayerName pname) { } PlayerCaravanNames Game::get_player_caravan_names(PlayerName pname) { - if (closed) - throw CaravanFatalException("The game has already closed."); + if (closed) throw CaravanFatalException(EXC_CLOSED); if (pa_ptr->get_name() == pname) return PlayerCaravanNames{CARAVAN_A, CARAVAN_B, CARAVAN_C}; @@ -45,27 +72,24 @@ PlayerCaravanNames Game::get_player_caravan_names(PlayerName pname) { } PlayerName Game::get_player_turn() { - if (closed) - throw CaravanFatalException("The game has already closed."); + if (closed) throw CaravanFatalException(EXC_CLOSED); return p_turn->get_name(); } Table *Game::get_table() { - if (closed) - throw CaravanFatalException("The game has already closed."); + if (closed) throw CaravanFatalException(EXC_CLOSED); return table_ptr; } PlayerName Game::get_winner() { + if (closed) throw CaravanFatalException(EXC_CLOSED); + uint8_t won_pa; uint8_t won_pb; int8_t comp[3]; - if (closed) - throw CaravanFatalException("The game has already closed."); - // The first player with an empty hand loses if (get_player(PLAYER_BOTTOM)->get_size_hand() == 0) @@ -115,9 +139,7 @@ bool Game::is_closed() { } void Game::play_option(GameOption *go) { - if (closed) - throw CaravanFatalException( - "The game has already closed."); + if (closed) throw CaravanFatalException(EXC_CLOSED); if (get_winner() != NO_PLAYER) throw CaravanFatalException( @@ -160,6 +182,8 @@ void Game::play_option(GameOption *go) { } CaravanName Game::winning_bid(CaravanName cvname1, CaravanName cvname2) { + if (closed) throw CaravanFatalException(EXC_CLOSED); + int8_t bidcomp = compare_bids(cvname1, cvname2); if (bidcomp < 0) diff --git a/src/caravan/model/player.cpp b/src/caravan/model/player.cpp index ce03e86..d498d4f 100644 --- a/src/caravan/model/player.cpp +++ b/src/caravan/model/player.cpp @@ -5,44 +5,74 @@ #include "caravan/model/player.h" #include "caravan/core/exceptions.h" +const std::string EXC_CLOSED = "Player is closed."; + +Player::Player(PlayerName pn, Deck *d) { + name = pn; + deck = d; + hand = {}; + i_hand = 0; + moves = 0; + closed = false; + + for(; i_hand < HAND_SIZE_MAX_START; i_hand++) { + hand[i_hand] = deck->back(); + deck->pop_back(); + } +} + +void Player::close() { + if(!closed) { + delete deck; + + closed = true; + } +} Card Player::get_from_hand_at(uint8_t pos) { + if (closed) throw CaravanFatalException(EXC_CLOSED); + if (i_hand == 0) - throw CaravanFatalException( - "Player's hand is empty."); + throw CaravanFatalException("Player's hand is empty."); if (pos < HAND_POS_MIN or pos > i_hand) - throw CaravanGameException( - "The chosen hand position is out of range."); + throw CaravanGameException("The chosen hand position is out of range."); return hand[pos - 1]; } Hand Player::get_hand() { + if (closed) throw CaravanFatalException(EXC_CLOSED); return hand; } uint16_t Player::get_moves_count() { + if (closed) throw CaravanFatalException(EXC_CLOSED); return moves; } PlayerName Player::get_name() { + if (closed) throw CaravanFatalException(EXC_CLOSED); return name; } uint8_t Player::get_size_deck() { + if (closed) throw CaravanFatalException(EXC_CLOSED); return deck->size(); } uint8_t Player::get_size_hand() { + if (closed) throw CaravanFatalException(EXC_CLOSED); return i_hand; } void Player::increment_moves() { + if (closed) throw CaravanFatalException(EXC_CLOSED); moves += 1; } void Player::maybe_add_card_to_hand() { + if (closed) throw CaravanFatalException(EXC_CLOSED); // If more cards in the deck if (!deck->empty()) { // If post-Start and hand not at post-Start max (5 cards) @@ -56,6 +86,7 @@ void Player::maybe_add_card_to_hand() { } Card Player::discard_from_hand_at(uint8_t pos) { + if (closed) throw CaravanFatalException(EXC_CLOSED); uint8_t i; Card c_ret; diff --git a/src/caravan/model/table.cpp b/src/caravan/model/table.cpp index f68c384..2c5fa44 100644 --- a/src/caravan/model/table.cpp +++ b/src/caravan/model/table.cpp @@ -5,24 +5,53 @@ #include "caravan/model/table.h" #include "caravan/core/exceptions.h" +const std::string EXC_CLOSED = "Table is closed."; + /** - * The table on which caravan tracks are placed, as well as the decks and hands - * of both players. + * The table on which caravan tracks are placed, as well as the decks and hands of both players. */ -Table::Table() {} +Table::Table() { + closed = false; +} + +void Table::close() { + if (!closed) { + a->close(); + b->close(); + c->close(); + d->close(); + e->close(); + f->close(); + + delete a; + delete b; + delete c; + delete d; + delete e; + delete f; + + closed = true; + } +} /** * @param cvname The caravan to clear. + * + * @throws CaravanFatalException Table is closed. */ void Table::clear_caravan(CaravanName cvname) { + if (closed) throw CaravanFatalException(EXC_CLOSED); caravans[caravan_name_to_uint8_t_index(cvname)]->clear(); } /** * @param cvname A caravan name. * @return The current bid of the named caravan. + * + * @throws CaravanFatalException Table is closed. */ uint16_t Table::get_caravan_bid(CaravanName cvname) { + if (closed) throw CaravanFatalException(EXC_CLOSED); return caravans[caravan_name_to_uint8_t_index(cvname)]->get_bid(); } @@ -30,32 +59,44 @@ uint16_t Table::get_caravan_bid(CaravanName cvname) { * @param cvname A caravan name. * @param pos The position at the named caravan. * @return The slot (i.e. numeral card and attached face cards) at the position. + * + * @throws CaravanFatalException Table is closed. */ Slot Table::get_slot_at(CaravanName cvname, uint8_t pos) { + if (closed) throw CaravanFatalException(EXC_CLOSED); return caravans[caravan_name_to_uint8_t_index(cvname)]->get_slot(pos); } /** * @param cvname A caravan name. * @return The current direction of the named caravan. + * + * @throws CaravanFatalException Table is closed. */ Direction Table::get_caravan_direction(CaravanName cvname) { + if (closed) throw CaravanFatalException(EXC_CLOSED); return caravans[caravan_name_to_uint8_t_index(cvname)]->get_direction(); } /** * @param cvname A caravan name. * @return The current number of numeral cards in the named caravan. + * + * @throws CaravanFatalException Table is closed. */ uint8_t Table::get_caravan_size(CaravanName cvname) { + if (closed) throw CaravanFatalException(EXC_CLOSED); return caravans[caravan_name_to_uint8_t_index(cvname)]->get_size(); } /** * @param cvname A caravan name. * @return The current suit of the named caravan. + * + * @throws CaravanFatalException Table is closed. */ Suit Table::get_caravan_suit(CaravanName cvname) { + if (closed) throw CaravanFatalException(EXC_CLOSED); return caravans[caravan_name_to_uint8_t_index(cvname)]->get_suit(); } @@ -63,14 +104,17 @@ Suit Table::get_caravan_suit(CaravanName cvname) { * @param cvname A caravan name. * @param card A face card. * @param pos The position of the numeral card on which to place the face card. + * + * @throws CaravanGameException QUEEN not played on latest numeral card in caravan. + * @throws CaravanFatalException Table is closed. */ void Table::play_face_card(CaravanName cvname, Card card, uint8_t pos) { + if (closed) throw CaravanFatalException(EXC_CLOSED); Caravan *cvn_target = caravans[caravan_name_to_uint8_t_index(cvname)]; if (card.rank == QUEEN and pos != cvn_target->get_size()) throw CaravanGameException( - "A QUEEN can only be played on the latest numeral card " - "in a caravan."); + "A QUEEN can only be played on the latest numeral card in a caravan."); // Play Face card on Caravan. // Returns the Numeric card that the Face card was played on. @@ -103,8 +147,11 @@ void Table::play_face_card(CaravanName cvname, Card card, uint8_t pos) { /** * @param cvname A caravan name. * @param card A numeral card to place in the caravan. + * + * @throws CaravanFatalException Table is closed. */ void Table::play_numeral_card(CaravanName cvname, Card card) { + if (closed) throw CaravanFatalException(EXC_CLOSED); Caravan *caravan_ptr = caravans[caravan_name_to_uint8_t_index(cvname)]; caravan_ptr->put_numeral_card(card); } @@ -117,6 +164,8 @@ void Table::play_numeral_card(CaravanName cvname, Card card) { * @param cvname A caravan name. * @return The index of the named caravan, as it is stored in the table's * internal array of caravans. + * + * @throws CaravanFatalException Invalid caravan name. */ uint8_t Table::caravan_name_to_uint8_t_index(CaravanName cvname) { switch (cvname) { diff --git a/src/caravan/view/view_tui.cpp b/src/caravan/view/view_tui.cpp index 5422bae..32e6d63 100644 --- a/src/caravan/view/view_tui.cpp +++ b/src/caravan/view/view_tui.cpp @@ -33,6 +33,8 @@ const uint16_t HEIGHT_CARD = 2; const uint16_t WIDTH_FACES = 5; const uint16_t HEIGHT_FACES = 2; +const uint8_t INPUT_MAX = 4; + std::shared_ptr gen_position(std::string position) { using namespace ftxui; return text(position) | borderEmpty | size(WIDTH, EQUAL, WIDTH_POSITION) | size(HEIGHT, EQUAL, HEIGHT_POSITION); @@ -139,36 +141,52 @@ std::shared_ptr gen_deck(std::string title, bool top, bool hide) { std::shared_ptr gen_input( std::shared_ptr comp_user_input, - std::string user_input, - std::string command, - std::string message) { + std::array notifs, + std::array moves) { using namespace ftxui; - return vbox({ - separatorEmpty(), - hbox(separatorEmpty(), text("YOU > "), comp_user_input->Render(), separatorEmpty()), - separatorEmpty(), + Elements e; - separator(), + e.push_back(separatorEmpty()); + e.push_back(hbox(separatorEmpty(), text("YOU > "), comp_user_input->Render(), separatorEmpty())); // TODO + e.push_back(separatorEmpty()); - separatorEmpty(), - hbox(separatorEmpty(), paragraph("YOU played KH onto 8C on Caravan C."), separatorEmpty()), - separatorEmpty(), - hbox(separatorEmpty(), paragraph("OPP has yet to move."), separatorEmpty()), - separatorEmpty(), + if(!notifs[0].empty() || !notifs[1].empty()) { + e.push_back(separator()); + e.push_back(separatorEmpty()); - separator(), + if(!notifs[0].empty()) { + e.push_back(hbox(separatorEmpty(), paragraph(notifs[0]), separatorEmpty())); + e.push_back(separatorEmpty()); + } - separatorEmpty(), - hbox(separatorEmpty(), paragraph("YOU to move next."), separatorEmpty()), - separatorEmpty(), - }) | border | size(WIDTH, EQUAL, 44); + if(!notifs[1].empty()) { + e.push_back(hbox(separatorEmpty(), paragraph(notifs[1]), separatorEmpty())); + e.push_back(separatorEmpty()); + } + } + + if(!moves[0].empty() || !moves[1].empty()) { + e.push_back(separator()); + e.push_back(separatorEmpty()); + + if(!moves[0].empty()) { + e.push_back(hbox(separatorEmpty(), paragraph(moves[0]), separatorEmpty())); + e.push_back(separatorEmpty()); + } + + if(!moves[1].empty()) { + e.push_back(hbox(separatorEmpty(), paragraph(moves[1]), separatorEmpty())); + e.push_back(separatorEmpty()); + } + } + + return vbox(e) | border | size(WIDTH, EQUAL, 44); } std::shared_ptr gen_game( std::shared_ptr comp_user_input, - std::string user_input, - std::string command, - std::string message) { + std::array notifs, + std::array moves) { using namespace ftxui; return hbox({ // OUTERMOST AREA @@ -219,7 +237,7 @@ std::shared_ptr gen_game( vbox({ // INPUT AREA hbox({}) | borderEmpty | size(HEIGHT, EQUAL, HEIGHT_CARAVAN), separatorEmpty(), - gen_input(comp_user_input, user_input, command, message) + gen_input(comp_user_input, notifs, moves) }), // input area }) | center; // outermost area @@ -234,7 +252,14 @@ std::shared_ptr gen_terminal_too_small( text("Width: " + std::to_string(terminal_size.dimx) + " < " + std::to_string(MIN_X)), text("Height: " + std::to_string(terminal_size.dimy) + " < " + std::to_string(MIN_Y)), separatorEmpty(), - text("Resize terminal or press Ctrl+C"), + text("Resize terminal or type Ctrl+C"), + }) | center; +} + +std::shared_ptr gen_closed() { + using namespace ftxui; + return vbox({ + text(""), }) | center; } @@ -244,12 +269,18 @@ void ViewTUI::run() { if(closed) return; - // Input data + // Screen config + bool exited; + Dimensions terminal_size {}; + + // User input std::string user_input; - bool confirmed; std::string command; - std::string message; - Dimensions terminal_size {}; + bool confirmed; + + // Messages to users + std::array notifs; + std::array moves; // Create screen ScreenInteractive screen = ScreenInteractive::Fullscreen(); @@ -264,45 +295,71 @@ void ViewTUI::run() { // Ensure maximum input length comp_user_input |= CatchEvent([&](Event event) { - return event.is_character() && user_input.size() >= 5; // TODO what is max input size? + return event.is_character() && user_input.size() >= INPUT_MAX; }); // Component tree auto component = Container::Vertical({ comp_user_input }); + // Initial notifications + notifs[0] = "Welcome to Caravan"; + notifs[1] = "YOU to move first."; // TODO + // Tweak how the component tree is rendered: auto renderer = Renderer(component, [&] { - // Closes on exit command from user input - if(closed) screen.Exit(); - - terminal_size = Terminal::Size(); - - // Error screen if less than minimum terminal dimensions - if (terminal_size.dimx < MIN_X || terminal_size.dimy < MIN_Y) { - user_input = ""; // Prevent user input change during error - return gen_terminal_too_small(terminal_size); - } - - // Handle user input - command = user_input; - if(command.ends_with('\n')) { - command.pop_back(); // removes '\n' - user_input = ""; - confirmed = true; - } else { - confirmed = false; + try { + if(closed) { + if(!exited) { + exited = true; + screen.Exit(); + } + return gen_closed(); + } + + terminal_size = Terminal::Size(); + + // Error screen if less than minimum terminal dimensions + if (terminal_size.dimx < MIN_X || terminal_size.dimy < MIN_Y) { + user_input = ""; // Prevent user input change during error + return gen_terminal_too_small(terminal_size); + } + + // Handle user input + command = user_input; + if(command.ends_with('\n')) { + command.pop_back(); // removes '\n' + user_input = ""; + confirmed = true; + + if(!command.empty()) + notifs[0] = "YOU entered: " + command; // TODO player name + + } else { + confirmed = false; + } + + // Send input to subscribers (i.e., Controller) + try { + for (ViewSubscriber *vs: subscribers) { + vs->on_view_user_input(command, confirmed); + } + } catch(CaravanInputException &e) { + // TODO on exception, show the previous command entered alongside error message + // "YOU entered P4F8. [error message]" + notifs[1] = e.what(); + } + + // TODO replace this with an 'exit early' signal from the model + // (i.e. not exciting because game has finished, but because of an exit signal from user) + //if(command == "EXIT") screen.Exit(); + + return gen_game(comp_user_input, notifs, moves); + + } catch(...) { + // Close gracefully on any unhandled exceptions + closed = true; + return gen_closed(); } - - // Send input to subscribers (i.e., Controller) - for (ViewSubscriber *vs: subscribers) { - vs->on_view_user_input(command, confirmed); - } - - // TODO replace this with an 'exit early' signal from the model - // (i.e. not exciting because game has finished, but because of an exit signal from user) - //if(command == "EXIT") screen.Exit(); - - return gen_game(comp_user_input, user_input, command, message); }); screen.Loop(renderer); diff --git a/test/caravan/model/test_caravan.cpp b/test/caravan/model/test_caravan.cpp index 1750a21..fe00290 100644 --- a/test/caravan/model/test_caravan.cpp +++ b/test/caravan/model/test_caravan.cpp @@ -4,6 +4,7 @@ #include "gtest/gtest.h" #include "caravan/model/caravan.h" +#include "caravan/core/common.h" #include "caravan/core/exceptions.h" @@ -332,8 +333,6 @@ TEST (TestCaravan, PutNumericCard_Error_CaravanFull) { Card c_num_7 = {SPADES, FIVE}; Card c_num_8 = {SPADES, THREE}; Card c_num_9 = {SPADES, FIVE}; - Card c_num_10 = {SPADES, THREE}; - Card c_num_11 = {SPADES, NINE}; cvn.put_numeral_card(c_num_1); cvn.put_numeral_card(c_num_2); @@ -343,13 +342,11 @@ TEST (TestCaravan, PutNumericCard_Error_CaravanFull) { cvn.put_numeral_card(c_num_6); cvn.put_numeral_card(c_num_7); cvn.put_numeral_card(c_num_8); - cvn.put_numeral_card(c_num_9); - cvn.put_numeral_card(c_num_10); - ASSERT_EQ(cvn.get_size(), 10); + ASSERT_EQ(cvn.get_size(), TRACK_NUMERIC_MAX); try { - cvn.put_numeral_card(c_num_11); + cvn.put_numeral_card(c_num_9); FAIL(); } catch (CaravanGameException &e) { @@ -437,19 +434,17 @@ TEST (TestCaravan, PutFaceCard_Error_FullFaceCardCapacity) { Card c_face_2 = {HEARTS, KING}; Card c_face_3 = {HEARTS, KING}; Card c_face_4 = {HEARTS, KING}; - Card c_face_5 = {HEARTS, KING}; - Card c_face_6 = {HEARTS, KING}; Slot ts; cvn.put_numeral_card(c_num); cvn.put_face_card(c_face_1, 1); cvn.put_face_card(c_face_2, 1); cvn.put_face_card(c_face_3, 1); - cvn.put_face_card(c_face_4, 1); - cvn.put_face_card(c_face_5, 1); + + ASSERT_EQ(cvn.get_slot(1).faces.size(), TRACK_FACE_MAX); try { - cvn.put_face_card(c_face_6, 1); + cvn.put_face_card(c_face_4, 1); FAIL(); } catch (CaravanGameException &e) { @@ -640,7 +635,7 @@ TEST (TestCaravan, RemoveSuit_Error_ExcludeOutOfRange) { } } -TEST (TestCaravan, RemoveNumericCard_RemovePos10) { +TEST (TestCaravan, RemoveNumericCard_WithJack_Position8) { auto cvn = Caravan(CARAVAN_D); cvn.put_numeral_card({SPADES, ACE}); @@ -651,23 +646,21 @@ TEST (TestCaravan, RemoveNumericCard_RemovePos10) { cvn.put_numeral_card({SPADES, SIX}); cvn.put_numeral_card({SPADES, SEVEN}); cvn.put_numeral_card({SPADES, EIGHT}); - cvn.put_numeral_card({SPADES, NINE}); - cvn.put_numeral_card({SPADES, TEN}); - ASSERT_EQ(cvn.get_size(), 10); + ASSERT_EQ(cvn.get_size(), 8); - cvn.put_face_card({SPADES, JACK}, 10); + cvn.put_face_card({SPADES, JACK}, 8); - ASSERT_EQ(cvn.get_size(), 9); + ASSERT_EQ(cvn.get_size(), 7); ASSERT_EQ(cvn.get_slot(1).card.suit, SPADES); ASSERT_EQ(cvn.get_slot(1).card.rank, ACE); - ASSERT_EQ(cvn.get_slot(9).card.suit, SPADES); - ASSERT_EQ(cvn.get_slot(9).card.rank, NINE); + ASSERT_EQ(cvn.get_slot(7).card.suit, SPADES); + ASSERT_EQ(cvn.get_slot(7).card.rank, SEVEN); try { - cvn.get_slot(10); + cvn.get_slot(8); FAIL(); } catch (CaravanGameException &e) { @@ -678,7 +671,7 @@ TEST (TestCaravan, RemoveNumericCard_RemovePos10) { } -TEST (TestCaravan, RemoveNumericCard_RemovePos1) { +TEST (TestCaravan, RemoveNumericCard_WithJack_Position1) { auto cvn = Caravan(CARAVAN_D); cvn.put_numeral_card({SPADES, ACE}); @@ -689,23 +682,21 @@ TEST (TestCaravan, RemoveNumericCard_RemovePos1) { cvn.put_numeral_card({SPADES, SIX}); cvn.put_numeral_card({SPADES, SEVEN}); cvn.put_numeral_card({SPADES, EIGHT}); - cvn.put_numeral_card({SPADES, NINE}); - cvn.put_numeral_card({SPADES, TEN}); - ASSERT_EQ(cvn.get_size(), 10); + ASSERT_EQ(cvn.get_size(), 8); cvn.put_face_card({SPADES, JACK}, 1); - ASSERT_EQ(cvn.get_size(), 9); + ASSERT_EQ(cvn.get_size(), 7); ASSERT_EQ(cvn.get_slot(1).card.suit, SPADES); ASSERT_EQ(cvn.get_slot(1).card.rank, TWO); - ASSERT_EQ(cvn.get_slot(9).card.suit, SPADES); - ASSERT_EQ(cvn.get_slot(9).card.rank, TEN); + ASSERT_EQ(cvn.get_slot(7).card.suit, SPADES); + ASSERT_EQ(cvn.get_slot(7).card.rank, EIGHT); try { - cvn.get_slot(10); + cvn.get_slot(8); FAIL(); } catch (CaravanGameException &e) { @@ -715,7 +706,7 @@ TEST (TestCaravan, RemoveNumericCard_RemovePos1) { } } -TEST (TestCaravan, RemoveNumericCard_RemovePos5) { +TEST (TestCaravan, RemoveNumericCard_WithJack_Position5) { auto cvn = Caravan(CARAVAN_D); cvn.put_numeral_card({SPADES, ACE}); @@ -726,14 +717,12 @@ TEST (TestCaravan, RemoveNumericCard_RemovePos5) { cvn.put_numeral_card({SPADES, SIX}); cvn.put_numeral_card({SPADES, SEVEN}); cvn.put_numeral_card({SPADES, EIGHT}); - cvn.put_numeral_card({SPADES, NINE}); - cvn.put_numeral_card({SPADES, TEN}); - ASSERT_EQ(cvn.get_size(), 10); + ASSERT_EQ(cvn.get_size(), 8); cvn.put_face_card({SPADES, JACK}, 5); - ASSERT_EQ(cvn.get_size(), 9); + ASSERT_EQ(cvn.get_size(), 7); ASSERT_EQ(cvn.get_slot(1).card.suit, SPADES); ASSERT_EQ(cvn.get_slot(1).card.rank, ACE); @@ -741,11 +730,11 @@ TEST (TestCaravan, RemoveNumericCard_RemovePos5) { ASSERT_EQ(cvn.get_slot(5).card.suit, SPADES); ASSERT_EQ(cvn.get_slot(5).card.rank, SIX); - ASSERT_EQ(cvn.get_slot(9).card.suit, SPADES); - ASSERT_EQ(cvn.get_slot(9).card.rank, TEN); + ASSERT_EQ(cvn.get_slot(7).card.suit, SPADES); + ASSERT_EQ(cvn.get_slot(7).card.rank, EIGHT); try { - cvn.get_slot(10); + cvn.get_slot(8); FAIL(); } catch (CaravanGameException &e) { diff --git a/test/caravan/model/test_game.cpp b/test/caravan/model/test_game.cpp index 1295f21..ca73c61 100644 --- a/test/caravan/model/test_game.cpp +++ b/test/caravan/model/test_game.cpp @@ -19,27 +19,6 @@ TEST (TestGame, Close) { ASSERT_TRUE(g.is_closed()); } -TEST (TestGame, Close_Error_AlreadyClosed) { - GameConfig gc = { - 30, 1, true, - 30, 1, true, - PLAYER_BOTTOM - }; - Game g{gc}; - - g.close(); - - try { - g.close(); - FAIL(); - - } catch (CaravanFatalException &e) { - - } catch (...) { - FAIL(); - } -} - TEST (TestGame, GetPlayer_Both) { GameConfig gc = { 30, 1, true,