From 00fe0c43e7080a8d8af2566196a8540eee553ad2 Mon Sep 17 00:00:00 2001 From: Joursoir Date: Wed, 17 Feb 2021 19:02:29 +0000 Subject: add command line user interface (clui); improve GameField class --- GameField.cpp | 34 ++++++++++-- GameField.hpp | 14 ++--- clui.cpp | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+), 11 deletions(-) create mode 100644 clui.cpp diff --git a/GameField.cpp b/GameField.cpp index 381275e..51c0347 100644 --- a/GameField.cpp +++ b/GameField.cpp @@ -1,17 +1,43 @@ #include "GameField.hpp" -bool GameField::CanMove(int x, int y) +GameField::GameField(int a_cols, int a_rows, int a_lwin) + : cols(a_cols), rows(a_rows), win_length(a_lwin), state(G_NONE), + who_move(G_XPLAYER) +{ + int c, r; + field = new int*[cols]; + for(c = 0; c < cols; c++) { + field[c] = new int[rows]; + for(r = 0; r < rows; r++) { + field[c][r] = G_EMPTY; + } + } + free_fields = cols * rows; +} + +GameField::~GameField() +{ + if(field) { + int c; + for(c = 0; c < cols; c++) { + delete[] field[c]; + } + delete[] field; + } +} + +bool GameField::CanMove(int y, int x) { if(field[y][x] != G_EMPTY) return false; return true; } -void GameField::Move(int x, int y) +void GameField::Move(int y, int x) { field[y][x] = who_move; who_move = -who_move; // change player - free--; + free_fields--; UpdateState(); } @@ -20,7 +46,7 @@ void GameField::UpdateState() { int tmp; - if(!free) { + if(!free_fields) { state = G_DRAW; return; } diff --git a/GameField.hpp b/GameField.hpp index 1d2af31..d312644 100644 --- a/GameField.hpp +++ b/GameField.hpp @@ -11,21 +11,21 @@ enum states { class GameField { // optional: - int field[3][3]; - int free; + int **field; + int cols, rows; + int free_fields; int win_length; // non-optional: int state; int who_move; public: - GameField() : field{0}, free(9), win_length(3), state(G_NONE), - who_move(G_XPLAYER) { } - ~GameField() { } + GameField(int a_cols, int a_rows, int a_lwin); + ~GameField(); int GetState() { return state; } - bool CanMove(int x, int y); - void Move(int x, int y); + bool CanMove(int y, int x); + void Move(int y, int x); private: void UpdateState(); diff --git a/clui.cpp b/clui.cpp new file mode 100644 index 0000000..9dc3140 --- /dev/null +++ b/clui.cpp @@ -0,0 +1,166 @@ +#include + +#include "GameField.hpp" + +#define SYMBOL_PLAYERONE 'x' +#define SYMBOL_PLAYERTWO 'o' + +enum keys { + key_restart = 'r', + key_escape = 27, + key_enter = 10 +}; + +/* clui vars */ +int min_y, max_y, min_x, max_x; + +/* game vars */ +GameField *game_field; + +/* players vars */ +int cursor_y, cursor_x; +char player_symbol; + +/* command line options */ +int gb_y = 3; +int gb_x = 3; +int gb_lwin = 3; +int gb_symbol = SYMBOL_PLAYERONE; + +void updateCursor() +{ + move(cursor_y, cursor_x); + refresh(); +} + +void dbgprint(const char *msg) +{ + mvprintw(10, 0, " "); // clear old + mvprintw(10, 0, msg); + updateCursor(); // return cursor back + refresh(); +} + +void drawGame(int cols, int rows, int symbol) +{ + /* MAKE: draw for custom cols and rows */ + mvprintw(0, 0, "012"); + mvprintw(1, 0, "345"); + mvprintw(2, 0, "678"); + + min_y = 0; + max_y = cols-1; + min_x = 0; + max_x = rows-1; + + cursor_y = max_y / 2; + cursor_x = max_x / 2; + player_symbol = symbol; + updateCursor(); +} + +void changePlayer() +{ + if(player_symbol == SYMBOL_PLAYERONE) + player_symbol = SYMBOL_PLAYERTWO; + else + player_symbol = SYMBOL_PLAYERONE; +} + +void printMove(int y, int x, int symbol) +{ + move(y, x); + addch(symbol); + updateCursor(); +} + +void handleMove() +{ + if(!game_field->CanMove(cursor_y, cursor_x)) { + dbgprint("yet 'x' or 'o'"); + return; + } + game_field->Move(cursor_y, cursor_x); + printMove(cursor_y, cursor_x, player_symbol); + changePlayer(); + + int state = game_field->GetState(); + if(state == G_NONE) { + /* if play with AI: + ai move */ + } + else if(state == G_DRAW) + dbgprint("DRAW!"); + else if(state == G_XPLAYER) + dbgprint("PLAYER 'X' WIN!"); + else if(state == G_OPLAYER) + dbgprint("PLAYER 'O' WIN!"); +} + +void handleButtons() +{ + int ch; + while((ch = getch()) != key_escape) + { + switch(ch) + { + case KEY_LEFT: + if(cursor_x != min_x) { + cursor_x -= 1; + } + else dbgprint("left border"); + break; + case KEY_DOWN: + if(cursor_y != max_y) { + cursor_y += 1; + } + else dbgprint("down border"); + break; + case KEY_UP: + if(cursor_y != min_y) { + cursor_y -= 1; + } + else dbgprint("up border"); + break; + case KEY_RIGHT: + if(cursor_x != max_x) { + cursor_x += 1; + } + else dbgprint("right border"); + break; + case key_enter: { + handleMove(); + break; + } + case key_restart: { + delete game_field; + drawGame(gb_y, gb_x, gb_symbol); + game_field = new GameField(gb_y, gb_x, gb_lwin); + // no break + } + default: + continue; + } + updateCursor(); + } +} + +int main(int argc, char *argv[]) +{ + /* ncurses settings */ + initscr(); + keypad(stdscr, TRUE); + noecho(); + + /* command line options */ + /* ... */ + + game_field = new GameField(gb_y, gb_x, gb_lwin); + drawGame(gb_y, gb_x, gb_symbol); + handleButtons(); + + if(game_field) + delete game_field; + endwin(); + return 0; +} -- cgit v1.2.3-18-g5258