summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoursoir <chat@joursoir.net>2021-02-17 19:02:29 +0000
committerJoursoir <chat@joursoir.net>2021-02-17 19:02:29 +0000
commit00fe0c43e7080a8d8af2566196a8540eee553ad2 (patch)
tree3e9c6af4a3af6cd68e89add8af09ef5fc832de0a
parent87d7320f84926c4d10734c773ecf3cf4eb47ddc4 (diff)
downloadlp-gomoku-00fe0c43e7080a8d8af2566196a8540eee553ad2.tar.gz
lp-gomoku-00fe0c43e7080a8d8af2566196a8540eee553ad2.tar.bz2
lp-gomoku-00fe0c43e7080a8d8af2566196a8540eee553ad2.zip
add command line user interface (clui); improve GameField class
-rw-r--r--GameField.cpp34
-rw-r--r--GameField.hpp14
-rw-r--r--clui.cpp166
3 files changed, 203 insertions, 11 deletions
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 <ncurses.h>
+
+#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;
+}