/* Last modified by Michael Kyritsis, Sunday 15h20 HexLib reads from hex.dat and writes to hex.out The format of hex.dat is byte // the size of the board, 1 byte the contents of the board, row1-column1, then row1-column2... one byte each with the value 1 for contestant hex, 2 for computer, 0 for no hex The format of hex.out is exactly the same as hex.dat with data appended The first byte appended is a 0 indicating no hex.dat found, or a 1 Then triples consisting of an identifier and 2 data bytes where the identifier by may be: 0 GameIsOver, byte is the value it returned 1 MakeLibMove, byte one is the row, byte two is the column //2 GetRow, byte is the row returned //3 GetColumn, byte is the row returned 4 PutHex, first byte is the row, second the column //5 GetMax, first byte is the return value //6 LookAtBoard, first byte is either -1, or the row looked at, second = col */ #include "hexlib.h" #define default_size 10 #define maxBoardSize 43 #define empty 0 #define competitor 1 #define marker 2 #define maxAssoc 5000 #define none 0 #define true 1 #define false 0 #define intelligence 3 // when no data file is present, play 1 intelligence move in 5 int returnRow = -1; int returnColumn = -1; int max = -1; // The current size of the board typedef unsigned int word; typedef unsigned char byte; typedef char boolean; typedef struct hextype{ byte owned; word con; word garcon; }; void primopen(char *filename, int *handle, int *error); void primclose(int handle, int *error); void primread(int *bytes, char *buffer, int handle, int *error); void primcreate(char *filename, int *error); void primappend(int handle, int *error); void primwrite(int *bytes, char *buffer, int handle, int *error); void primprint(char *string); void log (char* data, int bytes); struct hextype board[maxBoardSize][maxBoardSize]; /* This is the big internal data structure which will be used Ignore element 0 Always reference in the order [row][column] connectivity: rowA = rowB && colA = colB+1 rowA = rowB+1 && colA = colB rowA = rowB+1 && colA = colB+1 */ char signature; typedef struct assoctype{ byte lowest, highest; }; struct assoctype assoc[maxAssoc+1]; // Each hex belongs to a set. Adjacent hexes belong to the same set word myset; // grows upwards in the assoc stack word yourset; // grows downwards in the assoc stack boolean found_file = false; boolean last_move_was_contestant; boolean initialized = false; int my_height; // THE HEIGHT OF THE SET WHICH INCLUDES THIS HEX int your_height; int my_garcon_height = 0; int your_garcon_height = 0; char logged[3]; int modulo=0; // if no dat file is found then it plays a cleaver move every #intelligence // moves, using modulo to count the moves made. //-------------------------------------------------------------------------- void initialize (void) { int any_error = 0; int i_random, j_random, l, i, j, handle, error, bytes; if (initialized) return; signature = 0; for (i=1; iowned == marker || h->owned == competitor) { if (h->con == none) { if (h->owned == marker) { ++myset; h->con = myset; assoc [h->con].lowest = row; assoc [h->con].highest = row; } else { --yourset; h->con = yourset; assoc [h->con].lowest = col; assoc [h->con].highest = col; } return 1; } if (h->garcon == none) { if (h->owned == marker) { ++myset; h->garcon = myset; assoc [h->garcon].lowest = row; assoc[h->garcon].highest = row | 128; // 128 indicates garcon } else { --yourset; h->garcon = yourset; assoc [h->garcon].lowest = col; assoc [h->garcon].highest = col | 128; } return 1; } } ++col; } while (col <= max); ++row; } while (row <= max); return 0; } //-------------------------------------------------------------------------- /* ___ ___ Col 0 / \ / \ _/ / \___/ \ _/ Col -1 \ 11 / \ 10 / _/ _/ \___/ \___/ _/ _/ / \ 0 / \ _/ ___/ \___/ \___ _/ / \ 2 / \ 1 / \ / \___/ \___/ \ \ 6 / \ 12 / \ 7 / \___/ \___/ \___/ _ \ 4 / \ 3 / \_ \___/ \___/ _ \_ / \ 5 / \ \_ \_ / \___/ \ \_ \_ \ 9 / \ 8 / \_ Row 1 \___/ \___/ \_ Row 0 */ const signed int Dr[] = {+1, +1, +0, +0, -1, -1, -1, +1, -1, -2, +2, +1, +0}; const signed int Dc[] = {+1, +0, +1, -1, +0, -1, +1, -1, -2, -1, +1, +2, +0}; /* You can now loop from 0 to 11 to visit all the neighbours of a hex */ //-------------------------------------------------------------------------- typedef char bridgeType[12]; void blockBridge (byte dir, bridgeType bridge) /* hexes 6 to 11 may be reached by bridging */ { switch (dir) { case 0: bridge [10] = 0; bridge [11] = 0; break; case 1: bridge [10] = 0; bridge [7] = 0; break; case 2: bridge [6] = 0; bridge [11] = 0; break; case 3: bridge [7] = 0; bridge [8] = 0; break; case 4: bridge [9] = 0; bridge [6] = 0; break; case 5: bridge [8] = 0; bridge [9] = 0; } } //-------------------------------------------------------------------------- void findAssoc(void) { char tempr, tempc; byte direction; byte row; byte col; char forward=1; bridgeType bridge; struct hextype *h; boolean change_made; char garcon; myset = 0; yourset = maxAssoc + 1; for (row = 1; row <= max; row++) for (col = 1; col <= max; col++) board [row][col].con = board [row][col].garcon = none; while (SetNumberAssigned()) { do { change_made = false; forward *= -1; if (forward==1) row = 1; else row = max; for (; row >= 1 && row <= max; row+=forward) { // row loop if (forward==1) col = 1; else col = max; for (; col >= 1 && col <= max; col+=forward) { // col loop h = &board [row][col]; if ((h->owned == marker || h->owned == competitor) && (h->con == none || h->garcon == none)) { // find unsetted hex for (direction=0; direction<=11; direction++) bridge[direction] = true; for (direction=0; direction <=11; direction++) { // direction loop tempr = row + Dr[direction]; tempc = col + Dc[direction]; // check for connection to other hexes: if (board[tempr][tempc].owned != none) blockBridge (direction, bridge); if (tempr >= 1 && tempr <= max && tempc >= 1 && tempc <= max && (direction <= 5 || bridge [direction]) && h->owned == board [tempr][tempc].owned) { // bounds checking if (h->con == none && board [tempr][tempc].con != none && direction <= 5) { change_made = true; h->con = board [tempr][tempc].con; if (h->owned == marker) { if (row < assoc [h->con].lowest) assoc [h->con].lowest = row; if (row > assoc [h->con].highest) assoc [h->con].highest = row; } else { if (col < assoc [h->con].lowest) assoc [h->con].lowest = col; if (col > assoc [h->con].highest) assoc [h->con].highest = col; } } if (h->garcon == none && board [tempr][tempc].garcon != none) { change_made = true; h->garcon = board [tempr][tempc].garcon; if (h->owned == marker) { if (row < assoc [h->garcon].lowest) assoc [h->garcon].lowest = row; if (row > (assoc [h->garcon].highest & 127)) assoc [h->garcon].highest = row | 128; } else { if (col < assoc [h->garcon].lowest) assoc [h->garcon].lowest = col; if (col > (assoc [h->garcon].highest & 127)) assoc [h->garcon].highest = col | 128; } } } // end of bounds checking } // end of direction loop } // end of finding setted hex } // end of col loop } // end of row loop } while (change_made); } // end of setNumberAssigned loop // Now loop through the hexes and see if some are not the highest in a // set, or perhaps single hexes, and if they have a possible bridging // going upwards then decrease the assoc.lowest for that set. // For example a single hex should be considered to have a height of // 2 and not 0, which is what the previous block of code returns // start with stretching sets belonging to the marker for (row=2; row=(assoc[board[row][col].garcon].highest&127) && board[row][col].owned==marker && board[row+1][col].owned==none && board[row+1][col+1].owned==none) assoc[board[row][col].garcon].highest=row+1|garcon; } // stretch sets belonging to the competitor for (row=1; row<=max; row++) for (col=2; col=(assoc[board[row][col].garcon].highest&127) && board[row][col].owned==competitor && board[row][col+1].owned==none && board[row+1][col+1].owned==none) assoc[board[row][col].garcon].highest=col+1|garcon; } } //-------------------------------------------------------------------------- boolean I_complete_already; // HAVE I ALREADY WON? boolean you_complete_aready; boolean I_have_garcon; // DO I HAVE A GUARANTEED CONNECTED SET? boolean you_have_garcon; boolean connected; // LOOPING VARIABLE bridgeType bridge; //-------------------------------------------------------------------------- void selectHex ( int *my_gar_or_con_height, int *your_gar_or_con_height, int temp_row, int temp_col, int *row, int *col) { int threshhold; int agro; if (my_height < *my_gar_or_con_height) my_height = *my_gar_or_con_height; if (your_height < *your_gar_or_con_height) your_height = *your_gar_or_con_height; if (your_garcon_height+1 == max) agro = 2; else agro = 3; // AGGRESSIVENESS if (my_height * 2 - *my_gar_or_con_height * 2 + your_height * agro - *your_gar_or_con_height * agro > 0) { *my_gar_or_con_height = my_height; *your_gar_or_con_height = your_height; *row = temp_row; *col = temp_col; } } //-------------------------------------------------------------------------- int NAME(GameIsOver) (void) { struct assoctype *s; int my_con_height = 0; int your_con_height = 0; int set1; logged[0] = 0; // GameIsOver initialize (); findAssoc(); for (set1=1; set1<=myset; set1++) { s = &assoc[set1]; if (!(s->highest & 128)) // not interested in garcon if (s->highest - s->lowest > my_con_height) my_con_height = s->highest - s->lowest; } for (set1=yourset; set1<=maxAssoc; set1++) { s = &assoc[set1]; if (!(s->highest & 128)) if (s->highest - s->lowest > your_con_height) your_con_height = s->highest - s->lowest; } if (my_con_height+1 == max) { logged[1] = 3; log (logged, 3); return 3;// then I have won already } else if (your_con_height+1 == max) { logged[1] = 2; log(logged, 3); return 2;// then you have won already } else { logged[1] = 0; log (logged, 3); return 0; } } //-------------------------------------------------------------------------- void NAME(MakeLibMove(void)) /* calculate the next move and place the hex on the board. The change to the board is indicated by LookAtBoard(), GetRow() and GetColumn() */ { int my_highest; // THE HIGHEST HEX (GAR)CON TO THIS HEX int your_highest; int my_lowest; int your_lowest; int my_con_height; // THE HEIGHT OF MY LONGEST SET int your_con_height; int my_garcon_height; // THE HEIGHT OF MY LONGEST GUARANTEED SET int your_garcon_height; word set1; // LOOPING VARIABLE byte dir; struct assoctype *s; struct hextype *h; int row, col, r1, c1; initialize (); logged[0] = 1; // MakeLibMove if (!last_move_was_contestant) { logged[1] = -1; log (logged, 3); return; } findAssoc(); returnRow = -1; // UNDECIDED HEX returnColumn = -1; my_con_height = 0; my_garcon_height = 0; your_con_height = 0; your_garcon_height = 0; for (set1=1; set1<=myset; set1++) { s = &assoc[set1]; if ((s->highest) & 128) { s->highest &= 127; if (s->highest - s->lowest > my_garcon_height) my_garcon_height = s->highest - s->lowest; } else { if (s->highest - s->lowest > my_con_height) my_con_height = s->highest - s->lowest; } } for (set1=yourset; set1<=maxAssoc; set1++) { s = &assoc[set1]; if (s->highest & 128) { s->highest &= 127; if (s->highest - s->lowest > your_garcon_height) your_garcon_height = s->highest - s->lowest; } else { if (s->highest - s->lowest > your_con_height) your_con_height = s->highest - s->lowest; } } if (my_con_height+1 == max) { logged[1] = -1; log (logged, 3); return;// then I have won already } else if (your_con_height+1 == max) { logged[1] = -1; log (logged, 3); return;// then you have won already } else { I_have_garcon = my_garcon_height+1 == max; you_have_garcon = your_garcon_height+1 == max; for (row=1; row<=max; row++) for (col=1; col<=max; col++) if (board [row][col].owned == none) { // CONSIDER PLACING A HEX HERE my_highest = row; my_lowest = row; your_highest = col; your_lowest = col; for (dir=0; dir<=11; dir++) bridge [dir] = true; for (dir=0; dir<=11; dir++) { r1 = row + (int)Dr[dir]; c1 = col + (int)Dc[dir]; if (r1<=max && r1>=1 && c1<=max && c1>=1 && // WITHIN LIMITS OF BOARD ( dir<=5 || bridge [dir] )) { h = &board[r1][c1]; if (h->owned == marker) { blockBridge (dir, bridge); if (I_have_garcon) if (dir <= 5) set1 = h->con; else set1 = none; else set1 = h->garcon; if (set1 != none) { if (assoc[set1].highest > my_highest) my_highest = assoc [set1].highest; if (assoc [set1].lowest < my_lowest) my_lowest = assoc [set1].lowest; } } else if (h->owned == competitor) { blockBridge (dir, bridge); if (I_have_garcon) if (dir <= 5) set1 = h->con; else set1 = none; else if (you_have_garcon) if (dir <= 5) set1 = h->con; else set1 = none; else set1 = h->garcon; if (set1 != none) { if (assoc [set1].highest > your_highest) your_highest = assoc [set1].highest; if (assoc [set1].lowest < your_lowest) your_lowest = assoc [set1].lowest; } } } // end of within limits of board } // end of for dir = 0 to 11 my_height = my_highest - my_lowest; your_height = your_highest - your_lowest; if (I_have_garcon) selectHex (&my_con_height, &your_con_height, row, col, &returnRow, &returnColumn); else if (you_have_garcon) selectHex (&my_garcon_height, &your_con_height, row, col, &returnRow, &returnColumn); else selectHex (&my_garcon_height, &your_garcon_height, row, col, &returnRow, &returnColumn); } // end of if (board [row, column].owned == none) } // end of checking that modulo++; if (returnRow <= 0 || !found_file && modulo%intelligence) { row = returnRow; col = returnColumn; for (r1=1; r1<=max; r1++) for (c1=1; c1<=max; c1++) if (board[r1][c1].owned == none) { returnRow = r1; returnColumn = c1; } for (r1=1; r1<=10; r1++) { row = (row + returnRow) % max + 1; col = (col + returnColumn) % max + 1; if (board[row][col].owned == none) { returnRow = row; returnColumn = col; } } } board[returnRow][returnColumn].owned = marker; last_move_was_contestant = false; logged[1] = (char)returnRow; logged[2] = (char)returnColumn; log (logged, 3); } //-------------------------------------------------------------------------- int NAME(GetRow) () { initialize (); // logged[0] = 2; // GetRow // logged[1] = (char)returnRow; // log (logged, 3); return returnRow; } //-------------------------------------------------------------------------- int NAME(GetColumn) () { initialize (); // logged[0] = 3; // GetColumn // logged[1] = (char)returnColumn; // log (logged, 3); return returnColumn; } //-------------------------------------------------------------------------- void NAME(PutHex) (int row, int column) { initialize (); if (last_move_was_contestant || row < 1 || column < 1 || row > max || column > max) return; if (board[row][column].owned != none) return; board[row][column].owned = competitor; last_move_was_contestant = true; logged[0] = 4; // PutHex logged[1] = (char)row; logged[2] = (char)column; log (logged, 3); } //-------------------------------------------------------------------------- int NAME(GetMax)() { initialize (); // logged[0] = 5; // GetMax // logged[1] = (char)max; // log (logged, 3); return max; } //-------------------------------------------------------------------------- int NAME(LookAtBoard) (int row, int column) { initialize (); // logged[0] = 6; // LookAtBoard // logged[1] = (char)row; // logged[2] = (char)column; if (row < 1 || column < 1 || row > max || column > max) { // logged[1] = -1; // log (logged, 3); return -1; } // log (logged, 3); return board[row][column].owned; } //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- // primopen: opens file... // error codes: 1 = invalid function // 2 = file not found // 3 = path not found // 4 = no handles available // 5 = access denied // 12= invalid access code //-------------------------------------------------------------------------- void primopen(char *filename, int *handle, int *error) { int localhandle; int localerror; asm { mov ah, 3Dh // open file mov al, 2 // 2 = read and write access mov dx, word ptr [filename] // ds:dx = name - zero terminated string int 21h jc open_error mov localhandle,ax mov localerror,0 jmp proc_end } open_error: asm { mov localerror,ax } proc_end: *handle = localhandle; *error = localerror; } //-------------------------------------------------------------------------- // primcreate: creates a file // truncates it if it exists already //-------------------------------------------------------------------------- void primcreate(char *filename, int *error) { int localerror; asm { mov ah, 3Ch // create file mov cx, 0 // file attribute is normal mov dx, word ptr [filename] // ds:dx = name - zero terminated string int 21h jc create_error mov localerror,0 jmp proc_end } create_error: asm { mov localerror,ax } proc_end: *error = localerror; } //------------------------------------------------------------------------- // close (int handle, int *error) // error code: 6 = invalid handle //------------------------------------------------------------------------- void primclose(int handle, int *error) { int localerror; asm { mov ah, 3Eh // close file mov bx, handle int 21h jnc close_successful mov localerror,ax } close_successful: asm { mov localerror,0 } *error = localerror; } //------------------------------------------------------------------------- // primwrite (int *bytes, char *buffer, int handle, int *error) // error codes: 5 = access denied // 6 = invalid handle //------------------------------------------------------------------------- void primwrite(int *bytes, char *buffer, int handle, int *error) { int localbytes; int localerror; localbytes = *bytes; localerror = *error; asm { mov ah, 40h // read file or device mov cx, localbytes mov dx, word ptr [buffer] // ds:dx = pointer to buffer mov bx, handle int 21h jc write_error mov ax, localbytes // number of bytes successfully written mov localerror,0 jmp proc_end } write_error: asm { mov localerror,ax } proc_end: *bytes = localbytes; *error = localerror; } //------------------------------------------------------------------------- // primappend (int handle, int *error) // error codes: 5 = access denied // 6 = invalid handle //------------------------------------------------------------------------- void primappend(int handle, int *error) { int localerror; localerror = *error; asm { mov ah, 42h // move file pointer mov al, 2 // move relative to end of file mov cx, 0 // high order word of distance to move mov dx, 0 // low order word of distance to move mov bx, handle int 21h jc append_error mov localerror,0 jmp proc_end } append_error: asm { mov localerror,ax } proc_end: *error = localerror; } //------------------------------------------------------------------------- // read (int *bytes, char *buffer, int handle, int *error) // error codes: 5 = access denied // 6 = invalid handle //------------------------------------------------------------------------- void primread(int *bytes, char *buffer, int handle, int *error) { int localbytes; int localerror; localbytes = *bytes; localerror = *error; asm { mov ah, 3Fh // read file or device mov cx, localbytes mov dx, word ptr [buffer] // ds:dx = pointer to buffer mov bx, handle int 21h jc read_error mov localbytes, ax // number of bytes successfully read mov localerror,0 jmp proc_end } read_error: asm { mov localerror,ax } proc_end: *error = localerror; if (localbytes < *bytes) // if fewer bytes were read than requested *error |= 8; *bytes = localbytes; } //------------------------------------------------------------------------- // print (char *string) // string is terminated by '$' //------------------------------------------------------------------------- void primprint(char *string) { asm { mov ah, 9h // display string mov dx, word ptr [string] int 21h } }