After a couple more hours of work and I have my Abandoned Farmhouse text adventure game ported to CP/M using the BDS C compiler. The changes were similar to those needed for the Yum game, and included some changes for the available string functions and initialization of some large arrays.
I haven't played the game to completion but it seems to be working well. You can find source code and a CP/M binary here.
Below is a transcript of playing a short game.
B>advent
Abandoned Farmhouse Adventure
By Jeff Tranter
Your four-year-old grandson has gone missing and was last seen headed in the
direction of the abandoned family farm. It's a dangerous place to play. You
have to find him before he gets hurt, and it will be getting dark soon...
? help
Valid Commands:
Go east/west/north/south/up/down
Look
Use object
Examine object
Take object
Drop object
Inventory
Help
Quit
You can abbreviate commands and directions to the first letter.
Type just the first letter of a direction to move.
? i
You are carrying:
flashlight
? l
You are at the door to the house.
You see:
key
bottle
You can go: east west
? drop flashlight
Dropped flashlight.
? t key
Took key.
? t bottle
Took bottle.
? n
You can't go north from here.
? l
You are at the door to the house.
You see:
flashlight
You can go: east west
? w
You are in the kitchen.
? l
You are in the kitchen.
You see:
candybar
You can go: south east down
? t candybar
Took candybar.
? w
You can't go west from here.
? l
You are in the kitchen.
You see:
nothing special
You can go: south east down
? s
You are in the dining room.
? l
You are in the dining room.
You see:
stale meat
You can go: north west
? u stale meat
The meat looked and tasted bad. You feel very sick and pass out.
Game over after 7 turns.
Do you want to play again (y/n)? n
B>
Showing posts with label BDS C. Show all posts
Showing posts with label BDS C. Show all posts
Wednesday, April 16, 2014
Tuesday, April 15, 2014
Yum Game ported to BDS C
I've been playing some more with the Briel Altair 8800 running CP/M.
As a larger test of the BDS C compiler I was able to port the "Yum" game that I originally wrote to run on the Briel Apple Replica 1.
Porting it to BDS C was a few hours of work (mostly spent transferring new versions of the code between my Linux desktop and SD card and compiling on the Altair 8800.
The changes required were not too major. I was impressed by the reasonably complete run-time library included with BDS C. In all, the changes I had to make were the following:
Below is a partial log of a session playing the game against the computer.
# # # # # #
# # # # ## ##
# # # # # # # #
# # # # # #
# # # # #
# # # # #
# ##### # #
Welcome to Yum!
Do you want instructions (y/n) ? y
This is a computer version of the game Yum, similar to games known as Yahtzee,
Yacht and Generala. Each player rolls five dice up to three times and then
applies the dice toward a category to claim points. The game has 12 rounds
during which each player attempts to claim the most points in each category.
The winner is the person scoring the most points at the end of the game.
This version supports up to three players of which any can be human or
computer players.
Categories are as follows:
1'S through 6'S - dice of same type
Low Straight (15) - 1 2 3 4 5
High Straight (20) - 2 3 4 5 6
Low Score - total 21 or more
High Score - total 22 or more
Full House (25) - 3 of a kind and pair
Yum (30) - 5 dice the same
Bonus of 25 points if upper section is 63 or more.
How many human players (0-3)? 1
How many computer players (0-2)? 1
Name of player 1? Jeff
Press to start the game
Wait a few seconds, and type a CR:
Jeff's turn. Press to roll
First roll is: 2 2 2 4 5
Enter dice to roll again or D for dice or S for score: 4 5
Second roll is: 2 2 2 2 2
Enter dice to roll again or D for dice or S for score:
1 - 1'S
2 - 2'S
3 - 3'S
4 - 4'S
5 - 5'S
6 - 6'S
9 - Low Straight
10 - High Straight
11 - Low Score
12 - High Score
13 - Full House
14 - Yum
Jeff, What category do you want to claim? (1-14)? 14
Altair's turn. Press to roll
First roll is: 1 1 4 4 5
Altair keeps: 1 1 4 4
Second roll is: 1 1 4 4 5
Altair keeps: 1 1 4 4
Last roll is: 1 1 2 4 4
Altair plays 1'S
Press to continue
Score after 1 of 12 rounds:
Roll Jeff Altair
1'S 2
2'S
3'S
4'S
5'S
6'S
Sub-total 0 2
Bonus 0 0
Low Straight
High Straight
Low Score
High Score
Full House
Yum 30
Total 30 2
Press to continue
Jeff's turn. Press to roll
First roll is: 1 2 2 6 6
Enter dice to roll again or D for dice or S for score: 1
Second roll is: 2 2 4 6 6
Enter dice to roll again or D for dice or S for score: 4
Last roll is: 2 2 6 6 6
1 - 1'S
2 - 2'S
3 - 3'S
4 - 4'S
5 - 5'S
6 - 6'S
9 - Low Straight
10 - High Straight
11 - Low Score
12 - High Score
13 - Full House
Jeff, What category do you want to claim? (1-14)? 13
Altair's turn. Press to roll
First roll is: 2 4 4 6 6
Altair keeps: 4 4 6 6
Second roll is: 4 4 4 6 6
Altair keeps: 4 4 4 6 6
Altair plays Full House
Press to continue
Score after 2 of 12 rounds:
Roll Jeff Altair
1'S 2
2'S
3'S
4'S
5'S
6'S
Sub-total 0 2
Bonus 0 0
Low Straight
High Straight
Low Score
High Score
Full House 25 25
Yum 30
Total 55 27
Press to continue
I put the source code as well as a CP/M binary here on github. Next, I plan to try porting my text adventure game.
As a larger test of the BDS C compiler I was able to port the "Yum" game that I originally wrote to run on the Briel Apple Replica 1.
Porting it to BDS C was a few hours of work (mostly spent transferring new versions of the code between my Linux desktop and SD card and compiling on the Altair 8800.
The changes required were not too major. I was impressed by the reasonably complete run-time library included with BDS C. In all, the changes I had to make were the following:
- Includes changed (BDSC C has everything in stdio.h).
- sizeof does not work for arrays, so used a constant.
- Arrays cannot be initialized, but can use initptr() function instead.
- No bool type, so use int.
- Function declarations have to use old K&R format.
- Text supports lower case (original Apple 1 version had to be upper case only).
- Some text lines (like help) made wider due to 80 column screen.
- Variables cannot be initialized when declared.
- No strtol() so use atoi().
- Remove const qualifiers.
- Clear screen using ANSI escape sequence.
Below is a partial log of a session playing the game against the computer.
# # # # # #
# # # # ## ##
# # # # # # # #
# # # # # #
# # # # #
# # # # #
# ##### # #
Welcome to Yum!
Do you want instructions (y/n) ? y
This is a computer version of the game Yum, similar to games known as Yahtzee,
Yacht and Generala. Each player rolls five dice up to three times and then
applies the dice toward a category to claim points. The game has 12 rounds
during which each player attempts to claim the most points in each category.
The winner is the person scoring the most points at the end of the game.
This version supports up to three players of which any can be human or
computer players.
Categories are as follows:
1'S through 6'S - dice of same type
Low Straight (15) - 1 2 3 4 5
High Straight (20) - 2 3 4 5 6
Low Score - total 21 or more
High Score - total 22 or more
Full House (25) - 3 of a kind and pair
Yum (30) - 5 dice the same
Bonus of 25 points if upper section is 63 or more.
How many human players (0-3)? 1
How many computer players (0-2)? 1
Name of player 1? Jeff
Press
Wait a few seconds, and type a CR:
Jeff's turn. Press
First roll is: 2 2 2 4 5
Enter dice to roll again or D for dice or S for score: 4 5
Second roll is: 2 2 2 2 2
Enter dice to roll again or D for dice or S for score:
1 - 1'S
2 - 2'S
3 - 3'S
4 - 4'S
5 - 5'S
6 - 6'S
9 - Low Straight
10 - High Straight
11 - Low Score
12 - High Score
13 - Full House
14 - Yum
Jeff, What category do you want to claim? (1-14)? 14
Altair's turn. Press
First roll is: 1 1 4 4 5
Altair keeps: 1 1 4 4
Second roll is: 1 1 4 4 5
Altair keeps: 1 1 4 4
Last roll is: 1 1 2 4 4
Altair plays 1'S
Press
Score after 1 of 12 rounds:
Roll Jeff Altair
1'S 2
2'S
3'S
4'S
5'S
6'S
Sub-total 0 2
Bonus 0 0
Low Straight
High Straight
Low Score
High Score
Full House
Yum 30
Total 30 2
Press
Jeff's turn. Press
First roll is: 1 2 2 6 6
Enter dice to roll again or D for dice or S for score: 1
Second roll is: 2 2 4 6 6
Enter dice to roll again or D for dice or S for score: 4
Last roll is: 2 2 6 6 6
1 - 1'S
2 - 2'S
3 - 3'S
4 - 4'S
5 - 5'S
6 - 6'S
9 - Low Straight
10 - High Straight
11 - Low Score
12 - High Score
13 - Full House
Jeff, What category do you want to claim? (1-14)? 13
Altair's turn. Press
First roll is: 2 4 4 6 6
Altair keeps: 4 4 6 6
Second roll is: 4 4 4 6 6
Altair keeps: 4 4 4 6 6
Altair plays Full House
Press
Score after 2 of 12 rounds:
Roll Jeff Altair
1'S 2
2'S
3'S
4'S
5'S
6'S
Sub-total 0 2
Bonus 0 0
Low Straight
High Straight
Low Score
High Score
Full House 25 25
Yum 30
Total 55 27
Press
I put the source code as well as a CP/M binary here on github. Next, I plan to try porting my text adventure game.
Tuesday, March 18, 2014
Using the CP/M BDS C Compiler
I'll continue giving more details on the programs I demonstrated in the YouTube video The Briel Altair 8800 Kit, Part 5: Advanced Topics.
This time, the BDS C Compiler.
Go to Leo Zolman's BDS C web page and download the release file bdsc-all.zip.
BDS C comes with extensive documentation in the file bdsc-guide.pdf, but for the purposes of a simple demo, you can do the following. Unzip the file and copy these files to an SD card, and then transfer them to a CP/M drive:
BDSCIO.H C.CCC CC.COM CC2.COM
CLINK.COM DEFF.CRL DEFF2.CRL STDIO.H
The example program TAIL.C used in the demonstration was found here.
Here is an even shorter example C program that I wrote. I entered it as the filename EX1.C:
/* BDS C example 1 */
#include
main(argc,argv)
char **argv;
{
int i;
printf("Example Program 1\n");
for (i=1; i <=10; i++) {
printf("%d\n", i);
}
return 0;
}
Here is a sample session showing EX1.C and TAIL.C being compiled, linked, and run (commands typed by the user are in bold).
B>dir
B: EX1 C : NQUEENS C : BDSCIO H : C CCC
B: CC COM : CC2 COM : CLINK COM : DEFF CRL
B: DEFF2 CRL : STDIO H : TAIL C
B>cc ex1
BD Software C Compiler v1.60 (part I)
37K elbowroom
BD Software C Compiler v1.60 (part II)
34K to spare
B>clink ex1
BD Software C Linker v1.60
Last code address: 0E8D
Externals start at 0E8E, occupy 0006 bytes, last byte at 0E93
Top of memory: E805
Stack space: D972
Writing output...
46K link space remaining
B>ex1
Example Program 1
1
2
3
4
5
6
7
8
9
10
B>cc tail
BD Software C Compiler v1.60 (part I)
36K elbowroom
BD Software C Compiler v1.60 (part II)
33K to spare
B>clink tail
BD Software C Linker v1.60
Last code address: 1402
Externals start at 1403, occupy 0006 bytes, last byte at 1408
Top of memory: E805
Stack space: D3FD
Writing output...
44K link space remaining
B>tail -10 tail.c
}
int lastchar(c)
char c;
{
return (!c) || (c == CPMEOF);
}
B>tail
Usage: tail [-#]
B>dir
B: TAIL CRL : TAIL COM : NQUEENS CRL : NQUEENS COM
B: EX1 C : NQUEENS C : BDSCIO H : C CCC
B: CC COM : CC2 COM : CLINK COM : DEFF CRL
B: DEFF2 CRL : STDIO H : TAIL C : EX1 CRL
B: EX1 COM
Finally, here is the N Queens example program shown in the YouTube video. It will take a while to run to completion. First the source code, followed by example output.
/* Solve the n queens problem */
#include
#define MAX_N 8
int board[MAX_N*MAX_N];
int tries;
int solutions;
int n;
int nsq;
int cache[MAX_N+1]; /* get some savings by caching last position */
/* display the board */
void print_board()
{
int i;
printf("+");
for (i = 0; i < n ; i++)
printf("---");
printf("+\n");
for (i = 0; i < nsq ; i++) {
if ((i % n) == 0)
printf("|");
if (board[i])
printf(" Q ");
else
printf(" . ");
if (((i+1) % n) == 0)
printf("|\n");
}
printf("+");
for (i = 0; i < n ; i++)
printf("---");
printf("+\n");
}
/* find position of a piece */
int piece(n)
{
int i;
/* first try the cache */
if (board[cache[n]] == n)
return cache[n];
for (i = 0 ; i < nsq ; i++)
if (board[i] == n) {
cache[n] = i; /* cache it for next time */
return i;
}
return -1;
}
/* see if board is a solution */
void check_board()
{
int i, p, r, c, j;
/* loop over all pieces */
for (i = 1 ; i <= n ; i++) {
p = piece(i);
/* not a solution if piece in same row */
r = p / n;
for (c = 0 ; c < n ; c++) {
if (board[r*n+c] != 0 && board[r*n+c] != i)
return;
}
/* not a solution if piece in same column */
c = p % n;
for (r = 0 ; r < n ; r++) {
if (board[r*n+c] != 0 && board[r*n+c] != i)
return;
}
/* not a solution if piece in same \ diagonal */
for (j = -n ; j < n ; j++) {
r = p / n + j;
c = p % n + j;
if ((r >= 0) && (r < n) && (c >= 0) && (c < n) &&
(board[r*n+c] != 0) && (board[r*n+c] != i))
return;
}
/* not a solution if piece in same / diagonal */
for (j = -n ; j < n ; j++) {
r = p / n + j;
c = p % n - j;
if ((r >= 0) && (r < n) && (c >= 0) && (c < n) &&
(board[r*n+c] != 0) && (board[r*n+c] != i))
return;
}
}
solutions++;
print_board();
}
/* move piece p to next position */
int next_pos(p)
{
int i, t;
if (p < 1)
return 0;
i = piece(p);
if (i < nsq-n+p-1) {
board[i] = 0;
board[i+1] = p;
return 1;
} else {
t = next_pos(p-1);
board[i] = 0;
board[piece(p-1)+1] = p;
return t;
}
}
/* generate the next possible solution */
int next_board()
{
return next_pos(n);
}
int main()
{
int i;
solutions = 0;
n = 5;
nsq = n*n; /* save n^2 to avoid calculating it again */
printf("\n\n\n\nSOLVING N QUEENS PROBLEM FOR N = %d\n", n);
/* clear the board */
for (i = 0 ; i < nsq ; i++)
board[i] = 0;
/* initially place the queens */
for (i = 0 ; i < n ; i++)
board[i] = i+1;
do {
tries++;
check_board();
} while (next_board());
printf("FOUND %d SOLUTIONS AFTER %ld TRIES.\n", solutions, tries);
return 0;
}
B>nqueens
SOLVING N QUEENS PROBLEM FOR N = 5
+---------------+
| Q . . . . |
| . . Q . . |
| . . . . Q |
| . Q . . . |
| . . . Q . |
+---------------+
+---------------+
| Q . . . . |
| . . . Q . |
| . Q . . . |
| . . . . Q |
| . . Q . . |
+---------------+
+---------------+
| . Q . . . |
| . . . Q . |
| Q . . . . |
| . . Q . . |
| . . . . Q |
+---------------+
+---------------+
| . Q . . . |
| . . . . Q |
| . . Q . . |
| Q . . . . |
| . . . Q . |
+---------------+
+---------------+
| . . Q . . |
| Q . . . . |
| . . . Q . |
| . Q . . . |
| . . . . Q |
+---------------+
+---------------+
| . . Q . . |
| . . . . Q |
| . Q . . . |
| . . . Q . |
| Q . . . . |
+---------------+
+---------------+
| . . . Q . |
| Q . . . . |
| . . Q . . |
| . . . . Q |
| . Q . . . |
+---------------+
+---------------+
| . . . Q . |
| . Q . . . |
| . . . . Q |
| . . Q . . |
| Q . . . . |
+---------------+
+---------------+
| . . . . Q |
| . Q . . . |
| . . . Q . |
| Q . . . . |
| . . Q . . |
+---------------+
+---------------+
| . . . . Q |
| . . Q . . |
| Q . . . . |
| . . . Q . |
| . Q . . . |
+---------------+
FOUND 10 SOLUTIONS AFTER -12406 TRIES.
B>
This time, the BDS C Compiler.
Go to Leo Zolman's BDS C web page and download the release file bdsc-all.zip.
BDS C comes with extensive documentation in the file bdsc-guide.pdf, but for the purposes of a simple demo, you can do the following. Unzip the file and copy these files to an SD card, and then transfer them to a CP/M drive:
BDSCIO.H C.CCC CC.COM CC2.COM
CLINK.COM DEFF.CRL DEFF2.CRL STDIO.H
The example program TAIL.C used in the demonstration was found here.
Here is an even shorter example C program that I wrote. I entered it as the filename EX1.C:
/* BDS C example 1 */
#include
main(argc,argv)
char **argv;
{
int i;
printf("Example Program 1\n");
for (i=1; i <=10; i++) {
printf("%d\n", i);
}
return 0;
}
Here is a sample session showing EX1.C and TAIL.C being compiled, linked, and run (commands typed by the user are in bold).
B>dir
B: EX1 C : NQUEENS C : BDSCIO H : C CCC
B: CC COM : CC2 COM : CLINK COM : DEFF CRL
B: DEFF2 CRL : STDIO H : TAIL C
B>cc ex1
BD Software C Compiler v1.60 (part I)
37K elbowroom
BD Software C Compiler v1.60 (part II)
34K to spare
B>clink ex1
BD Software C Linker v1.60
Last code address: 0E8D
Externals start at 0E8E, occupy 0006 bytes, last byte at 0E93
Top of memory: E805
Stack space: D972
Writing output...
46K link space remaining
B>ex1
Example Program 1
1
2
3
4
5
6
7
8
9
10
B>cc tail
BD Software C Compiler v1.60 (part I)
36K elbowroom
BD Software C Compiler v1.60 (part II)
33K to spare
B>clink tail
BD Software C Linker v1.60
Last code address: 1402
Externals start at 1403, occupy 0006 bytes, last byte at 1408
Top of memory: E805
Stack space: D3FD
Writing output...
44K link space remaining
B>tail -10 tail.c
}
int lastchar(c)
char c;
{
return (!c) || (c == CPMEOF);
}
B>tail
Usage: tail [-#]
B>dir
B: TAIL CRL : TAIL COM : NQUEENS CRL : NQUEENS COM
B: EX1 C : NQUEENS C : BDSCIO H : C CCC
B: CC COM : CC2 COM : CLINK COM : DEFF CRL
B: DEFF2 CRL : STDIO H : TAIL C : EX1 CRL
B: EX1 COM
Finally, here is the N Queens example program shown in the YouTube video. It will take a while to run to completion. First the source code, followed by example output.
/* Solve the n queens problem */
#include
#define MAX_N 8
int board[MAX_N*MAX_N];
int tries;
int solutions;
int n;
int nsq;
int cache[MAX_N+1]; /* get some savings by caching last position */
/* display the board */
void print_board()
{
int i;
printf("+");
for (i = 0; i < n ; i++)
printf("---");
printf("+\n");
for (i = 0; i < nsq ; i++) {
if ((i % n) == 0)
printf("|");
if (board[i])
printf(" Q ");
else
printf(" . ");
if (((i+1) % n) == 0)
printf("|\n");
}
printf("+");
for (i = 0; i < n ; i++)
printf("---");
printf("+\n");
}
/* find position of a piece */
int piece(n)
{
int i;
/* first try the cache */
if (board[cache[n]] == n)
return cache[n];
for (i = 0 ; i < nsq ; i++)
if (board[i] == n) {
cache[n] = i; /* cache it for next time */
return i;
}
return -1;
}
/* see if board is a solution */
void check_board()
{
int i, p, r, c, j;
/* loop over all pieces */
for (i = 1 ; i <= n ; i++) {
p = piece(i);
/* not a solution if piece in same row */
r = p / n;
for (c = 0 ; c < n ; c++) {
if (board[r*n+c] != 0 && board[r*n+c] != i)
return;
}
/* not a solution if piece in same column */
c = p % n;
for (r = 0 ; r < n ; r++) {
if (board[r*n+c] != 0 && board[r*n+c] != i)
return;
}
/* not a solution if piece in same \ diagonal */
for (j = -n ; j < n ; j++) {
r = p / n + j;
c = p % n + j;
if ((r >= 0) && (r < n) && (c >= 0) && (c < n) &&
(board[r*n+c] != 0) && (board[r*n+c] != i))
return;
}
/* not a solution if piece in same / diagonal */
for (j = -n ; j < n ; j++) {
r = p / n + j;
c = p % n - j;
if ((r >= 0) && (r < n) && (c >= 0) && (c < n) &&
(board[r*n+c] != 0) && (board[r*n+c] != i))
return;
}
}
solutions++;
print_board();
}
/* move piece p to next position */
int next_pos(p)
{
int i, t;
if (p < 1)
return 0;
i = piece(p);
if (i < nsq-n+p-1) {
board[i] = 0;
board[i+1] = p;
return 1;
} else {
t = next_pos(p-1);
board[i] = 0;
board[piece(p-1)+1] = p;
return t;
}
}
/* generate the next possible solution */
int next_board()
{
return next_pos(n);
}
int main()
{
int i;
solutions = 0;
n = 5;
nsq = n*n; /* save n^2 to avoid calculating it again */
printf("\n\n\n\nSOLVING N QUEENS PROBLEM FOR N = %d\n", n);
/* clear the board */
for (i = 0 ; i < nsq ; i++)
board[i] = 0;
/* initially place the queens */
for (i = 0 ; i < n ; i++)
board[i] = i+1;
do {
tries++;
check_board();
} while (next_board());
printf("FOUND %d SOLUTIONS AFTER %ld TRIES.\n", solutions, tries);
return 0;
}
B>nqueens
SOLVING N QUEENS PROBLEM FOR N = 5
+---------------+
| Q . . . . |
| . . Q . . |
| . . . . Q |
| . Q . . . |
| . . . Q . |
+---------------+
+---------------+
| Q . . . . |
| . . . Q . |
| . Q . . . |
| . . . . Q |
| . . Q . . |
+---------------+
+---------------+
| . Q . . . |
| . . . Q . |
| Q . . . . |
| . . Q . . |
| . . . . Q |
+---------------+
+---------------+
| . Q . . . |
| . . . . Q |
| . . Q . . |
| Q . . . . |
| . . . Q . |
+---------------+
+---------------+
| . . Q . . |
| Q . . . . |
| . . . Q . |
| . Q . . . |
| . . . . Q |
+---------------+
+---------------+
| . . Q . . |
| . . . . Q |
| . Q . . . |
| . . . Q . |
| Q . . . . |
+---------------+
+---------------+
| . . . Q . |
| Q . . . . |
| . . Q . . |
| . . . . Q |
| . Q . . . |
+---------------+
+---------------+
| . . . Q . |
| . Q . . . |
| . . . . Q |
| . . Q . . |
| Q . . . . |
+---------------+
+---------------+
| . . . . Q |
| . Q . . . |
| . . . Q . |
| Q . . . . |
| . . Q . . |
+---------------+
+---------------+
| . . . . Q |
| . . Q . . |
| Q . . . . |
| . . . Q . |
| . Q . . . |
+---------------+
FOUND 10 SOLUTIONS AFTER -12406 TRIES.
B>
Subscribe to:
Posts (Atom)