1
0
Fork 0

Moved Backgammon to this repository

This commit is contained in:
acn 2020-07-01 15:28:08 +02:00
parent 54fe73b528
commit 9008c67a38
21 changed files with 7349 additions and 6 deletions

View File

@ -0,0 +1,62 @@
# Compiling Gammon IV
## Requirements
To compile this program, you need the following:
* The Software Toolworks' C/80 v3.1 compiler for CP/M
* Microsoft MACRO-80 assembler (M80.com)
* Microsoft LINK-80 linker (L80.COM)
All of these tools can also be found here:
http://www.retroarchive.org/cpm/lang/lang.htm
## Configuration
The C compiler needs to be configured in order to be able to compile Gammon IV.
Just use CCONFIG.COM to make the following settings:
Symbol table size: 512
String constant table: 3200
Dump constants after each routine: YES
Macro table size: 500
Switch table size: 128
Structure table size: 200
Merge duplicate string constants: YES
Assembler: C/80's AS
Initialize arrays to zero: < 256 BYES ONLY
Generate ROMable code in Macro-80: YES
Screen size: 24 (doesn't matter)
Generate slightly larger, faster code: NO
Sign extension on char to int conversion: YES
Device for library files: A: (your choice)
## Compilation
I assume that all of the following files are placed on a hard disk or "big" floppy disk.
If you are compiling this game on a old system with limited disk space, please look into backgmmn.c, where you can find tips on how to distribute the files onto several disks.
The following files are needed:
BACKGMMN.C, GAMEPLAN.C, GAMEPLAN.HDR, MYLIB2.C,
From the C compiler:
PRINTF.C, STDLIB.REL, CLIBRARY.REL, C.COM
Assembler/Linker:
L80.COM, M80.COM
To use the submit scripts, you also need ``SUBMIT.COM`` from your CP/M installation.
Using ``SUBMIT BGMAKE``, all steps of compiling, assembling and linking will run.
Using ``SUBMIT BGCLEAN``, all compiled files and intermediary files will be deleted.
If you don't want to use the script or just want to compile some parts, these steps are taken in the script:
c -m backgmmn
m80 =backgmmn
c -m gameplan
m80 =gameplan
l80 backgmmn,gameplan,stdlib/s,clibrary/s,backgmmn/n/e

View File

@ -0,0 +1,8 @@
era *.bak
era *.mac
era backgmmn.rel
era gameplan.rel
era backgmmn.com
era backgmmn.mac
era gameplan.mac


View File

@ -0,0 +1,13 @@
era *.bak
era *.mac
era backgmmn.rel
era gameplan.rel
era backgmmn.com
c -m backgmmn
m80 =backgmmn
era backgmmn.mac
c -m gameplan
m80 =gameplan
era gameplan.mac
l80 backgmmn,gameplan,stdlib/s,clibrary/s,backgmmn/n/e


Binary file not shown.

BIN
Backgammon/Compiler/l80.com Normal file

Binary file not shown.

BIN
Backgammon/Compiler/m80.com Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,14 @@
era *.bak
era *.mac
era backgmmn.rel
era gameplan.rel
era backgmmn.com
b:c -m backgmmn
b:m80 =backgmmn
era backgmmn.mac
b:c -m gameplan
b:m80 =gameplan
era gameplan.mac
b:l80 backgmmn,gameplan,stdlib/s,clibrary/s,backgmmn/n/e
backgmmn


View File

@ -0,0 +1,866 @@
/* Gammon IV, by David C. Oshel, Ames, Iowa */
/*--------------------------------------------------------------------*/
/* GAMEPLAN.C -- separately compiled module, contains the tactics and */
/* strategy for making the computer's move in Gammon IV */
/* BACKGMMN.REL calls MyMove(), MyMove() calls topstone */
/* and movestone and a few others. Uses the globals in */
/* GAMEPLAN.HDR quite heavily. Bgversion declared here */
/*--------------------------------------------------------------------*/
#include "gameplan.hdr" /* contains external, global declarations */
/*-------------------------------------------------------------------------*/
/* */
/* Bgversion is an external reference in the main module. Use this string */
/* to take credit for a decent gameplaying algorithm if you find one! */
/* */
char *bgversion = ".20 -April 1, 1986- by David C. Oshel";
/*....v....1....v....2....v....3....v...*/
/* just 38 characters for version info! */
/* */
/*-------------------------------------------------------------------------*/
/*=============================================*/
/* M Y M O V E */
/*=============================================*/
naked() { /* am I leaving too many blots? */
static int i, clink;
i = 24; clink = 0;
while (i) {
if (point[i].stones == 1 && point[i].owner == ME) clink++;
i--;
}
return (clink > 2);
} /* end: naked */
yourfolly() { /* look for lotsa blots in your inner table */
static int i, clink;
i = 18; clink = 0;
while (i < 25) {
if (point[i].owner == YU && point[i].stones == 1)
clink++;
i++;
}
return (clink >= 3);
} /* end: yourfolly */
goodboard() { /* look for four made points near my inner table */
static int i, clank, clink;
i = 9; clank = 0;
while (i > 3) {
if (point[i].owner == ME && point[i].stones > 1) clank++;
i--;
}
if (clank > 4) return (TRUE); /* bar is nearly blocked */
i = 6; clank = clink = 0;
while (i) {
if (point[i].owner != ME)
;
else if (point[i].stones == 1) clink++; else clank++;
i--;
}
return (clank > 3 && clink < 2);
} /* end: goodboard */
bearoff() {
return (topstone(ME) < 7);
} /* end: bearoff */
scanahead( from ) int from; {
static int count;
count = 0;
while (--from > 0) {
++count;
if ( point[ from ].owner == YU ) return (count);
}
return (7);
} /* end: scanahead */
endgame() { /* Is no strategy required from here on in? */
return ( (25 - topstone(YU)) > topstone(ME) );
} /* end: endgame */
/*------------------------------------------------------------*/
/* MATCHUP */
/* */
/* 2-stone functions that force the choice of the next move. */
/* These are the HEART and SOUL of this backgammon algorithm! */
/*------------------------------------------------------------*/
setpend( from, to ) int from, to; {
pending.fr = from;
pending.to = to;
pending.flag = TRUE;
} /* end: setpend */
clrpend() {
pending.flag = FALSE;
} /* end: clrpend */
natural(f1,t1,f2,t2) int f1,t1,f2,t2; {
clrpend();
if (point[t2].stones == 1 && t1 == f2) setpend(f2,t2);
return (pending.flag);
} /* end: natural */
matchup( test4 ) int (* test4)(); {
static int i, j, ti, tj;
if ( pending.flag ) return (FALSE); /* this is probably redundant */
for (i = 1; i < 26; i++) {
ti = list[0][i];
if ( ti == ERROR ) goto zoo;
for (j = 1; j < 26; j++) {
tj = list[1][j];
if ( tj == ERROR ) goto voo;
if ( (* test4)( i, ti, j, tj ) ) {
lurch( i, ti, 0);
return (TRUE);
}
voo: ;
}
zoo: ;
}
return (FALSE);
} /* end: matchup */
matchhi( test4 ) int (* test4)(); {
static int i, j, ti, tj;
if ( pending.flag ) return (FALSE); /* this is probably redundant */
for (i = 1; i < 26; i++) {
ti = list[1][i];
if ( ti == ERROR ) goto zoo;
for (j = 1; j < 26; j++) {
tj = list[0][j];
if ( tj == ERROR ) goto voo;
if ( (* test4)( i, ti, j, tj ) ) {
lurch( i, ti, 1);
return (TRUE);
}
voo: ;
}
zoo: ;
}
return (FALSE);
} /* end: matchhi */
/*--------------------------------------------------------*/
/* CLOCKWISE and COUNTERCLOCK */
/* */
/* the rest of these are single-stone decisions based on */
/* rules of thumb, board-scanning functions */
/*--------------------------------------------------------*/
plainstupid( from ) int from; { /* don't break a safe point */
return (from < 13 && (point[from].stones == 2 && scanahead(from) < 7));
} /* end: plainstupid */
unwise( innertablept ) int innertablept; {
/* if it's a hit, just for god's sake don't put him on the bar!! */
if ( innertablept < 7 ) {
if (point[ innertablept ].owner == YU ||
point[ YRBAR ].stones > 0)
return (TRUE);
}
return(FALSE);
} /* end: unwise */
covermine( from, to ) int from, to; {
if ( from < 8 ) return(FALSE);
return ( (point[ to ].stones == 1) && (point[ to ].owner == ME) );
} /* end: covermine */
idareyou( from, to ) int from, to; {
if (unwise( to )) return (FALSE);
if ( (point[ from ].stones != 2)
&& (point[ to ].stones < 2)
&& (scanahead( to ) > 6) ) return ( TRUE );
else return (FALSE);
} /* end: idareyou */
hitandrun( from, to ) int from, to; {
return ( point[ to ].owner == YU );
} /* end: hitandrun */
dbuild( from, to ) int from, to; {
static int diceleft;
diceleft = (myturns? 2 + movesleft: movesleft);
if (diceleft > 1) {
/* can't possibly be only one stone on from point */
/* or kamikaze would have covered it on last move */
return ( point[to].stones == 0 );
}
return (FALSE);
} /* end: dbuild */
kamikaze( from, to ) int from, to; {
/* cover my distant blot, or razzle-dazzle 'em with the long doubles hit */
static int j, k, diceleft;
k = from;
j = from - to;
diceleft = myturns * movesleft; /* NB: 2*2 == 2+2, "fourtunately" */
while ( diceleft-- ) { /* predicting where doubles land is easy! */
k -= j;
if (k < 1) return (FALSE); /* out of bounds */
if ( point[ k ].stones == 0 ) continue; /* simplify */
if ( point[ k ].stones == 1 ) /* found my blot or yours? */
return (TRUE);
else if ( point[k].owner == YU ) /* found your blockade? */
return (FALSE);
else continue; /* found my safe point, so ignore it */
}
return (FALSE);
} /* end: kamikaze */
hittite( from, to ) int from, to; {
return (hitandrun(from,to) && to > 9);
} /* end: hittite */
safehit( from, to ) int from, to; {
return (hittite(from,to) && idareyou(from,to));
} /* end: safehit */
foolsdemise( from, to ) int from, to; {
/* annihilate orphaned blots in enemy's inner, my outer table */
return (to > 17 && point[to].owner == YU);
} /* end: foolsdemise */
landonme( from, to ) int from, to; {
if ( plainstupid(from) ) return (FALSE);
if ( loneranger(from,to) ) {
if (from < 19 && to > 6) return(TRUE);
}
else return ( point[ to ].owner == ME && point[to].stones < 4);
} /* end: landonme */
/* these evaluations have meaning only in the endgame */
nobackgammon( from, to ) int from, to; { /* endgame */
return (from > 19);
} /* end: nobackgammon */
crosstable( from, to ) int from, to; {
/* always move a table ahead if possible, in the endgame */
if (from < 7) return (FALSE);
if (from > 18 && to <= 18) return (TRUE);
if (from > 12 && to <= 12) return (TRUE);
if (from > 6 && to <= 6) return (TRUE);
return (FALSE);
} /* end: crosstable */
fiftytworule( from, to ) int from, to; { /* endgame */
static int p;
if (from < 7) return (FALSE); /* not in inner table! */
p = from % 6;
if (p == 0) return (TRUE); /* improve the six */
if (p != 5) return ( (to % 6) < 3 ); /* best improve under five */
} /* end: fiftytworule */
/* these evaluations are universally applicable, last resort moves */
gohome( from, to ) int from, to; { /* always go home if you can */
return (to == MYHOME);
} /* end: gohome */
scatter( from, to ) int from, to; { /* scatter, esp. in the endgame */
if (plainstupid(from) || unwise(to)) return (FALSE);
return ( point[ from ].stones > 1 && point[ to ].stones == 0 );
} /* end: scatter */
runnerup( from, to ) int from, to; {
if (from < 10 || from > 18) return (FALSE);
return (TRUE);
} /* end: runnerup */
loneranger( from, to ) int from, to; {
return( point[ from ].stones == 1 );
} /* end: loneranger */
run( dummy1, dummy2 ) int dummy1, dummy2; { /* MUST move something! */
return (TRUE);
} /* end: run */
/* clockwise and counterclock make a 1-stone choice on rules of thumb */
counterclock( test ) int (* test)(); {
static int i,j;
for (i = 0; i < 2; i++) {
for (j = 1; j < 25; j++) {
if ( list[i][j] == ERROR ) continue;
if ( (* test)( j, list[i][j] ) ) {
lurch( j, list[i][j], i);
return ( TRUE );
} } }
return (FALSE);
} /* end: counterclock */
clockwise( test ) int (* test)(); {
static int i,j;
for (i = 0; i < 2; i++) {
for (j = 25; j > 0; j--) {
if ( list[i][j] == ERROR ) continue;
if ( (* test)( j, list[i][j] ) ) {
lurch( j, list[i][j], i);
return ( TRUE );
} } }
return (FALSE);
} /* end: clockwise */
/*-------------------------------------------*/
/* Make Prime */
/*-------------------------------------------*/
static int prmchk;
buildprime( f1,t1,f2,t2 ) int f1,t1,f2,t2; {
clrpend();
/* check for the doubles bug */
if ((dice[0] == dice[1]) && (point[f1].stones < 2)) return(FALSE);
/* look for the combination */
if ( t1 == prmchk && t2 == prmchk) setpend(f2,t2);
/* stick like glue to a made point, but doubles may move forward */
if (dice[0] != dice[1]) {
if ((f2 < 8) && (point[f2].stones == 2)) clrpend();
if ((f1 < 8) && (point[f1].stones == 2)) clrpend();
}
return(pending.flag);
} /* end: buildprime */
makeprime() {
static int i, tab[] = { ERROR,1,2,3,20,22,24,9,4,6,8,5,7 };
i = 12;
while (i) {
prmchk = tab[i];
i--;
if ( point[ prmchk ].stones > 1 ) continue;
else if ( matchup( buildprime ) ) return(TRUE);
}
return(FALSE);
} /* end: makeprime */
coverprime( from, to ) int from, to; {
return (((to == prmchk) &&
(point[prmchk].owner == ME)) &&
(point[from].stones != 2));
} /* coverprime */
cleanup() {
static int i, tab[] = { ERROR,1,2,3,20,22,24,9,4,6,8,5,7 };
i = 12;
while (i) {
prmchk = tab[i];
i--;
if ( point[ prmchk ].stones != 1 ) continue;
else if ( counterclock( coverprime ) ) return(TRUE);
}
return(FALSE);
} /* end: cleanup */
/*-------------------------------------*/
/* Walking Prime */
/*-------------------------------------*/
swivelhips( from, to ) int from, to; {
return ( from > prmchk );
} /* end: swivelhips */
slink( from, to ) int from, to; {
return( (from > prmchk) && (point[to].stones == 1) );
} /* end: slink */
weasel() {
if ( clockwise( slink ) )
return(TRUE);
if ( counterclock( swivelhips ) )
return(TRUE);
if ( clockwise( run ) )
return(TRUE);
} /* end: weasel */
ihaveprime( from ) int from; {
static int i, to, ez;
ez = 0;
for (i = 0; i < 6; i++) {
to = from - i;
if ((point[to].owner == ME) && (point[to].stones > 1)) ez++;
}
return (ez > 4);
} /* end: ihaveprime */
walkingprime() {
/* looks for the walking prime anywhere in the front tables */
/* then tries to bring up a runner from behind the prime, */
/* ensuring that a back stone WILL move before a front one */
static int i;
i = 12;
while (i > 5) {
if ( ihaveprime(i) ) {
prmchk = i;
if ( weasel() ) return (TRUE);
}
i--;
}
return(FALSE);
} /* end: walkingprime */
/*---------- Book Moves ----------*/
/* only valid if my move is first */
/*--------------------------------*/
zip(a,b,c,d) int a,b,c,d; {
lurch(a,b,0);
lurch(c,d,0);
movesleft = 0; return( TRUE );
} /* end: zip */
zoom( a,b,c,d,e,f,g,h ) int a,b,c,d,e,f,g,h; {
myturns = 0; zip(a,b,c,d); zip(e,f,g,h); return( TRUE );
} /* end: zoom */
book() {
int a,b;
if (!firstmove) return (FALSE);
firstmove = FALSE;
a = min(dice[0],dice[1]);
b = max(dice[0],dice[1]);
switch (level) {
case 0: { return ( book0(a,b) ); break; }
case 1: { return ( book1(a,b) ); break; }
case 2: { return ( book2(a,b) ); break; }
}
}
book0( a,b ) int a, b; {
switch (a) {
case 1: { switch (b) {
case 1: return ( zoom(8,7,8,7,6,5,6,5) );
case 2: return ( zip(24,23,13,11) );
case 3: return ( zip(8,5,6,5) );
case 4: return ( zip(24,23,13,9) );
case 5: return ( zip(24,23,13,8) );
case 6: return ( zip(13,7,8,7) );
}
break; }
case 2: { switch (b) {
case 2: return ( zoom(6,4,6,4,13,11,13,11) );
case 3: return ( zip(13,11,13,10) );
case 4: return ( zip(8,4,6,4) );
case 5: return ( zip(13,8,13,11) );
case 6: return ( zip(24,18,13,11) );
}
break; }
case 3: { switch (b) {
case 3: return ( zoom(13,10,13,10,10,7,10,7) );
case 4: return ( zip(13,10,13,9) );
case 5: return ( zip(13,10,13,8) );
case 6: return ( zip(24,18,13,10) );
}
break; }
case 4: { switch (b) {
case 4: return ( zoom(13,9,13,9,24,20,24,20) );
case 5: return ( zip(13,8,13,9) );
case 6: return ( zip(24,18,18,14) );
}
break; }
case 5: { switch (b) {
case 5: return ( zoom(13,8,13,8,8,3,8,3) );
case 6: return ( zip(24,18,18,13) );
}
break; }
case 6: { return ( zoom(13,7,13,7,24,18,24,18) );
break; }
}
} /* end: book0 */
book1( a,b ) int a, b; { /* mostly follows Becker */
switch (a) {
case 1: { switch (b) {
case 1: return ( zoom(8,7,8,7,6,5,6,5) );
case 2: return ( zip(13,11,6,5) );
case 3: return ( zip(8,5,6,5) );
case 4: return ( zip(13,9,6,5) );
case 5: return ( zip(13,8,6,5) );
case 6: return ( zip(13,7,8,7) );
}
break; }
case 2: { switch (b) {
case 2: return ( zoom(6,4,6,4,13,11,13,11) );
case 3: return ( zip(13,11,13,10) );
case 4: return ( zip(8,4,6,4) );
case 5: return ( zip(13,8,13,11) );
case 6: return ( zip(13,7,7,5) );
}
break; }
case 3: { switch (b) {
case 3: return ( zoom(13,10,13,10,8,5,8,5) );
case 4: return ( zip(13,10,13,9) );
case 5: return ( zip(13,8,8,5) );
case 6: return ( zip(13,7,13,10) );
}
break; }
case 4: { switch (b) {
case 4: return ( zoom(13,9,13,9,9,5,9,5) );
case 5: return ( zip(13,8,13,9) );
case 6: return ( zip(13,7,13,9) );
}
break; }
case 5: { switch (b) {
case 5: return ( zoom(13,8,13,8,8,3,8,3) );
case 6: return ( zip(13,7,13,8) );
}
break; }
case 6: { return ( zoom(13,7,13,7,24,18,24,18) );
break; }
}
} /* end: book1 */
book2( a,b ) int a, b; { /* mostly follows Becker */
switch (a) {
case 1: { switch (b) {
case 1: return ( zoom(8,7,8,7,6,5,6,5) );
case 2: return ( zip(13,11,24,23) );
case 3: return ( zip(8,5,6,5) );
case 4: return ( zip(13,9,24,23) );
case 5: return ( zip(13,8,24,23) );
case 6: return ( zip(13,7,8,7) );
}
break; }
case 2: { switch (b) {
case 2: return ( zoom(6,4,6,4,24,23,24,23) );
case 3: return ( zip(13,11,13,10) );
case 4: return ( zip(8,4,6,4) );
case 5: return ( zip(13,8,13,11) );
case 6: return ( zip(13,7,13,11) );
}
break; }
case 3: { switch (b) {
case 3: return ( zoom(13,10,13,10,10,7,10,7) );
case 4: return ( zip(13,10,13,9) );
case 5: return ( zip(13,8,8,5) );
case 6: return ( zip(13,7,13,10) );
}
break; }
case 4: { switch (b) {
case 4: return ( zoom(13,9,13,9,9,5,9,5) );
case 5: return ( zip(13,8,13,9) );
case 6: return ( zip(13,7,13,9) );
}
break; }
case 5: { switch (b) {
case 5: return ( zoom(13,8,13,8,8,3,8,3) );
case 6: return ( zip(13,7,13,8) );
}
break; }
case 6: { return ( zoom(13,7,13,7,24,18,24,18) );
break; }
}
} /* end: book2 */
/*====== MyMove ======*/
torve() {
if ( makeprime() ) { /* this will use doubles, if it can */
return;
}
else if ( walkingprime() ) { /* i have six prime points, so run!!! */
return;
}
else if ( dice[0] == dice[1] ) { /* this is too easy! */
if ( counterclock( kamikaze ) )
return;
if ( counterclock( dbuild ) ) /* claim new turf */
return;
if ( clockwise( run ) )
return;
}
else if ( cleanup() ) { /* cover my single blot on prime points */
return;
}
else if ( bearoff() ) { /* I'm ready, but you're in the back game! */
if ( counterclock( gohome ) )
return;
if ( clockwise( run ) )
return;
}
else {
if ( clockwise( hitandrun ) )
return;
if ( matchup( natural ) )
return;
if ( clockwise( landonme ) )
return;
if ( counterclock( runnerup ) )
return;
if ( clockwise( scatter ) )
return;
if ( clockwise( run ) )
return;
}
} /* end: torve */
villiers() {
if ( makeprime() ) { /* this will use doubles, if it can */
return;
}
else if ( walkingprime() ) { /* i have six prime points, so run!!! */
return;
}
else if ( dice[0] == dice[1] ) { /* this is too easy! */
if ( counterclock( kamikaze ) )
return;
if ( counterclock( dbuild ) ) /* claim new turf */
return;
if ( clockwise( run ) )
return;
}
else if ( cleanup() ) { /* cover my single blot on prime points */
return;
}
else if ( bearoff() ) { /* I'm ready, but you're in the back game! */
if ( counterclock( gohome ) )
return;
if ( clockwise( run ) )
return;
}
else {
if ( clockwise( foolsdemise ) )
return;
if ( clockwise( idareyou ) )
return;
if ( counterclock( covermine ) )
return;
if ( matchup( natural ) )
return;
if ( clockwise( landonme ) )
return;
if ( clockwise( runnerup ) )
return;
if ( clockwise( scatter ) )
return;
if ( clockwise( run ) )
return;
}
} /* end: villiers */
louisa() {
if ( makeprime() ) { /* this will use doubles, if it can */
return;
}
else if ( walkingprime() ) { /* i have six prime points, so run!!! */
return;
}
else if ( dice[0] == dice[1] ) { /* this is too easy! */
if ( counterclock( kamikaze ) )
return;
if ( counterclock( dbuild ) ) /* claim new turf */
return;
if ( clockwise( run ) )
return;
}
else if ( cleanup() ) { /* cover my single blot on prime points */
return;
}
else if ( bearoff() ) { /* I'm ready, but you're in the back game! */
if ( counterclock( gohome ) )
return;
if ( clockwise( run ) )
return;
}
else if ( (!naked() && goodboard()) || yourfolly() ) {
if ( clockwise( hitandrun ) )
return;
if ( matchup( natural ) )
return;
if ( clockwise( landonme ) )
return;
if ( counterclock( runnerup ) )
return;
if ( clockwise( scatter ) )
return;
if ( clockwise( run ) )
return;
}
else {
if ( clockwise( foolsdemise ) )
return;
if ( clockwise( idareyou ) )
return;
if ( counterclock( covermine ) )
return;
if ( matchup( natural ) )
return;
if ( clockwise( landonme ) )
return;
if ( clockwise( runnerup ) )
return;
if ( clockwise( scatter ) )
return;
if ( clockwise( run ) )
return;
}
} /* end: louisa */
mymove() {
int i, d;
if ( nomove() ) {
if (lookforit && (dice[0] != dice[1])) {
lookforit = FALSE;
puts("\008... ");
switch (level) {
case 0: { puts("Blocked!"); break; }
case 1: { puts("Well, no!"); break; }
case 2: { puts("Thurb!"); break; }
}
sleep(10);
restoreboard();
update();
/* put the high die in list zero */
d = dice[0]; dice[0] = dice[1]; dice[1] = d;
cantuse = ERROR; movesleft = 2; myturns = 1;
switch (level) {
case 0: { setchat("I move"); break; }
case 1: { setchat("Let's try"); break; }
case 2: { setchat("Move is"); break; }
}
debug(chatter);
prmchk = 12;
weasel();
/* the rules say, use both dice if you can, or */
/* the highest if one or the other but not both */
}
else {
lookforit = TRUE;
strcat(chatter," and now I'm blocked ");
myturns = movesleft = 0;
} }
else if ( book() ) {
return;
}
else if ( pending.flag ) {
lurch( pending.fr, pending.to, 1 );
clrpend();
}
else if ( endgame() ) { /* very solid tactics here!! */
if ( clockwise( gohome ) )
return;
if ( clockwise( nobackgammon ) ) /* no excuse! */
return;
if ( clockwise( crosstable ) )
return;
if ( clockwise( fiftytworule ) )
return;
if ( clockwise( scatter ) )
return;
if ( clockwise( run ) )
return;
}
else if ( point[ MYBAR ].stones > 0 ) { /* I'm on the bar! */
if ( clockwise( hitandrun ) ) /* wreak havoc, please */
return;
if ( clockwise( run ) ) /* note: uses low die first */
return;
}
else switch (level) {
case 0: { villiers(); break; }
case 1: { louisa(); break; }
case 2: { torve(); break; }
}
} /* end: mymove */
/*------------------------------*/
/* end of the GAMEPLAN.C module */
/*------------------------------*/


View File

@ -0,0 +1,42 @@
/* GAMEPLAN.HDR */
/*================================================================*/
/* change nothing in this file */
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#define TRUE 1
#define FALSE 0
#define ME 1
#define YU 2
#define YRBAR 0
#define MYBAR 25
#define YRHOME 26
#define MYHOME 27
#define ERROR 999
#define MYLEVEL 2
extern int list[2][28]; /* two dice, two lists */
extern struct board {
int stones, /* number of stones on that point */
owner, /* and whose they are */
x,y, /* x and y coordinates of point base */
lastx,lasty, /* last location drawn on this point */
cx,cy; /* coordinates for column numbers */
}
point[28], bdsave[28]; /* 24 points, plus 2 bars, 2 homes */
extern struct { int cube, whosecube; } doubles;
extern struct { int fr,to,flag; } pending;
extern int level, dice[2], myscore, yrscore, player, movesleft, cantuse,
myturns, swapped, tswap, deciding, expert, tone, show, moremsgline,
firstmove, helpdisabled, yrdice, lookforit, startcubevalue;
extern char *chatter[80];
/*----------------------------------------------*/
/* end of header -- change NOTHING in this file */
/*----------------------------------------------*/


View File

@ -0,0 +1,541 @@
/*
MYLIB2.C
These routines are CONDITIONALLY compiled; i.e., only as needed.
----------------------------------------------------------------------
Incorporates special mods used by my Backgammon game, BACKGMMN.C etc.
----------------------------------------------------------------------
A set of common I/O functions that seem to turn up a lot in my programs,
including terminal functions for Kaypro 10, 4'84, 2X etc.
Uses Software Toolworks' C/80 3.1 compiler. Place #include "mylib2.c" at the
end of your source file for correct CONDITIONAL COMPILATION.
David C. Oshel
1219 Harding Ave.
Ames, Iowa 50010
Last modified: March 25, 1986
-----------------------------------------------------------------------------
** WARNING ** These routines use direct console IO, bdos function 6!
YOU MUST CALL INIT_LIB() BEFORE USING THESE ROUTINES!
======= UTILITIES =======
* init_lib() - CALL THIS FIRST, OR THE RESULT WILL BE VERY STRANGE!
*
* puts(p) - unformatted print, e.g., puts("Hello, sailor!\n");
* gets(p,max) - printable input only, no prompt character
*
* ask(p) - demand Yes or No response to question p
* random() - effective random 16-bit integer IFF gets() is used
* sleep(n) - sleep n/10ths of a second, roughly (from C80.LIB)
* rollup() - roll up 23 lines of screen
* ONscript() - printer echo ON for output via puts, chrout
* OFFscript() - printer echo OFF for output via puts, chrout
* ONinterrupt() - Ctl-C, Ctl-B cause program exit
* OFFinterrupt() - Ctl-C, Ctl-B cause comedy
* hide_input(p,max) - like gets, but used when entering passwords
* chrout(c) - if scripting, echo output also to LST:
* putscreen(p) - like puts, but always and only to screen
======= KAYPRO 10 TERMINAL/VIDEO FUNCTIONS =======
* gotoxy(x,y) - 0,0 is top left, horz <= 79 precedes vert <= 24,
* where 0,24 is on the 25th, status, line.
* beep() - terminal bell
* home() - home cursor, do not clear screen
* clr_screen() - home and clear
*
* shadow_box(h,v,x1,y1,x2,y2) - like box, but with shadow, calls box
* box(tlx,tly,brx,bry) - draw a line box, coords: topleft XY, bottomright XY
* note that box calls ldraw(x1,y1,x2,y2), below
*
* clr_lend() - clear from cursor to end of line
* clr_send() - clear from cursor to end of screen
* rev_vid(),
* nor_vid() - reverse field
* dim_vid(),
* bri_vid() - low/high intensity
* on_blink(),
* off_blink() - blinking chars
* ul_start(),
* ul_stop() - start/stop underline
* save_cursor(),
* retn_cursor() - remember/restore current cursor location
* ins_line(),
* del_line() - insert/delete screen text line
* on_cursor(),
* off_cursor() - hide/show cursor
* vm_on(),
* vm_off() - "Video Mode" commands
* pixel(x,y) - draw pixel at x,y (video coords, x <= 159, y <= 99)
* no_pixel(x,y) - erase pixel at x,y
* ldraw(x1,y1,x2,y2) - draw/ erase graphics line, see discussion for box
* lwipe(x1,y1,x2,y2) - range for video coordinates as for pixel
*/
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* hide this here so's not to worry about it elsewhere */
/* "printf.c" collides with one of these, can't remember which */
/* puts() takes longer to write, but executes faster */
extern char Cmode, IOpread[4], IOpwrit[4], IOpeof[4];
/* make these known only to what follows */
static int MYbstout, MYscrtp, MYretnirp; /* odd names mark semi-private */
static unsigned RNDloc; /* effective random location, bumped by gets() */
/* and scrambled when the LCG random() is called */
/* makes a decent algorithm for interactive games */
#ifneed init_lib
init_lib() {
MYretnirp = fopen("LST:","w");
OFFscript();
ONinterrupt();
Cmode = 0;
IOpread[0] = 6; IOpwrit[0] = 6;
} /* end: init_lib */
#endif
#ifneed random
random() { /* depends on effective random location spun by gets() */
RNDloc = 2053 * RNDloc + 13849;
return (RNDloc);
}
#endif
#ifneed ONscript
ONscript() {
MYscrtp = TRUE;
}
#endif
#ifneed OFFscript
OFFscript() {
MYscrtp = FALSE;
}
#endif
#ifneed ONinterrupt
ONinterrupt() {
MYbstout = TRUE;
}
#endif
#ifneed OFFinterrupt
OFFinterrupt() {
MYbstout = FALSE;
}
#endif
#ifneed ask
ask(p) char *p; {
char ch, resp[2];
loo: puts(p);
gets(resp,1);
ch = toupper( *resp );
if ( !( ch == 'Y' || ch == 'N' )) {
puts("Please answer the question, Yes or No.\n");
goto loo;
}
return (ch == 'Y');
} /* end: ask */
#endif
#ifneed rollup
rollup() {
int i;
for (i=0; i<23; i++) puts("\n");
} /* end: rollup */
#endif
#ifneed sleep
sleep( n ) int n; { /* sleep for n/10 seconds, 0 <= n < 256 */
n; /* get n into HL */
#asm
MOV B,L ;delay B/10ths of a second
__DL0: MVI A,100 ;100 milliseconds, 1/10 second
__DL1: MVI C,249 ;1 millisecond per unit of A at 4 MHz
__DL2: DCR C ;Leventhal, Z80 Assembly Language Programming
JNZ __DL2
DCR A
JNZ __DL1
DCR B
JNZ __DL0 ;on exit, HL has FALSE if n was 0, else TRUE
#endasm
} /* end: sleep */
#endif
/*========================================*/
/* GETS(p, maxinput) */
/* Local getline function with special *---* WARNING: */
/* input handling, 1 <= len <= maxinput *---* Execute INIT_LIB() first !! */
/* Updates effective random, RNDloc, */
/* Forces input from CONSOLE only! */
/*========================================*/
#ifneed gets
gets(p,maxinput) char *p; int maxinput; {
/* This function depends on BDOS Function #6. Init_lib() sets Cmode=0 and
IOpread[0]=6 and IOpwrit[0]=6 (courtesy of and peculiar to C/80 3.1)
YOU must ensure that the target string is long enough to collect the
entire maximum input allowed and specified, INCLUDING FINAL NULL! */
static int len;
static char ch;
len = -1;
if (maxinput < 1 || maxinput > 127) maxinput = 79;
/*--------------------------------*/
/* SPECIAL ROUTINE FOR BACKGAMMON */
/*--------------------------------*/
loo: while ( !(ch = getc(0)) ) acg(); /* keep the game lively */
if (len < 0) len = 0; /* don't destroy prompt by backing up */
if (ch == '\n') { /* end of line? don't store newline */
*p = '\0'; /* mark it with a B for baby and me */
/* chrout('\n'); */ /* but DON'T echo newline */
return ( len ); /* <--- HERE IS THE FUNCTION EXIT! */
}
else if (ch == '\b' || ch == 0x7F) { /* backspace? rubout? */
if (len--) { /* where's the prompt? */
puts("\008 \008"); /* we're ok, echo erase */
p--; /* delete from string */
}
}
/*--------------------------------*/
/* SPECIAL ROUTINE FOR BACKGAMMON */
/*--------------------------------*/
else if (ch == '\003') { /* user bailout key is Ctrl-C, not ESC */
if (MYbstout) exit();
else {
haltgame(); /* sets whofirst flag and does jumpjack() */
}
}
else if (ch == '\025' || ch == '\030') { /* Ctl-U, Ctl-X */
while (len--) {
p--;
puts("\008 \008");
}
}
else if (len == maxinput) { /* test specials before testing len */
chrout('\007');
}
else if (ch > 31 && ch < 127) { /* printable char? */
chrout(ch); /* yes, echo it */
*p++ = ch; /* collect it */
len++; /* keep track of it */
}
else { /* control chars? */
chrout('\007');
}
goto loo;
} /* end: gets */
#endif
#ifneed hide_input
hide_input(s,len) char *s; int len; {
/* receive at most len chars in s buffer,
terminate string with zero,
but echo each char with 1, 2, or 3 meaningless dots */
char ch; int num;
if ((len < 1) || (len > 127)) len = 127;
num = 0;
for (;;) { /* forever */
while ((ch = getc(0)) == 0) /* bdos 6 does not wait, so we do */
;
if ((ch == '\r') || (ch == '\n') || (num++ > len)) {
/* not sure what the CR key actually is to bdos 6 & C/80 */
*s++ = '\0';
return; /* this way out */
}
if ((num % 2) == 0) putc('.',0); /* deception, illusion */
if ((num % 5) == 0) putc('.',0);
putc('.',0);
*s++ = ch;
}
} /* end: hide_input */
#endif
/*------------------------ kpro stuff -------------------------*/
#ifneed shadow_box
/* like box, but with horizontal & vertical displacement for shadow */
shadow_box(h,v,x1,y1,x2,y2) int h,v,x1,y1,x2,y2;
{
box(x1+h,y1+v,x2+h,y2+v); /* draw the shadow */
box(x1,y1,x2,y2); /* draw the box */
ldraw(x1+h,y1+v,x1,y1); /* draw the corners */
ldraw(x2+h,y2+v,x2,y2);
ldraw(x2+h,y1+v,x2,y1);
ldraw(x1+h,y2+v,x1,y2);
}
#endif
#ifneed box
/* parameters are topleft X,Y and bottomright X,Y
X ranges from 0 to 159, Y ranges from 0 to 99, top left is 0,0
*/
box(x1,y1,x2,y2) int x1,y1,x2,y2; {
ldraw(x1,y1,x1,y2);
ldraw(x1,y2,x2,y2); /* appears to draw the box anticlockwise */
ldraw(x2,y1,x2,y2);
ldraw(x1,y1,x2,y1);
}
#endif
#ifneed gotoxy
gotoxy (xpos,ypos) int xpos,ypos; { /* 0,0 is top left corner */
putscreen("\033=");
putc(ypos+' ',0);
putc(xpos+' ',0);
}
#endif
#ifneed beep
beep() { putc(7,0); } /* send bell character */
#endif
#ifneed home
home() { putc(30,0); } /* home cursor to top left */
#endif
#ifneed clr_screen
clr_screen() { putc(26,0); } /* home and erase screen */
#endif
#ifneed clr_lend
clr_lend() { putc(24,0); } /* clear to end of line */
#endif
#ifneed clr_send
clr_send() { putc(23,0); } /* clear to end of screen */
#endif
#ifneed rev_vid
rev_vid() { putscreen ("\033B0"); } /* reverse background */
#endif
#ifneed nor_vid
nor_vid() { putscreen ("\033C0"); }
#endif
#ifneed dim_vid
dim_vid() { putscreen ("\033B1"); } /* low intensity */
#endif
#ifneed bri_vid
bri_vid() { putscreen ("\033C1"); }
#endif
#ifneed on_blink
on_blink() { putscreen ("\033B2"); } /* blinking characters */
#endif
#ifneed off_blink
off_blink() { putscreen ("\033C2"); }
#endif
#ifneed ul_start
ul_start() { putscreen ("\033B3"); } /* underline */
#endif
#ifneed ul_stop
ul_stop() { putscreen ("\033C3"); }
#endif
#ifneed save_cursor
save_cursor() { putscreen ("\033B6"); } /* remember cursor position */
#endif
#ifneed retn_cursor
retn_cursor() { putscreen ("\033C6"); } /* return to remembered pos */
#endif
#ifneed on_status
on_status() { putscreen ("\033B7"); } /* status line preservation on */
#endif
#ifneed off_status
off_status() { putscreen ("\033C7"); }
#endif
#ifneed ins_line
ins_line() { /* insert text line */
putscreen("\033R");
}
#endif
#ifneed del_line
del_line() { /* delete text line */
putscreen("\033E");
}
#endif
#ifneed on_cursor
on_cursor() { putscreen ("\033B4"); } /* (in)visible cursor */
#endif
#ifneed off_cursor
off_cursor() { putscreen ("\033C4"); }
#endif
/* Video Mode ON/OFF: video WORD, 8 bit video if 15 and 7 are both high */
/* VM-ON 10000001 11111111 VM-OFF */
/* ^video ^x^video */
/* otherwise, video BYTE, high bit 7 interprets bits 0-6 as screen dots */
/* 11111111 */
/* ^video */
/* e.g., */
/* Non-VideoMode VideoMode */
/* xx 1 11:0 where % is 1 01:0 1 11:0 xx */
/* xx 3 11 2 the video 3 00 2 3 11 2 xx */
/* xx 5 11 4 flag bit, 5 00 4 5 11 4 xx */
/* x 7:%1 6 x is pixel 7:%0 6 7:%1 6 xx */
/* ^ ^ ^ */
/* to set the pixels, first do a gotoxy to character screen position */
/* this mode is faster than Pixel ON/OFF if values are drawn from table */
#ifneed vm_on
vm_on() { putscreen ("\033B5"); } /* video mode on */
#endif
#ifneed vm_off
vm_off() { putscreen ("\033C5"); }
#endif
#ifneed pixel
pixel(x,y) int x,y; { /* x <= 159, y <= 99 */
putscreen("\033*");
putc(y+' ',0); putc(x+' ',0);
}
#endif
#ifneed no_pixel
no_pixel(x,y) int x,y; { /* x <= 159, y <= 99 */
putscreen("\033 ");
putc(y+' ',0); putc(x+' ',0);
}
#endif
#ifneed ldraw
/* use x1 <= x2, y1 <= y2, order is significant (Kaypro bug?) */
ldraw(x1,y1,x2,y2) int x1,x2,y1,y2; { /* x <= 159, y <= 99 */
putscreen("\033L");
putc(y1+' ',0); putc(x1+' ',0);
putc(y2+' ',0); putc(x2+' ',0);
}
#endif
#ifneed lwipe
lwipe(x1,y1,x2,y2) int x1,x2,y1,y2; { /* x <= 159, y <= 99 */
putscreen("\033D");
putc(y1+' ',0); putc(x1+' ',0);
putc(y2+' ',0); putc(x2+' ',0);
}
#endif
#ifneed putscreen
putscreen(p) char *p; {
while (*p) putc(*p++,0);
} /* end: putscreen */
#endif
#ifneed puts
puts(p) char *p; {
while (*p) chrout(*p++);
} /* end: puts */
#endif
#ifneed chrout
chrout(c) char c; { /* SPECIAL FOR SCRIPT OPTION WITH LST: */
putc(c,0);
if ( MYscrtp ) putc(c,MYretnirp);
} /* end: chrout */
#endif
/* end: MYLIB.C */


View File

@ -0,0 +1,56 @@
GAMNIV20.LBR
------------
Gammon IV, Version 2.0, April 1, 1986. Full-screen backgammon for CP/M.
This is the April Fool's Day (1986) edition of Gammon IV, the first major
update in many months.
BACKGMMN.COM is the compiled and ready-to-run object file. It requires
either an ADM-3A compatible terminal ("old" Kaypro) or a screen with video
characteristics exactly like the Kaypro 2X, 4'84 or 10. However, this
version has the same CRT Module as formerly, including a clearly-marked user
patch area for non-Kaypro terminals.
Improvements for Version 2.0 include:
a) Several bugs and poltergeists, especially in the Arrange command, have
been completely exorcised. No bugs have been found in the Play command
for months; but, as before, Gammon IV will not invariably recognize a
forced move, either in your play or in its own. Gammon IV knows and
obeys all other official rules of backgammon.
b) There are no "hidden" commands anymore. All commands are now shown in
the command lines, including X(pert and G(raphic. The G(raphic command
turns on the Kaypro video-able display.
c) Input error handling now documents the BAR, HOME and HELP commands, so
first-time players do not need to read anything else in order to play
the game successfully. The X(pert mode dispenses with these messages,
so X(pert actually does mean expert, now!
d) The "break" command is Control-C again, instead of ESCAPE. It was
all too easy to hit ESC instead of 1 on the Kaypro keyboard, leading to
an inadvertently paused game.
e) The sanction against cheating (your opponent became Torve) has been
removed.
f) If the cube is doubled during the opening rolloff to see who goes
first, and the cube value reaches 8, additional pairs on the dice
have no further effect. The cube's opening value will not go above 8.
The computer's three styles of play have not been changed. Judging from the
feedback I've received, Gammon IV plays acceptably well at the current
levels. All information needed to re-compile the program is included in the
BACKGMMN.C file, including the details of C/80 3.1 configuration. The
compile and link steps are governed by BACKGMMN.SUB.
This program is in the public domain, so distribute it freely.
Enjoy!
David C. Oshel
1219 Harding Ave.
Ames, Iowa 50010


51
Backgammon/README.md Normal file
View File

@ -0,0 +1,51 @@
# Gammon IV (VT100 ANSI edition)
By:
David C. Oshel
1219 Harding Ave.
Ames, Iowa 50010
This is a patched version of "Gammon IV, Version 2.0, April 1, 1986", a full-screen backgammon for CP/M.
I patched the game to use VT100 compatible escape sequences (including ANSI color).
Therefore, I removed most of the "user patch area" and hardcoded the VT100 sequences in the C code,
replaced the asm code of gotoxy() with C code and removed the Kaypro graphics routines
(and the "G(raphics" command) as it is not needed for my VT100 version.
``BACKGMMN.COM`` is the compiled and ready-to-run game.
Have fun playing!
Anna Christina Naß <acn@acn.wtf>
## Compiling the game
See [Compiler/Compiling.md](Compiler/Compiling.md) for information on compiling the game on CP/M.
## From the original Version 2.0 READ.ME:
Improvements for Version 2.0 include:
a) Several bugs and poltergeists, especially in the Arrange command, have been completely exorcised. No bugs have been found in the Play command for months; but, as before, Gammon IV will not invariably recognize a forced move, either in your play or in its own. Gammon IV knows and obeys all other official rules of backgammon.
b) There are no "hidden" commands anymore. All commands are now shown in the command lines, including X(pert.
c) Input error handling now documents the BAR, HOME and HELP commands, so first-time players do not need to read anything else in order to play the game successfully. The X(pert mode dispenses with these messages, so X(pert actually does mean expert, now!
d) The "break" command is Control-C again, instead of ESCAPE. It was all too easy to hit ESC instead of 1 on the Kaypro keyboard, leading to an inadvertently paused game.
e) The sanction against cheating (your opponent became Torve) has been removed.
f) If the cube is doubled during the opening rolloff to see who goes first, and the cube value reaches 8, additional pairs on the dice have no further effect. The cube's opening value will not go above 8.
The computer's three styles of play have not been changed. Judging from the feedback I've received, Gammon IV plays acceptably well at the current levels. All information needed to re-compile the program is included in the BACKGMMN.C file, including the details of C/80 3.1 configuration. The compile and link steps are governed by BACKGMMN.SUB.
This program is in the public domain, so distribute it freely.
Enjoy!
David C. Oshel
1219 Harding Ave.
Ames, Iowa 50010

1968
Backgammon/backgmmn.c Normal file

File diff suppressed because it is too large Load Diff

BIN
Backgammon/backgmmn.com Normal file

Binary file not shown.

866
Backgammon/gameplan.c Normal file
View File

@ -0,0 +1,866 @@
/* Gammon IV, by David C. Oshel, Ames, Iowa */
/*--------------------------------------------------------------------*/
/* GAMEPLAN.C -- separately compiled module, contains the tactics and */
/* strategy for making the computer's move in Gammon IV */
/* BACKGMMN.REL calls MyMove(), MyMove() calls topstone */
/* and movestone and a few others. Uses the globals in */
/* GAMEPLAN.HDR quite heavily. Bgversion declared here */
/*--------------------------------------------------------------------*/
#include "gameplan.hdr" /* contains external, global declarations */
/*-------------------------------------------------------------------------*/
/* */
/* Bgversion is an external reference in the main module. Use this string */
/* to take credit for a decent gameplaying algorithm if you find one! */
/* */
char *bgversion = ".20 -April 1, 1986- by David C. Oshel";
/*....v....1....v....2....v....3....v...*/
/* just 38 characters for version info! */
/* */
/*-------------------------------------------------------------------------*/
/*=============================================*/
/* M Y M O V E */
/*=============================================*/
naked() { /* am I leaving too many blots? */
static int i, clink;
i = 24; clink = 0;
while (i) {
if (point[i].stones == 1 && point[i].owner == ME) clink++;
i--;
}
return (clink > 2);
} /* end: naked */
yourfolly() { /* look for lotsa blots in your inner table */
static int i, clink;
i = 18; clink = 0;
while (i < 25) {
if (point[i].owner == YU && point[i].stones == 1)
clink++;
i++;
}
return (clink >= 3);
} /* end: yourfolly */
goodboard() { /* look for four made points near my inner table */
static int i, clank, clink;
i = 9; clank = 0;
while (i > 3) {
if (point[i].owner == ME && point[i].stones > 1) clank++;
i--;
}
if (clank > 4) return (TRUE); /* bar is nearly blocked */
i = 6; clank = clink = 0;
while (i) {
if (point[i].owner != ME)
;
else if (point[i].stones == 1) clink++; else clank++;
i--;
}
return (clank > 3 && clink < 2);
} /* end: goodboard */
bearoff() {
return (topstone(ME) < 7);
} /* end: bearoff */
scanahead( from ) int from; {
static int count;
count = 0;
while (--from > 0) {
++count;
if ( point[ from ].owner == YU ) return (count);
}
return (7);
} /* end: scanahead */
endgame() { /* Is no strategy required from here on in? */
return ( (25 - topstone(YU)) > topstone(ME) );
} /* end: endgame */
/*------------------------------------------------------------*/
/* MATCHUP */
/* */
/* 2-stone functions that force the choice of the next move. */
/* These are the HEART and SOUL of this backgammon algorithm! */
/*------------------------------------------------------------*/
setpend( from, to ) int from, to; {
pending.fr = from;
pending.to = to;
pending.flag = TRUE;
} /* end: setpend */
clrpend() {
pending.flag = FALSE;
} /* end: clrpend */
natural(f1,t1,f2,t2) int f1,t1,f2,t2; {
clrpend();
if (point[t2].stones == 1 && t1 == f2) setpend(f2,t2);
return (pending.flag);
} /* end: natural */
matchup( test4 ) int (* test4)(); {
static int i, j, ti, tj;
if ( pending.flag ) return (FALSE); /* this is probably redundant */
for (i = 1; i < 26; i++) {
ti = list[0][i];
if ( ti == ERROR ) goto zoo;
for (j = 1; j < 26; j++) {
tj = list[1][j];
if ( tj == ERROR ) goto voo;
if ( (* test4)( i, ti, j, tj ) ) {
lurch( i, ti, 0);
return (TRUE);
}
voo: ;
}
zoo: ;
}
return (FALSE);
} /* end: matchup */
matchhi( test4 ) int (* test4)(); {
static int i, j, ti, tj;
if ( pending.flag ) return (FALSE); /* this is probably redundant */
for (i = 1; i < 26; i++) {
ti = list[1][i];
if ( ti == ERROR ) goto zoo;
for (j = 1; j < 26; j++) {
tj = list[0][j];
if ( tj == ERROR ) goto voo;
if ( (* test4)( i, ti, j, tj ) ) {
lurch( i, ti, 1);
return (TRUE);
}
voo: ;
}
zoo: ;
}
return (FALSE);
} /* end: matchhi */
/*--------------------------------------------------------*/
/* CLOCKWISE and COUNTERCLOCK */
/* */
/* the rest of these are single-stone decisions based on */
/* rules of thumb, board-scanning functions */
/*--------------------------------------------------------*/
plainstupid( from ) int from; { /* don't break a safe point */
return (from < 13 && (point[from].stones == 2 && scanahead(from) < 7));
} /* end: plainstupid */
unwise( innertablept ) int innertablept; {
/* if it's a hit, just for god's sake don't put him on the bar!! */
if ( innertablept < 7 ) {
if (point[ innertablept ].owner == YU ||
point[ YRBAR ].stones > 0)
return (TRUE);
}
return(FALSE);
} /* end: unwise */
covermine( from, to ) int from, to; {
if ( from < 8 ) return(FALSE);
return ( (point[ to ].stones == 1) && (point[ to ].owner == ME) );
} /* end: covermine */
idareyou( from, to ) int from, to; {
if (unwise( to )) return (FALSE);
if ( (point[ from ].stones != 2)
&& (point[ to ].stones < 2)
&& (scanahead( to ) > 6) ) return ( TRUE );
else return (FALSE);
} /* end: idareyou */
hitandrun( from, to ) int from, to; {
return ( point[ to ].owner == YU );
} /* end: hitandrun */
dbuild( from, to ) int from, to; {
static int diceleft;
diceleft = (myturns? 2 + movesleft: movesleft);
if (diceleft > 1) {
/* can't possibly be only one stone on from point */
/* or kamikaze would have covered it on last move */
return ( point[to].stones == 0 );
}
return (FALSE);
} /* end: dbuild */
kamikaze( from, to ) int from, to; {
/* cover my distant blot, or razzle-dazzle 'em with the long doubles hit */
static int j, k, diceleft;
k = from;
j = from - to;
diceleft = myturns * movesleft; /* NB: 2*2 == 2+2, "fourtunately" */
while ( diceleft-- ) { /* predicting where doubles land is easy! */
k -= j;
if (k < 1) return (FALSE); /* out of bounds */
if ( point[ k ].stones == 0 ) continue; /* simplify */
if ( point[ k ].stones == 1 ) /* found my blot or yours? */
return (TRUE);
else if ( point[k].owner == YU ) /* found your blockade? */
return (FALSE);
else continue; /* found my safe point, so ignore it */
}
return (FALSE);
} /* end: kamikaze */
hittite( from, to ) int from, to; {
return (hitandrun(from,to) && to > 9);
} /* end: hittite */
safehit( from, to ) int from, to; {
return (hittite(from,to) && idareyou(from,to));
} /* end: safehit */
foolsdemise( from, to ) int from, to; {
/* annihilate orphaned blots in enemy's inner, my outer table */
return (to > 17 && point[to].owner == YU);
} /* end: foolsdemise */
landonme( from, to ) int from, to; {
if ( plainstupid(from) ) return (FALSE);
if ( loneranger(from,to) ) {
if (from < 19 && to > 6) return(TRUE);
}
else return ( point[ to ].owner == ME && point[to].stones < 4);
} /* end: landonme */
/* these evaluations have meaning only in the endgame */
nobackgammon( from, to ) int from, to; { /* endgame */
return (from > 19);
} /* end: nobackgammon */
crosstable( from, to ) int from, to; {
/* always move a table ahead if possible, in the endgame */
if (from < 7) return (FALSE);
if (from > 18 && to <= 18) return (TRUE);
if (from > 12 && to <= 12) return (TRUE);
if (from > 6 && to <= 6) return (TRUE);
return (FALSE);
} /* end: crosstable */
fiftytworule( from, to ) int from, to; { /* endgame */
static int p;
if (from < 7) return (FALSE); /* not in inner table! */
p = from % 6;
if (p == 0) return (TRUE); /* improve the six */
if (p != 5) return ( (to % 6) < 3 ); /* best improve under five */
} /* end: fiftytworule */
/* these evaluations are universally applicable, last resort moves */
gohome( from, to ) int from, to; { /* always go home if you can */
return (to == MYHOME);
} /* end: gohome */
scatter( from, to ) int from, to; { /* scatter, esp. in the endgame */
if (plainstupid(from) || unwise(to)) return (FALSE);
return ( point[ from ].stones > 1 && point[ to ].stones == 0 );
} /* end: scatter */
runnerup( from, to ) int from, to; {
if (from < 10 || from > 18) return (FALSE);
return (TRUE);
} /* end: runnerup */
loneranger( from, to ) int from, to; {
return( point[ from ].stones == 1 );
} /* end: loneranger */
run( dummy1, dummy2 ) int dummy1, dummy2; { /* MUST move something! */
return (TRUE);
} /* end: run */
/* clockwise and counterclock make a 1-stone choice on rules of thumb */
counterclock( test ) int (* test)(); {
static int i,j;
for (i = 0; i < 2; i++) {
for (j = 1; j < 25; j++) {
if ( list[i][j] == ERROR ) continue;
if ( (* test)( j, list[i][j] ) ) {
lurch( j, list[i][j], i);
return ( TRUE );
} } }
return (FALSE);
} /* end: counterclock */
clockwise( test ) int (* test)(); {
static int i,j;
for (i = 0; i < 2; i++) {
for (j = 25; j > 0; j--) {
if ( list[i][j] == ERROR ) continue;
if ( (* test)( j, list[i][j] ) ) {
lurch( j, list[i][j], i);
return ( TRUE );
} } }
return (FALSE);
} /* end: clockwise */
/*-------------------------------------------*/
/* Make Prime */
/*-------------------------------------------*/
static int prmchk;
buildprime( f1,t1,f2,t2 ) int f1,t1,f2,t2; {
clrpend();
/* check for the doubles bug */
if ((dice[0] == dice[1]) && (point[f1].stones < 2)) return(FALSE);
/* look for the combination */
if ( t1 == prmchk && t2 == prmchk) setpend(f2,t2);
/* stick like glue to a made point, but doubles may move forward */
if (dice[0] != dice[1]) {
if ((f2 < 8) && (point[f2].stones == 2)) clrpend();
if ((f1 < 8) && (point[f1].stones == 2)) clrpend();
}
return(pending.flag);
} /* end: buildprime */
makeprime() {
static int i, tab[] = { ERROR,1,2,3,20,22,24,9,4,6,8,5,7 };
i = 12;
while (i) {
prmchk = tab[i];
i--;
if ( point[ prmchk ].stones > 1 ) continue;
else if ( matchup( buildprime ) ) return(TRUE);
}
return(FALSE);
} /* end: makeprime */
coverprime( from, to ) int from, to; {
return (((to == prmchk) &&
(point[prmchk].owner == ME)) &&
(point[from].stones != 2));
} /* coverprime */
cleanup() {
static int i, tab[] = { ERROR,1,2,3,20,22,24,9,4,6,8,5,7 };
i = 12;
while (i) {
prmchk = tab[i];
i--;
if ( point[ prmchk ].stones != 1 ) continue;
else if ( counterclock( coverprime ) ) return(TRUE);
}
return(FALSE);
} /* end: cleanup */
/*-------------------------------------*/
/* Walking Prime */
/*-------------------------------------*/
swivelhips( from, to ) int from, to; {
return ( from > prmchk );
} /* end: swivelhips */
slink( from, to ) int from, to; {
return( (from > prmchk) && (point[to].stones == 1) );
} /* end: slink */
weasel() {
if ( clockwise( slink ) )
return(TRUE);
if ( counterclock( swivelhips ) )
return(TRUE);
if ( clockwise( run ) )
return(TRUE);
} /* end: weasel */
ihaveprime( from ) int from; {
static int i, to, ez;
ez = 0;
for (i = 0; i < 6; i++) {
to = from - i;
if ((point[to].owner == ME) && (point[to].stones > 1)) ez++;
}
return (ez > 4);
} /* end: ihaveprime */
walkingprime() {
/* looks for the walking prime anywhere in the front tables */
/* then tries to bring up a runner from behind the prime, */
/* ensuring that a back stone WILL move before a front one */
static int i;
i = 12;
while (i > 5) {
if ( ihaveprime(i) ) {
prmchk = i;
if ( weasel() ) return (TRUE);
}
i--;
}
return(FALSE);
} /* end: walkingprime */
/*---------- Book Moves ----------*/
/* only valid if my move is first */
/*--------------------------------*/
zip(a,b,c,d) int a,b,c,d; {
lurch(a,b,0);
lurch(c,d,0);
movesleft = 0; return( TRUE );
} /* end: zip */
zoom( a,b,c,d,e,f,g,h ) int a,b,c,d,e,f,g,h; {
myturns = 0; zip(a,b,c,d); zip(e,f,g,h); return( TRUE );
} /* end: zoom */
book() {
int a,b;
if (!firstmove) return (FALSE);
firstmove = FALSE;
a = min(dice[0],dice[1]);
b = max(dice[0],dice[1]);
switch (level) {
case 0: { return ( book0(a,b) ); break; }
case 1: { return ( book1(a,b) ); break; }
case 2: { return ( book2(a,b) ); break; }
}
}
book0( a,b ) int a, b; {
switch (a) {
case 1: { switch (b) {
case 1: return ( zoom(8,7,8,7,6,5,6,5) );
case 2: return ( zip(24,23,13,11) );
case 3: return ( zip(8,5,6,5) );
case 4: return ( zip(24,23,13,9) );
case 5: return ( zip(24,23,13,8) );
case 6: return ( zip(13,7,8,7) );
}
break; }
case 2: { switch (b) {
case 2: return ( zoom(6,4,6,4,13,11,13,11) );
case 3: return ( zip(13,11,13,10) );
case 4: return ( zip(8,4,6,4) );
case 5: return ( zip(13,8,13,11) );
case 6: return ( zip(24,18,13,11) );
}
break; }
case 3: { switch (b) {
case 3: return ( zoom(13,10,13,10,10,7,10,7) );
case 4: return ( zip(13,10,13,9) );
case 5: return ( zip(13,10,13,8) );
case 6: return ( zip(24,18,13,10) );
}
break; }
case 4: { switch (b) {
case 4: return ( zoom(13,9,13,9,24,20,24,20) );
case 5: return ( zip(13,8,13,9) );
case 6: return ( zip(24,18,18,14) );
}
break; }
case 5: { switch (b) {
case 5: return ( zoom(13,8,13,8,8,3,8,3) );
case 6: return ( zip(24,18,18,13) );
}
break; }
case 6: { return ( zoom(13,7,13,7,24,18,24,18) );
break; }
}
} /* end: book0 */
book1( a,b ) int a, b; { /* mostly follows Becker */
switch (a) {
case 1: { switch (b) {
case 1: return ( zoom(8,7,8,7,6,5,6,5) );
case 2: return ( zip(13,11,6,5) );
case 3: return ( zip(8,5,6,5) );
case 4: return ( zip(13,9,6,5) );
case 5: return ( zip(13,8,6,5) );
case 6: return ( zip(13,7,8,7) );
}
break; }
case 2: { switch (b) {
case 2: return ( zoom(6,4,6,4,13,11,13,11) );
case 3: return ( zip(13,11,13,10) );
case 4: return ( zip(8,4,6,4) );
case 5: return ( zip(13,8,13,11) );
case 6: return ( zip(13,7,7,5) );
}
break; }
case 3: { switch (b) {
case 3: return ( zoom(13,10,13,10,8,5,8,5) );
case 4: return ( zip(13,10,13,9) );
case 5: return ( zip(13,8,8,5) );
case 6: return ( zip(13,7,13,10) );
}
break; }
case 4: { switch (b) {
case 4: return ( zoom(13,9,13,9,9,5,9,5) );
case 5: return ( zip(13,8,13,9) );
case 6: return ( zip(13,7,13,9) );
}
break; }
case 5: { switch (b) {
case 5: return ( zoom(13,8,13,8,8,3,8,3) );
case 6: return ( zip(13,7,13,8) );
}
break; }
case 6: { return ( zoom(13,7,13,7,24,18,24,18) );
break; }
}
} /* end: book1 */
book2( a,b ) int a, b; { /* mostly follows Becker */
switch (a) {
case 1: { switch (b) {
case 1: return ( zoom(8,7,8,7,6,5,6,5) );
case 2: return ( zip(13,11,24,23) );
case 3: return ( zip(8,5,6,5) );
case 4: return ( zip(13,9,24,23) );
case 5: return ( zip(13,8,24,23) );
case 6: return ( zip(13,7,8,7) );
}
break; }
case 2: { switch (b) {
case 2: return ( zoom(6,4,6,4,24,23,24,23) );
case 3: return ( zip(13,11,13,10) );
case 4: return ( zip(8,4,6,4) );
case 5: return ( zip(13,8,13,11) );
case 6: return ( zip(13,7,13,11) );
}
break; }
case 3: { switch (b) {
case 3: return ( zoom(13,10,13,10,10,7,10,7) );
case 4: return ( zip(13,10,13,9) );
case 5: return ( zip(13,8,8,5) );
case 6: return ( zip(13,7,13,10) );
}
break; }
case 4: { switch (b) {
case 4: return ( zoom(13,9,13,9,9,5,9,5) );
case 5: return ( zip(13,8,13,9) );
case 6: return ( zip(13,7,13,9) );
}
break; }
case 5: { switch (b) {
case 5: return ( zoom(13,8,13,8,8,3,8,3) );
case 6: return ( zip(13,7,13,8) );
}
break; }
case 6: { return ( zoom(13,7,13,7,24,18,24,18) );
break; }
}
} /* end: book2 */
/*====== MyMove ======*/
torve() {
if ( makeprime() ) { /* this will use doubles, if it can */
return;
}
else if ( walkingprime() ) { /* i have six prime points, so run!!! */
return;
}
else if ( dice[0] == dice[1] ) { /* this is too easy! */
if ( counterclock( kamikaze ) )
return;
if ( counterclock( dbuild ) ) /* claim new turf */
return;
if ( clockwise( run ) )
return;
}
else if ( cleanup() ) { /* cover my single blot on prime points */
return;
}
else if ( bearoff() ) { /* I'm ready, but you're in the back game! */
if ( counterclock( gohome ) )
return;
if ( clockwise( run ) )
return;
}
else {
if ( clockwise( hitandrun ) )
return;
if ( matchup( natural ) )
return;
if ( clockwise( landonme ) )
return;
if ( counterclock( runnerup ) )
return;
if ( clockwise( scatter ) )
return;
if ( clockwise( run ) )
return;
}
} /* end: torve */
villiers() {
if ( makeprime() ) { /* this will use doubles, if it can */
return;
}
else if ( walkingprime() ) { /* i have six prime points, so run!!! */
return;
}
else if ( dice[0] == dice[1] ) { /* this is too easy! */
if ( counterclock( kamikaze ) )
return;
if ( counterclock( dbuild ) ) /* claim new turf */
return;
if ( clockwise( run ) )
return;
}
else if ( cleanup() ) { /* cover my single blot on prime points */
return;
}
else if ( bearoff() ) { /* I'm ready, but you're in the back game! */
if ( counterclock( gohome ) )
return;
if ( clockwise( run ) )
return;
}
else {
if ( clockwise( foolsdemise ) )
return;
if ( clockwise( idareyou ) )
return;
if ( counterclock( covermine ) )
return;
if ( matchup( natural ) )
return;
if ( clockwise( landonme ) )
return;
if ( clockwise( runnerup ) )
return;
if ( clockwise( scatter ) )
return;
if ( clockwise( run ) )
return;
}
} /* end: villiers */
louisa() {
if ( makeprime() ) { /* this will use doubles, if it can */
return;
}
else if ( walkingprime() ) { /* i have six prime points, so run!!! */
return;
}
else if ( dice[0] == dice[1] ) { /* this is too easy! */
if ( counterclock( kamikaze ) )
return;
if ( counterclock( dbuild ) ) /* claim new turf */
return;
if ( clockwise( run ) )
return;
}
else if ( cleanup() ) { /* cover my single blot on prime points */
return;
}
else if ( bearoff() ) { /* I'm ready, but you're in the back game! */
if ( counterclock( gohome ) )
return;
if ( clockwise( run ) )
return;
}
else if ( (!naked() && goodboard()) || yourfolly() ) {
if ( clockwise( hitandrun ) )
return;
if ( matchup( natural ) )
return;
if ( clockwise( landonme ) )
return;
if ( counterclock( runnerup ) )
return;
if ( clockwise( scatter ) )
return;
if ( clockwise( run ) )
return;
}
else {
if ( clockwise( foolsdemise ) )
return;
if ( clockwise( idareyou ) )
return;
if ( counterclock( covermine ) )
return;
if ( matchup( natural ) )
return;
if ( clockwise( landonme ) )
return;
if ( clockwise( runnerup ) )
return;
if ( clockwise( scatter ) )
return;
if ( clockwise( run ) )
return;
}
} /* end: louisa */
mymove() {
int i, d;
if ( nomove() ) {
if (lookforit && (dice[0] != dice[1])) {
lookforit = FALSE;
puts("\008... ");
switch (level) {
case 0: { puts("Blocked!"); break; }
case 1: { puts("Well, no!"); break; }
case 2: { puts("Thurb!"); break; }
}
sleep(10);
restoreboard();
update();
/* put the high die in list zero */
d = dice[0]; dice[0] = dice[1]; dice[1] = d;
cantuse = ERROR; movesleft = 2; myturns = 1;
switch (level) {
case 0: { setchat("I move"); break; }
case 1: { setchat("Let's try"); break; }
case 2: { setchat("Move is"); break; }
}
debug(chatter);
prmchk = 12;
weasel();
/* the rules say, use both dice if you can, or */
/* the highest if one or the other but not both */
}
else {
lookforit = TRUE;
strcat(chatter," and now I'm blocked ");
myturns = movesleft = 0;
} }
else if ( book() ) {
return;
}
else if ( pending.flag ) {
lurch( pending.fr, pending.to, 1 );
clrpend();
}
else if ( endgame() ) { /* very solid tactics here!! */
if ( clockwise( gohome ) )
return;
if ( clockwise( nobackgammon ) ) /* no excuse! */
return;
if ( clockwise( crosstable ) )
return;
if ( clockwise( fiftytworule ) )
return;
if ( clockwise( scatter ) )
return;
if ( clockwise( run ) )
return;
}
else if ( point[ MYBAR ].stones > 0 ) { /* I'm on the bar! */
if ( clockwise( hitandrun ) ) /* wreak havoc, please */
return;
if ( clockwise( run ) ) /* note: uses low die first */
return;
}
else switch (level) {
case 0: { villiers(); break; }
case 1: { louisa(); break; }
case 2: { torve(); break; }
}
} /* end: mymove */
/*------------------------------*/
/* end of the GAMEPLAN.C module */
/*------------------------------*/


42
Backgammon/gameplan.hdr Normal file
View File

@ -0,0 +1,42 @@
/* GAMEPLAN.HDR */
/*================================================================*/
/* change nothing in this file */
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#define TRUE 1
#define FALSE 0
#define ME 1
#define YU 2
#define YRBAR 0
#define MYBAR 25
#define YRHOME 26
#define MYHOME 27
#define ERROR 999
#define MYLEVEL 2
extern int list[2][28]; /* two dice, two lists */
extern struct board {
int stones, /* number of stones on that point */
owner, /* and whose they are */
x,y, /* x and y coordinates of point base */
lastx,lasty, /* last location drawn on this point */
cx,cy; /* coordinates for column numbers */
}
point[28], bdsave[28]; /* 24 points, plus 2 bars, 2 homes */
extern struct { int cube, whosecube; } doubles;
extern struct { int fr,to,flag; } pending;
extern int level, dice[2], myscore, yrscore, player, movesleft, cantuse,
myturns, swapped, tswap, deciding, expert, tone, show, moremsgline,
firstmove, helpdisabled, yrdice, lookforit, startcubevalue;
extern char *chatter[80];
/*----------------------------------------------*/
/* end of header -- change NOTHING in this file */
/*----------------------------------------------*/


541
Backgammon/mylib2.c Normal file
View File

@ -0,0 +1,541 @@
/*
MYLIB2.C
These routines are CONDITIONALLY compiled; i.e., only as needed.
----------------------------------------------------------------------
Incorporates special mods used by my Backgammon game, BACKGMMN.C etc.
----------------------------------------------------------------------
A set of common I/O functions that seem to turn up a lot in my programs,
including terminal functions for Kaypro 10, 4'84, 2X etc.
Uses Software Toolworks' C/80 3.1 compiler. Place #include "mylib2.c" at the
end of your source file for correct CONDITIONAL COMPILATION.
David C. Oshel
1219 Harding Ave.
Ames, Iowa 50010
Last modified: March 25, 1986
-----------------------------------------------------------------------------
** WARNING ** These routines use direct console IO, bdos function 6!
YOU MUST CALL INIT_LIB() BEFORE USING THESE ROUTINES!
======= UTILITIES =======
* init_lib() - CALL THIS FIRST, OR THE RESULT WILL BE VERY STRANGE!
*
* puts(p) - unformatted print, e.g., puts("Hello, sailor!\n");
* gets(p,max) - printable input only, no prompt character
*
* ask(p) - demand Yes or No response to question p
* random() - effective random 16-bit integer IFF gets() is used
* sleep(n) - sleep n/10ths of a second, roughly (from C80.LIB)
* rollup() - roll up 23 lines of screen
* ONscript() - printer echo ON for output via puts, chrout
* OFFscript() - printer echo OFF for output via puts, chrout
* ONinterrupt() - Ctl-C, Ctl-B cause program exit
* OFFinterrupt() - Ctl-C, Ctl-B cause comedy
* hide_input(p,max) - like gets, but used when entering passwords
* chrout(c) - if scripting, echo output also to LST:
* putscreen(p) - like puts, but always and only to screen
======= KAYPRO 10 TERMINAL/VIDEO FUNCTIONS =======
* gotoxy(x,y) - 0,0 is top left, horz <= 79 precedes vert <= 24,
* where 0,24 is on the 25th, status, line.
* beep() - terminal bell
* home() - home cursor, do not clear screen
* clr_screen() - home and clear
*
* shadow_box(h,v,x1,y1,x2,y2) - like box, but with shadow, calls box
* box(tlx,tly,brx,bry) - draw a line box, coords: topleft XY, bottomright XY
* note that box calls ldraw(x1,y1,x2,y2), below
*
* clr_lend() - clear from cursor to end of line
* clr_send() - clear from cursor to end of screen
* rev_vid(),
* nor_vid() - reverse field
* dim_vid(),
* bri_vid() - low/high intensity
* on_blink(),
* off_blink() - blinking chars
* ul_start(),
* ul_stop() - start/stop underline
* save_cursor(),
* retn_cursor() - remember/restore current cursor location
* ins_line(),
* del_line() - insert/delete screen text line
* on_cursor(),
* off_cursor() - hide/show cursor
* vm_on(),
* vm_off() - "Video Mode" commands
* pixel(x,y) - draw pixel at x,y (video coords, x <= 159, y <= 99)
* no_pixel(x,y) - erase pixel at x,y
* ldraw(x1,y1,x2,y2) - draw/ erase graphics line, see discussion for box
* lwipe(x1,y1,x2,y2) - range for video coordinates as for pixel
*/
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* hide this here so's not to worry about it elsewhere */
/* "printf.c" collides with one of these, can't remember which */
/* puts() takes longer to write, but executes faster */
extern char Cmode, IOpread[4], IOpwrit[4], IOpeof[4];
/* make these known only to what follows */
static int MYbstout, MYscrtp, MYretnirp; /* odd names mark semi-private */
static unsigned RNDloc; /* effective random location, bumped by gets() */
/* and scrambled when the LCG random() is called */
/* makes a decent algorithm for interactive games */
#ifneed init_lib
init_lib() {
MYretnirp = fopen("LST:","w");
OFFscript();
ONinterrupt();
Cmode = 0;
IOpread[0] = 6; IOpwrit[0] = 6;
} /* end: init_lib */
#endif
#ifneed random
random() { /* depends on effective random location spun by gets() */
RNDloc = 2053 * RNDloc + 13849;
return (RNDloc);
}
#endif
#ifneed ONscript
ONscript() {
MYscrtp = TRUE;
}
#endif
#ifneed OFFscript
OFFscript() {
MYscrtp = FALSE;
}
#endif
#ifneed ONinterrupt
ONinterrupt() {
MYbstout = TRUE;
}
#endif
#ifneed OFFinterrupt
OFFinterrupt() {
MYbstout = FALSE;
}
#endif
#ifneed ask
ask(p) char *p; {
char ch, resp[2];
loo: puts(p);
gets(resp,1);
ch = toupper( *resp );
if ( !( ch == 'Y' || ch == 'N' )) {
puts("Please answer the question, Yes or No.\n");
goto loo;
}
return (ch == 'Y');
} /* end: ask */
#endif
#ifneed rollup
rollup() {
int i;
for (i=0; i<23; i++) puts("\n");
} /* end: rollup */
#endif
#ifneed sleep
sleep( n ) int n; { /* sleep for n/10 seconds, 0 <= n < 256 */
n; /* get n into HL */
#asm
MOV B,L ;delay B/10ths of a second
__DL0: MVI A,100 ;100 milliseconds, 1/10 second
__DL1: MVI C,249 ;1 millisecond per unit of A at 4 MHz
__DL2: DCR C ;Leventhal, Z80 Assembly Language Programming
JNZ __DL2
DCR A
JNZ __DL1
DCR B
JNZ __DL0 ;on exit, HL has FALSE if n was 0, else TRUE
#endasm
} /* end: sleep */
#endif
/*========================================*/
/* GETS(p, maxinput) */
/* Local getline function with special *---* WARNING: */
/* input handling, 1 <= len <= maxinput *---* Execute INIT_LIB() first !! */
/* Updates effective random, RNDloc, */
/* Forces input from CONSOLE only! */
/*========================================*/
#ifneed gets
gets(p,maxinput) char *p; int maxinput; {
/* This function depends on BDOS Function #6. Init_lib() sets Cmode=0 and
IOpread[0]=6 and IOpwrit[0]=6 (courtesy of and peculiar to C/80 3.1)
YOU must ensure that the target string is long enough to collect the
entire maximum input allowed and specified, INCLUDING FINAL NULL! */
static int len;
static char ch;
len = -1;
if (maxinput < 1 || maxinput > 127) maxinput = 79;
/*--------------------------------*/
/* SPECIAL ROUTINE FOR BACKGAMMON */
/*--------------------------------*/
loo: while ( !(ch = getc(0)) ) acg(); /* keep the game lively */
if (len < 0) len = 0; /* don't destroy prompt by backing up */
if (ch == '\n') { /* end of line? don't store newline */
*p = '\0'; /* mark it with a B for baby and me */
/* chrout('\n'); */ /* but DON'T echo newline */
return ( len ); /* <--- HERE IS THE FUNCTION EXIT! */
}
else if (ch == '\b' || ch == 0x7F) { /* backspace? rubout? */
if (len--) { /* where's the prompt? */
puts("\008 \008"); /* we're ok, echo erase */
p--; /* delete from string */
}
}
/*--------------------------------*/
/* SPECIAL ROUTINE FOR BACKGAMMON */
/*--------------------------------*/
else if (ch == '\003') { /* user bailout key is Ctrl-C, not ESC */
if (MYbstout) exit();
else {
haltgame(); /* sets whofirst flag and does jumpjack() */
}
}
else if (ch == '\025' || ch == '\030') { /* Ctl-U, Ctl-X */
while (len--) {
p--;
puts("\008 \008");
}
}
else if (len == maxinput) { /* test specials before testing len */
chrout('\007');
}
else if (ch > 31 && ch < 127) { /* printable char? */
chrout(ch); /* yes, echo it */
*p++ = ch; /* collect it */
len++; /* keep track of it */
}
else { /* control chars? */
chrout('\007');
}
goto loo;
} /* end: gets */
#endif
#ifneed hide_input
hide_input(s,len) char *s; int len; {
/* receive at most len chars in s buffer,
terminate string with zero,
but echo each char with 1, 2, or 3 meaningless dots */
char ch; int num;
if ((len < 1) || (len > 127)) len = 127;
num = 0;
for (;;) { /* forever */
while ((ch = getc(0)) == 0) /* bdos 6 does not wait, so we do */
;
if ((ch == '\r') || (ch == '\n') || (num++ > len)) {
/* not sure what the CR key actually is to bdos 6 & C/80 */
*s++ = '\0';
return; /* this way out */
}
if ((num % 2) == 0) putc('.',0); /* deception, illusion */
if ((num % 5) == 0) putc('.',0);
putc('.',0);
*s++ = ch;
}
} /* end: hide_input */
#endif
/*------------------------ kpro stuff -------------------------*/
#ifneed shadow_box
/* like box, but with horizontal & vertical displacement for shadow */
shadow_box(h,v,x1,y1,x2,y2) int h,v,x1,y1,x2,y2;
{
box(x1+h,y1+v,x2+h,y2+v); /* draw the shadow */
box(x1,y1,x2,y2); /* draw the box */
ldraw(x1+h,y1+v,x1,y1); /* draw the corners */
ldraw(x2+h,y2+v,x2,y2);
ldraw(x2+h,y1+v,x2,y1);
ldraw(x1+h,y2+v,x1,y2);
}
#endif
#ifneed box
/* parameters are topleft X,Y and bottomright X,Y
X ranges from 0 to 159, Y ranges from 0 to 99, top left is 0,0
*/
box(x1,y1,x2,y2) int x1,y1,x2,y2; {
ldraw(x1,y1,x1,y2);
ldraw(x1,y2,x2,y2); /* appears to draw the box anticlockwise */
ldraw(x2,y1,x2,y2);
ldraw(x1,y1,x2,y1);
}
#endif
#ifneed gotoxy
gotoxy (xpos,ypos) int xpos,ypos; { /* 0,0 is top left corner */
putscreen("\033=");
putc(ypos+' ',0);
putc(xpos+' ',0);
}
#endif
#ifneed beep
beep() { putc(7,0); } /* send bell character */
#endif
#ifneed home
home() { putc(30,0); } /* home cursor to top left */
#endif
#ifneed clr_screen
clr_screen() { putc(26,0); } /* home and erase screen */
#endif
#ifneed clr_lend
clr_lend() { putc(24,0); } /* clear to end of line */
#endif
#ifneed clr_send
clr_send() { putc(23,0); } /* clear to end of screen */
#endif
#ifneed rev_vid
rev_vid() { putscreen ("\033B0"); } /* reverse background */
#endif
#ifneed nor_vid
nor_vid() { putscreen ("\033C0"); }
#endif
#ifneed dim_vid
dim_vid() { putscreen ("\033B1"); } /* low intensity */
#endif
#ifneed bri_vid
bri_vid() { putscreen ("\033C1"); }
#endif
#ifneed on_blink
on_blink() { putscreen ("\033B2"); } /* blinking characters */
#endif
#ifneed off_blink
off_blink() { putscreen ("\033C2"); }
#endif
#ifneed ul_start
ul_start() { putscreen ("\033B3"); } /* underline */
#endif
#ifneed ul_stop
ul_stop() { putscreen ("\033C3"); }
#endif
#ifneed save_cursor
save_cursor() { putscreen ("\033B6"); } /* remember cursor position */
#endif
#ifneed retn_cursor
retn_cursor() { putscreen ("\033C6"); } /* return to remembered pos */
#endif
#ifneed on_status
on_status() { putscreen ("\033B7"); } /* status line preservation on */
#endif
#ifneed off_status
off_status() { putscreen ("\033C7"); }
#endif
#ifneed ins_line
ins_line() { /* insert text line */
putscreen("\033R");
}
#endif
#ifneed del_line
del_line() { /* delete text line */
putscreen("\033E");
}
#endif
#ifneed on_cursor
on_cursor() { putscreen ("\033B4"); } /* (in)visible cursor */
#endif
#ifneed off_cursor
off_cursor() { putscreen ("\033C4"); }
#endif
/* Video Mode ON/OFF: video WORD, 8 bit video if 15 and 7 are both high */
/* VM-ON 10000001 11111111 VM-OFF */
/* ^video ^x^video */
/* otherwise, video BYTE, high bit 7 interprets bits 0-6 as screen dots */
/* 11111111 */
/* ^video */
/* e.g., */
/* Non-VideoMode VideoMode */
/* xx 1 11:0 where % is 1 01:0 1 11:0 xx */
/* xx 3 11 2 the video 3 00 2 3 11 2 xx */
/* xx 5 11 4 flag bit, 5 00 4 5 11 4 xx */
/* x 7:%1 6 x is pixel 7:%0 6 7:%1 6 xx */
/* ^ ^ ^ */
/* to set the pixels, first do a gotoxy to character screen position */
/* this mode is faster than Pixel ON/OFF if values are drawn from table */
#ifneed vm_on
vm_on() { putscreen ("\033B5"); } /* video mode on */
#endif
#ifneed vm_off
vm_off() { putscreen ("\033C5"); }
#endif
#ifneed pixel
pixel(x,y) int x,y; { /* x <= 159, y <= 99 */
putscreen("\033*");
putc(y+' ',0); putc(x+' ',0);
}
#endif
#ifneed no_pixel
no_pixel(x,y) int x,y; { /* x <= 159, y <= 99 */
putscreen("\033 ");
putc(y+' ',0); putc(x+' ',0);
}
#endif
#ifneed ldraw
/* use x1 <= x2, y1 <= y2, order is significant (Kaypro bug?) */
ldraw(x1,y1,x2,y2) int x1,x2,y1,y2; { /* x <= 159, y <= 99 */
putscreen("\033L");
putc(y1+' ',0); putc(x1+' ',0);
putc(y2+' ',0); putc(x2+' ',0);
}
#endif
#ifneed lwipe
lwipe(x1,y1,x2,y2) int x1,x2,y1,y2; { /* x <= 159, y <= 99 */
putscreen("\033D");
putc(y1+' ',0); putc(x1+' ',0);
putc(y2+' ',0); putc(x2+' ',0);
}
#endif
#ifneed putscreen
putscreen(p) char *p; {
while (*p) putc(*p++,0);
} /* end: putscreen */
#endif
#ifneed puts
puts(p) char *p; {
while (*p) chrout(*p++);
} /* end: puts */
#endif
#ifneed chrout
chrout(c) char c; { /* SPECIAL FOR SCRIPT OPTION WITH LST: */
putc(c,0);
if ( MYscrtp ) putc(c,MYretnirp);
} /* end: chrout */
#endif
/* end: MYLIB.C */


View File

@ -8,12 +8,6 @@ These games use VT100 either per default or were adopted to using them.
Whenever possible, I will provide working binaries (i.e. .COM files) and also the
sources or original files that I found online.
## Backgammon
by David C. Oshel; C/asm sources available; I've adopted the code to VT100.
See this repository: https://git.imzadi.de/acn/backgammon-vt100
## Games in this repository
* [2048](2048/)
@ -34,6 +28,7 @@ See this repository: https://git.imzadi.de/acn/backgammon-vt100
* [Robot Chase](RobotChase/)
* [MazezaM](MazezaM/)
* [Pac](Pac/)
* [Backgammon](Backgammon/)
## More Games on the Interwebs