* Author: Carl Worth <cworth@cworth.org>
*/
+#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
+#include <string.h>
+#include <ctype.h>
#include <glib.h>
#include "loa-board.h"
+static loa_bool_t
+loa_move_is_valid (const loa_move_t *move)
+{
+ return (move->x1 >= 0 && move->x1 < LOA_BOARD_SIZE &&
+ move->y1 >= 0 && move->y1 < LOA_BOARD_SIZE &&
+ move->x2 >= 0 && move->x2 < LOA_BOARD_SIZE &&
+ move->y2 >= 0 && move->y2 < LOA_BOARD_SIZE);
+}
+
+const char *
+loa_move_to_string (const loa_move_t *move)
+{
+#define LOA_MOVE_STRING_SIZE 6
+ static char move_string[LOA_MOVE_STRING_SIZE];
+
+ if (! loa_move_is_valid (move)) {
+ strcpy (move_string, "***");
+ return move_string;
+ }
+
+ snprintf (move_string, LOA_MOVE_STRING_SIZE,
+ "%c%d%c%c%d",
+ 'a' + move->x1, LOA_BOARD_SIZE - move->y1,
+ move->is_capture ? 'x' : '-',
+ 'a' + move->x2, LOA_BOARD_SIZE - move->y2);
+
+ return move_string;
+}
+
+loa_bool_t
+loa_move_init_from_string (loa_move_t *move, const char *string)
+{
+ char xc1, xc2, sep;
+ int x1, y1, x2, y2;
+ int matched;
+
+ /* Avoid returning uninitialized data on error. */
+ move->x1 = 0;
+ move->y1 = 0;
+ move->x2 = 0;
+ move->y2 = 0;
+ move->is_capture = 0;
+
+ matched = sscanf (string, " %c%d%c%c%d", &xc1, &y1, &sep, &xc2, &y2);
+ if (matched != 5)
+ return FALSE;
+
+ x1 = tolower (xc1) - 'a';
+ x2 = tolower (xc2) - 'a';
+ y1 = LOA_BOARD_SIZE - y1;
+ y2 = LOA_BOARD_SIZE - y2;
+
+ if (x1 < 0 || x1 >= LOA_BOARD_SIZE ||
+ y1 < 0 || y1 >= LOA_BOARD_SIZE ||
+ x2 < 0 || x2 >= LOA_BOARD_SIZE ||
+ y2 < 0 || y2 >= LOA_BOARD_SIZE)
+ {
+ return FALSE;
+ }
+
+ if (sep != '-' && sep != 'x' && sep != 'X')
+ return FALSE;
+
+ move->x1 = x1;
+ move->y1 = y1;
+ move->x2 = x2;
+ move->y2 = y2;
+
+ if (sep == 'x' || sep == 'X')
+ move->is_capture = TRUE;
+ else
+ move->is_capture = FALSE;
+
+ return TRUE;
+}
+
/* Given an (x,y) position on the board, return the index of the array
* used to count pieces in diagonal rows running from upper-left to
* lower-right, (like a grave accent: à or like a backslash: \).
void
loa_board_init (loa_board_t *board)
+{
+ board->moves = NULL;
+ board->moves_size = 0;
+
+ loa_board_reset (board);
+}
+
+void
+loa_board_fini (loa_board_t *board)
+{
+ if (board->moves)
+ free (board->moves);
+}
+
+void
+loa_board_reset (loa_board_t *board)
{
int i, x, y;
loa_board_add_piece (board, LOA_BOARD_SIZE - 1, i, LOA_CELL_WHITE);
}
+ /* Leave board->moves and board->moves_size as allocated */
+ board->num_moves = 0;
+
board->player = LOA_PLAYER_BLACK;
}
return 0;
}
-static loa_bool_t
-loa_board_move_legal (loa_board_t *board,
- int x1, int y1,
- int x2, int y2,
- char **error)
+loa_bool_t
+loa_board_move_is_legal (loa_board_t *board,
+ loa_move_t *move,
+ char **error)
{
int x, y;
+ int x1, y1, x2, y2;
int dx, dy;
int step_x, step_y;
- if (x1 < 0 || y1 < 0 || x1 >= LOA_BOARD_SIZE || y1 >= LOA_BOARD_SIZE) {
+ if (! loa_move_is_valid (move))
+ {
*error = "Invalid coordinates (not on board)";
return FALSE;
}
+ x1 = move->x1;
+ y1 = move->y1;
+ x2 = move->x2;
+ y2 = move->y2;
if (board->cells[x1][y1] == LOA_CELL_EMPTY) {
*error = "There is no piece there to move";
return FALSE;
}
+ if (board->cells[x2][y2] == LOA_CELL_EMPTY)
+ move->is_capture = FALSE;
+ else
+ move->is_capture = TRUE;
+
dx = x2 - x1;
dy = y2 - y1;
return TRUE;
}
+/* Once the move is validated and executed, append it to the moves
+ * array that stores the move history. */
+static void
+loa_board_add_move_to_history (loa_board_t *board,
+ const loa_move_t *move)
+{
+ board->num_moves++;
+
+ if (board->num_moves > board->moves_size) {
+ if (board->moves_size)
+ board->moves_size *= 2;
+ else
+ board->moves_size = 20;
+
+ board->moves = realloc (board->moves,
+ board->moves_size * sizeof (loa_move_t));
+ if (board->moves == NULL) {
+ fprintf (stderr, "Out of memory.\n");
+ exit (1);
+ }
+ }
+
+ board->moves[board->num_moves - 1] = *move;
+}
+
int
loa_board_move (loa_board_t *board,
- int x1, int y1,
- int x2, int y2,
+ loa_move_t *move,
char **error)
{
loa_cell_t cell;
- if (! loa_board_move_legal (board, x1, y1, x2, y2, error))
+ if (! loa_board_move_is_legal (board, move, error))
return FALSE;
- cell = loa_board_remove_piece (board, x1, y1);
- loa_board_remove_piece (board, x2, y2);
- loa_board_add_piece (board, x2, y2, cell);
+ cell = loa_board_remove_piece (board, move->x1, move->y1);
+ assert (cell == board->player);
+
+ cell = loa_board_remove_piece (board, move->x2, move->y2);
+ assert (cell == LOA_CELL_EMPTY ||
+ (move->is_capture && cell != board->player));
+
+ loa_board_add_piece (board,
+ move->x2, move->y2,
+ board->player);
+
+ loa_board_add_move_to_history (board, move);
loa_board_next_player (board);