introduced single machine mode

Tue, 01 Apr 2014 14:04:00 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 01 Apr 2014 14:04:00 +0200
changeset 26
e0a76ee1bb2b
parent 25
3ab0c2e1a4e2
child 27
efeb98bc69c9

introduced single machine mode

conf.mk file | annotate | diff | comparison | revisions
src/chess/chess.h file | annotate | diff | comparison | revisions
src/chess/conf.mk file | annotate | diff | comparison | revisions
src/chess/rules.h file | annotate | diff | comparison | revisions
src/game.c file | annotate | diff | comparison | revisions
src/game.h file | annotate | diff | comparison | revisions
src/main.c file | annotate | diff | comparison | revisions
src/terminal-chess.h file | annotate | diff | comparison | revisions
--- a/conf.mk	Tue Apr 01 12:30:25 2014 +0200
+++ b/conf.mk	Tue Apr 01 14:04:00 2014 +0200
@@ -32,7 +32,7 @@
 
 BIN        = terminal-chess
 CC         = gcc
-CFLAGS     = -g -O2 -std=gnu99 -Wall -Werror -pedantic
+CFLAGS     = -g -O2 -std=gnu99 -Wall -pedantic
 LD         = gcc
 LDFLAGS    = -lncurses
 ARFLAGS    = -r
--- a/src/chess/chess.h	Tue Apr 01 12:30:25 2014 +0200
+++ b/src/chess/chess.h	Tue Apr 01 14:04:00 2014 +0200
@@ -33,4 +33,4 @@
 #include "knight.h"
 #include "bishop.h"
 #include "queen.h"
-#include "king.h"
\ No newline at end of file
+#include "king.h"
--- a/src/chess/conf.mk	Tue Apr 01 12:30:25 2014 +0200
+++ b/src/chess/conf.mk	Tue Apr 01 14:04:00 2014 +0200
@@ -31,7 +31,7 @@
 AR      = ar
 
 CC         = gcc
-CFLAGS     = -g -O2 -std=gnu99 -Wall -Werror -pedantic
+CFLAGS     = -g -O2 -std=gnu99 -Wall -pedantic
 ARFLAGS    = -r
 MKDIRFLAGS = -p
 RMFLAGS    = -f -R
--- a/src/chess/rules.h	Tue Apr 01 12:30:25 2014 +0200
+++ b/src/chess/rules.h	Tue Apr 01 14:04:00 2014 +0200
@@ -78,6 +78,7 @@
     uint8_t promotion;
     _Bool check;
     _Bool checkmate;
+    _Bool stalemate; // TODO: find a better place for checkmate and stalemate
     _Bool capture;
 } Move;
 
--- a/src/game.c	Tue Apr 01 12:30:25 2014 +0200
+++ b/src/game.c	Tue Apr 01 14:04:00 2014 +0200
@@ -112,6 +112,78 @@
     }
 }
 
+static void eval_move_failed_msg(int code) {
+    switch (code) {
+    case AMBIGUOUS_MOVE:
+        printw("Ambiguous move - please specify the piece to move.");
+        break;
+    case INVALID_POSITION:
+        printw("Cannot find the piece that shall be moved.");
+        break;
+    case NEED_PROMOTION:
+        printw("You need to promote the pawn (append \"=Q\" e.g.)!");
+        break;
+    default:
+        printw("Can't interpret move - please use algebraic notation.");
+    }
+}
+
+static int domove_singlemachine(GameState *gamestate) {
+    
+    const size_t buflen = 8;
+    char movestr[buflen];
+    
+    int inputy = getmaxy(stdscr) - 6;
+    while (1) {
+        move(inputy, 0);
+        printw(
+            "Use chess notation to enter your move.\n"
+            "Or type 'surr' to surrender or 'remis' to end with remis.\n\n"
+            "Type your move: ");
+        clrtoeol();
+        refresh();
+        getnstr(movestr, buflen);
+
+        if (strncmp(movestr, "surr", buflen) == 0) {
+            printw("%s surrendered!",
+                gamestate->mycolor==WHITE?"White":"Black");
+            clrtoeol();
+            refresh();
+            return 1;
+        } else if (strncmp(movestr, "remis", buflen) == 0) {
+            printw("Game ends remis.");
+            clrtoeol();
+            refresh();
+            return 1;
+        } else {
+            Move move;
+            int eval_result = eval_move(gamestate, movestr, &move);
+            switch (eval_result) {
+            case VALID_MOVE_SYNTAX:
+                if (validate_move(gamestate, &move)) {
+                    apply_move(gamestate, &move);
+                    if (move.checkmate) {
+                        printw("Checkmate!");
+                        clrtoeol();
+                        return 1;
+                    } else if (move.stalemate) {
+                        printw("Stalemate!");
+                        clrtoeol();
+                        return 1;
+                    } else {
+                        return 0;
+                    }
+                } else {
+                    printw("Invalid move.");
+                }
+                break;
+            default:
+                eval_move_failed_msg(eval_result);
+            }
+            clrtoeol();
+        }
+    }
+}
 
 static int sendmove(GameState *gamestate, int opponent) {
     
@@ -167,6 +239,7 @@
                 code = net_recieve_code(opponent);
                 move.check = code == NETCODE_CHECK;
                 move.checkmate = code == NETCODE_CHECKMATE;
+                move.stalemate = code == NETCODE_STALEMATE;
                 if (code == NETCODE_DECLINE) {
                     printw("Invalid move.");
                 } else {
@@ -175,22 +248,17 @@
                         printw("Checkmate!");
                         clrtoeol();
                         return 1;
+                    } else if (move.stalemate) {
+                        printw("Stalemate!");
+                        clrtoeol();
+                        return 1;
                     } else {
                         return 0;
                     }
                 }
                 break;
-            case AMBIGUOUS_MOVE:
-                printw("Ambiguous move - please specify the piece to move.");
-                break;
-            case INVALID_POSITION:
-                printw("Cannot find the piece that shall be moved.");
-                break;
-            case NEED_PROMOTION:
-                printw("You need to promote the pawn (append \"=Q\" e.g.)!");
-                break;
             default:
-                printw("Can't interpret move - please use algebraic notation.");
+                eval_move_failed_msg(eval_result);
             }
             clrtoeol();
         }
@@ -234,6 +302,14 @@
                         net_send_code(opponent, NETCODE_CHECK);
                     } else if (move.checkmate) {
                         net_send_code(opponent, NETCODE_CHECKMATE);
+                        printw("\rCheckmate!");
+                        clrtoeol();
+                        return 1;
+                    } else if (move.stalemate) {
+                        net_send_code(opponent, NETCODE_STALEMATE);
+                        printw("\rStalemate!");
+                        clrtoeol();
+                        return 1;
                     } else {
                         net_send_code(opponent, NETCODE_ACCEPT);
                     }
@@ -245,11 +321,7 @@
     }
 }
 
-void game_start(Settings *settings, int opponent) {
-    _Bool myturn = is_server(settings) ==
-        (settings->gameinfo.servercolor == WHITE);
-    
-    GameState gamestate;
+static void init_board(GameState *gamestate) {
     Board initboard = {
         {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK},
         {WPAWN, WPAWN,   WPAWN,   WPAWN,  WPAWN, WPAWN,   WPAWN,   WPAWN},
@@ -260,7 +332,38 @@
         {BPAWN, BPAWN,   BPAWN,   BPAWN,  BPAWN, BPAWN,   BPAWN,   BPAWN},
         {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK}
     };
-    memcpy(gamestate.board, initboard, sizeof(Board));
+    memcpy(gamestate->board, initboard, sizeof(Board));
+}
+
+void game_start_singlemachine(Settings *settings) {
+    GameState gamestate;
+    init_board(&gamestate);
+    gamestate.mycolor = WHITE;
+    gamestate.movelist = gamestate.lastmove = NULL;
+    // TODO: time limit
+    _Bool running;
+    do {
+        clear();
+        draw_board(&gamestate);
+        running = !domove_singlemachine(&gamestate);
+        gamestate.mycolor = opponent_color(gamestate.mycolor);
+    }  while (running);
+    
+    gamestate_cleanup(&gamestate);
+    
+    mvaddstr(getmaxy(stdscr)-1, 0,
+        "Game has ended. Press any key to leave...");
+    refresh();
+    getch();
+}
+
+void game_start(Settings *settings, int opponent) {
+    _Bool myturn = is_server(settings) ==
+        (settings->gameinfo.servercolor == WHITE);
+    
+    // TODO: time limit
+    GameState gamestate;
+    init_board(&gamestate);
     gamestate.mycolor = myturn ? WHITE:BLACK;
     gamestate.movelist = gamestate.lastmove = NULL;
     
@@ -281,5 +384,6 @@
     
     mvaddstr(getmaxy(stdscr)-1, 0,
         "Game has ended. Press any key to leave...");
+    refresh();
     getch();
 }
--- a/src/game.h	Tue Apr 01 12:30:25 2014 +0200
+++ b/src/game.h	Tue Apr 01 14:04:00 2014 +0200
@@ -38,6 +38,7 @@
 #endif
 
 void game_start(Settings *settings, int opponent);
+void game_start_singlemachine(Settings *settings);
 
 #ifdef	__cplusplus
 }
--- a/src/main.c	Tue Apr 01 12:30:25 2014 +0200
+++ b/src/main.c	Tue Apr 01 14:04:00 2014 +0200
@@ -40,7 +40,7 @@
     uint8_t timeunit = 60;
     size_t len;
     
-    for (char opt ; (opt = getopt(argc, argv, "a:bhp:rt:")) != -1 ;) {
+    for (char opt ; (opt = getopt(argc, argv, "a:bhp:rst:")) != -1 ;) {
         switch (opt) {
         case 'b':
             settings->gameinfo.servercolor = BLACK;
@@ -48,6 +48,9 @@
         case 'r':
             settings->gameinfo.servercolor = rand() & 1 ? WHITE : BLACK;
             break;
+        case 's':
+            settings->singlemachine = 1;
+            break;
         case 't':
         case 'a':
             len = strlen(optarg);
@@ -150,10 +153,9 @@
             "  -a <time>     Specifies the time to add after each move\n"
             "  -b            Server plays black pieces (default: white)\n"
             "  -r            Distribute color randomly\n"
+            "  -s            Single machine mode\n"
             "  -t <time>     Specifies time limit (default: no limit)\n"
             "\nNotes\n"
-            "White pieces are displayed as uppercase and black pieces as "
-            "lowercase letters.\n"
             "The time unit for -a is seconds and for -t minutes by default. To "
             "specify\nseconds for the -t option, use the s suffix.\n"
             "Example: -t 150s\n"
@@ -173,6 +175,11 @@
     }
     atexit(leavescr);
     
-    return is_server(&settings) ? server_run(&settings) : client_run(&settings);
+    if (settings.singlemachine) {
+        game_start_singlemachine(&settings);
+    } else {
+        return is_server(&settings) ?
+            server_run(&settings) : client_run(&settings);
+    }
 }
 
--- a/src/terminal-chess.h	Tue Apr 01 12:30:25 2014 +0200
+++ b/src/terminal-chess.h	Tue Apr 01 14:04:00 2014 +0200
@@ -48,10 +48,11 @@
 } Gameinfo;
 
 typedef struct {
-    uint8_t printhelp;
     Gameinfo gameinfo;
     char* port;
     char* serverhost; /* NULL, if we are about to start a server */
+    _Bool printhelp;
+    _Bool singlemachine;
 } Settings;
 
 #define is_server(settings) !((settings)->serverhost)

mercurial