(************************************************************
*	PART OF OTHELLO.PAS see file for details
**************************************************************)
 
 PROCEDURE calcmove( mover: color; VAR status: gamestatus;
                    VAR legallist: movelist; VAR bestmove: movedesc);
 TYPE
 movearray = ARRAY[1..30] OF movedesc;
 VAR
 bestsofar,cornmoves,m,respcornmoves:         INTEGER;
 move,movetemp:                               movedesc;
 aftermove:                                   gamestatus;
 responses:                                   movelist;
 
 PROCEDURE checkposition(VAR legallist: movelist; VAR cornmoves: INTEGER);
 VAR
 m,bestm,bestyet:  INTEGER;
 BEGIN
 bestyet := -MAXINT;
 cornmoves := 0;
 FOR m := 1 TO legallist.movecount DO WITH legallist.okmove[m],
 board[moveloc.row,moveloc.col] DO
    BEGIN
 bordnoncorn := FALSE;
 IF incenter4by4 THEN
 points := points + 10
 ELSE BEGIN
 IF corner THEN BEGIN
 points := points + 60;
 cornmoves := cornmoves + 1;
 END
 ELSE IF border THEN BEGIN
 bordnoncorn := TRUE;
 points := points + 25;
 END
 ELSE IF diagnexttocorner THEN
 points := points - 50;
 END;
                     IF points > bestyet THEN BEGIN
 bestyet := points;
 bestm := m;
 end;
 END; (*FOR m := 1 TO legallist.movecount...*)
 movetemp := legallist.okmove[1];
 legallist.okmove[1] := legallist.okmove[bestm];
 legallist.okmove[bestm] := movetemp;
 END; (*checkposition*)
 
 PROCEDURE sortmoves(VAR okmove: movearray;
                     l,r: INTEGER) (*into descending order by points*) ;
 VAR
    i,j,baseval:      INTEGER;
 BEGIN
 i := l;
 j := r;
 baseval := okmove[(i+j) DIV 2].points;
 REPEAT
 WHILE okmove[i].points > baseval DO
 i := i+1;
 WHILE okmove[j].points < baseval DO
 j := j-1;
 IF i <= j THEN BEGIN
 movetemp := okmove[i];
 okmove[i] := okmove[j];
 okmove[j] := movetemp;
 i := i+1;
 j := j-1;
 END;
 UNTIL i > j;
 IF l < j THEN sortmoves(okmove, l, j );
 IF i < r THEN sortmoves(okmove, i, r )
 END (* sortmoves *) ;

 PROCEDURE checkresponses(mover: color; VAR move: movedesc;
                          VAR responses: movelist; bestsofar: INTEGER);
 (*$G+*)
 LABEL 0;
       VAR
 contingent,c,r:                   INTEGER;
 x,y:                              coordinate;
 sq:                               squareloc;
 direc:                            direction;
 oppcolor:                         color;
 afterresp:                        gamestatus;
 cornercounter:                    BOOLEAN;
 respondmove:                      movedesc;
    counterresp:                      movelist;
 BEGIN
 oppcolor := flipof(mover);
 WITH move DO BEGIN
 contingent := 0;
 r := 1;
  REPEAT
 respondmove := responses.okmove[r];
 IF NOT board[moveloc.row,moveloc.col].incenter4by4 THEN
 FOR direc := north TO nw DO  WITH respondmove DO
 IF direc IN dirsflipped THEN  WITH moveloc DO
 IF board[row,col].adjacentsq[direc] = move.moveloc THEN BEGIN
 move.points := move.points - 5;
 IF move.points <= bestsofar THEN
 EXIT(checkresponses);
              END;
 afterresp := aftermove;
 makemove(afterresp,respondmove,FALSE);
 IF bordnoncorn THEN  WITH moveloc DO
                           IF afterresp.boardstatus[row,col].occupier = oppcolor THEN BEGIN
 bordnoncorn := FALSE;
 points := points - 65; (*40, plus the 25 given in checkposition*)
 IF points <= bestsofar THEN
 EXIT(checkresponses);
 END
    ELSE
 contingent := contingent + 8*respondmove.bordrsqsflipped;
 WITH respondmove.moveloc DO
 IF board[row,col].corner THEN BEGIN
 points := points - 55;
 IF cornmoves > 1 THEN
 IF board[moveloc.row,moveloc.col].corner THEN
 points := points -20;
 IF points <= bestsofar THEN
 EXIT(checkresponses);
 END;
 FOR x:=1 TO 8 DO FOR y:=1 TO 8 DO WITH afterresp.boardstatus[x,y] DO
 IF occupied THEN
 IF occupier = mover THEN
 FOR direc := north TO nw DO WITH afterresp DO BEGIN
 sq.row := x;
 sq.col := y;
 REPEAT
 sq := board[sq.row,sq.col].adjacentsq[direc];
 IF NOT sq.onboard THEN
 GOTO 0;
 IF NOT boardstatus[sq.row,sq.col].occupied THEN
 GOTO 0
 UNTIL boardstatus[sq.row,sq.col].occupier = oppcolor;
 END;
 makemove(afterresp,respondmove,TRUE);
                               findlegalmoves(afterresp,counterresp);
 cornercounter := FALSE;
 c := 1;
 WITH counterresp DO
 WHILE ( (c <= movecount) AND (NOT cornercounter) ) DO BEGIN
 WITH okmove[c].moveloc DO
 IF board[row,col].corner THEN
 cornercounter := TRUE;
 c := c + 1;
 END;
 IF NOT cornercounter THEN BEGIN
 points := points -190;
             IF points <= bestsofar THEN
 EXIT(checkresponses);
             END;
 0:
 IF afterresp.score[mover] = 0 THEN BEGIN
 points := -MAXINT+1; (*might be our only choice, so +1*)
 EXIT(checkresponses);
 END;
 r := r + 1;
 UNTIL r > responses.movecount;
 IF bordnoncorn THEN BEGIN
 points := points - contingent;
 WITH board[moveloc.row,moveloc.col] DO
 IF specialbordersq THEN WITH otherofpair,
 status.boardstatus[row,col] DO
 IF occupied THEN
 IF occupier = mover THEN
 WITH status.boardstatus[between.row,between.col] DO
 IF NOT occupied THEN
 points := points - 90;
 END;
       END; (*WITH move...*)
 END; (*checkresponses*)
 
 BEGIN (*calcmove*)
               GOTOXY(0,23);
 WRITE('Calculating move for ',colorword[mover],'...');
 checkposition(legallist,cornmoves);
 IF legallist.movecount > 2 THEN
    sortmoves(legallist.okmove,2,legallist.movecount);
 bestsofar := -MAXINT;
 FOR m := 1 TO legallist.movecount DO BEGIN
 move := legallist.okmove[m];
 aftermove := status;
 makemove(aftermove,move,TRUE);
 findlegalmoves(aftermove,responses);
 WITH move DO BEGIN
 IF responses.movecount = 0 THEN
 points := points + 100
 ELSE
 IF points > bestsofar THEN BEGIN
 checkposition(responses,respcornmoves);
 checkresponses(mover,move,responses,bestsofar);
       END;
 IF points > bestsofar THEN BEGIN
 bestsofar := points;
 bestmove := move;
 END;
 END; (*WITH move...*)
 END; (*FOR m := 1 TO legallist.movecount...*)
 END; (*calcmove*)
 
 PROCEDURE play(mover: color);
 BEGIN
 GOTOXY(0,20+ORD(mover));
 IF legalmoves[mover] > 0 THEN BEGIN
 WRITE(spaces);
 IF mover = usercolor THEN
 inputmove(mover,legallist,move)
 ELSE
                               calcmove(mover,status,legallist,move);
 makemove(status,move,TRUE);
 updatecrt(crtstatus,status);
 crtstatus := status;
 END
 ELSE BEGIN
 WRITE('(No legal moves for ',colorword[mover],')');
 status.nextmover := flipof(mover);
 END;
 END; (*play*)
 
 FUNCTION userquits: BOOLEAN;
 VAR
 playagain:        CHAR;
 BEGIN
 GOTOXY(0,20);
 WRITELN(spaces); WRITELN(spaces); WRITELN; WRITE(spaces);
 GOTOXY(0,23);
 WRITE('Start a new game? (y/n): ');
 READ(playagain);
 userquits := NOT (playagain IN ['Y','y']);
 END; (*userquits*)
 
 
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     
