home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
056.lha
/
Four
/
four.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-11-20
|
16KB
|
652 lines
/*********************************************************************/
/* 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;
}