#include <perms.h>
// Edinburgh IMP77 Compiler - Version 8.4
//
// 1 %begin
int main(int argc, char **argv) { /*%begin*/
_imp_initialise(argc, argv);
// 2 %constant %byte maximising player = 0
// 3 %constant %byte maximising symbol = 'O'
// 4
// 5 %constant %byte minimising player = 1
// 6 %constant %byte minimising symbol = 'X'
// 7
// 8 %constant %byte unused symbol = '-'
// 9
// 10 %constant %byte machine = maximising player
// 11 %constant %byte machine symbol = maximising symbol
// 12 %constant %byte human = minimising player
// 13 %constant %byte human symbol = minimising symbol
// 14
// 15 ! Values to indicate game board layout
// 16 %constant %byte top left = 1
// 17 %constant %byte top centre = 2
// 18 %constant %byte top right = 3
// 19 %constant %byte middle left = 4
// 20 %constant %byte centre = 5
// 21 %constant %byte middle right = 6
// 22 %constant %byte bottom left = 7
// 23 %constant %byte bottom centre = 8
// 24 %constant %byte bottom right = 9
// 25
// 26 ! Assuming 32-bit integers are used
// 27 %constant %integer minus infinity = 16_80000000
// 28 %constant %integer plus infinity = 16_7fffffff
// 29
// 30 %integer game
int GAME;
// 31 %string(9) game state
_imp_string9 GAMESTATE;
// 32
// 33 %integer %function max( %integer a, b)
int MAX(int A, int B) {
// 34 %result = b %if (b > a)
if (B <= A) goto L_0001;
return B;
L_0001:;
// 35 %result = a
return A;
// 36 %end
} /* end of MAX */
// 37
// 38 %integer %function min( %integer a, b)
int MIN(int A, int B) {
// 39 %result = b %if (b < a)
if (B >= A) goto L_0002;
return B;
L_0002:;
// 40 %result = a
return A;
// 41 %end
} /* end of MIN */
// 42
// 43 %string(9) %function reset game
_imp_string9 RESETGAME(void) {
// 44 %integer i
int I;
// 45 %string(9) initial state
_imp_string9 INITIALSTATE;
// 46
// 47 ! clear the game state
// 48 initial state = ""
_imp_strncpy(/*?*/ &INITIALSTATE, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("");
(void *)&tmp;
}),
/*max:*/ 9);
// 49 ! completely populate the game state with the unused symbol
// 50 %for i = 1,1,9 %cycle
// %for I = 1, 1, 9 %cycle
{
I = 0;
L_0003:
if (I == 9) goto L_0004;
I += 1;
// 51 initial state = initial state.to string( unused symbol )
_imp_strncpy(/*?*/ &INITIALSTATE, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = *({
_imp_string255 tmp = _imp_join((_imp_string *)/*?*/ &INITIALSTATE, ({
__typeof__(_imp_string1) tmp; /*E*/
tmp = _imp_TOSTRING(45);
(void *)&tmp;
}));
(_imp_string255 *)&tmp;
});
(void *)&tmp;
}),
/*max:*/ 9);
// 52 %repeat
goto L_0003;
}
L_0004:;
// 53
// 54 %result = initial state
return *(_imp_string9 *)/*?*/ &INITIALSTATE;
// 55 %end
} /* end of RESETGAME */
// 56
// 57 %string(32) %function slot2name( %byte slot )
_imp_string32 SLOT2NAME(unsigned char SLOT) {
// 58 %string(32) name
_imp_string32 NAME;
// 59 %switch sw(0:255)
int SW_index;
int SW_line;
char *SW_file;
static const void *SW[256] = {
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing};
// 60
// 61 -> sw( slot )
SW_line = __LINE__;
SW_file = __FILE__;
SW_index = SLOT;
goto case_SW_dispatch;
// 62 sw(top left): name = "top left"; -> esac
case_SW_1:;
_imp_strncpy(/*?*/ &NAME, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("top left");
(void *)&tmp;
}),
/*max:*/ 32);
goto U_1000;
// 63 sw(top centre): name = "top centre"; -> esac
case_SW_2:;
_imp_strncpy(/*?*/ &NAME, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("top centre");
(void *)&tmp;
}),
/*max:*/ 32);
goto U_1000;
// 64 sw(top right): name = "top right"; -> esac
case_SW_3:;
_imp_strncpy(/*?*/ &NAME, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("top right");
(void *)&tmp;
}),
/*max:*/ 32);
goto U_1000;
// 65 sw(middle left): name = "middle left"; -> esac
case_SW_4:;
_imp_strncpy(/*?*/ &NAME, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("middle left");
(void *)&tmp;
}),
/*max:*/ 32);
goto U_1000;
// 66 sw(centre): name = "centre"; -> esac
case_SW_5:;
_imp_strncpy(/*?*/ &NAME, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("centre");
(void *)&tmp;
}),
/*max:*/ 32);
goto U_1000;
// 67 sw(middle right): name = "middle right"; -> esac
case_SW_6:;
_imp_strncpy(/*?*/ &NAME, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("middle right");
(void *)&tmp;
}),
/*max:*/ 32);
goto U_1000;
// 68 sw(bottom left): name = "bottom left"; -> esac
case_SW_7:;
_imp_strncpy(/*?*/ &NAME, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("bottom left");
(void *)&tmp;
}),
/*max:*/ 32);
goto U_1000;
// 69 sw(bottom centre): name = "bottom centre"; -> esac
case_SW_8:;
_imp_strncpy(/*?*/ &NAME, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("bottom centre");
(void *)&tmp;
}),
/*max:*/ 32);
goto U_1000;
// 70 sw(bottom right): name = "bottom right"; -> esac
case_SW_9:;
_imp_strncpy(/*?*/ &NAME, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("bottom right");
(void *)&tmp;
}),
/*max:*/ 32);
goto U_1000;
// 71 sw(*): name = "an illegal square"; -> esac
case_SW_default:;
_imp_strncpy(/*?*/ &NAME, ({
__typeof__(_imp_string255) tmp; /*B*/
tmp = _imp_str_literal("an illegal square");
(void *)&tmp;
}),
/*max:*/ 32);
goto U_1000;
// 72 esac:
U_1000:;
// 73
// 74 %result = name
return *(_imp_string32 *)/*?*/ &NAME;
// 75 %end
case_SW_dispatch:
if (SW_index < 0 || SW_index > 255)
_imp_signalf(6, 3, SW_index, "->SW(%d) out of bounds at %s line %d", SW_index, SW_file, SW_line);
goto *SW[SW_index - 0];
case_SW_missing:
_imp_signalf(8, 2, SW_index, "switch jump to undefined label SW(%d): at %s line %d", SW_index, SW_file, SW_line);
} /* end of SLOT2NAME */
// 76
// 77 %routine show state( %string(9) state )
void SHOWSTATE(_imp_string9 STATE) {
// 78 %integer i, j
int I;
int J;
// 79 %byte symbol
unsigned char SYMBOL;
// 80 %switch sw(1:9)
int SW_index;
int SW_line;
char *SW_file;
static const void *SW[9] = {&&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing,
&&case_SW_missing, &&case_SW_missing, &&case_SW_missing};
// 81
// 82 select output( 0 )
_imp_SELECTOUTPUT(0);
// 83 print string( state )
_imp_PRINTSTRING(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string255 *)&tmp;
})
);
// 84 newline
_imp_NEWLINE();
// 85 newline
_imp_NEWLINE();
// 86 %for i = 1,1,9 %cycle
// %for I = 1, 1, 9 %cycle
{
I = 0;
L_0007:
if (I == 9) goto L_0008;
I += 1;
// 87 symbol = charno( state, i )
SYMBOL = *_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &STATE, I);
// 88 %if (symbol = unused symbol) %then symbol = ' '
if (SYMBOL != 45) goto L_0009;
SYMBOL = 32;
L_0009:;
// 89
// 90 -> sw(i)
SW_line = __LINE__;
SW_file = __FILE__;
SW_index = I;
goto case_SW_dispatch;
// 91 sw(1): print symbol( symbol ); print symbol( '|' ); -> esac
case_SW_1:;
_imp_PRINTSYMBOL(SYMBOL);
_imp_PRINTSYMBOL(124);
goto U_1001;
// 92 sw(2): print symbol( symbol ); print symbol( '|' ); -> esac
case_SW_2:;
_imp_PRINTSYMBOL(SYMBOL);
_imp_PRINTSYMBOL(124);
goto U_1001;
// 93 sw(3): print symbol( symbol ); newline
case_SW_3:;
_imp_PRINTSYMBOL(SYMBOL);
_imp_NEWLINE();
// 94 print string( "-+-+-" ); newline; -> esac
_imp_PRINTSTRING(_imp_str_literal("-+-+-"));
_imp_NEWLINE();
goto U_1001;
// 95 sw(4): print symbol( symbol ); print symbol( '|' ); -> esac
case_SW_4:;
_imp_PRINTSYMBOL(SYMBOL);
_imp_PRINTSYMBOL(124);
goto U_1001;
// 96 sw(5): print symbol( symbol ); print symbol( '|' ); -> esac
case_SW_5:;
_imp_PRINTSYMBOL(SYMBOL);
_imp_PRINTSYMBOL(124);
goto U_1001;
// 97 sw(6): print symbol( symbol ); newline
case_SW_6:;
_imp_PRINTSYMBOL(SYMBOL);
_imp_NEWLINE();
// 98 print string( "-+-+-" ); newline; -> esac
_imp_PRINTSTRING(_imp_str_literal("-+-+-"));
_imp_NEWLINE();
goto U_1001;
// 99 sw(7): print symbol( symbol ); print symbol( '|' ); -> esac
case_SW_7:;
_imp_PRINTSYMBOL(SYMBOL);
_imp_PRINTSYMBOL(124);
goto U_1001;
// 100 sw(8): print symbol( symbol ); print symbol( '|' ); -> esac
case_SW_8:;
_imp_PRINTSYMBOL(SYMBOL);
_imp_PRINTSYMBOL(124);
goto U_1001;
// 101 sw(9): print symbol( symbol ); newline; -> esac
case_SW_9:;
_imp_PRINTSYMBOL(SYMBOL);
_imp_NEWLINE();
goto U_1001;
// 102
// 103 esac:
U_1001:;
// 104 %repeat
goto L_0007;
}
L_0008:;
// 105
// 106 newline
_imp_NEWLINE();
// 107
// 108 %end
return;
case_SW_dispatch:
if (SW_index < 1 || SW_index > 9)
_imp_signalf(6, 3, SW_index, "->SW(%d) out of bounds at %s line %d", SW_index, SW_file, SW_line);
goto *SW[SW_index - 1];
case_SW_missing:
_imp_signalf(8, 2, SW_index, "switch jump to undefined label SW(%d): at %s line %d", SW_index, SW_file, SW_line);
} /* end of SHOWSTATE */
// ?J unused
// 109
// 110 %predicate unused slot( %string(9) state, %byte square )
int UNUSEDSLOT(_imp_string9 STATE, unsigned char SQUARE) {
// 111 %true %if (charno( state , square ) = unused symbol)
if (*_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &STATE, SQUARE) != 45) goto L_000B;
return 1 /*TRUE*/;
L_000B:;
// 112 %false
return 0 /*FALSE*/;
// 113 %end
} /* end of UNUSEDSLOT */
// 114
// 115 ! Make a game move by storing player's symbol at given slot
// 116 %string(9) %function make move( %string(9) state, %byte slot, symbol )
_imp_string9 MAKEMOVE(_imp_string9 STATE, unsigned char SLOT, unsigned char SYMBOL) {
// 117 %string(9) next state
_imp_string9 NEXTSTATE;
// 118
// 119 next state = state
_imp_strncpy(/*?*/ &NEXTSTATE, ({
__typeof__(_imp_string9) tmp; /*B*/
tmp = STATE;
(void *)&tmp;
}),
/*max:*/ 9);
// 120 %if (top left <= slot <= bottom right) %start
{
// Double-sided test on SLOT (Part I)
unsigned char tmp;
if (1 > (tmp = SLOT)) goto L_000C;
// Double-sided test on SLOT (Part II)
if (tmp > 9) goto L_000C;
}
// 121 %if unused slot( state , slot ) %start
if (!(UNUSEDSLOT(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
SLOT)))
goto L_000D;
// 122 charno( next state, slot ) = symbol
*_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &NEXTSTATE, SLOT) = SYMBOL;
// 123 %finish %else %start
goto L_000E;
L_000D:;
// 124 select output( 0 )
_imp_SELECTOUTPUT(0);
// 125 print string( "Cheating detected! Player " )
_imp_PRINTSTRING(_imp_str_literal("Cheating detected! Player "));
// 126 print symbol( '"' )
_imp_PRINTSYMBOL(34);
// 127 print symbol( symbol )
_imp_PRINTSYMBOL(SYMBOL);
// 128 print symbol( '"' )
_imp_PRINTSYMBOL(34);
// 129 print string( " tried to overwrite player ")
_imp_PRINTSTRING(_imp_str_literal(" tried to overwrite player "));
// 130 print symbol( '"' )
_imp_PRINTSYMBOL(34);
// 131 print symbol( charno( state, slot ) )
_imp_PRINTSYMBOL(*_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &STATE, SLOT));
// 132 print symbol( '"' )
_imp_PRINTSYMBOL(34);
// 133 print string( " at square '".slot2name( slot )."'" )
_imp_PRINTSTRING(
*({
__typeof__(_imp_string255) tmp = *({
_imp_string255 tmp = _imp_join((_imp_string *)/*?*/ &*({
_imp_string255 tmp =
_imp_join((_imp_string *)/*?*/ _imp_str_literal_ptr(" at square '"), ({
__typeof__(_imp_string32) tmp; /*E*/
tmp = SLOT2NAME(SLOT);
(void *)&tmp;
}));
(_imp_string255 *)&tmp;
}),
(_imp_string *)/*?*/ _imp_str_literal_ptr("'"));
(_imp_string255 *)&tmp;
}) /*q*/;
(_imp_string255 *)&tmp;
})
);
// 134 new line
_imp_NEWLINE();
// 135 %finish
L_000E:;
// 136 %finish %else %start
goto L_000F;
L_000C:;
// 137 select output( 0 )
_imp_SELECTOUTPUT(0);
// 138 print string( "Cheating detected! Player '" )
_imp_PRINTSTRING(_imp_str_literal("Cheating detected! Player '"));
// 139 print symbol( symbol )
_imp_PRINTSYMBOL(SYMBOL);
// 140 print string( "' tried to move to '" )
_imp_PRINTSTRING(_imp_str_literal("' tried to move to '"));
// 141 print string( slot2name( slot ) )
_imp_PRINTSTRING(
*({
__typeof__(_imp_string32) tmp = SLOT2NAME(SLOT) /*q*/;
(_imp_string255 *)&tmp;
})
);
// 142 print string( "'" )
_imp_PRINTSTRING(_imp_str_literal("'"));
// 143 new line
_imp_NEWLINE();
// 144 print string( " Only squares 1..9 are valid!" )
_imp_PRINTSTRING(_imp_str_literal(" Only squares 1..9 are valid!"));
// 145 new line
_imp_NEWLINE();
// 146 %finish
L_000F:;
// 147 %result = next state
return *(_imp_string9 *)/*?*/ &NEXTSTATE;
// 148 %end
} /* end of MAKEMOVE */
// 149
// 150 %predicate my slot( %string(9) state, %byte slot id, symbol )
int MYSLOT(_imp_string9 STATE, unsigned char SLOTID, unsigned char SYMBOL) {
// 151 %true %if (charno( state, slot id ) = unused symbol)
if (*_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &STATE, SLOTID) != 45) goto L_0010;
return 1 /*TRUE*/;
L_0010:;
// 152 %false
return 0 /*FALSE*/;
// 153 %end
} /* end of MYSLOT */
// ?SYMBOL unused
// 154
// 155 ! Would the player win on their next move?
// 156 %predicate potential win line( %string(9) state, %byte symbol, p1,p2,p3 )
int POTENTIALWINLINE(_imp_string9 STATE, unsigned char SYMBOL, unsigned char P1, unsigned char P2, unsigned char P3) {
// 157 %byte pos 1, pos 2, pos 3
unsigned char POS1;
unsigned char POS2;
unsigned char POS3;
// 158
// 159 %predicate free slot( %byte slot id )
int FREESLOT(unsigned char SLOTID) {
// 160 %true %if (charno( state, slot id ) = unused symbol)
if (*_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &STATE, SLOTID) != 45) goto L_0011;
return 1 /*TRUE*/;
L_0011:;
// 161 %false
return 0 /*FALSE*/;
// 162 %end
} /* end of FREESLOT */
// 163
// 164 %predicate my slot( %byte slot id )
int MYSLOT(unsigned char SLOTID) {
// 165 %true %if (charno( state, slot id ) = symbol )
if (*_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &STATE, SLOTID) != SYMBOL) goto L_0012;
return 1 /*TRUE*/;
L_0012:;
// 166 %false
return 0 /*FALSE*/;
// 167 %end
} /* end of MYSLOT */
// 168
// 169 %true %if free slot( p1 ) %and my slot( p2 ) %and my slot( p3 )
if (!(FREESLOT(P1))) goto L_0013;
if (!(MYSLOT(P2))) goto L_0013;
if (!(MYSLOT(P3))) goto L_0013;
return 1 /*TRUE*/;
L_0013:;
// 170 %true %if my slot( p1 ) %and free slot( p2 ) %and my slot( p3 )
if (!(MYSLOT(P1))) goto L_0014;
if (!(FREESLOT(P2))) goto L_0014;
if (!(MYSLOT(P3))) goto L_0014;
return 1 /*TRUE*/;
L_0014:;
// 171 %true %if my slot( p1 ) %and my slot( p2 ) %and free slot( p3 )
if (!(MYSLOT(P1))) goto L_0015;
if (!(MYSLOT(P2))) goto L_0015;
if (!(FREESLOT(P3))) goto L_0015;
return 1 /*TRUE*/;
L_0015:;
// 172 %false
return 0 /*FALSE*/;
// 173 %end
} /* end of POTENTIALWINLINE */
// ?POS3 unused
// ?POS2 unused
// ?POS1 unused
// 174
// 175 ! Check for a potential winning line for the player using the given symbol
// 176 %predicate next move win( %string(9) state, %byte player symbol )
int NEXTMOVEWIN(_imp_string9 STATE, unsigned char PLAYERSYMBOL) {
// 177
// 178 ! Check for any potential winning lines for player symbol
// 179
// 180 ! check for any potential win in a horizontal row for player symbol
// 181 ! check top row (left,centre,right) == (1,2,3)
// 182 %true %if potential win line( state, player symbol, 1, 2, 3 )
if (!(POTENTIALWINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 1, 2, 3)))
goto L_0016;
return 1 /*TRUE*/;
L_0016:;
// 183
// 184 ! check middle row (left,centre,right) == (4,5,6)
// 185 %true %if potential win line( state, player symbol, 4, 5, 6 )
if (!(POTENTIALWINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 4, 5, 6)))
goto L_0017;
return 1 /*TRUE*/;
L_0017:;
// 186
// 187 ! check bottom row (left,centre,right) == (7,8,9)
// 188 %true %if potential win line( state, player symbol, 7, 8, 9 )
if (!(POTENTIALWINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 7, 8, 9)))
goto L_0018;
return 1 /*TRUE*/;
L_0018:;
// 189
// 190 ! check for any potential win in a vertical column for player symbol
// 191 ! check left column (top,middle,bottom) == (1,4,7)
// 192 %true %if potential win line( state, player symbol, 1, 4, 7 )
if (!(POTENTIALWINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 1, 4, 7)))
goto L_0019;
return 1 /*TRUE*/;
L_0019:;
// 193
// 194 ! check middle column (top,middle,bottom) == (2,5,8)
// 195 %true %if potential win line( state, player symbol, 2, 5, 8 )
if (!(POTENTIALWINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 2, 5, 8)))
goto L_001A;
return 1 /*TRUE*/;
L_001A:;
// 196
// 197 ! check right column (top,middle,bottom) == (3,6,9)
// 198 %true %if potential win line( state, player symbol, 3, 6, 9 )
if (!(POTENTIALWINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 3, 6, 9)))
goto L_001B;
return 1 /*TRUE*/;
L_001B:;
// 199
// 200 ! check for any potential diagonal win for the player symbol
// 201 ! check diagonal from top left to bottom right
// 202 ! diagonal is (top left,middle centre,bottom right) == (1,5,9)
// 203 %true %if potential win line( state, player symbol, 1, 5, 9 )
if (!(POTENTIALWINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 1, 5, 9)))
goto L_001C;
return 1 /*TRUE*/;
L_001C:;
// 204
// 205 ! check diagonal from top right to bottom left
// 206 ! diagonal is (top right,middle centre,bottom left) == (3,5,7)
// 207 %true %if potential win line( state, player symbol, 3, 5, 7 )
if (!(POTENTIALWINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 3, 5, 7)))
goto L_001D;
return 1 /*TRUE*/;
L_001D:;
// 208
// 209 ! no potential win line for symbol player
// 210 %false
return 0 /*FALSE*/;
// 211 %end
} /* end of NEXTMOVEWIN */
// 212
// 213 ! Check for a winning line for the player using the given symbol
// 214 %predicate win line( %string(9) state, %byte symbol, %byte p1,p2,p3 )
int WINLINE(_imp_string9 STATE, unsigned char SYMBOL, unsigned char P1, unsigned char P2, unsigned char P3) {
// 215 %byte pos 1, pos 2, pos 3
unsigned char POS1;
unsigned char POS2;
unsigned char POS3;
// 216
// 217 pos 1 = charno( state, p1 )
POS1 = *_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &STATE, P1);
// 218 pos 2 = charno( state, p2 )
POS2 = *_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &STATE, P2);
// 219 pos 3 = charno( state, p3 )
POS3 = *_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &STATE, P3);
// 220
// 221 %true %if (pos 1 = symbol) %and (pos 2 = symbol) %and (pos 3 = symbol)
if (POS1 != SYMBOL) goto L_001E;
if (POS2 != SYMBOL) goto L_001E;
if (POS3 != SYMBOL) goto L_001E;
return 1 /*TRUE*/;
L_001E:;
// 222 %false
return 0 /*FALSE*/;
// 223 %end
} /* end of WINLINE */
// 224
// 225 ! Check for a winning line for the player using the given symbol
// 226 %predicate player win( %string(9) state, %byte player symbol )
int PLAYERWIN(_imp_string9 STATE, unsigned char PLAYERSYMBOL) {
// 227
// 228 ! Check for any winning lines for player symbol
// 229
// 230 ! check for any win in a horizontal row for player symbol
// 231 ! check top row (left,centre,right) == (1,2,3)
// 232 %true %if win line( state, player symbol, 1, 2, 3 )
if (!(WINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 1, 2, 3)))
goto L_001F;
return 1 /*TRUE*/;
L_001F:;
// 233
// 234 ! check middle row (left,centre,right) == (4,5,6)
// 235 %true %if win line( state, player symbol, 4, 5, 6 )
if (!(WINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 4, 5, 6)))
goto L_0020;
return 1 /*TRUE*/;
L_0020:;
// 236
// 237 ! check bottom row (left,centre,right) == (7,8,9)
// 238 %true %if win line( state, player symbol, 7, 8, 9 )
if (!(WINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 7, 8, 9)))
goto L_0021;
return 1 /*TRUE*/;
L_0021:;
// 239
// 240 ! check for any win in a vertical column for player symbol
// 241 ! check left column (top,middle,bottom) == (1,4,7)
// 242 %true %if win line( state, player symbol, 1, 4, 7 )
if (!(WINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 1, 4, 7)))
goto L_0022;
return 1 /*TRUE*/;
L_0022:;
// 243
// 244 ! check middle column (top,middle,bottom) == (2,5,8)
// 245 %true %if win line( state, player symbol, 2, 5, 8 )
if (!(WINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 2, 5, 8)))
goto L_0023;
return 1 /*TRUE*/;
L_0023:;
// 246
// 247 ! check right column (top,middle,bottom) == (3,6,9)
// 248 %true %if win line( state, player symbol, 3, 6, 9 )
if (!(WINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 3, 6, 9)))
goto L_0024;
return 1 /*TRUE*/;
L_0024:;
// 249
// 250 ! check for any diagonal win for the player symbol
// 251 ! check diagonal from top left to bottom right
// 252 ! diagonal is (top left,centre,bottom right) == (1,5,9)
// 253 %true %if win line( state, player symbol, 1, 5, 9 )
if (!(WINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 1, 5, 9)))
goto L_0025;
return 1 /*TRUE*/;
L_0025:;
// 254
// 255 ! check diagonal from top right to bottom left
// 256 ! diagonal is (top right,centre,bottom left) == (3,5,7)
// 257 %true %if win line( state, player symbol, 3, 5, 7 )
if (!(WINLINE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
PLAYERSYMBOL, 3, 5, 7)))
goto L_0026;
return 1 /*TRUE*/;
L_0026:;
// 258
// 259 ! no win line for symbol player
// 260 %false
return 0 /*FALSE*/;
// 261 %end
} /* end of PLAYERWIN */
// 262
// 263 %predicate game over( %string(9) state )
int GAMEOVER(_imp_string9 STATE) {
// 264 %integer i
int I;
// 265 %integer unused
int UNUSED;
// 266
// 267 ! Check if there are any unused slots
// 268 unused = 0
UNUSED = 0;
// 269 %for i = 1,1,9 %cycle
// %for I = 1, 1, 9 %cycle
{
I = 0;
L_0027:
if (I == 9) goto L_0028;
I += 1;
// 270 unused = unused + 1 %if (charno( state, i ) <> unused symbol)
if (*_imp_CHARNO((_imp_string255 *)/*p*/ /*?*/ &STATE, I) == 45) goto L_0029;
UNUSED = UNUSED + 1;
L_0029:;
// 271 %repeat
goto L_0027;
}
L_0028:;
// 272
// 273 ! there are no unused slots so game must be over
// 274 %true %if (unused = 0)
if (UNUSED != 0) goto L_002A;
return 1 /*TRUE*/;
L_002A:;
// 275
// 276 ! there are some unused slots so game is not over
// 277 %false
return 0 /*FALSE*/;
// 278 %end
} /* end of GAMEOVER */
// 279
// 280 %predicate terminal state( %string(9) state )
int TERMINALSTATE(_imp_string9 STATE) {
// 281
// 282 ! Check for win lines for maximising player (machine)
// 283 %true %if player win( state, maximising symbol )
if (!(PLAYERWIN(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
79)))
goto L_002B;
return 1 /*TRUE*/;
L_002B:;
// 284
// 285 ! Check for win lines for minimising player
// 286 %true %if player win( state, minimising symbol )
if (!(PLAYERWIN(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
88)))
goto L_002C;
return 1 /*TRUE*/;
L_002C:;
// 287
// 288 ! check to see if the game has reached a state with no more moves
// 289 %true %if game over( state )
if (!(GAMEOVER(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
)))
goto L_002D;
return 1 /*TRUE*/;
L_002D:;
// 290
// 291 ! At this point:
// 292 ! there are no win lines for either player
// 293 ! and there are more moves to make
// 294 ! hence this is not a terminal node ( or game state )
// 295 %false
return 0 /*FALSE*/;
// 296 %end
} /* end of TERMINALSTATE */
// 297
// 298 %integer %function heuristic( %string(9) state )
int HEURISTIC(_imp_string9 STATE) {
// 299 ! check for a current/future win for the maximising player (machine)
// 300 %result = plus infinity %if player win( state, machine )
if (!(PLAYERWIN(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
0)))
goto L_002E;
return 2147483647;
L_002E:;
// 301 %result = plus infinity %if next move win( state, machine )
if (!(NEXTMOVEWIN(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
0)))
goto L_002F;
return 2147483647;
L_002F:;
// 302
// 303 ! check for a current/future win for the minimising player (human)
// 304 %result = minus infinity %if player win( state, human )
if (!(PLAYERWIN(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
1)))
goto L_0030;
return -2147483648;
L_0030:;
// 305 %result = minus infinity %if next move win( state, human )
if (!(NEXTMOVEWIN(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
1)))
goto L_0031;
return -2147483648;
L_0031:;
// 306
// 307 %result = 0
return 0;
// 308 %end
} /* end of HEURISTIC */
// 309
// 310 ! maximising player uses the 'maximising symbol' (machine)
// 311 ! minimising player uses the 'minimising symbol' (humane)
// 312 %integer %function minimax( %string(9) state,
int MINIMAX(_imp_string9 STATE, int DEPTH, int PLAYERGO) {
// 313+ %integer depth,
// 314+ %integer player go )
// 315 %string(9) new state
_imp_string9 NEWSTATE;
// 316 %integer value, response
int VALUE;
int RESPONSE;
// 317 %integer i
int I;
// 318
// 319 %if (depth = 0) %or terminal state( state ) %start
if (DEPTH == 0) goto L_0005;
if (!(TERMINALSTATE(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
)))
goto L_0032;
L_0005:;
// 320 value = heuristic( state )
VALUE = HEURISTIC(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
);
// 321 %finish %else %if (player go = machine) %start
goto L_0033;
L_0032:;
if (PLAYERGO != 0) goto L_0034;
// 322 ! check possible moves for the maximising player (machine)
// 323 ! set value = - infinity
// 324 value = minus infinity
VALUE = -2147483648;
// 325
// 326 ! for each potential next game state
// 327 %for i=1,1,9 %cycle
// %for I = 1, 1, 9 %cycle
{
I = 0;
L_0035:
if (I == 9) goto L_0036;
I += 1;
// 328 ! find an empty slot
// 329 %if unused slot( state, i) %start
if (!(UNUSEDSLOT(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
I)))
goto L_0038;
// 330 ! next state after the maximising player (machine) move
// 331 new state = make move( state, i, machine symbol )
_imp_strncpy(/*?*/ &NEWSTATE, ({
__typeof__(_imp_string9) tmp; /*B*/
tmp = MAKEMOVE(*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
}),
I, 79);
(void *)&tmp;
}),
/*max:*/ 9);
// 332 ! response from the minimising player (human)
// 333 response = minimax( new state, depth - 1, human )
RESPONSE = MINIMAX(
*({
__typeof__(_imp_string9) tmp = NEWSTATE /*q*/;
(_imp_string9 *)&tmp;
})
,
DEPTH - 1, 1);
// 334 value = max( value, response )
VALUE = MAX(VALUE, RESPONSE);
// 335 %finish
L_0038:;
// 336 %repeat
goto L_0035;
}
L_0036:;
// 337 %finish %else %start
goto L_0033;
L_0034:;
// 338 ! Oh! this must be for the minimising player (human)
// 339 ! set value = + infinity
// 340 value = plus infinity
VALUE = 2147483647;
// 341
// 342 ! for each potential next game state
// 343 %for i=1,1,9 %cycle
// %for I = 1, 1, 9 %cycle
{
I = 0;
L_0039:
if (I == 9) goto L_003A;
I += 1;
// 344 %if unused slot( state, i ) %start
if (!(UNUSEDSLOT(
*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
})
,
I)))
goto L_003B;
// 345 ! next state after the minimising player (human) move
// 346 new state = make move( state, i, human symbol )
_imp_strncpy(/*?*/ &NEWSTATE, ({
__typeof__(_imp_string9) tmp; /*B*/
tmp = MAKEMOVE(*({
__typeof__(_imp_string9) tmp = STATE /*q*/;
(_imp_string9 *)&tmp;
}),
I, 88);
(void *)&tmp;
}),
/*max:*/ 9);
// 347 ! response from the maximising player (machine)
// 348 response = minimax( new state, depth - 1, machine )
RESPONSE = MINIMAX(
*({
__typeof__(_imp_string9) tmp = NEWSTATE /*q*/;
(_imp_string9 *)&tmp;
})
,
DEPTH - 1, 0);
// 349 value = min( value, response )
VALUE = MIN(VALUE, RESPONSE);
// 350 %finish
L_003B:;
// 351 %repeat
goto L_0039;
}
L_003A:;
// 352 %finish
L_0033:;
// 353 %result = value
return VALUE;
// 354 %end
} /* end of MINIMAX */
// 355
// 356 ! form the initial game state
// 357 game state = reset game
_imp_strncpy(/*?*/ &GAMESTATE, ({
__typeof__(_imp_string9) tmp; /*B*/
tmp = RESETGAME();
(void *)&tmp;
}),
/*max:*/ 9);
// 358
// 359 ! make the first move for the minimising player (human)
// 360 game state = make move( game state, 27, human symbol )
_imp_strncpy(/*?*/ &GAMESTATE, ({
__typeof__(_imp_string9) tmp; /*B*/
tmp = MAKEMOVE(*({
__typeof__(_imp_string9) tmp = GAMESTATE /*q*/;
(_imp_string9 *)&tmp;
}),
27, 88);
(void *)&tmp;
}),
/*max:*/ 9);
// 361
// 362 ! after the first move
// 363 ! evaluate the game for the maximising player (machine)
// 364 game = minimax( game state, 4, machine symbol )
GAME = MINIMAX(
*({
__typeof__(_imp_string9) tmp = GAMESTATE /*q*/;
(_imp_string9 *)&tmp;
})
,
4, 79);
// 365
// 366 show state( "XO-X--X--")
SHOWSTATE(_imp_str_literal_size(9, "XO-X--X--"));
// 367 %end
_imp_stop(0);
return 0;
end_0:;
}
// ?MYSLOT unused
// 368 %endoffile