+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;
+}
+