diff --git a/testing/history/data/files/artificial_player.cpp b/testing/history/data/files/artificial_player.cpp new file mode 100644 index 00000000..a6457f73 --- /dev/null +++ b/testing/history/data/files/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/testing/history/data/files/artificial_player.h b/testing/history/data/files/artificial_player.h new file mode 100644 index 00000000..8b564edd --- /dev/null +++ b/testing/history/data/files/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/testing/history/data/files/field.cpp b/testing/history/data/files/field.cpp new file mode 100644 index 00000000..d87128a8 --- /dev/null +++ b/testing/history/data/files/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/testing/history/data/files/field.h b/testing/history/data/files/field.h new file mode 100644 index 00000000..c93ea640 --- /dev/null +++ b/testing/history/data/files/field.h @@ -0,0 +1,43 @@ +#ifndef _FIELD_ +#define _FIELD_ + +#include "game_object.h" + +class Field : public GameObject { +public: + enum Token { + None = 0, + PlayerA = 1, + PlayerB = 4 + }; + + static Token Opponent( Token token ); + + struct Move { + int row; + int col; + }; + + Field(); + ~Field(); + + Field Clone() const; + void Clear(); + + void Show() const; + + int SameInRow( Token token, int amount ) const; + + bool InRange( const Move& move ) const; + bool IsEmpty( const Move& move ) const; + bool IsFull() const; + + void MakeMove( const Move& move, Token token ); + void ClearMove( const Move& move ); + +private: + Token** grid_; + int left_; +}; + +#endif // _FIELD_ diff --git a/testing/history/data/files/game_object.h b/testing/history/data/files/game_object.h new file mode 100644 index 00000000..fba0e6f3 --- /dev/null +++ b/testing/history/data/files/game_object.h @@ -0,0 +1,10 @@ +#ifndef _GAME_OBJECT_ +#define _GAME_OBJECT_ + +class GameObject { +public: + GameObject() {} + virtual ~GameObject() {} +}; + +#endif // _GAME_OBJECT_ diff --git a/testing/history/data/files/human_player.cpp b/testing/history/data/files/human_player.cpp new file mode 100644 index 00000000..4357d897 --- /dev/null +++ b/testing/history/data/files/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/testing/history/data/files/human_player.h b/testing/history/data/files/human_player.h new file mode 100644 index 00000000..afa98d55 --- /dev/null +++ b/testing/history/data/files/human_player.h @@ -0,0 +1,20 @@ +#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/testing/history/data/files/io.cpp b/testing/history/data/files/io.cpp new file mode 100644 index 00000000..ec65d0da --- /dev/null +++ b/testing/history/data/files/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/testing/history/data/files/io.h b/testing/history/data/files/io.h new file mode 100644 index 00000000..bacfe58e --- /dev/null +++ b/testing/history/data/files/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/testing/history/data/files/main.cpp b/testing/history/data/files/main.cpp new file mode 100644 index 00000000..8d15ea5f --- /dev/null +++ b/testing/history/data/files/main.cpp @@ -0,0 +1,11 @@ +#include "tictactoe.h" + +int main() { + TicTacToe tictactoe; + + while ( tictactoe.Start() ) { + tictactoe.Run(); + } + + return 0; +} diff --git a/testing/history/data/files/player.cpp b/testing/history/data/files/player.cpp new file mode 100644 index 00000000..a1b3694c --- /dev/null +++ b/testing/history/data/files/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/testing/history/data/files/player.h b/testing/history/data/files/player.h new file mode 100644 index 00000000..700b3e5e --- /dev/null +++ b/testing/history/data/files/player.h @@ -0,0 +1,23 @@ +#ifndef _PLAYER_ +#define _PLAYER_ + +#include "field.h" +#include "game_object.h" + + +class Player : public GameObject { +public: + Player( Field::Token token, const char* name ); + virtual ~Player(); + + virtual Field::Move Turn( const Field& field ) const = 0; + + const Field::Token& getToken() const; + const char* getName() const; + +protected: + const Field::Token token_; + const char* name_; +}; + +#endif // _PLAYER_ diff --git a/testing/history/data/files/template.cpp b/testing/history/data/files/template.cpp new file mode 100644 index 00000000..80e079ad --- /dev/null +++ b/testing/history/data/files/template.cpp @@ -0,0 +1,8 @@ + +#include "template.h" + +void work() +{ + int v = diff(9, 5); + double w = diff(0.5, 0.3); +} diff --git a/testing/history/data/files/template.h b/testing/history/data/files/template.h new file mode 100644 index 00000000..b0ae449a --- /dev/null +++ b/testing/history/data/files/template.h @@ -0,0 +1,6 @@ + +template +T diff(T a, T b) +{ + return a - b; +} diff --git a/testing/history/data/files/tictactoe.cpp b/testing/history/data/files/tictactoe.cpp new file mode 100644 index 00000000..b4ba8ef1 --- /dev/null +++ b/testing/history/data/files/tictactoe.cpp @@ -0,0 +1,86 @@ +#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/testing/history/data/files/tictactoe.h b/testing/history/data/files/tictactoe.h new file mode 100644 index 00000000..6bf279da --- /dev/null +++ b/testing/history/data/files/tictactoe.h @@ -0,0 +1,23 @@ +#ifndef _TIC_TAC_TOE_ +#define _TIC_TAC_TOE_ + +#include "field.h" +#include "player.h" + +class TicTacToe { +public: + TicTacToe(); + ~TicTacToe(); + + bool Start(); + void Run(); + +private: + void Reset(); + Player* SelectPlayer( Field::Token token, const char* name ) const; + + Player* players_[2]; + Field field_; +}; + +#endif // _TIC_TAC_TOE_ diff --git a/testing/history/data/invocation_tests.cpp b/testing/history/data/invocation_tests.cpp new file mode 100644 index 00000000..b57aa6ac --- /dev/null +++ b/testing/history/data/invocation_tests.cpp @@ -0,0 +1,119 @@ + +#define INVOCATION_TESTS + +// TEST: build history +// START ---------------------------------------------------------------------- + +// ACTIONS: activate all these symbols top to bottom: +class One; +int two; +struct Three; +enum Four +{ + FIVE +}; +#define SIX +typedef bool Seven; + +// RESULTS: +// - Seven is active +// - dropdown position at top: Seven +// - history menu: Seven at top + +// END ------------------------------------------------------------------------ + + + +// TEST: dropdown open/close - click +// START ---------------------------------------------------------------------- + +// ACTION: Expand dropdown and click outside +// RESULT: dropdown disappears + +// END ------------------------------------------------------------------------ + + + +// TEST: dropdown open/close - ESC +// START ---------------------------------------------------------------------- + +// ACTION: Expand dropdown and press ESC +// RESULT: dropdown disappears + +// END ------------------------------------------------------------------------ + + + +// TEST: going back +// START ---------------------------------------------------------------------- + +// ACTION: Click back button +// ACTION: Use action History -> Back +// ACTION: Context menu: Back +// ACTION: Press Backspace + +// RESULTS: +// - symbol name goes down +// - dropdown position goes down +// - history menu: current symbol always on top, end result: +// Three, Four, FIVE, SIX, Seven, two, One + +// END ------------------------------------------------------------------------ + + + +// TEST: going forward +// START ---------------------------------------------------------------------- + +// ACTION: Click forward button +// ACTION: Use action History -> Forward +// ACTION: Context menu: Forward + +// RESULTS: +// - symbol name goes up +// - dropdown position goes up +// - history menu: current symbl always on top, end result: +// SIX, FIVE, Four, Three, Seven, two, One + +// END ------------------------------------------------------------------------ + + + +// TEST: dropdown selection +// START ---------------------------------------------------------------------- + +// ACTION: Expand dropdown and click on One +// RESULTS: +// - One is activated +// - dropdown position down at One + +// END ------------------------------------------------------------------------ + + + +// TEST: history overwrite +// START ---------------------------------------------------------------------- + +namespace eight {} // <- ACTION: Activate namespace + +// RESULTS: +// - dropdown list shrinked to: eight, One +// - dropdown position at top +// - history menu shows: eight, SIX, FIVE, Four, ... + +// END ------------------------------------------------------------------------ + + + +// TEST: history menu selection +// START ---------------------------------------------------------------------- + +// ACTION: Select 'Three' from history menu + +// RESULTS: +// - dropdown list: Three, eight, One +// - dropdown position at top +// - history menu shows: Three, eight, SIX, FIVE, ... + +// END ------------------------------------------------------------------------ + diff --git a/testing/history/data/state_tests.cpp b/testing/history/data/state_tests.cpp new file mode 100644 index 00000000..23282a0f --- /dev/null +++ b/testing/history/data/state_tests.cpp @@ -0,0 +1,176 @@ + +#define STATE_TESTS + +// TEST: edge clicks +// START ---------------------------------------------------------------------- + +// ACTION 1: Search for 'TicTacToe::Run()' +// ACTION 2: Click edge 'TicTacToe::Run()' -> 'Field::Show()' +// ACTION 3: Click edge 'TicTacToe::Run()' -> 'Player::Turn()' +// ACTION 4: Click 'main()' + +// ACTION 5: go back +// RESULT 5: graph and code restored to edge 'TicTacToe::Run()' -> 'Player::Turn()' + +// ACTION 6: go back again +// RESULT 6: graph and code restored to edge 'TicTacToe::Run()' -> 'Field::Show()' + +// ACTION 6: go back again +// RESULT 6: graph and code restored to node 'TicTacToe::Run()' + +// END ------------------------------------------------------------------------ + + + +// TEST: graph manipulations & scroll position +// START ---------------------------------------------------------------------- + +// ACTION 1: Search for 'Field::Show()' +// ACTION 2: Click on 'Field' +// ACTION 3: Expand node 'Player' +// ACTION 4: Hide node 'GameObject' +// ACTION 5: Move node 'numberOut' far to the right +// ACTION 6: Scroll all the way to the right +// ACTION 7: Search for 'main' + +// ACTION 8: go back +// RESULTS 8: +// - scroll position restored +// - graph restored +// - Player expanded +// - GameObject hidden +// - 'numberOut' far right + +// ACTION 9: go back +// RESULTS 9: +// - 'GameObject' visible +// - 'numberOut' back to old position +// - Player still expanded + +// ACTION 10: go back +// RESULT 10: 'Field::Show()' restored + +// END ------------------------------------------------------------------------ + + + +// TEST: depth graph +// START ---------------------------------------------------------------------- + +// ACTION 1: Search for 'io::stringOut' +// ACTION 2: Show callee graph +// ACTION 3: Change depth to 1 +// ACTION 3: Hide node 'Field' +// ACTION 4: Search for 'main' + +// ACTION 5: go back +// RESULT 5: graph depth 1 restored + +// ACTION 6: go back +// RESULT 6: 'Field' restored + +// ACTION 7: go back +// RESULT 7: graph depth 5 restored + +// ACTION 8: go back +// RESULT 8: 'io::stringOut' graph restored + +// END ------------------------------------------------------------------------ + + + +// TEST: graph multiple active +// START ---------------------------------------------------------------------- + +// ACTION 1: Search for 'diff<..>' +// ACTION 2: Click on 'diff' +// ACTION 3: Search for 'main' + +// ACTION 4: go back +// RESULT 4: graph to 'diff' restored + +// ACTION 5: go back +// RESULT 5: graph with multiple active 'diff<..>' restored + +// END ------------------------------------------------------------------------ + + + +// TEST: local symbol +// START ---------------------------------------------------------------------- + +// ACTION 1: Search for 'Field::Show()' +// ACTION 2: Click local symbol 'row' +// ACTION 3: Activate other symbol + +// ACTION 4: go back +// RESULTS 4: +// - graph and code restored to 'Field::Show()' +// - local symbol 'row' active + +// END ------------------------------------------------------------------------ + + + +// TEST: code reference +// START ---------------------------------------------------------------------- + +// ACTION 1: Search for 'io::numberIn()' +// ACTION 2: Navigate to 3rd reference +// ACTION 3: Activate other symbol + +// ACTION 4: go back +// RESULTS 4: graph and code restored to 3rd reference of 'io::numberIn()' + +// END ------------------------------------------------------------------------ + + + +// TEST: snippet state & scroll position +// START ---------------------------------------------------------------------- + +// ACTION 1: Switch to code snippet mode +// ACTION 2: Search for 'io::stringOut()' +// ACTION 3: Minimize 2nd and 3rd snippet +// ACTION 4: Expand last snippet +// ACTION 5: Scroll to recognizeable position +// ACTION 6: Activate other symbol + +// ACTION 7: go back +// RESULTS 7: +// - Scroll position restored +// - Only first and last snippet expanded + +// END ------------------------------------------------------------------------ + + + +// TEST: code view mode +// START ---------------------------------------------------------------------- + +// ACTION 1: Search for 'Field::Show()' +// ACTION 2: Click maximize on second snippet + +// ACTION 3: go back +// RESULTS 3: +// - Snippet mode restored +// - Scroll position restored + +// END ------------------------------------------------------------------------ + + + +// TEST: single mode scroll position +// START ---------------------------------------------------------------------- + +// ACTION 1: Switch to code single file mode +// ACTION 2: Search for 'Field::SameInRow()' +// ACTION 3: Scroll to recognizeable position +// ACTION 4; Activate other symbol + +// ACTION 5: go back +// RESULTS 5: +// - Active symbol 'Field::SameInRow()' restored +// - Scroll position restored + +// END ------------------------------------------------------------------------ diff --git a/testing/history/history_tests.srctrlprj b/testing/history/history_tests.srctrlprj new file mode 100644 index 00000000..07739fe8 --- /dev/null +++ b/testing/history/history_tests.srctrlprj @@ -0,0 +1,33 @@ + + + Test Suites:\n\n [::\tmINVOCATION_TESTS\ts\tp]\n [::\tmSTATE_TESTS\ts\tp]\n + + + c++17 + + + unknown + x86_64 + unknown + unknown + + 0 + + + data/files/template.h + + C++ Source Group + + .cpp + .cxx + .cc + + + data + + enabled + C++ Source Group + + + 7 +