#include #include #include #include #include "kalaha.h" #include "kalaha_io.h" /* Show a kalaha state on the screen using ncurses. We make no assumptions * about the contents of the screen but we assume that ncurses is * initialized and that the window size is at least 24 lines and 80 columns. */ void drawstate (kalaha_state * state, int lastmove) { char tmp[20]; int i, j, x, y, xadd, yadd; int maxx, maxy; int ys[5] = { 3, 5, 11, 17, 19 }; int cs[5] = { ACS_TTEE, ACS_PLUS, ACS_PLUS, ACS_PLUS, ACS_BTEE }; /* Clear the screen */ clear (); /* Assert the minimum screen size. */ getmaxyx (stdscr, maxy, maxx); assert (maxy >= 24); assert (maxx >= 80); /* Draw the boundaries around the holes unsing line segments * (see addch (3X)). */ /* Horizontal lines */ for (i=10; i<70; ++i) { mvaddch (3,i,ACS_HLINE); mvaddch (5,i,ACS_HLINE); mvaddch (11,i,ACS_HLINE); mvaddch (17,i,ACS_HLINE); mvaddch (19,i,ACS_HLINE); } /* Vertical lines */ for (j=3; j<19; ++j) { mvaddch (j, 10, ACS_VLINE); mvaddch (j, 19, ACS_VLINE); mvaddch (j, 20, ACS_VLINE); mvaddch (j, 29, ACS_VLINE); mvaddch (j, 30, ACS_VLINE); mvaddch (j, 39, ACS_VLINE); mvaddch (j, 40, ACS_VLINE); mvaddch (j, 49, ACS_VLINE); mvaddch (j, 50, ACS_VLINE); mvaddch (j, 59, ACS_VLINE); mvaddch (j, 60, ACS_VLINE); mvaddch (j, 69, ACS_VLINE); } /* Corners */ mvaddch (3, 10, ACS_ULCORNER); mvaddch (3, 69, ACS_URCORNER); mvaddch (19, 10, ACS_LLCORNER); mvaddch (19, 69, ACS_LRCORNER); /* Fix most intersections */ for (i=0; i<5; ++i) { mvaddch (ys[i], 19, cs[i]); mvaddch (ys[i], 20, cs[i]); mvaddch (ys[i], 29, cs[i]); mvaddch (ys[i], 30, cs[i]); mvaddch (ys[i], 39, cs[i]); mvaddch (ys[i], 40, cs[i]); mvaddch (ys[i], 49, cs[i]); mvaddch (ys[i], 50, cs[i]); mvaddch (ys[i], 59, cs[i]); mvaddch (ys[i], 60, cs[i]); } /* Fix rest of intersections */ mvaddch (5, 10, ACS_LTEE); mvaddch (5, 69, ACS_RTEE); mvaddch (11, 10, ACS_LTEE); mvaddch (11, 69, ACS_RTEE); mvaddch (17, 10, ACS_LTEE); mvaddch (17, 69, ACS_RTEE); /* The rest will draw the boundaries around A7 and B7 */ /* Horizontal lines */ for (i=1; i<=8; ++i) { mvaddch (7, i, ACS_HLINE); mvaddch (9, i, ACS_HLINE); mvaddch (19,i, ACS_HLINE); mvaddch (15, i+70, ACS_HLINE); mvaddch (13, i+70, ACS_HLINE); mvaddch (3, i+70, ACS_HLINE); } /* Vertical lines for A7 */ for (i=8; i<19; ++i) { mvaddch (i, 0, ACS_VLINE); mvaddch (i, 9, ACS_VLINE); } /* Vertical lines for B7 */ for (i=4; i<15; ++i) { mvaddch (i, 70, ACS_VLINE); mvaddch (i, 79, ACS_VLINE); } /* Fix intersections of A7 and B7 */ mvaddch (7, 0, ACS_ULCORNER); mvaddch (19, 0, ACS_LLCORNER); mvaddch (3, 79, ACS_URCORNER); mvaddch (15, 79, ACS_LRCORNER); mvaddch (7, 9, ACS_TTEE); mvaddch (7, 10, ACS_RTEE); mvaddch (9, 0, ACS_LTEE); mvaddch (9, 9, ACS_PLUS); mvaddch (9, 10, ACS_RTEE); mvaddch (19, 9, ACS_BTEE); mvaddch (19, 10, ACS_BTEE); mvaddch (15, 69, ACS_LTEE); mvaddch (15, 70, ACS_BTEE); mvaddch (13, 79, ACS_RTEE); mvaddch (13, 70, ACS_PLUS); mvaddch (13, 69, ACS_LTEE); mvaddch (3, 70, ACS_TTEE); mvaddch (3, 69, ACS_TTEE); tmp[0] = 'B'; tmp[1] = '7'; /* Draw one O per piece in each hole of player B. */ for (i=B7, x=1; i>=B1; --i, x+=10, tmp[1]--) { assert (state->holes[i] <= 72); y = 4 + ((i==B7)?4:0); mvaddch (y, x+3, tmp[0] | A_REVERSE); mvaddch (y, x+4, tmp[1] | A_REVERSE); y += 2; xadd = 0; yadd = 0; for (j=0; jholes[i]; j++) { mvaddch (y+yadd, x+xadd, 'O'); xadd++; if (xadd == 8) { yadd++; xadd = 0; } } } /* Draw one O per piece in each hole of player A. */ tmp[0] = 'A'; tmp[1] = '1'; for (i=A1, x=11; i<=A7; ++i, x+=10, tmp[1]++) { assert (state->holes[i] <= 80); y = 18 - ((i==A7)?4:0); mvaddch (y, x+3, tmp[0] | A_REVERSE); mvaddch (y, x+4, tmp[1] | A_REVERSE); y -= 2; xadd = 0; yadd = 0; for (j=0; jholes[i]; j++) { mvaddch (y+yadd, x+xadd, 'O'); xadd++; if (xadd == 8) { yadd--; xadd = 0; } } } /* Show current state on the top line. */ sprintf (tmp, "Player A %d", state->holes[A7]); mvaddstr (0, 0, tmp); sprintf (tmp, "%d Player B", state->holes[B7]); mvaddstr (0, 80-strlen(tmp), tmp); /* Show the last move received on the firste line. */ if (lastmove >= 0) { sprintf (tmp, "Last Move %c%d", (lastmove<=A7)?'A':'B', 1 + lastmove % 7); } else { sprintf (tmp, "Last Move None"); } /* Indicate that we're waiting for a move from the server. * This string will be overwritten by readmove. */ mvaddstr (0, 40-strlen (tmp)/2, tmp); mvaddstr (20, 0, "Waiting ... "); refresh (); } /* Read a kalaha state from a file. */ int readstate (FILE * file, kalaha_state * state) { char line[100], *p; int gotmachine = 0; int gotplayer = 0; int gotdot = 0; while (1) { if (fgets (line, 100, file) == NULL) break; /* Skip rest of line if the line was too small for * our buffer. The line is ignored completly. */ if (strchr (line, '\n') == NULL) { do { if (fgets (line, 100, file) == NULL) break; } while (strchr (line, '\n') == NULL); continue; } /* End of state description is signalled by a line with * a single dot. */ if ((strcmp (line, ".\n") == 0) || (strcmp (line, ".\r\n") == 0)) { gotdot = 1; break; } /* The number of pieces in each hole is in a line that * start with "Machine: " */ if (strncasecmp (line, "Machine: ", 9) == 0) { char * p = line+9; int i, count, tmp; gotmachine = 1; for (i=0; i<14; ++i) { if (sscanf (p, "%d%n", &tmp, &count) != 1) { gotmachine = 0; break; } else { p += count; state->holes[i] = tmp; } } while (isspace ((int)*p)) p++; if (*p) gotmachine = 0; continue; } /* The current player is in a line that starts with * the text "Player: ". */ if (strncasecmp (line, "Player: ", 8) == 0) { p = line+8; while (isspace ((int)*p)) p++; switch (*p) { case 'a': case 'A': gotplayer = 1; p++; state->player = PLAYERA; break; case 'b': case 'B': gotplayer = 1; p++; state->player = PLAYERB; break; default: gotplayer = 0; break; } while (isspace ((int)*p)) p++; if (*p) gotplayer = 0; continue; } } return gotmachine && gotplayer && gotdot; }