windows-nt/Source/XPSP1/NT/shell/osshell/ep/tictac/rtns.c
2020-09-26 16:20:57 +08:00

544 lines
8.2 KiB
C

/************/
/* ROUTINES */
/************/
#define _WINDOWS
#include <windows.h>
#include <port1632.h>
#include "main.h"
#include "res.h"
#include "rtns.h"
#include "grafix.h"
#include "pref.h"
#include "sound.h"
#include "util.h"
/*** Global/Local Variables ***/
INT iPlayer;
BOOL fFlash = fFalse; /* Integerate these ! */
BOOL fFlashOnOff;
BOOL f4; /* TRUE if need 4 in a row */
INT cPlane; /* Number of planes */
INT cBlkRow; /* Number of balls in a row */
INT cBlkPlane; /* Number of positions in a single plane */
INT cBlkMac; /* Total number of available positions */
/* Computer stuff */
INT iBlkLose; /* Place to put if about to lose */
INT iMoveCurr;
BLK rgBlk[cBlkMax]; /* The main grid data */
BLK rgFlash[cDimMax]; /* list of balls to flash */
BLK rgMove[cBlkMax]; /* list of moves (for UNDO) */
BLK rgBest[cBlkMax]; /* count of times "best" */
#include "tbls.inc"
#define cChkMax k4x4x4
INT cChkMac;
INT rgChk[cChkMax][cDimMax];
/*** Global/External Variables ***/
extern STATUS status;
extern PREF Preferences;
extern blkCurr;
BLK ComputerMove(VOID);
/****** F C H E C K W I N ******/
/* Return TRUE if anyone won */
/* rgFlash contains winning set */
BOOL FCheckWin(VOID)
{
REGISTER INT x;
REGISTER INT y;
INT c;
if (f4)
{
for (y = 0; y < cChkMac; y++)
{
if (c = rgBlk[rgChk[y][0]])
if (c == rgBlk[rgChk[y][1]])
if (c == rgBlk[rgChk[y][2]])
if (c == rgBlk[rgChk[y][3]])
{
for (x = 0; x < cBlkRow; x++)
rgFlash[x] = rgChk[y][x];
return (fFlash = fTrue);
}
}
}
else
{
for (y = 0; y < cChkMac; y++)
{
if (c = rgBlk[rgChk[y][0]])
if (c == rgBlk[rgChk[y][1]])
if (c == rgBlk[rgChk[y][2]])
{
for (x = 0; x < cBlkRow; x++)
rgFlash[x] = rgChk[y][x];
return (fFlash = fTrue);
}
}
}
return fFalse;
}
/****** D O M O V E ******/
VOID DoMove(BLK blk)
{
#ifdef DEBUG3
CHAR sz[80];
LMove:
wsprintf(sz,"Move=%d Player=%d\r\n",blk,iPlayer);
OutputDebugString(sz);
if (blk < 0 || blk >= cBlkMac)
{
Oops("Invalid blk");
return;
}
else if (rgBlk[blk])
{
Oops("Invalid Move!");
return;
}
#else
LMove:
#endif
rgMove[iMoveCurr++] = blk; /* Remember move */
PlaceBall(blk, iPlayer);
if (FCheckWin())
{
ClrStatusPlay();
fFlashOnOff = fTrue;
fFlash = fTrue;
PlayTune(iPlayer == iComputer ? TUNE_LOSEGAME : TUNE_WINGAME);
}
else if (iMoveCurr == cBlkMac)
ClrStatusPlay();
else
{
blkCurr = blk;
if ((iPlayer ^= 3) == iComputer)
{
blk = ComputerMove();
goto LMove;
}
else
PlayTune(TUNE_DROP); /* Computer makes noise too */
}
}
/****** U N D O M O V E ******/
VOID UnDoMove(VOID)
{
if (iMoveCurr)
{
rgBlk[rgMove[--iMoveCurr]] = iBallBlank; /* Undo Computer move */
if (iMoveCurr)
{
rgBlk[rgMove[--iMoveCurr]] = iBallBlank; /* Undo Human move */
ReDoDisplay();
DisplayGrid();
}
else
{
iPlayer = iComputer;
DoMove(ComputerMove());
}
}
else
MessageBeep(0); /* Should be a sound !!! */
}
/****** G E T B E S T B L K ******/
BLK GetBestBlk(VOID)
{
INT cMac;
BLK blkBest;
BLK iBlk;
INT cBlk;
/* Future: If f4 & we have a set of corners, try recursion */
/* Find most promising position */
cMac = 0;
cBlk = 0;
blkBest = 0;
for (iBlk = 0; iBlk < cBlkMac; iBlk++)
if (rgBest[iBlk] != 0)
{
if (rgBest[iBlk] > cMac)
{
cBlk = 1;
blkBest = iBlk;
cMac = rgBest[iBlk];
}
else if (rgBest[iBlk] == cMac)
{
if (Rnd(++cBlk) == 0)
blkBest = iBlk;
}
}
if (blkBest != 0)
return blkBest;
switch (Preferences.iGameType)
{
case iGame3x3:
if (rgBlk[4] == iBallBlank)
return 4;
break;
case iGame3x3x3:
if (rgBlk[13] == iBallBlank)
return 13;
break;
default:
break;
}
/* Find an empty corner */
iBlk = Rnd(8);
for (cMac = 0; cMac++ < 8;)
{
if (rgBlk[blkBest = rgCorner[Preferences.iGameType][iBlk]] == iBallBlank)
return blkBest;
iBlk = (iBlk+1) % 8;
}
return iBlkNil;
}
/****** B L K C H K 3 ******/
BLK BlkChk3(INT b1, INT b2, INT b3)
{
#ifdef DEBUG
CHAR sz[80];
wsprintf(sz,"BlkChk3=%d %d %d v=%d\r\n",b1,b2,b3,rgBlk[b1]+rgBlk[b2]*3+rgBlk[b3]*9);
OutputDebugString(sz);
#endif
switch (rgBlk[b1] + rgBlk[b2]*3 + rgBlk[b3]*9)
{
case 4:
return b3;
case 10:
return b2;
case 12:
return b1;
case 8:
iBlkLose = b3;
break;
case 20:
iBlkLose = b2;
break;
case 24:
iBlkLose = b1;
break;
case 1:
rgBest[b3]++;
break;
case 9:
rgBest[b1]++;
break;
}
return iBlkNil;
}
/****** B L K C H K 4 ******/
BLK BlkChk4(INT b1, INT b2, INT b3, INT b4)
{
switch (rgBlk[b1] + rgBlk[b2]*3 + rgBlk[b3]*9 + rgBlk[b4]*27)
{
case 13:
return b4;
case 31:
return b3;
case 37:
return b2;
case 39:
return b1;
case 26:
iBlkLose = b4;
break;
case 62:
iBlkLose = b3;
break;
case 74:
iBlkLose = b2;
break;
case 78:
iBlkLose = b1;
break;
case 1:
rgBest[b4]++;
break;
case 27:
rgBest[b1]++;
break;
case 28:
rgBest[b2] += 4;
rgBest[b3] += 4;
break;
}
return iBlkNil;
}
/****** S K I L L ******/
BOOL Skill(INT intel, INT chance)
{
if (Preferences.skill > intel)
return fTrue;
return (Rnd(100) < chance);
}
/****** C O M P U T E R M O V E ******/
BLK ComputerMove(VOID)
{
REGISTER INT iBlk;
REGISTER INT y;
iBlkLose = iBlkNil;
for (iBlk = 0; iBlk < cBlkMac; iBlk++) /** USE A BLT !!! **/
rgBest[iBlk] = 0;
if (Skill(10, 10))
{
if (Skill(10, 50))
/* Search for winning location */
{
if (f4)
{
for (y = 0; y < cChkMac; y++)
if ((iBlk = BlkChk4(rgChk[y][0], rgChk[y][1], rgChk[y][2], rgChk[y][3])) != iBlkNil)
return iBlk;
}
else
{
for (y = 0; y < cChkMac; y++)
if ((iBlk = BlkChk3(rgChk[y][0], rgChk[y][1], rgChk[y][2])) != iBlkNil)
return iBlk;
}
}
/* Is there a losing location ? */
if ((iBlkLose != iBlkNil) && Skill(50, 50))
return iBlkLose;
/* Is there a best spot ? */
if (Skill(70, 80) && ((iBlk = GetBestBlk()) != iBlkNil))
return iBlk;
}
/* Random search for a valid spot */
while (rgBlk[iBlk = Rnd(cBlkMac)] != iBallBlank)
;
return iBlk;
}
/****** D O T I M E R ******/
VOID DoTimer(VOID)
{
if (fFlash)
DoFlash(fFlashOnOff ^= 1);
}
/****** S E T U P D A T A */
VOID SetupData(VOID)
{
#ifdef DEBUG2
CHAR sz[80];
#endif
INT c,c2,c3;
POS pos;
INT iTbl = 0;
INT cTblMac = 0;
switch (Preferences.iGameType)
{
case iGame3x3:
f4 = fFalse;
cBlkRow = 3;
cPlane = 1;
iTbl = i3x3;
cTblMac = c3x3;
break;
case iGame3x3x3:
f4 = fFalse;
cBlkRow = 3;
cPlane = 3;
iTbl = i3x3x3;
cTblMac = c3x3x3;
break;
case iGame4x4x4:
f4 = fTrue;
cBlkRow = 4;
cPlane = 4;
iTbl = i4x4x4;
cTblMac = c4x4x4;
break;
}
cBlkPlane = cBlkRow * cBlkRow;
cBlkMac = cBlkPlane * cPlane;
#ifdef DEBUG3
wsprintf(sz,"Game=%d cBlkRow=%d cPlane=%d\r\n",Preferences.iGameType, cBlkRow, cPlane);
OutputDebugString(sz);
wsprintf(sz,"cBlkPlane=%d cBlkMac=%d cTblMac=%d\r\n",cBlkPlane, cBlkMac, cTblMac);
OutputDebugString(sz);
#endif
cChkMac = 0;
c3 = 0;
while (c3++ < cTblMac)
{
pos = rgtbl[iTbl][iposStart];
c2 = 0;
while (c2 < cBlkRow)
{
for (c=0; c < cBlkRow; c++)
{
rgChk[cChkMac][c] = pos;
#ifdef DEBUG2
wsprintf(sz," %d",pos);
OutputDebugString(sz);
#endif
pos = (pos + rgtbl[iTbl][iposOff]) % cBlkMac;
}
cChkMac++;
c2++;
if (rgtbl[iTbl][iposLine] == (BYTE) -1)
c2 = cBlkRow;
else
pos = (pos + rgtbl[iTbl][iposLine] - rgtbl[iTbl][iposOff]) % cBlkMac;
#ifdef DEBUG2
OutputDebugString("\r\n");
#endif
}
iTbl++;
#ifdef DEBUG2
OutputDebugString("------\r\n");
#endif
}
#ifdef DEBUG2
wsprintf(sz,"cChkMac=%d",cChkMac);
OutputDebugString(sz);
#endif
}
/****** S T A R T G A M E *******/
VOID StartGame(VOID)
{
REGISTER i;
fFlash = fFalse;
ClrStatusIcon();
SetStatusPlay();
iMoveCurr = 0;
#ifdef DEBUG3
OutputDebugString("*** New Game ***\r\n");
#endif
for (i = 0; i < cBlkMac; i++) /* USE A BLT ! */
rgBlk[i] = iBallBlank;
ReDoDisplay();
DisplayGrid();
if (Preferences.iStart == iStartRnd)
iPlayer = 1 + Rnd(2);
else
iPlayer = Preferences.iStart;
if (iPlayer == iComputer)
{
iPlayer = iComputer;
DoMove(ComputerMove());
}
}