home *** CD-ROM | disk | FTP | other *** search
- /*********************************************************************/
- /* Four in a Row V1.0 8/14/87 */
- /* Copyright (C) 1987 by Pery Pearson */
- /* */
- /* Note the 'readme' file. */
- /* Feel free to modify the program if you like; the computer player */
- /* ( my_move() and related routines ) really could use some type of */
- /* strategy routine. */
- /*********************************************************************/
-
-
- #include <intuition/intuition.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <ctype.h>
-
- #include <graphics/gfxbase.h>
-
- #include "struct.c" /* structures and definitions */
-
-
- int grid [MAXX] [MAXY];
- int on_pole[8];
- int polepick, turn, bead_count;
- int player2, finished, newgame;
- int first_turn, illegal;
- int inrow[4], empty[4], maybe[4], possibles[4];
-
- /**************************************************************************
- some variables used in making the computer's move(I hope they help):
-
- * inrow[x] : the number of beads in a row including the proposed bead;
- x is a direction (vertically, horizontally, & both
- diagonals). Which direction depends upon how inrow was
- assigned. i.e. inrow[0]=in_row(..., 1, 1,...) is in the
- positive slope diagonal.
- * maybe[x] : Unused, but it is the number of WHO's beads in the direction
- being used which are separated from WHO's beads that are
- in-a-row by spaces only, no intervening enemy beads. x is
- a direction here too. (is that clear ?!? - I thought this
- might be useful for a stategy.)
- * empty[x] : the number of spaces in the direction in question on both
- sides of WHO's in-a-row beads which are empty or contain
- other of WHO's beads. This is bounded by the grid
- boundaries and enemy beads. x is a direction.
- * possibles[x]: the number of possible 4-in-a-rows with (x+1) beads in a row
- already (including the hypothetical move in question).
- *************************************************************************/
-
- /* make C happy by declaring functions */
-
- void open_libraries(), done();
- void handle_message(), setup(), put_text();
- void handle_menu(), whose_move(), get_possibles();
- void up_gadgets(), set_ball(), main();
- void clear_grid(), draw_grid(), draw_base();
- void handle_proj(), handle_game(), initialize();
- void illegal_move(), my_move(), player_move();
- void reset_menu_item(), clear_square();
-
-
- void main()
- {
- initialize();
-
- FOREVER {
- if (newgame) setup();
- whose_move();
- if (!finished && turn == ME && player2 == ME) {
- my_move();
- whose_move();
- }
- if ((message = (struct IntuiMessage *)GetMsg(window1->UserPort))==NULL)
- {
- Wait(1<<window1->UserPort->mp_SigBit);
- continue;
- }
- handle_message(message);
- }
- }
-
-
- void whose_move()
- {
- int xoff, yoff;
-
- xoff = XOFF-2*8-2;
- yoff = YOFF+(MAXY+3)*ROWS+3;
-
- if (!finished) {
- if (player2 == ME) {
- if (turn == ME) {
- put_text(xoff-4, yoff, " My move ", 4);
- }
- else {
- put_text(xoff-4, yoff, " Your move ", 3);
- }
- }
- else {
- if (turn == YOU) {
- put_text(xoff, yoff, " White's move ", 3);
- }
- else {
- put_text(xoff, yoff, " Brown's move ", 4);
- }
- }
- }
- return;
- }
-
-
- void put_text(x, y, text, c)
- int x, y, c;
- char *text;
- {
- SetAPen(window1->RPort, c);
- TEXT(window1, x, y, text);
- return;
- }
-
-
- void reset_menu_item(menuitem, newtext)
- struct MenuItem *menuitem;
- APTR newtext;
- {
- ClearMenuStrip(window1);
- menuitem-> ItemFill = newtext;
- SetMenuStrip(window1, &menu1);
-
- return;
- }
-
-
- void handle_message(message)
- struct IntuiMessage *message;
- {
- ULONG class;
- USHORT code;
-
- class = message->Class;
- code = message->Code;
-
- if (illegal) {
- illegal = 0;
- put_text(XOFF-2*8-2, YOFF+(MAXY+4)*ROWS+3, " ", 0);
- }
-
- switch (class) {
- case GADGETUP : up_gadgets();
- break;
- case MOUSEBUTTONS : break;
- case CLOSEWINDOW : ReplyMsg(message);
- done(NULL);
- break;
- case MENUPICK :
- handle_menu(code, message);
- break;
- }
- ReplyMsg(message);
- return;
- }
-
-
- void handle_menu(code, message)
- USHORT code;
- struct IntuiMessage *message;
- {
- while (code != MENUNULL) {
- switch (MENUNUM(code)) {
- case PROJECT : handle_proj(code, message);
- break;
- case GAME : handle_game(code);
- }
- code = ItemAddress(&menu1, code)->NextSelect;
- }
- return;
- }
-
-
- void handle_proj(code, message)
- USHORT code;
- struct IntuiMessage *message;
- {
- switch (ITEMNUM(code)) {
- case ABOUT :
- (void)AutoRequest(window1 , &about1, &positive,
- &negative, 0, 0, 38*8, 20*ROWS);
- break;
- case QUIT : ReplyMsg(message);
- done(NULL);
- }
- return;
- }
-
-
- void handle_game(code)
- USHORT code;
- {
- int menu_num;
-
- switch (ITEMNUM(code)) {
- case NEWGAME : newgame = 1;
- put_text(XOFF-7, YOFF, " ", 0);
- break;
- case PLAYER2 : menu_num = SHIFTMENU(GAME) +
- SHIFTITEM(FIRSTPLAYER);
- if (player2 == ME) {
- player2 = YOU;
- reset_menu_item(&m2_item2,(APTR)&m2_text2b);
- OffMenu(window1, menu_num);
- }
- else {
- player2 = ME;
- reset_menu_item(&m2_item2, (APTR)&m2_text2a);
- OnMenu(window1, menu_num);
- }
- break;
- case FIRSTPLAYER :
- if (first_turn == ME) {
- first_turn = YOU;
- reset_menu_item(&m2_item3, (APTR)&m2_text3b);
- }
- else {
- first_turn = ME;
- reset_menu_item(&m2_item3, (APTR)&m2_text3a);
- }
- break;
- case INSTRUCTIONS :
- (void)AutoRequest(window1 , &instr1, &positive,
- &negative, 0, 0, 33*8, 10*ROWS);
- }
- return;
- }
-
-
- void up_gadgets()
-
- {
- struct Gadget *igad;
- int gadget_id;
-
- igad = (struct Gadget *)message -> IAddress;
- gadget_id = igad -> GadgetID;
- polepick = -1;
- switch(gadget_id) {
- case GAD1 : polepick = 0;
- break;
- case GAD2 : polepick = 1;
- break;
- case GAD3 : polepick = 2;
- break;
- case GAD4 : polepick = 3;
- break;
- case GAD5 : polepick = 4;
- break;
- case GAD6 : polepick = 5;
- break;
- case GAD7 : polepick = 6;
- break;
- case GAD8 : polepick = 7;
- }
-
- if ( !finished && polepick >= 0 ) player_move();
-
- return;
- }
-
-
- int count_em(who, x, y, empty, maybe, pole, onpole)
- int who, x, y, *empty, *maybe, pole, onpole;
- {
- int count = 0,
- xn, yn;
-
- xn = pole;
- yn = on_pole[pole] - onpole;
- while ( grid[yn += y][xn += x] == who && yn < MAXY && xn < MAXX
- && yn >= 0 && xn >= 0) {
- count++;
- }
- while ( (grid[yn][xn] == NOONE || grid[yn][xn] == who)
- && yn < MAXY && xn < MAXX && yn >= 0 && xn >= 0) {
- (*empty)++;
- if (grid[yn][xn] == who)
- (*maybe)++;
- yn += y;
- xn += x;
- }
-
- return(count);
- }
-
-
- int in_row(who, x, y, empty, maybe, pole, onpole)
- int who, x, y, *empty, *maybe, pole, onpole;
- {
- *empty = 0;
- *maybe = 0;
- return( count_em(who, x, y, empty, maybe, pole, onpole)
- + count_em(who, -x, -y, empty, maybe, pole, onpole) + 1 );
- }
-
-
- int check_win()
- {
- int tempret, win, who,
- dum; /* dummy var */
-
- dum = 0; /* just to stop C's warning */
- tempret = 0;
- who = turn;
- if (in_row(who, 1, 1, &dum, &dum, polepick, 1) >= 4) win = 1;
- else if (in_row(who, -1, 1, &dum, &dum, polepick, 1) >= 4) win = 1;
- else if (in_row(who, 1, 0, &dum, &dum, polepick, 1) >= 4) win = 1;
- else if(in_row(who, 0, 1, &dum, &dum, polepick, 1) >= 4) win = 1;
- else win = 0;
-
- if (win) {
- tempret = 1;
- if (player2 == ME) {
- if (turn == ME) {
- put_text(XOFF+4*8-3, YOFF, "I win", 4);
- }
- else {
- put_text(XOFF+3*8-3, YOFF, "You win", 3);
- }
- }
- else {
- if (turn == YOU) {
- put_text(XOFF+1*8+1, YOFF, "White wins", 3);
- }
- else {
- put_text(XOFF+1*8+1, YOFF, "Brown wins", 4);
- }
- }
- }
- else {
- if (bead_count == MAXX*MAXY) {
- tempret = 1;
- put_text(XOFF-7, YOFF, "It's a tie !!!", 14);
- }
- }
-
- if (tempret) {
- put_text(XOFF-2*8-6, YOFF+(MAXY+3)*ROWS+3, " ", 0);
- }
-
- return(tempret);
- }
-
-
- void illegal_move()
- {
- put_text(XOFF-2*8-2, YOFF+(MAXY+4)*ROWS+3, "That column's full", 15);
- DisplayBeep(screen1);
- illegal = 1;
-
- return;
- }
-
-
- void get_possibles(who, pole, onpole)
- int who, pole, onpole;
- {
- int dir;
-
- inrow[0] = in_row(who, 1, 1, &empty[0], &maybe[0], pole, onpole);
- inrow[1] = in_row(who, -1, 1, &empty[1], &maybe[1], pole, onpole);
- inrow[2] = in_row(who, 0, 1, &empty[2], &maybe[2], pole, onpole);
- inrow[3] = in_row(who, 1, 0, &empty[3], &maybe[3], pole, onpole);
- for (dir = 0; dir < 4; dir++) {
- possibles[dir] = 0;
- }
- for (dir = 0; dir < 4; dir++) {
- if (inrow[dir] >3) {
- possibles[3] = 5;
- }
- else {
- if (empty[dir] + inrow[dir] >= 4) {
- possibles[inrow[dir]-1]++;
- }
- }
- }
- return;
- }
-
-
- int best_move(who, pole, otherhigh, bad)
- int who, pole, otherhigh, *bad;
- {
- int inrow, temp_high, mult;
-
- get_possibles(who, pole, 0);
- inrow = 3;
- temp_high = possibles[inrow];
- while (temp_high < 1 && inrow > 0) {
- inrow--;
- temp_high = possibles[inrow];
- }
- if (inrow == 0) mult = 1;
- else if (inrow == 1) mult = 4;
- else if (inrow == 2) mult = 13;
- else mult = 40;
- temp_high *= mult;
-
- /* try not to set up the player for a win */
-
- if (who == YOU && temp_high < 100
- && otherhigh < 100 && on_pole[pole] < MAXY-1) {
- get_possibles(YOU, pole, -1);
- if (possibles[3] > 4) {
- *bad = 1;
- temp_high = 0;
- }
- }
-
- return(temp_high);
- }
-
-
- int random_move()
- {
- int pole;
-
- while (on_pole[(pole = rand()&7)] >= MAXY) ;
- return(pole);
- }
-
-
- void my_move()
- {
- int high_move, polenum, move, block, badmoves, bad, winmove;
-
- high_move = 0;
- badmoves = 1;
- winmove = 0;
- for (polenum = 0; polenum < MAXX; polenum++) {
- if (on_pole[polenum] < MAXY) {
- bad = 0;
- if ((move = best_move(ME, polenum, 0, &bad)) >100) {
- if (!winmove || (winmove && rand() < rand() )) {
- winmove = 1;
- high_move = move;
- badmoves = 0;
- polepick = polenum;
- }
- }
- else if (!winmove) {
- block = best_move(YOU, polenum, move, &bad);
- if (block > move || bad)
- move = block;
- if (move > high_move || ( move == high_move && move > 0 &&
- rand() < rand() )) {
- high_move = move;
- badmoves = 0;
- polepick = polenum;
- }
- }
- }
- }
- if (badmoves) {
- polepick = random_move();
- }
- set_ball(ME);
- if (check_win()) finished = 1;
- else turn = YOU;
-
- return;
- }
-
-
- void set_ball(who)
- int who;
- {
- struct Image *image_ptr;
- int i, j;
-
- j = polepick;
- i = on_pole[j];
-
- grid[i][j] = who;
- switch (who) {
- case YOU : if (i) image_ptr = &ball_1;
- else image_ptr = &base_ball_1;
- break;
- case ME : if (i) image_ptr = &ball_2;
- else image_ptr = &base_ball_2;
- }
- DrawImage(window1->RPort, image_ptr,
- XOFF+j*COLS, YOFF+(MAXY-i-1)*(ROWS-1)+MAXY-1);
- on_pole[polepick] += 1;
- bead_count += 1;
-
- return;
- }
-
-
- void player_move()
- {
- if (on_pole[polepick] >= MAXY) illegal_move();
- else {
- if ( turn == YOU )
- set_ball(YOU);
- else
- set_ball(ME); /* ME is player2 in two player mode */
- if (check_win() ) finished = 1;
- else if ( (turn += 1) > 1) turn = 0;
- }
- return;
- }
-
-
- void open_libraries()
- {
- if ((IntuitionBase = (struct IntuitionBase *)
- OpenLibrary("intuition.library",I_REV)) == NULL) done(2);
- if ((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",G_REV))
- == NULL) done(3);
- oldview = GfxBase -> ActiView;
- return;
- }
-
-
- void done(s)
- SHORT s;
- {
- if (window1) {
- ClearMenuStrip(window1);
- CloseWindow(window1);
- }
- if (screen1) {
- CloseScreen(screen1);
- LoadView(oldview);
- }
- if (colormap != NULL) FreeColorMap(colormap);
- if (GfxBase) CloseLibrary(GfxBase);
- if (IntuitionBase) CloseLibrary(IntuitionBase);
-
- if (s) {
- printf("Error #%d",s);
- }
-
- exit(s);
- }
-
-
- void clear_grid()
- {
- int i, j;
- for (i=0; i<MAXX; i++) {
- for (j=0; j<MAXY; j++) {
- grid [i][j] = NOONE;
- }
- }
- return;
- }
-
-
- void clear_square()
- {
- DrawImage(window1->RPort, &clear_block, XOFF, YOFF);
- return;
- }
-
-
- void draw_grid()
- {
- int i, j;
- struct Image *image_ptr;
-
- for (i=0 ; i<MAXY; i++) {
- for (j=0; j<MAXX; j++) {
- switch (grid [i][j]) {
- case NOONE : image_ptr = &pole;
- break;
- case YOU : if (i) image_ptr = &ball_1;
- else image_ptr = &base_ball_1;
- break;
- case ME : if (i) image_ptr = &ball_2;
- else image_ptr = &base_ball_2;
- }
- DrawImage(window1->RPort, image_ptr,
- XOFF+j*COLS, YOFF+(MAXY-i-1)*(ROWS-1)+MAXY-1);
- }
- }
- return;
- }
-
-
- void draw_base()
- {
- DrawImage(window1->RPort, &base_top, XOFF-5, YOFF+MAXY*ROWS-5);
- DrawImage(window1->RPort, &base_bot, XOFF-15, YOFF+MAXY*ROWS+5);
- DrawImage(window1->RPort, &top_left, XOFF-15, YOFF+MAXY*ROWS-5);
- DrawImage(window1->RPort, &end_rect, XOFF-15, YOFF+MAXY*ROWS+5);
- DrawImage(window1->RPort, &bot_left, XOFF-15, YOFF+MAXY*ROWS+15);
- DrawImage(window1->RPort, &top_right,XOFF+MAXX*COLS+5, YOFF+MAXY*ROWS-5);
-
- DrawBorder(window1->RPort, &line1, 0*COLS, 0);
- DrawBorder(window1->RPort, &line1, 1*COLS, 0);
- DrawBorder(window1->RPort, &line1, 2*COLS, 0);
- DrawBorder(window1->RPort, &line1, 3*COLS, 0);
- DrawBorder(window1->RPort, &line1, 4*COLS, 0);
- DrawBorder(window1->RPort, &line1, 5*COLS, 0);
- DrawBorder(window1->RPort, &line1, 6*COLS, 0);
- DrawBorder(window1->RPort, &line1, 7*COLS, 0);
-
- RefreshGadgets(&Gadget1, window1, NULL);
-
- return;
- }
-
-
- void initialize()
- {
- open_libraries();
-
- font = &Font80;
-
- init_images();
- init_menus();
- init_gadgets();
- init_display(80*W, 20*H, 160*W, 148*H, 4, "Four in a Row");
-
- player2 = 0;
- first_turn = YOU;
- newgame = 1;
-
- return;
- }
-
-
- void setup()
- {
- int i;
-
- newgame = 0;
- clear_grid();
- clear_square();
- draw_base();
- draw_grid();
- turn = first_turn;
- bead_count = 0;
- finished = 0;
- for (i=0; i<MAXY; i++) {
- on_pole[i] = 0;
- }
- illegal = 0;
-
- return;
- }
-