mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-02-05 19:32:48 -08:00
23
38 Fur Trader/c/README.md
Normal file
23
38 Fur Trader/c/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [ANSI-C](https://en.wikipedia.org/wiki/ANSI_C)
|
||||
|
||||
##### Translator Notes:
|
||||
I tried to preserve as much of the original layout and flow of the code
|
||||
as possible. However I did use enumerated types for the Fort numbers
|
||||
and Fur types. I think this was certainly a change for the better, and
|
||||
makes the code much easier to read.
|
||||
|
||||
I also tried to minimise the use of pointers, and stuck with old-school
|
||||
C formatting, because you never know how old the compiler is.
|
||||
|
||||
Interestingly the code seems to have a bug around the prices of Fox Furs.
|
||||
The commodity-rate for these is stored in the variable `D1`, however some
|
||||
paths through the code do not set this price. So there was a chance of
|
||||
using this uninitialised, or whatever the previous loop set. I don't
|
||||
think this was the original authors intent. So I preserved the original flow
|
||||
of the code (using the previous `D1` value), but also catching the
|
||||
uninitialised path, and assigning a "best guess" value.
|
||||
|
||||
krt@krt.com.au 2020-10-10
|
||||
|
||||
475
38 Fur Trader/c/furtrader.c
Executable file
475
38 Fur Trader/c/furtrader.c
Executable file
@@ -0,0 +1,475 @@
|
||||
|
||||
/*
|
||||
* Ported from furtrader.bas to ANSI C (C99) by krt@krt.com.au
|
||||
*
|
||||
* compile with:
|
||||
* gcc -g -Wall -Werror furtrader.c -o furtrader
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
/* Constants */
|
||||
#define FUR_TYPE_COUNT 4
|
||||
#define FUR_MINK 0
|
||||
#define FUR_BEAVER 1
|
||||
#define FUR_ERMINE 2
|
||||
#define FUR_FOX 3
|
||||
#define MAX_FURS 190
|
||||
const char *FUR_NAMES[FUR_TYPE_COUNT] = { "MINK", "BEAVER", "ERMINE", "FOX" };
|
||||
|
||||
#define FORT_TYPE_COUNT 3
|
||||
#define FORT_MONTREAL 1
|
||||
#define FORT_QUEBEC 2
|
||||
#define FORT_NEWYORK 3
|
||||
const char *FORT_NAMES[FORT_TYPE_COUNT] = { "HOCHELAGA (MONTREAL)", "STADACONA (QUEBEC)", "NEW YORK" };
|
||||
|
||||
|
||||
|
||||
/* Print the words at the specified column */
|
||||
void printAtColumn( int column, const char *words )
|
||||
{
|
||||
int i;
|
||||
for ( i=0; i<column; i++ )
|
||||
printf( " " );
|
||||
printf( "%s\n", words );
|
||||
}
|
||||
|
||||
/* trivial function to output a line with a \n */
|
||||
void print( const char *words )
|
||||
{
|
||||
printf( "%s\n", words );
|
||||
}
|
||||
|
||||
/* Show the player the introductory message */
|
||||
void showIntroduction()
|
||||
{
|
||||
print( "YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN " );
|
||||
print( "1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET" );
|
||||
print( "SUPPLIES FOR THE NEXT YEAR. YOU HAVE A CHOICE OF THREE" );
|
||||
print( "FORTS AT WHICH YOU MAY TRADE. THE COST OF SUPPLIES" );
|
||||
print( "AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND" );
|
||||
print( "ON THE FORT THAT YOU CHOOSE." );
|
||||
print( "" );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prompt the user for input.
|
||||
* When input is given, try to conver it to an integer
|
||||
* return the integer converted value or 0 on error
|
||||
*/
|
||||
int getNumericInput()
|
||||
{
|
||||
int result = -1;
|
||||
char buffer[64]; /* somewhere to store user input */
|
||||
char *endstr;
|
||||
|
||||
while ( result == -1 )
|
||||
{
|
||||
printf( ">> " ); /* prompt the user */
|
||||
fgets( buffer, sizeof( buffer ), stdin ); /* read from the console into the buffer */
|
||||
result = (int)strtol( buffer, &endstr, 10 ); /* only simple error checking */
|
||||
|
||||
if ( endstr == buffer ) /* was the string -> integer ok? */
|
||||
result = -1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prompt the user for YES/NO input.
|
||||
* When input is given, try to work out if it's YES, Yes, yes, Y, etc.
|
||||
* And convert to a single upper-case letter
|
||||
* Returns a character of 'Y' or 'N'.
|
||||
*/
|
||||
char getYesOrNo()
|
||||
{
|
||||
char result = '!';
|
||||
char buffer[64]; /* somewhere to store user input */
|
||||
|
||||
while ( !( result == 'Y' || result == 'N' ) ) /* While the answer was not Yes or No */
|
||||
{
|
||||
print( "ANSWER YES OR NO" );
|
||||
printf( ">> " );
|
||||
|
||||
fgets( buffer, sizeof( buffer ), stdin ); /* read from the console into the buffer */
|
||||
if ( buffer[0] == 'Y' || buffer[0] == 'y' )
|
||||
result = 'Y';
|
||||
else if ( buffer[0] == 'N' || buffer[0] == 'n' )
|
||||
result = 'N';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Show the player the choices of Fort, get their input, if the
|
||||
* input is a valid choice (1,2,3) return it, otherwise keep
|
||||
* prompting the user.
|
||||
*/
|
||||
int getFortChoice()
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
while ( result == 0 )
|
||||
{
|
||||
print( "" );
|
||||
print( "YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2," );
|
||||
print( "OR FORT 3. FORT 1 IS FORT HOCHELAGA (MONTREAL)" );
|
||||
print( "AND IS UNDER THE PROTECTION OF THE FRENCH ARMY." );
|
||||
print( "FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE" );
|
||||
print( "PROTECTION OF THE FRENCH ARMY. HOWEVER, YOU MUST" );
|
||||
print( "MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS." );
|
||||
print( "FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL." );
|
||||
print( "YOU MUST CROSS THROUGH IROQUOIS LAND." );
|
||||
print( "ANSWER 1, 2, OR 3." );
|
||||
|
||||
result = getNumericInput(); /* get input from the player */
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print the description for the fort
|
||||
*/
|
||||
void showFortComment( int which_fort )
|
||||
{
|
||||
print( "" );
|
||||
if ( which_fort == FORT_MONTREAL )
|
||||
{
|
||||
print( "YOU HAVE CHOSEN THE EASIEST ROUTE. HOWEVER, THE FORT" );
|
||||
print( "IS FAR FROM ANY SEAPORT. THE VALUE" );
|
||||
print( "YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST" );
|
||||
print( "OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK." );
|
||||
}
|
||||
else if ( which_fort == FORT_QUEBEC )
|
||||
{
|
||||
print( "YOU HAVE CHOSEN A HARD ROUTE. IT IS, IN COMPARSION," );
|
||||
print( "HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN" );
|
||||
print( "THE ROUTE TO NEW YORK. YOU WILL RECEIVE AN AVERAGE VALUE" );
|
||||
print( "FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE." );
|
||||
}
|
||||
else if ( which_fort == FORT_NEWYORK )
|
||||
{
|
||||
print( "YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE. AT" );
|
||||
print( "FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE" );
|
||||
print( "FOR YOUR FURS. THE COST OF YOUR SUPPLIES" );
|
||||
print( "WILL BE LOWER THAN AT ALL THE OTHER FORTS." );
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "Internal error #1, fort %d does not exist\n", which_fort );
|
||||
exit( 1 ); /* you have a bug */
|
||||
}
|
||||
print( "" );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prompt the player for how many of each fur type they want.
|
||||
* Accept numeric inputs, re-prompting on incorrect input values
|
||||
*/
|
||||
void getFursPurchase( int *furs )
|
||||
{
|
||||
int i;
|
||||
|
||||
printf( "YOUR %d FURS ARE DISTRIBUTED AMONG THE FOLLOWING\n", FUR_TYPE_COUNT );
|
||||
print( "KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX." );
|
||||
print( "" );
|
||||
|
||||
for ( i=0; i<FUR_TYPE_COUNT; i++ )
|
||||
{
|
||||
printf( "HOW MANY %s DO YOU HAVE\n", FUR_NAMES[i] );
|
||||
furs[i] = getNumericInput();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (Re)Set the player's inventory to zero
|
||||
*/
|
||||
void zeroInventory( int *player_fur_count )
|
||||
{
|
||||
int i;
|
||||
for ( i=0; i<FUR_TYPE_COUNT; i++ )
|
||||
{
|
||||
player_fur_count[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Tally the player's inventory
|
||||
*/
|
||||
int sumInventory( int *player_fur_count )
|
||||
{
|
||||
int result = 0;
|
||||
int i;
|
||||
for ( i=0; i<FUR_TYPE_COUNT; i++ )
|
||||
{
|
||||
result += player_fur_count[i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return a random number between a & b
|
||||
* Ref: https://stackoverflow.com/a/686376/1730895
|
||||
*/
|
||||
float randomAB(float a, float b)
|
||||
{
|
||||
return ((b - a) * ((float)rand() / (float)RAND_MAX)) + a;
|
||||
}
|
||||
/* Random floating point number between 0 and 1 */
|
||||
float randFloat()
|
||||
{
|
||||
return randomAB( 0, 1 );
|
||||
}
|
||||
|
||||
|
||||
/* States to allow switching in main game-loop */
|
||||
#define STATE_STARTING 1
|
||||
#define STATE_CHOOSING_FORT 2
|
||||
#define STATE_TRAVELLING 3
|
||||
#define STATE_TRADING 4
|
||||
|
||||
int main( void )
|
||||
{
|
||||
/* variables for storing player's status */
|
||||
float player_funds = 0; /* no money */
|
||||
int player_furs[FUR_TYPE_COUNT] = { 0, 0, 0, 0 }; /* no furs */
|
||||
|
||||
/* player input holders */
|
||||
char yes_or_no;
|
||||
int event_picker;
|
||||
int which_fort;
|
||||
|
||||
/* what part of the game is in play */
|
||||
int game_state = STATE_STARTING;
|
||||
|
||||
/* commodity prices */
|
||||
float mink_price = -1;
|
||||
float beaver_price = -1;
|
||||
float ermine_price = -1;
|
||||
float fox_price = -1; /* sometimes this takes the "last" price (probably this was a bug) */
|
||||
|
||||
float mink_value;
|
||||
float beaver_value;
|
||||
float ermine_value;
|
||||
float fox_value; /* for calculating sales results */
|
||||
|
||||
|
||||
srand( time( NULL ) ); /* seed the random number generator */
|
||||
|
||||
printAtColumn( 31, "FUR TRADER" );
|
||||
printAtColumn( 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" );
|
||||
printAtColumn( 15, "(Ported to ANSI-C Oct 2012 krt@krt.com.au)" );
|
||||
print( "\n\n\n" );
|
||||
|
||||
/* Loop forever until the player asks to quit */
|
||||
while ( 1 )
|
||||
{
|
||||
if ( game_state == STATE_STARTING )
|
||||
{
|
||||
showIntroduction();
|
||||
|
||||
player_funds = 600; /* Initial player start money */
|
||||
zeroInventory( player_furs ); /* Player fur inventory */
|
||||
|
||||
print( "DO YOU WISH TO TRADE FURS?" );
|
||||
yes_or_no = getYesOrNo();
|
||||
if ( yes_or_no == 'N' )
|
||||
exit( 0 ); /* STOP */
|
||||
game_state = STATE_TRADING;
|
||||
}
|
||||
|
||||
else if ( game_state == STATE_TRADING )
|
||||
{
|
||||
print( "" );
|
||||
printf( "YOU HAVE $ %1.2f IN SAVINGS\n", player_funds );
|
||||
printf( "AND %d FURS TO BEGIN THE EXPEDITION\n", MAX_FURS );
|
||||
getFursPurchase( player_furs );
|
||||
|
||||
if ( sumInventory( player_furs ) > MAX_FURS )
|
||||
{
|
||||
print( "" );
|
||||
print( "YOU MAY NOT HAVE THAT MANY FURS." );
|
||||
print( "DO NOT TRY TO CHEAT. I CAN ADD." );
|
||||
print( "YOU MUST START AGAIN." );
|
||||
print( "" );
|
||||
game_state = STATE_STARTING; /* T/N: Wow, harsh. */
|
||||
}
|
||||
else
|
||||
{
|
||||
game_state = STATE_CHOOSING_FORT;
|
||||
}
|
||||
}
|
||||
|
||||
else if ( game_state == STATE_CHOOSING_FORT )
|
||||
{
|
||||
which_fort = getFortChoice();
|
||||
showFortComment( which_fort );
|
||||
print( "DO YOU WANT TO TRADE AT ANOTHER FORT?" );
|
||||
yes_or_no = getYesOrNo();
|
||||
if ( yes_or_no == 'N' )
|
||||
game_state = STATE_TRAVELLING;
|
||||
}
|
||||
|
||||
else if ( game_state == STATE_TRAVELLING )
|
||||
{
|
||||
print( "" );
|
||||
if ( which_fort == FORT_MONTREAL )
|
||||
{
|
||||
mink_price = ( ( 0.2 * randFloat() + 0.70 ) * 100 + 0.5 ) / 100;
|
||||
ermine_price = ( ( 0.2 * randFloat() + 0.65 ) * 100 + 0.5 ) / 100;
|
||||
beaver_price = ( ( 0.2 * randFloat() + 0.75 ) * 100 + 0.5 ) / 100;
|
||||
fox_price = ( ( 0.2 * randFloat() + 0.80 ) * 100 + 0.5 ) / 100;
|
||||
|
||||
print( "SUPPLIES AT FORT HOCHELAGA COST $150.00." );
|
||||
print( "YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00." );
|
||||
player_funds -= 160;
|
||||
}
|
||||
|
||||
else if ( which_fort == FORT_QUEBEC )
|
||||
{
|
||||
mink_price = ( ( 0.30 * randFloat() + 0.85 ) * 100 + 0.5 ) / 100;
|
||||
ermine_price = ( ( 0.15 * randFloat() + 0.80 ) * 100 + 0.5 ) / 100;
|
||||
beaver_price = ( ( 0.20 * randFloat() + 0.90 ) * 100 + 0.5 ) / 100;
|
||||
fox_price = ( ( 0.25 * randFloat() + 1.10 ) * 100 + 0.5 ) / 100;
|
||||
event_picker = ( 10 * randFloat() ) + 1;
|
||||
|
||||
if ( event_picker <= 2 )
|
||||
{
|
||||
print( "YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS" );
|
||||
print( "THE PORTAGE. YOU HAD TO LEAVE THE PELTS, BUT FOUND" );
|
||||
print( "THEM STOLEN WHEN YOU RETURNED." );
|
||||
player_furs[ FUR_BEAVER ] = 0;
|
||||
}
|
||||
else if ( event_picker <= 6 )
|
||||
{
|
||||
print( "YOU ARRIVED SAFELY AT FORT STADACONA." );
|
||||
}
|
||||
else if ( event_picker <= 8 )
|
||||
{
|
||||
print( "YOUR CANOE UPSET IN THE LACHINE RAPIDS. YOU" );
|
||||
print( "LOST ALL YOUR FURS." );
|
||||
zeroInventory( player_furs );
|
||||
}
|
||||
else if ( event_picker <= 10 )
|
||||
{
|
||||
print( "YOUR FOX PELTS WERE NOT CURED PROPERLY." );
|
||||
print( "NO ONE WILL BUY THEM." );
|
||||
player_furs[ FUR_FOX ] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "Internal Error #3, Out-of-bounds event_picker %d\n", event_picker );
|
||||
exit( 1 ); /* you have a bug */
|
||||
}
|
||||
|
||||
print( "" );
|
||||
print( "SUPPLIES AT FORT STADACONA COST $125.00." );
|
||||
print( "YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00." );
|
||||
player_funds -= 140;
|
||||
}
|
||||
|
||||
else if ( which_fort == FORT_NEWYORK )
|
||||
{
|
||||
mink_price = ( ( 0.15 * randFloat() + 1.05 ) * 100 + 0.5 ) / 100;
|
||||
ermine_price = ( ( 0.15 * randFloat() + 0.95 ) * 100 + 0.5 ) / 100;
|
||||
beaver_price = ( ( 0.25 * randFloat() + 1.00 ) * 100 + 0.5 ) / 100;
|
||||
if ( fox_price < 0 )
|
||||
{
|
||||
/* Original Bug? There is no Fox price generated for New York,
|
||||
it will use any previous "D1" price.
|
||||
So if there was no previous value, make one up */
|
||||
fox_price = ( ( 0.25 * randFloat() + 1.05 ) * 100 + 0.5 ) / 100; /* not in orginal code */
|
||||
}
|
||||
event_picker = ( 10 * randFloat() ) + 1;
|
||||
|
||||
if ( event_picker <= 2 )
|
||||
{
|
||||
print( "YOU WERE ATTACKED BY A PARTY OF IROQUOIS." );
|
||||
print( "ALL PEOPLE IN YOUR TRADING GROUP WERE" );
|
||||
print( "KILLED. THIS ENDS THE GAME." );
|
||||
exit( 0 );
|
||||
}
|
||||
else if ( event_picker <= 6 )
|
||||
{
|
||||
print( "YOU WERE LUCKY. YOU ARRIVED SAFELY" );
|
||||
print( "AT FORT NEW YORK." );
|
||||
}
|
||||
else if ( event_picker <= 8 )
|
||||
{
|
||||
print( "YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY." );
|
||||
print( "HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND." );
|
||||
zeroInventory( player_furs );
|
||||
}
|
||||
else if ( event_picker <= 10 )
|
||||
{
|
||||
mink_price /= 2;
|
||||
fox_price /= 2;
|
||||
print( "YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP." );
|
||||
print( "YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS." );
|
||||
}
|
||||
else
|
||||
{
|
||||
print( "Internal Error #4, Out-of-bounds event_picker %d\n" );
|
||||
exit( 1 ); /* you have a bug */
|
||||
}
|
||||
|
||||
print( "" );
|
||||
print( "SUPPLIES AT NEW YORK COST $85.00." );
|
||||
print( "YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00." );
|
||||
player_funds -= 105;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
printf( "Internal error #2, fort %d does not exist\n", which_fort );
|
||||
exit( 1 ); /* you have a bug */
|
||||
}
|
||||
|
||||
/* Calculate sales */
|
||||
beaver_value = beaver_price * player_furs[ FUR_BEAVER ];
|
||||
fox_value = fox_price * player_furs[ FUR_FOX ];
|
||||
ermine_value = ermine_price * player_furs[ FUR_ERMINE ];
|
||||
mink_value = mink_price * player_furs[ FUR_MINK ];
|
||||
|
||||
print( "" );
|
||||
printf( "YOUR BEAVER SOLD FOR $%6.2f\n", beaver_value );
|
||||
printf( "YOUR FOX SOLD FOR $%6.2f\n", fox_value );
|
||||
printf( "YOUR ERMINE SOLD FOR $%6.2f\n", ermine_value );
|
||||
printf( "YOUR MINK SOLD FOR $%6.2f\n", mink_value );
|
||||
|
||||
player_funds += beaver_value + fox_value + ermine_value + mink_value;
|
||||
|
||||
print( "" );
|
||||
printf( "YOU NOW HAVE $ %1.2f INCLUDING YOUR PREVIOUS SAVINGS\n", player_funds );
|
||||
|
||||
print( "" );
|
||||
print( "DO YOU WANT TO TRADE FURS NEXT YEAR?" );
|
||||
yes_or_no = getYesOrNo();
|
||||
if ( yes_or_no == 'N' )
|
||||
exit( 0 ); /* STOP */
|
||||
else
|
||||
game_state = STATE_TRADING;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* exit OK */
|
||||
}
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Python](https://www.python.org/about/)
|
||||
|
||||
##### Translator Notes:
|
||||
I tried to preserve as much of the original layout and flow of the code
|
||||
as possible. However I did use quasi enumerated types for the Fort numbers
|
||||
and Fur types. I think this was certainly a change for the better, and
|
||||
makes the code much easier to read.
|
||||
|
||||
I program in many different languages on a daily basis. Most languages
|
||||
require brackets around expressions, so I just cannot bring myself to
|
||||
write an expression without brackets. IMHO it makes the code easier to study,
|
||||
but it does contravene the Python PEP-8 Style guide.
|
||||
|
||||
Interestingly the code seems to have a bug around the prices of Fox Furs.
|
||||
The commodity-rate for these is stored in the variable `D1`, however some
|
||||
paths through the code do not set this price. So there was a chance of
|
||||
using this uninitialised, or whatever the previous loop set. I don't
|
||||
think this was the original authors intent. So I preserved the original flow
|
||||
of the code (using the previous `D1` value), but also catching the
|
||||
uninitialised path, and assigning a "best guess" value.
|
||||
|
||||
krt@krt.com.au 2020-10-10
|
||||
|
||||
|
||||
297
38 Fur Trader/python/furtrader.py
Executable file
297
38 Fur Trader/python/furtrader.py
Executable file
@@ -0,0 +1,297 @@
|
||||
#! /usr/bin/env python3
|
||||
|
||||
import sys # for system function, like exit()
|
||||
import random # for generating random numbers
|
||||
|
||||
|
||||
### global variables for storing player's status
|
||||
player_funds = 0 # no money
|
||||
player_furs = [ 0, 0, 0, 0 ] # no furs
|
||||
|
||||
|
||||
### Constants
|
||||
FUR_MINK = 0
|
||||
FUR_BEAVER = 1
|
||||
FUR_ERMINE = 2
|
||||
FUR_FOX = 3
|
||||
MAX_FURS = 190
|
||||
FUR_NAMES = [ "MINK", "BEAVER", "ERMINE", "FOX" ]
|
||||
|
||||
FORT_MONTREAL = 1
|
||||
FORT_QUEBEC = 2
|
||||
FORT_NEWYORK = 3
|
||||
FORT_NAMES = [ "HOCHELAGA (MONTREAL)", "STADACONA (QUEBEC)", "NEW YORK" ]
|
||||
|
||||
|
||||
|
||||
def printAtColumn( column:int, words:str ):
|
||||
""" Print the words at the specified column """
|
||||
spaces = ' ' * column # make a fat string of spaces
|
||||
print( spaces + words )
|
||||
|
||||
|
||||
def showIntroduction():
|
||||
""" Show the player the introductory message """
|
||||
print( "YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN " )
|
||||
print( "1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET" )
|
||||
print( "SUPPLIES FOR THE NEXT YEAR. YOU HAVE A CHOICE OF THREE" )
|
||||
print( "FORTS AT WHICH YOU MAY TRADE. THE COST OF SUPPLIES" )
|
||||
print( "AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND" )
|
||||
print( "ON THE FORT THAT YOU CHOOSE." )
|
||||
print( "" )
|
||||
|
||||
|
||||
def getFortChoice():
|
||||
""" Show the player the choices of Fort, get their input, if the
|
||||
input is a valid choice (1,2,3) return it, otherwise keep
|
||||
prompting the user. """
|
||||
result = 0
|
||||
while ( result == 0 ):
|
||||
print( "" )
|
||||
print( "YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2," )
|
||||
print( "OR FORT 3. FORT 1 IS FORT HOCHELAGA (MONTREAL)" )
|
||||
print( "AND IS UNDER THE PROTECTION OF THE FRENCH ARMY." )
|
||||
print( "FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE" )
|
||||
print( "PROTECTION OF THE FRENCH ARMY. HOWEVER, YOU MUST" )
|
||||
print( "MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS." )
|
||||
print( "FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL." )
|
||||
print( "YOU MUST CROSS THROUGH IROQUOIS LAND." )
|
||||
print( "ANSWER 1, 2, OR 3." )
|
||||
|
||||
player_choice = input( ">> " ) # get input from the player
|
||||
|
||||
# try to convert the player's string input into an integer
|
||||
try:
|
||||
result = int( player_choice ) # string to integer
|
||||
except:
|
||||
# Whatever the player typed, it could not be interpreted as a number
|
||||
pass
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def showFortComment( which_fort ):
|
||||
""" Print the description for the fort """
|
||||
print( "" )
|
||||
if ( which_fort == FORT_MONTREAL ):
|
||||
print( "YOU HAVE CHOSEN THE EASIEST ROUTE. HOWEVER, THE FORT" )
|
||||
print( "IS FAR FROM ANY SEAPORT. THE VALUE" )
|
||||
print( "YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST" )
|
||||
print( "OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK." )
|
||||
elif ( which_fort == FORT_QUEBEC ):
|
||||
print( "YOU HAVE CHOSEN A HARD ROUTE. IT IS, IN COMPARSION," )
|
||||
print( "HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN" )
|
||||
print( "THE ROUTE TO NEW YORK. YOU WILL RECEIVE AN AVERAGE VALUE" )
|
||||
print( "FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE." )
|
||||
elif ( which_fort == FORT_NEWYORK ):
|
||||
print( "YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE. AT" )
|
||||
print( "FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE" )
|
||||
print( "FOR YOUR FURS. THE COST OF YOUR SUPPLIES" )
|
||||
print( "WILL BE LOWER THAN AT ALL THE OTHER FORTS." )
|
||||
else:
|
||||
print( "Internal error #1, fort " + str( which_fort ) + " does not exist" )
|
||||
sys.exit( 1 ) # you have a bug
|
||||
print( "" )
|
||||
|
||||
|
||||
def getYesOrNo():
|
||||
""" Prompt the player to enter 'YES' or 'NO'. Keep prompting until
|
||||
valid input is entered. Accept various spellings by only
|
||||
checking the first letter of input.
|
||||
Return a single letter 'Y' or 'N' """
|
||||
result = 0
|
||||
while ( result not in ( 'Y', 'N' ) ):
|
||||
print( "ANSWER YES OR NO" )
|
||||
player_choice = input( ">> " )
|
||||
player_choice = player_choice.strip().upper() # trim spaces, make upper-case
|
||||
if ( player_choice.startswith( 'Y' ) ):
|
||||
result = 'Y'
|
||||
elif ( player_choice.startswith( 'N' ) ):
|
||||
result = 'N'
|
||||
return result
|
||||
|
||||
|
||||
def getFursPurchase():
|
||||
""" Prompt the player for how many of each fur type they want.
|
||||
Accept numeric inputs, re-prompting on incorrect input values """
|
||||
results = []
|
||||
|
||||
print( "YOUR " + str( MAX_FURS ) + " FURS ARE DISTRIBUTED AMONG THE FOLLOWING" )
|
||||
print( "KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX." )
|
||||
print( "" )
|
||||
|
||||
for i in ( range( len( FUR_NAMES ) ) ):
|
||||
print( "HOW MANY " + FUR_NAMES[i] + " DO YOU HAVE" )
|
||||
count_str = input( ">> " )
|
||||
try:
|
||||
count = int( count_str )
|
||||
results.append( count )
|
||||
except:
|
||||
# invalid input, prompt again by re-looping
|
||||
i -= 1
|
||||
return results
|
||||
|
||||
|
||||
|
||||
###
|
||||
### MAIN
|
||||
###
|
||||
|
||||
if ( __name__ == '__main__' ):
|
||||
|
||||
printAtColumn( 31, "FUR TRADER" )
|
||||
printAtColumn( 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" )
|
||||
printAtColumn( 15, "(Ported to Python Oct 2012 krt@krt.com.au)" )
|
||||
print( "\n\n\n" )
|
||||
|
||||
game_state = 'starting'
|
||||
fox_price = None # sometimes this takes the "last" price (probably this was a bug)
|
||||
|
||||
while ( True ):
|
||||
|
||||
if ( game_state == 'starting' ):
|
||||
showIntroduction()
|
||||
|
||||
player_funds = 600 # Initial player start money
|
||||
player_furs = [ 0, 0, 0, 0 ] # Player fur inventory
|
||||
|
||||
print( "DO YOU WISH TO TRADE FURS?" )
|
||||
should_trade = getYesOrNo()
|
||||
if ( should_trade == 'N' ):
|
||||
sys.exit( 0 ) # STOP
|
||||
game_state = 'trading'
|
||||
|
||||
elif ( game_state == 'trading' ):
|
||||
print( "" )
|
||||
print( "YOU HAVE $ %1.2f IN SAVINGS" % ( player_funds ) )
|
||||
print( "AND " + str( MAX_FURS ) + " FURS TO BEGIN THE EXPEDITION" )
|
||||
player_furs = getFursPurchase()
|
||||
|
||||
if ( sum( player_furs ) > MAX_FURS ):
|
||||
print( "" )
|
||||
print( "YOU MAY NOT HAVE THAT MANY FURS." )
|
||||
print( "DO NOT TRY TO CHEAT. I CAN ADD." )
|
||||
print( "YOU MUST START AGAIN." )
|
||||
game_state = 'starting' # T/N: Wow, harsh.
|
||||
else:
|
||||
game_state = 'choosing fort'
|
||||
|
||||
elif ( game_state == 'choosing fort' ):
|
||||
which_fort = getFortChoice()
|
||||
showFortComment( which_fort )
|
||||
print( "DO YOU WANT TO TRADE AT ANOTHER FORT?" )
|
||||
change_fort = getYesOrNo()
|
||||
if ( change_fort == 'N' ):
|
||||
game_state = 'travelling'
|
||||
|
||||
elif ( game_state == 'travelling' ):
|
||||
print( "" )
|
||||
if ( which_fort == FORT_MONTREAL ):
|
||||
mink_price = int( ( 0.2 * random.random() + 0.70 ) * 100 + 0.5 ) / 100 #INT((.2*RND(1)+.7)*10^2+.5)/10^2
|
||||
ermine_price = int( ( 0.2 * random.random() + 0.65 ) * 100 + 0.5 ) / 100 #INT((.2*RND(1)+.65)*10^2+.5)/10^2
|
||||
beaver_price = int( ( 0.2 * random.random() + 0.75 ) * 100 + 0.5 ) / 100 #INT((.2*RND(1)+.75)*10^2+.5)/10^2
|
||||
fox_price = int( ( 0.2 * random.random() + 0.80 ) * 100 + 0.5 ) / 100 #INT((.2*RND(1)+.8)*10^2+.5)/10^2
|
||||
|
||||
print( "SUPPLIES AT FORT HOCHELAGA COST $150.00." )
|
||||
print( "YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00." )
|
||||
player_funds -= 160
|
||||
|
||||
elif ( which_fort == FORT_QUEBEC ):
|
||||
mink_price = int( ( 0.30 * random.random() + 0.85 ) * 100 + 0.5 ) / 100 #INT((.3*RND(1)+.85)*10^2+.5)/10^2
|
||||
ermine_price = int( ( 0.15 * random.random() + 0.80 ) * 100 + 0.5 ) / 100 #INT((.15*RND(1)+.8)*10^2+.5)/10^2
|
||||
beaver_price = int( ( 0.20 * random.random() + 0.90 ) * 100 + 0.5 ) / 100 #INT((.2*RND(1)+.9)*10^2+.5)/10^2
|
||||
fox_price = int( ( 0.25 * random.random() + 1.10 ) * 100 + 0.5 ) / 100 #INT((.25*RND(1)+1.1)*10^2+.5)/10^2
|
||||
event_picker = int( 10 * random.random() ) + 1
|
||||
|
||||
if ( event_picker <= 2 ):
|
||||
print( "YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS" )
|
||||
print( "THE PORTAGE. YOU HAD TO LEAVE THE PELTS, BUT FOUND" )
|
||||
print( "THEM STOLEN WHEN YOU RETURNED." )
|
||||
player_furs[ FUR_BEAVER ] = 0
|
||||
elif ( event_picker <= 6 ):
|
||||
print( "YOU ARRIVED SAFELY AT FORT STADACONA." )
|
||||
elif ( event_picker <= 8 ):
|
||||
print( "YOUR CANOE UPSET IN THE LACHINE RAPIDS. YOU" )
|
||||
print( "LOST ALL YOUR FURS." )
|
||||
player_furs = [ 0, 0, 0, 0 ]
|
||||
elif ( event_picker <= 10 ):
|
||||
print( "YOUR FOX PELTS WERE NOT CURED PROPERLY." )
|
||||
print( "NO ONE WILL BUY THEM." )
|
||||
player_furs[ FUR_FOX ] = 0
|
||||
else:
|
||||
print( "Internal Error #3, Out-of-bounds event_picker" + str( event_picker ) )
|
||||
sys.exit( 1 ) # you have a bug
|
||||
|
||||
print( "" )
|
||||
print( "SUPPLIES AT FORT STADACONA COST $125.00." )
|
||||
print( "YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00." )
|
||||
player_funds -= 140
|
||||
|
||||
elif ( which_fort == FORT_NEWYORK ):
|
||||
mink_price = int( ( 0.15 * random.random() + 1.05 ) * 100 + 0.5 ) / 100 #INT((.15*RND(1)+1.05)*10^2+.5)/10^2
|
||||
ermine_price = int( ( 0.15 * random.random() + 0.95 ) * 100 + 0.5 ) / 100 #INT((.15*RND(1)+.95)*10^2+.5)/10^2
|
||||
beaver_price = int( ( 0.25 * random.random() + 1.00 ) * 100 + 0.5 ) / 100 #INT((.25*RND(1)+1.00)*10^2+.5)/10^2
|
||||
if ( fox_price == None ):
|
||||
# Original Bug? There is no Fox price generated for New York, it will use any previous "D1" price
|
||||
# So if there was no previous value, make one up
|
||||
fox_price = int( ( 0.25 * random.random() + 1.05 ) * 100 + 0.5 ) / 100 # not in orginal code
|
||||
event_picker = int( 10 * random.random() ) + 1
|
||||
|
||||
if ( event_picker <= 2 ):
|
||||
print( "YOU WERE ATTACKED BY A PARTY OF IROQUOIS." )
|
||||
print( "ALL PEOPLE IN YOUR TRADING GROUP WERE" )
|
||||
print( "KILLED. THIS ENDS THE GAME." )
|
||||
sys.exit( 0 )
|
||||
elif ( event_picker <= 6 ):
|
||||
print( "YOU WERE LUCKY. YOU ARRIVED SAFELY" )
|
||||
print( "AT FORT NEW YORK." )
|
||||
elif ( event_picker <= 8 ):
|
||||
print( "YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY." )
|
||||
print( "HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND." )
|
||||
player_furs = [ 0, 0, 0, 0 ]
|
||||
elif ( event_picker <= 10 ):
|
||||
mink_price /= 2
|
||||
fox_price /= 2
|
||||
print( "YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP." )
|
||||
print( "YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS." )
|
||||
else:
|
||||
print( "Internal Error #4, Out-of-bounds event_picker" + str( event_picker ) )
|
||||
sys.exit( 1 ) # you have a bug
|
||||
|
||||
print( "" )
|
||||
print( "SUPPLIES AT NEW YORK COST $85.00." )
|
||||
print( "YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00." )
|
||||
player_funds -= 105
|
||||
|
||||
|
||||
else:
|
||||
print( "Internal error #2, fort " + str( which_fort ) + " does not exist" )
|
||||
sys.exit( 1 ) # you have a bug
|
||||
|
||||
# Calculate sales
|
||||
beaver_value = beaver_price * player_furs[ FUR_BEAVER ]
|
||||
fox_value = fox_price * player_furs[ FUR_FOX ]
|
||||
ermine_value = ermine_price * player_furs[ FUR_ERMINE ]
|
||||
mink_value = mink_price * player_furs[ FUR_MINK ]
|
||||
|
||||
print( "" )
|
||||
print( "YOUR BEAVER SOLD FOR $%6.2f" % ( beaver_value ) )
|
||||
print( "YOUR FOX SOLD FOR $%6.2f" % ( fox_value ) )
|
||||
print( "YOUR ERMINE SOLD FOR $%6.2f" % ( ermine_value ) )
|
||||
print( "YOUR MINK SOLD FOR $%6.2f" % ( mink_value ) )
|
||||
|
||||
player_funds += beaver_value + fox_value + ermine_value + mink_value
|
||||
|
||||
print( "" )
|
||||
print( "YOU NOW HAVE $ %1.2f INCLUDING YOUR PREVIOUS SAVINGS" % ( player_funds ) )
|
||||
|
||||
print( "" )
|
||||
print( "DO YOU WANT TO TRADE FURS NEXT YEAR?" )
|
||||
should_trade = getYesOrNo()
|
||||
if ( should_trade == 'N' ):
|
||||
sys.exit( 0 ) # STOP
|
||||
else:
|
||||
game_state = 'trading'
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
|
||||
|
||||
##### Translator Notes:
|
||||
I tried to preserve as much of the original layout and flow of the code
|
||||
as possible. I added a procedure for the printing of the die-face; and
|
||||
another to read an integer from the player, as I was unhappy with the runtime
|
||||
error message spat out when a non-number is given to readln(<integer>).
|
||||
|
||||
I was torn between using the correct singular term "die" instead of "dice".
|
||||
In the end I used a (poor?) combination of both.
|
||||
|
||||
krt@krt.com.au 2020-10-12
|
||||
|
||||
|
||||
129
61 Math Dice/pascal/mathdice.pas
Normal file
129
61 Math Dice/pascal/mathdice.pas
Normal file
@@ -0,0 +1,129 @@
|
||||
(*
|
||||
* Ported from mathdice.bas to Pascal by krt@krt.com.au
|
||||
*
|
||||
* Compile with Free Pascal (https://www.freepascal.org/) ~
|
||||
* fpc mathdice.pas
|
||||
*)
|
||||
|
||||
program MathDice;
|
||||
|
||||
|
||||
procedure printDice( face_value: integer );
|
||||
(* Prints a box with spots representing a die face for the user *)
|
||||
begin
|
||||
writeln( ' ----- ' );
|
||||
|
||||
if ( face_value = 1 ) then
|
||||
writeln( 'I I' )
|
||||
else if ( ( face_value = 2 ) or ( face_value = 3 ) ) then
|
||||
writeln( 'I * I' )
|
||||
else
|
||||
writeln( 'I * * I' );
|
||||
|
||||
if ( ( face_value = 2 ) or ( face_value = 4 ) ) then
|
||||
writeln( 'I I' )
|
||||
else if ( face_value = 6 ) then
|
||||
writeln( 'I * * I' )
|
||||
else
|
||||
writeln( 'I * I' );
|
||||
|
||||
if ( face_value = 1 ) then
|
||||
writeln( 'I I' )
|
||||
else if ( ( face_value = 2 ) or ( face_value = 3 ) ) then
|
||||
writeln( 'I * I' )
|
||||
else
|
||||
writeln( 'I * * I' );
|
||||
|
||||
writeln( ' ----- ' );
|
||||
end;
|
||||
|
||||
|
||||
procedure writeAtColumn( width: integer; words: string );
|
||||
(* Prints <width> worth of spaces before the <words> to justify the text *)
|
||||
var
|
||||
i: integer;
|
||||
begin
|
||||
for i := 1 to width do
|
||||
write( ' ' );
|
||||
writeln( words );
|
||||
end;
|
||||
|
||||
|
||||
function inputNumber(): integer;
|
||||
(* Get a number from the player with error checking.
|
||||
If they type a non-number, ask them again *)
|
||||
var
|
||||
player_input: string; (* The string entered by the player *)
|
||||
player_answer: integer; (* The converted value of the text *)
|
||||
input_error: integer; (* The letter's column that caused an error *)
|
||||
begin
|
||||
|
||||
input_error := 1;
|
||||
while ( input_error <> 0 ) do
|
||||
begin
|
||||
readln( player_input );
|
||||
|
||||
val( player_input, player_answer, input_error );
|
||||
|
||||
if ( input_error <> 0 ) then
|
||||
write( 'Please input a number: ' );
|
||||
end;
|
||||
|
||||
inputNumber := player_answer;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
var
|
||||
dice1: integer; (* die 1 face value *)
|
||||
dice2: integer; (* die 2 face value *)
|
||||
answer: integer; (* the sum of the dice *)
|
||||
player_answer: integer; (* The value entered by the player *)
|
||||
begin
|
||||
writeAtColumn( 31, 'MATH DICE' );
|
||||
writeAtColumn( 15, 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY' );
|
||||
writeAtColumn( 15, '(Ported to Pascal Oct 2012 krt@krt.com.au)' );
|
||||
writeln( '' );
|
||||
writeln( '' );
|
||||
writeln( '' );
|
||||
|
||||
writeln( 'THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.' );
|
||||
writeln( 'WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION' );
|
||||
writeln( 'MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.' );
|
||||
writeln( 'TO CONCLUDE THE LESSON, TYPE CONTROL-C AS YOUR ANSWER.' );
|
||||
writeln( '' );
|
||||
writeln( '' );
|
||||
|
||||
while ( true ) do
|
||||
begin
|
||||
dice1 := Random( 6 ) + 1; (* Random number between 1 and 6 (including) *)
|
||||
dice2 := Random( 6 ) + 1; (* Random number between 1 and 6 (including) *)
|
||||
answer := dice1 + dice2;
|
||||
|
||||
(* Show the player two dice faces *)
|
||||
printDice( dice1 );
|
||||
writeln( ' +' );
|
||||
printDice( dice2 );
|
||||
|
||||
write( ' = ' );
|
||||
|
||||
player_answer := inputNumber();
|
||||
|
||||
if ( player_answer <> answer ) then
|
||||
begin
|
||||
(* Give the player a second chance at the answer... *)
|
||||
writeln( 'NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER.' );
|
||||
write( ' = ' );
|
||||
player_answer := inputNumber();
|
||||
end;
|
||||
|
||||
if ( player_answer <> answer ) then
|
||||
writeln( 'NO, THE ANSWER IS ', answer )
|
||||
else
|
||||
writeln( 'RIGHT!' );
|
||||
|
||||
writeln( '' );
|
||||
writeln( 'THE DICE ROLL AGAIN...' );
|
||||
end;
|
||||
end.
|
||||
|
||||
Reference in New Issue
Block a user