diff --git a/38 Fur Trader/c/README.md b/38 Fur Trader/c/README.md new file mode 100644 index 00000000..a5b55dd8 --- /dev/null +++ b/38 Fur Trader/c/README.md @@ -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 + diff --git a/38 Fur Trader/c/furtrader.c b/38 Fur Trader/c/furtrader.c new file mode 100755 index 00000000..80ffbcef --- /dev/null +++ b/38 Fur Trader/c/furtrader.c @@ -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 +#include +#include +#include + + +/* 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> " ); /* 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 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 */ +} + diff --git a/38 Fur Trader/python/README.md b/38 Fur Trader/python/README.md index 781945ec..d90f8449 100644 --- a/38 Fur Trader/python/README.md +++ b/38 Fur Trader/python/README.md @@ -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 + diff --git a/38 Fur Trader/python/furtrader.py b/38 Fur Trader/python/furtrader.py new file mode 100755 index 00000000..b26b2f1a --- /dev/null +++ b/38 Fur Trader/python/furtrader.py @@ -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' + + + diff --git a/61 Math Dice/pascal/README.md b/61 Math Dice/pascal/README.md index aa1b3ae5..0e40aa9f 100644 --- a/61 Math Dice/pascal/README.md +++ b/61 Math Dice/pascal/README.md @@ -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(). + +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 + diff --git a/61 Math Dice/pascal/mathdice.pas b/61 Math Dice/pascal/mathdice.pas new file mode 100644 index 00000000..617f898f --- /dev/null +++ b/61 Math Dice/pascal/mathdice.pas @@ -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 worth of spaces before the 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. +