/* allow.c Copyright (C) 1994 Lambert Klasen & Detlef Steuer klasen@asterix.uni-muenster.de steuer@amadeus.statistik.uni-dortmund.de This file is free source code; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See COPYING for more details. */ #include #include #include /* for the BOARD */ #include "gammon.h" /* check if a move is allowed */ int max_depth, /* max of current_depth */ current_depth = 0, /* current depth of move */ written_incomplete; /* flag if there are valid moves before there is a move with all dice used */ int done_yet; /* stones set yet */ extern int done_hit; /* stones hit (for UndoMove() only) */ MOVE current_move[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; /* global only for un_do() */ int test_move (void); int create_possible_moves (int dice_to_set, int *w, int actual_pin); int move_is_allowed (int from_pin, int to_pin); int current_in_rest (MOVE current_move[], MOVE rest_move[]); void print_possible_moves (void); extern void AppendMoveString (); extern int have_to_hit (); #define OFF_BOARD ((turn==BLACK) ? i+w[j] >= end_pin : i+w[j] <= end_pin) #define aim i+w[j] int create_possible_moves (int dice_to_set, int *w, int actual_pin) { int stop_pin, /* last pin with stones of color */ rest_dice = dice_to_set, /* are there dice to set */ rest[4], /* of dice to set */ endgame = 0, /* the game is in the endgame */ hit, /* hit some stones ? */ diffdice, /* difference of dice values */ maxpin; /* first pin with stones of color */ int i, j, k; static MOVE latest[4] = {{0, 0}, {0, 0}, {0, 0}, {0, 0}}; /* latest move examined */ if (actual_pin == end_pin) return dice_to_set; /* all done */ maxpin = start_pin; /* lookup first stone of color */ #ifdef DEBUG_POSSIBLE_MOVES printf("max- startpin: %d\n", maxpin); #endif while (!(Pin[maxpin].count && Pin[maxpin].color == turn)) maxpin += direction; #ifdef DEBUG_POSSIBLE_MOVES printf("maxpin: %d ", maxpin); #endif if (turn == BLACK && maxpin > 18) endgame = 1; else if (turn == WHITE && maxpin < 7) endgame = 1; if (Pin[BAR].count) /* where to stop */ stop_pin = BAR + direction; else stop_pin = end_pin; /* stop_pin letzter besetzter von machen */ if (actual_pin == stop_pin) return dice_to_set; /* at the end */ current_depth ++; while (!(Pin[actual_pin].count && Pin[actual_pin].color == turn)) { actual_pin += direction; if (actual_pin == end_pin) { current_depth --; /* don't forget */ return dice_to_set; } } #ifdef DEBUG_POSSIBLE_MOVES printf("stop pin: %d\n", stop_pin); #endif diffdice = dice_to_set; if (dice_to_set > 2) diffdice = 1; if (dice_to_set == 2) { if (w[0] == w[1]) diffdice = 1; else { if ( ((turn==BLACK) ? maxpin+w[0] >= end_pin : maxpin+w[0] <= end_pin) && ((turn==BLACK) ? maxpin+w[1] >= end_pin : maxpin+w[1] <= end_pin) ) diffdice = 1; else diffdice = 2; } } for (i=actual_pin; i!=stop_pin; i+=direction) { int break_flag = 0; while (Pin[i].color != turn) { i += direction; if (i == stop_pin) { break_flag = 1; break; } } if (break_flag) break; for (j=0; j 1)) || /* no other there ? */ (OFF_BOARD && ((endgame && i == maxpin) || (endgame && aim == end_pin)))) { /* case not on board a finish? */ /* have a move */ if (!OFF_BOARD) { /* no endgame */ if (Pin[aim].color == other) { /* hit other */ hit = 1; Pin[aim].color = turn; Pin[i].count --; if (Pin[i].count == 0) Pin[i].color = 0; } else { /* no hit */ Pin[aim].count ++; Pin[aim].color = turn; Pin[i].count --; if (Pin[i].count == 0) Pin[i].color = 0; } } else { /* endgame move */ Pin[i].count--; if (Pin[i].count == 0) Pin[i].color = 0; } for (k=0; k<4; k++) { /* delete dice */ if (kj) rest[k-1] = w[k]; } rest[3] = 0; latest[to_move-dice_to_set].from = i; /* possible entry in possible_moves */ if (!OFF_BOARD) latest[to_move-dice_to_set].to = aim; else latest[to_move-dice_to_set].to = end_pin; if (dice_to_set == 1) { /* last dice set i.e. move is complete */ if (written_incomplete) { list = possible_moves; written_incomplete = 0; } for (k = 0; k < to_move; k++) { /* enter in list */ list->from = latest[k].from; list->to = latest[k].to; list++; } for (k = to_move; k < 4; k++) { /* we decided that a move has alaways 4 parts so case no pash append zeros */ list->from = 0; list->to = 0; list++; } rest_dice = 0; max_depth = to_move; } else { /* move still incomplete */ if (j==0) rest_dice = create_possible_moves (dice_to_set-1, rest, i); else { rest_dice = create_possible_moves (dice_to_set-1, rest, i+direction); } if ((current_depth-1) >= max_depth) { written_incomplete = current_depth; /* flag to delete this moves if dice can be set comlete later (try figure out why!) */ max_depth = current_depth-1; /* max number of dice set yet */ for (k=0; kfrom = latest[k].from; list->to = latest[k].to; list ++; } for (k=current_depth; k<4; k++) { list->from = 0; list->to = 0; list ++; } } } /* end incomplete move */ Pin[i].count++; /* restore the board */ if (Pin[i].count == 1) Pin[i].color = turn; if (!OFF_BOARD) { if (hit) { Pin[aim].color = other; } else { Pin[aim].count--; if (Pin[aim].count == 0) Pin[aim].color = 0; } } } /* have found a movable stone */ } /* for all dice */ } /* for the board */ current_depth--; return rest_dice; } int test_move (void) { int move_depth; int possible_move_count; int k; max_depth = 0; current_depth = 0; written_incomplete = 0; list = possible_moves; move_depth = create_possible_moves (to_move, roll, start_pin); #ifdef WHATS_MAX_NUMBER { static int maxnumber=0; FILE *fid; if ((list-possible_moves)/4 > maxnumber) { maxnumber = (list-possible_moves)/4; fid = fopen("maxpos.xgammon", "a"); fprintf(fid," %d \n",maxnumber); fclose(fid); } } #endif #ifdef DEBUG_POSSIBLE_MOVES printf("maxdepth: %d\n", max_depth); printf("movedepth: %d\n", move_depth); print_possible_moves (); #endif /* check how many dice can be used this value should be returned by create_possible_moves() but doesn't */ for (k=0; k<4; k ++) { if (!(possible_moves+k)->from && !(possible_moves+k)->to ) break; } if (k < to_move) { to_move = k; if (k == 0) roll[0] = 0; /* global move done */ } #ifdef DEBUG_TM fprintf (stderr, "to_move %d\n", to_move); #endif /* check for use of greater dice value */ if (to_move == 1 && !pash) { int bigger_value = (abs(roll[0]) > abs(roll[1])) ? roll[0] : roll[1]; int have_bigger = 0; MOVE *m, *e = possible_moves; for (m=possible_moves; m!=list; m+=4) { if (m->to - m->from == bigger_value) { have_bigger = 1; break; } } if (have_bigger) { for (m=possible_moves; m!=list; m+=4) { if (m->to - m->from == bigger_value) { e->from = m->from; e->to = m->to; e += 4; } } list = e; } } possible_move_count = (list - possible_moves) / 4; return possible_move_count; } void print_possible_moves(void) { int k; MOVE *d; for (d = possible_moves; d!=list; d ++) { for (k = 0; k < 4; k++) printf ("%2d -> %2d ", d->from, d->to); printf ("\n"); } printf ("count = %d\n", (list - possible_moves) / 4); } int current_in_rest (MOVE current_move[], MOVE rest_move[]) { int i, j, possible = 1; for (i=0; ifrom == from_pin && (m+k)->to == to_pin) { for (j=0;jfrom; current_move[done_yet].to = (m+k)->to; done_yet++; } break; } } m += 4; } if (!allow) { m = possible_moves; while (!allow && m!= list) { /* test compound move */ from = from_pin; for (k=0; kfrom == from) { rest_move[k].from = rest_move[k].to = 0; if ((m+k)->to == to_pin) { allow = 1; } else from = (m+k)->to; } else { rest_move[k].from = (m+k)->from; rest_move[k].to = (m+k)->to; } } /* at this point it is clear, that the move is allowed and there is anything left over to move */ if (allow) { allow = current_in_rest(current_move,rest_move); } /* if current_in_rest() returns true, there is a possibible_move containing the already moved stones and the current move, so we can break the while loop */ if (!allow) m+=4; } /* while !allow && list */ if (allow ) { if (have_to_hit (from_pin, to_pin)) return 0; /* have a compound move and on between to hit a stone */ from = from_pin; for (k=0;kfrom == from) { current_move[done_yet].from = (m+k)->from; current_move[done_yet].to = (m+k)->to; done_yet++; if ((m+k)->to == to_pin) { break; } else from = (m+k)->to; } } } } /* test compound move */ if (allow) { if (done_yet == to_move) { AppendMoveString (current_move); for (i = 0; i < 4; i++) { current_move[i].from = 0; current_move[i].to = 0; } done_yet = 0; done_hit = 0; roll[0] = 0; /* reckon global */ return 1; } } else { /* !allow */ done_yet = old_done_yet; } return allow; }