diff --git a/bin/app/data/src/tictactoe/artificial_player.cpp b/bin/app/data/src/tictactoe/artificial_player.cpp new file mode 100644 index 00000000..a6457f73 --- /dev/null +++ b/bin/app/data/src/tictactoe/artificial_player.cpp @@ -0,0 +1,67 @@ +#include "artificial_player.h" + +ArtificialPlayer::ArtificialPlayer( Field::Token token, const char* name ) + : Player( token, name ) { +} + +ArtificialPlayer::~ArtificialPlayer() { +} + +Field::Move ArtificialPlayer::Turn( const Field& field ) const { + Field fakeField = field.Clone(); + Node node = MinMax( fakeField, token_ ); + return node.move; +} + +ArtificialPlayer::Node ArtificialPlayer::MinMax( Field& field, Field::Token token ) const { + Node node; + node.value = -10000; + + Field::Move move; + int sameMove; + + for ( int i = 0; i < 3; i++ ) { + move.row = i; + + for ( int j = 0; j < 3; j++ ) { + move.col = j; + + if ( !field.IsEmpty( move ) ) { + continue; + } + + field.MakeMove( move, token ); + + int turnValue = Evaluate( field, token ); + if ( !turnValue && !field.IsFull() ) { + turnValue = -MinMax( field, Field::Opponent( token ) ).value; + } + + field.ClearMove( move ); + + if ( turnValue > node.value ) { + node.move = move; + node.value = turnValue; + sameMove = 1; + } else if ( turnValue == node.value ) { + sameMove++; + if ( 1 % sameMove == 0 ) { + node.move = move; + } + } + } + } + + return node; +} + +int ArtificialPlayer::Evaluate( const Field& field, Field::Token token ) const { + if ( field.SameInRow( token, 3 ) ) { + return 2; + } else if ( field.SameInRow( Field::Opponent( token ), 2 ) ) { + return -1; + } else if ( field.SameInRow( token, 2 ) > 1 ) { + return 1; + } + return 0; +} diff --git a/bin/app/data/src/tictactoe/artificial_player.h b/bin/app/data/src/tictactoe/artificial_player.h new file mode 100644 index 00000000..8b564edd --- /dev/null +++ b/bin/app/data/src/tictactoe/artificial_player.h @@ -0,0 +1,24 @@ +#ifndef _ARTIFICIAL_PLAYER_ +#define _ARTIFICIAL_PLAYER_ + +#include "player.h" + +class ArtificialPlayer : public Player { +public: + ArtificialPlayer( Field::Token token, const char* name ); + virtual ~ArtificialPlayer(); + + virtual Field::Move Turn( const Field& field ) const; + +private: + struct Node { + Field::Move move; + int value; + }; + + Node MinMax( Field& field, Field::Token token ) const; + + int Evaluate( const Field& field, Field::Token token ) const; +}; + +#endif // _ARTIFICIAL_PLAYER_ diff --git a/bin/app/data/src/tictactoe/field.cpp b/bin/app/data/src/tictactoe/field.cpp new file mode 100644 index 00000000..313ed89a --- /dev/null +++ b/bin/app/data/src/tictactoe/field.cpp @@ -0,0 +1,126 @@ +#include "field.h" + +#include "io.h" + +Field::Token Field::Opponent( Token token ) { + if ( token == PlayerA ) { + return PlayerB; + } else if (token == PlayerB){ + return PlayerA; + } else { + return None; + } +} + +Field::Field() + : left_( 9 ) { + grid_ = new Token* [3]; + for ( int i = 0; i < 3 ; i++ ) { + grid_[i] = new Token[3]; + } +} + +Field::~Field() { + for ( int i = 0; i < 3; i++ ) { + delete grid_[i]; + } + delete [] grid_; +} + +Field Field::Clone() const { + Field field; + for ( int i = 0; i < 3; i++ ) { + for ( int j = 0; j < 3; j++ ) { + field.grid_[i][j] = grid_[i][j]; + } + } + field.left_ = left_; + return field; +} + +void Field::Clear() { + for ( int i = 0; i < 3; i++ ) { + for ( int j = 0; j < 3; j++ ) { + grid_[i][j] = None; + } + } + left_ = 9; +} + +void Field::Show() const { + io::stringOut(" 1 2 3\n"); + for ( int row = 0; row < 3; row++ ) { + io::numberOut(row + 1); + io::stringOut(" "); + + for ( int col = 0; col < 3; col++ ) { + if ( grid_[row][col] == PlayerA ) { + io::stringOut(" X "); + } else if ( grid_[row][col] == PlayerB ) { + io::stringOut(" O "); + } else { + io::stringOut(" "); + } + + if ( col < 2 ) { + io::stringOut("|"); + } + } + + if ( row < 2 ) { + io::stringOut("\n -----------\n"); + } + } + io::stringOut("\n\n"); +} + +int Field::SameInRow( Token token, int amount ) const { + int sum = amount * token; + int count = 0; + + for ( int i = 0; i < 3; i++ ) { + if ( grid_[i][0] + grid_[i][1] + grid_[i][2] == sum ) { + count++; + } else if ( grid_[0][i] + grid_[1][i] + grid_[2][i] == sum ) { + count++; + } + } + + if ( grid_[0][0] + grid_[1][1] + grid_[2][2] == sum ) { + count++; + } else if ( grid_[2][0] + grid_[1][1] + grid_[0][2] == sum ) { + count++; + } + + return count; +} + +bool Field::InRange( const Move& move ) const { + return move.row >= 0 && move.row < 3 && move.col >= 0 && move.col < 3; +} + +bool Field::IsEmpty( const Move& move ) const { + return grid_[move.row][move.col] == None; +} + +bool Field::IsFull() const { + return left_ == 0; +} + +void Field::MakeMove( const Move& move, Token token ) { + if ( !InRange( move ) || !IsEmpty( move ) || token == None || !left_ ) { + return; + } + + grid_[move.row][move.col] = token; + left_--; +} + +void Field::ClearMove( const Move& move ) { + if ( !InRange( move ) || !IsEmpty( move ) || left_ == 9 ) { + return; + } + + grid_[move.row][move.col] = None; + left_++; +} diff --git a/bin/app/data/src/tictactoe/field.h b/bin/app/data/src/tictactoe/field.h index 24c3588a..ef3201e8 100644 --- a/bin/app/data/src/tictactoe/field.h +++ b/bin/app/data/src/tictactoe/field.h @@ -1,9 +1,6 @@ #ifndef _FIELD_ #define _FIELD_ -#include -#include - class Field { public: enum Token { @@ -12,132 +9,29 @@ public: PlayerB = 4 }; - static Token Opponent( Token token ) { - assert( token != None ); - if ( token == PlayerA ) { - return PlayerB; - } else { - return PlayerA; - } - } + static Token Opponent( Token token ); struct Move { int row; int col; }; - Field() - : left_( 9 ) { - grid_ = new Token* [3]; - for ( int i = 0; i < 3 ; i++ ) { - grid_[i] = new Token[3]; - } - } + Field(); + ~Field(); - ~Field() { - for ( int i = 0; i < 3; i++ ) { - delete grid_[i]; - } - delete [] grid_; - } + Field Clone() const; + void Clear(); - Field Clone() const { - Field field; - for ( int i = 0; i < 3; i++ ) { - for ( int j = 0; j < 3; j++ ) { - field.grid_[i][j] = grid_[i][j]; - } - } - field.left_ = left_; - return field; - } + void Show() const; - void Clear() { - for ( int i = 0; i < 3; i++ ) { - for ( int j = 0; j < 3; j++ ) { - grid_[i][j] = None; - } - } - left_ = 9; - } + int SameInRow( Token token, int amount ) const; - void Show() const { - std::cout << " 1 2 3\n"; - for ( int row = 0; row < 3; row++ ) { - std::cout << row + 1 << " "; + bool InRange( const Move& move ) const; + bool IsEmpty( const Move& move ) const; + bool IsFull() const; - for ( int col = 0; col < 3; col++ ) { - if ( grid_[row][col] == PlayerA ) { - std::cout << " X "; - } else if ( grid_[row][col] == PlayerB ) { - std::cout << " O "; - } else { - std::cout << " "; - } - - if ( col < 2 ) { - std::cout << "|"; - } - } - - if ( row < 2 ) { - std::cout << "\n -----------\n"; - } - } - std::cout << "\n\n"; - } - - int SameInRow( Token token, int amount ) const { - int sum = amount * token; - int count = 0; - - for ( int i = 0; i < 3; i++ ) { - if ( grid_[i][0] + grid_[i][1] + grid_[i][2] == sum ) { - count++; - } else if ( grid_[0][i] + grid_[1][i] + grid_[2][i] == sum ) { - count++; - } - } - - if ( grid_[0][0] + grid_[1][1] + grid_[2][2] == sum ) { - count++; - } else if ( grid_[2][0] + grid_[1][1] + grid_[0][2] == sum ) { - count++; - } - - return count; - } - - bool InRange( const Move& move ) const { - return move.row >= 0 && move.row < 3 && move.col >= 0 && move.col < 3; - } - - bool IsEmpty( const Move& move ) const { - return grid_[move.row][move.col] == None; - } - - bool IsFull() const { - return left_ == 0; - } - - void MakeMove( const Move& move, Token token ) { - assert( InRange( move ) ); - assert( IsEmpty( move ) ); - assert( token != None ); - assert( left_ ); - - grid_[move.row][move.col] = token; - left_--; - } - - void ClearMove( const Move& move ) { - assert( InRange(move) ); - assert( !IsEmpty(move) ); - assert( left_ < 9 ); - - grid_[move.row][move.col] = None; - left_++; - } + void MakeMove( const Move& move, Token token ); + void ClearMove( const Move& move ); private: Token** grid_; diff --git a/bin/app/data/src/tictactoe/human_player.cpp b/bin/app/data/src/tictactoe/human_player.cpp new file mode 100644 index 00000000..4357d897 --- /dev/null +++ b/bin/app/data/src/tictactoe/human_player.cpp @@ -0,0 +1,49 @@ +#include "human_player.h" + +#include "io.h" + +HumanPlayer::HumanPlayer( Field::Token token, const char* name ) + : Player( token, name ) { +} + +HumanPlayer::~HumanPlayer() { +} + +Field::Move HumanPlayer::Turn( const Field& field ) const { + Field::Move move; + io::stringOut(name_); + io::stringOut("\n"); + + do { + move = Input(); + move.row -= 1; + move.col -= 1; + } while ( !Check( field, move ) ); + return move; +} + +Field::Move HumanPlayer::Input() const { + Field::Move move; + move.row = -1; + move.col = -1; + + io::stringOut("Insert row: "); + move.row = io::numberIn(); + + io::stringOut("Insert column: "); + move.col = io::numberIn(); + + io::stringOut("\n"); + return move; +} + +bool HumanPlayer::Check( const Field& field, const Field::Move& move ) const { + if ( !field.InRange( move ) ) { + io::stringOut("Wrong input!\n"); + return false; + } else if ( !field.IsEmpty( move ) ) { + io::stringOut("Is occupied!\n"); + return false; + } + return true; +} diff --git a/bin/app/data/src/tictactoe/human_player.h b/bin/app/data/src/tictactoe/human_player.h new file mode 100644 index 00000000..a2039fa3 --- /dev/null +++ b/bin/app/data/src/tictactoe/human_player.h @@ -0,0 +1,19 @@ +#ifndef _HUMAN_PLAYER_ +#define _HUMAN_PLAYER_ + +#include "player.h" + +class HumanPlayer : public Player { +public: + HumanPlayer( Field::Token token, const char* name ); + virtual ~HumanPlayer(); + + virtual Field::Move Turn( const Field& field ) const; + +private: + Field::Move Input() const; + + bool Check( const Field& field, const Field::Move& move ) const; +}; + +#endif // _HUMAN_PLAYER_ diff --git a/bin/app/data/src/tictactoe/io.cpp b/bin/app/data/src/tictactoe/io.cpp new file mode 100644 index 00000000..2b9511cc --- /dev/null +++ b/bin/app/data/src/tictactoe/io.cpp @@ -0,0 +1,23 @@ +#include "io.h" + +// #include +// #include +// #include + +int io::numberIn() { + // std::string input; + // getline( std::cin, input ); + // std::stringstream stream( input ); + + int number; + // stream >> number; + return number; +} + +void io::numberOut(int num) { + // std::cout << num; +} + +void io::stringOut(const char* str) { + // std::cout << str; +} diff --git a/bin/app/data/src/tictactoe/io.h b/bin/app/data/src/tictactoe/io.h new file mode 100644 index 00000000..bacfe58e --- /dev/null +++ b/bin/app/data/src/tictactoe/io.h @@ -0,0 +1,13 @@ +#ifndef _IO_ +#define _IO_ + +namespace io { + + int numberIn(); + void numberOut(int num); + + void stringOut(const char* str); + +} + +#endif // _IO_ diff --git a/bin/app/data/src/tictactoe/player.cpp b/bin/app/data/src/tictactoe/player.cpp new file mode 100644 index 00000000..a1b3694c --- /dev/null +++ b/bin/app/data/src/tictactoe/player.cpp @@ -0,0 +1,19 @@ +#include "player.h" + +Player::Player( Field::Token token, const char* name ) + : token_( token ) + , name_( name ) { +} + +Player::~Player() { +} + +const Field::Token& Player::getToken() const +{ + return token_; +} + +const char* Player::getName() const +{ + return name_; +} diff --git a/bin/app/data/src/tictactoe/player.h b/bin/app/data/src/tictactoe/player.h index f0029566..71a691a4 100644 --- a/bin/app/data/src/tictactoe/player.h +++ b/bin/app/data/src/tictactoe/player.h @@ -1,33 +1,21 @@ #ifndef _PLAYER_ #define _PLAYER_ -#include - #include "field.h" class Player { public: - Player( Field::Token token, const std::string& name ) - : token_( token ) - , name_( name ) { - } - virtual ~Player() {} + Player( Field::Token token, const char* name ); + virtual ~Player(); virtual Field::Move Turn( const Field& field ) const = 0; - const Field::Token& getToken() const - { - return token_; - } - - const std::string getName() const - { - return name_; - } + const Field::Token& getToken() const; + const char* getName() const; protected: const Field::Token token_; - const std::string name_; + const char* name_; }; #endif // _PLAYER_ diff --git a/bin/app/data/src/tictactoe/tictactoe.cpp b/bin/app/data/src/tictactoe/tictactoe.cpp new file mode 100644 index 00000000..d21a1025 --- /dev/null +++ b/bin/app/data/src/tictactoe/tictactoe.cpp @@ -0,0 +1,85 @@ +#include "tictactoe.h" + +#include "artificial_player.h" +#include "human_player.h" +#include "io.h" + +TicTacToe::TicTacToe() { + players_[0] = 0; + players_[1] = 0; +} + +TicTacToe::~TicTacToe() { + Reset(); +} + +bool TicTacToe::Start() { + Reset(); + io::stringOut("Tic Tac Toe\n\n[1] Human\n[2] Computer\n[3] Quit\n\n"); + + players_[0] = SelectPlayer( Field::PlayerA, "Player A" ); + if ( !players_[0] ) { + return false; + } + + players_[1] = SelectPlayer( Field::PlayerB, "Player B" ); + if ( !players_[1] ) { + return false; + } + + io::stringOut("\n"); + return true; +} + +void TicTacToe::Run() { + field_.Show(); + + int playerIndex = 0; + + for ( int i = 0; i < 9; i++ ) { + Player& player = *players_[playerIndex]; + + field_.MakeMove( player.Turn( field_ ), player.getToken() ); + field_.Show(); + + if ( field_.SameInRow( player.getToken(), 3 ) ) { + io::stringOut(player.getName()); + io::stringOut(" won!\n\n"); + return; + } + + playerIndex = ( playerIndex + 1 ) % 2; + } + + io::stringOut("Game ends in draw!\n\n"); +} + +void TicTacToe::Reset() { + field_.Clear(); + + for ( int i = 0; i < 2; i++ ) { + if ( players_[i] ) { + delete players_[i]; + players_[i] = 0; + } + } +} + +Player* TicTacToe::SelectPlayer( Field::Token token, const char* name ) const { + int selection = 0; + + while ( true ) { + io::stringOut("Choose "); + io::stringOut(name); + io::stringOut(": "); + + selection = io::numberIn(); + + switch ( selection ) { + case 1 : return new HumanPlayer( token, name ); + case 2 : return new ArtificialPlayer( token, name ); + case 3 : return 0; + default : io::stringOut("Wrong input!\n"); + } + } +} diff --git a/bin/app/data/src/tictactoe/tictactoe.h b/bin/app/data/src/tictactoe/tictactoe.h index cea41845..6bf279da 100644 --- a/bin/app/data/src/tictactoe/tictactoe.h +++ b/bin/app/data/src/tictactoe/tictactoe.h @@ -1,90 +1,20 @@ #ifndef _TIC_TAC_TOE_ #define _TIC_TAC_TOE_ -#include "computer.h" #include "field.h" -#include "human.h" -#include "input.h" #include "player.h" class TicTacToe { public: - TicTacToe() { - players_[0] = NULL; - players_[1] = NULL; - } + TicTacToe(); + ~TicTacToe(); - ~TicTacToe() { - Reset(); - } - - bool Start() { - Reset(); - std::cout << "Tic Tac Toe\n\n[1] Human\n[2] Computer\n[3] Quit\n\n"; - - players_[0] = SelectPlayer( Field::PlayerA, "PlayerA" ); - if ( !players_[0] ) { - return false; - } - - players_[1] = SelectPlayer( Field::PlayerB, "PlayerB" ); - if ( !players_[1] ) { - return false; - } - - std::cout << '\n'; - return true; - } - - void Run() { - field_.Show(); - - int playerIndex = 0; - - for ( int i = 0; i < 9; i++ ) { - Player& player = *players_[playerIndex]; - - field_.MakeMove( player.Turn( field_ ), player.getToken() ); - field_.Show(); - - if ( field_.SameInRow( player.getToken(), 3 ) ) { - std::cout << player.getName() << " won!\n\n"; - return; - } - - playerIndex = ( playerIndex + 1 ) % 2; - } - - std::cout << "Game ends in draw!\n\n"; - } + bool Start(); + void Run(); private: - void Reset() { - field_.Clear(); - - for ( int i = 0; i < 2; i++ ) { - if ( players_[i] ) { - delete players_[i]; - players_[i] = NULL; - } - } - } - - Player* SelectPlayer( Field::Token token, const std::string& name ) const { - int selection; - - while ( true ) { - std::cout << "Choose " << name << ": "; - input::number( &selection ); - - switch ( selection ) { - case 1 : return new HumanPlayer( token, name ); - case 2 : return new ArtificialPlayer( token, name ); - case 3 : return NULL; - default : std::cout << "Wrong input!\n"; - } - } - } + void Reset(); + Player* SelectPlayer( Field::Token token, const char* name ) const; Player* players_[2]; Field field_; diff --git a/bin/app/data/src/tictactoe/computer.h b/bin/app/data/src/tictactoe_old/computer.h similarity index 100% rename from bin/app/data/src/tictactoe/computer.h rename to bin/app/data/src/tictactoe_old/computer.h diff --git a/bin/app/data/src/tictactoe_old/field.h b/bin/app/data/src/tictactoe_old/field.h new file mode 100644 index 00000000..24c3588a --- /dev/null +++ b/bin/app/data/src/tictactoe_old/field.h @@ -0,0 +1,147 @@ +#ifndef _FIELD_ +#define _FIELD_ + +#include +#include + +class Field { +public: + enum Token { + None = 0, + PlayerA = 1, + PlayerB = 4 + }; + + static Token Opponent( Token token ) { + assert( token != None ); + if ( token == PlayerA ) { + return PlayerB; + } else { + return PlayerA; + } + } + + struct Move { + int row; + int col; + }; + + Field() + : left_( 9 ) { + grid_ = new Token* [3]; + for ( int i = 0; i < 3 ; i++ ) { + grid_[i] = new Token[3]; + } + } + + ~Field() { + for ( int i = 0; i < 3; i++ ) { + delete grid_[i]; + } + delete [] grid_; + } + + Field Clone() const { + Field field; + for ( int i = 0; i < 3; i++ ) { + for ( int j = 0; j < 3; j++ ) { + field.grid_[i][j] = grid_[i][j]; + } + } + field.left_ = left_; + return field; + } + + void Clear() { + for ( int i = 0; i < 3; i++ ) { + for ( int j = 0; j < 3; j++ ) { + grid_[i][j] = None; + } + } + left_ = 9; + } + + void Show() const { + std::cout << " 1 2 3\n"; + for ( int row = 0; row < 3; row++ ) { + std::cout << row + 1 << " "; + + for ( int col = 0; col < 3; col++ ) { + if ( grid_[row][col] == PlayerA ) { + std::cout << " X "; + } else if ( grid_[row][col] == PlayerB ) { + std::cout << " O "; + } else { + std::cout << " "; + } + + if ( col < 2 ) { + std::cout << "|"; + } + } + + if ( row < 2 ) { + std::cout << "\n -----------\n"; + } + } + std::cout << "\n\n"; + } + + int SameInRow( Token token, int amount ) const { + int sum = amount * token; + int count = 0; + + for ( int i = 0; i < 3; i++ ) { + if ( grid_[i][0] + grid_[i][1] + grid_[i][2] == sum ) { + count++; + } else if ( grid_[0][i] + grid_[1][i] + grid_[2][i] == sum ) { + count++; + } + } + + if ( grid_[0][0] + grid_[1][1] + grid_[2][2] == sum ) { + count++; + } else if ( grid_[2][0] + grid_[1][1] + grid_[0][2] == sum ) { + count++; + } + + return count; + } + + bool InRange( const Move& move ) const { + return move.row >= 0 && move.row < 3 && move.col >= 0 && move.col < 3; + } + + bool IsEmpty( const Move& move ) const { + return grid_[move.row][move.col] == None; + } + + bool IsFull() const { + return left_ == 0; + } + + void MakeMove( const Move& move, Token token ) { + assert( InRange( move ) ); + assert( IsEmpty( move ) ); + assert( token != None ); + assert( left_ ); + + grid_[move.row][move.col] = token; + left_--; + } + + void ClearMove( const Move& move ) { + assert( InRange(move) ); + assert( !IsEmpty(move) ); + assert( left_ < 9 ); + + grid_[move.row][move.col] = None; + left_++; + } + +private: + Token** grid_; + int left_; +}; + +#endif // _FIELD_ diff --git a/bin/app/data/src/tictactoe/human.h b/bin/app/data/src/tictactoe_old/human.h similarity index 100% rename from bin/app/data/src/tictactoe/human.h rename to bin/app/data/src/tictactoe_old/human.h diff --git a/bin/app/data/src/tictactoe/input.h b/bin/app/data/src/tictactoe_old/input.h similarity index 100% rename from bin/app/data/src/tictactoe/input.h rename to bin/app/data/src/tictactoe_old/input.h diff --git a/bin/app/data/src/tictactoe_old/main.cpp b/bin/app/data/src/tictactoe_old/main.cpp new file mode 100644 index 00000000..8d15ea5f --- /dev/null +++ b/bin/app/data/src/tictactoe_old/main.cpp @@ -0,0 +1,11 @@ +#include "tictactoe.h" + +int main() { + TicTacToe tictactoe; + + while ( tictactoe.Start() ) { + tictactoe.Run(); + } + + return 0; +} diff --git a/bin/app/data/src/tictactoe_old/player.h b/bin/app/data/src/tictactoe_old/player.h new file mode 100644 index 00000000..f0029566 --- /dev/null +++ b/bin/app/data/src/tictactoe_old/player.h @@ -0,0 +1,33 @@ +#ifndef _PLAYER_ +#define _PLAYER_ + +#include + +#include "field.h" + +class Player { +public: + Player( Field::Token token, const std::string& name ) + : token_( token ) + , name_( name ) { + } + virtual ~Player() {} + + virtual Field::Move Turn( const Field& field ) const = 0; + + const Field::Token& getToken() const + { + return token_; + } + + const std::string getName() const + { + return name_; + } + +protected: + const Field::Token token_; + const std::string name_; +}; + +#endif // _PLAYER_ diff --git a/bin/app/data/src/tictactoe_old/tictactoe.h b/bin/app/data/src/tictactoe_old/tictactoe.h new file mode 100644 index 00000000..cea41845 --- /dev/null +++ b/bin/app/data/src/tictactoe_old/tictactoe.h @@ -0,0 +1,93 @@ +#ifndef _TIC_TAC_TOE_ +#define _TIC_TAC_TOE_ + +#include "computer.h" +#include "field.h" +#include "human.h" +#include "input.h" +#include "player.h" + +class TicTacToe { +public: + TicTacToe() { + players_[0] = NULL; + players_[1] = NULL; + } + + ~TicTacToe() { + Reset(); + } + + bool Start() { + Reset(); + std::cout << "Tic Tac Toe\n\n[1] Human\n[2] Computer\n[3] Quit\n\n"; + + players_[0] = SelectPlayer( Field::PlayerA, "PlayerA" ); + if ( !players_[0] ) { + return false; + } + + players_[1] = SelectPlayer( Field::PlayerB, "PlayerB" ); + if ( !players_[1] ) { + return false; + } + + std::cout << '\n'; + return true; + } + + void Run() { + field_.Show(); + + int playerIndex = 0; + + for ( int i = 0; i < 9; i++ ) { + Player& player = *players_[playerIndex]; + + field_.MakeMove( player.Turn( field_ ), player.getToken() ); + field_.Show(); + + if ( field_.SameInRow( player.getToken(), 3 ) ) { + std::cout << player.getName() << " won!\n\n"; + return; + } + + playerIndex = ( playerIndex + 1 ) % 2; + } + + std::cout << "Game ends in draw!\n\n"; + } + +private: + void Reset() { + field_.Clear(); + + for ( int i = 0; i < 2; i++ ) { + if ( players_[i] ) { + delete players_[i]; + players_[i] = NULL; + } + } + } + + Player* SelectPlayer( Field::Token token, const std::string& name ) const { + int selection; + + while ( true ) { + std::cout << "Choose " << name << ": "; + input::number( &selection ); + + switch ( selection ) { + case 1 : return new HumanPlayer( token, name ); + case 2 : return new ArtificialPlayer( token, name ); + case 3 : return NULL; + default : std::cout << "Wrong input!\n"; + } + } + } + + Player* players_[2]; + Field field_; +}; + +#endif // _TIC_TAC_TOE_