2020-06-14 02:04:08 -04:00
/*
* hammurabi - ancient Sumerian city - state resource management game
*
* Copyright 2020 David Meyer < papa @ sdf . org > + JMJ
*
*/
# include <u.h>
# include <libc.h>
# include <stdio.h>
# define MAXYEARS 10
# define INITPOP 100
# define INITGRAIN 2800
# define INITLAND 1000
typedef enum { FALSE , TRUE } Boolean ;
2020-06-15 10:24:12 -04:00
typedef enum { BUY , SELL , FEED , PLANT , RESET , EXEC , CALC , QUIT } Plancmd ;
2020-06-14 02:04:08 -04:00
char MSGDIV [ ] =
" ------------------------------<<<<>>>>----------------------------------- \n " ;
char MSGHELP [ ] =
" Help text here \n \
Land price varies between 17 and 26 bushels of grain per acre . \ n \
Planting two acres requires one bushel of grain . \ n \
One person can farm ten acres of land . \ n \
One person needs to eat 20 bushels of grain per year to stay healthy . \ n \
" ;
char MSGSPLASH [ ] =
" ___ ___ ___. .__ \n \
/ | \ \ _____ _____ _____ __ ______________ \ \ _ | __ | __ | \ n \
/ ~ \ \ __ \ \ / \ \ / \ \ | | \ \ _ __ \ \ __ \ \ | __ \ \ | | \ n \
\ \ Y / / __ \ \ | Y Y \ \ Y Y \ \ | / | | \ \ / / __ \ \ | \ \ _ \ \ \ \ | \ n \
\ \ ___ | _ / ( ____ / __ | _ | / __ | _ | / ____ / | __ | ( ____ / ___ / __ | \ n \
\ \ / \ \ / \ \ / \ \ / \ \ / \ \ / \ n \
, . __ . , \ n \
/ , ' , . ` . \ \ \ n \
____ | : | db | : | ____ \ n \
___ / / \ " \" \" |:|88|:| \" \" \" \\ \\ ___ \n \
_____ / / \ " :=_=_=_=|--|=_=_=_=: \" \\ \\ _____ \n \
__ / . - . _ / / __ | L_L_L_L | - - | L_L_L_L | __ \ \ \ \ _ . - . \ \ __ \ n \
/ / \ " ||m|:.-. .-. .-.,.__.,.-. .-. .-.:|m|| \" \\ \\ \n \
/ / | | 8 | | : : L_L_L_ / . ' , . ` . \ \ _L_L_L : : | | 8 | | \ \ \ \ \ n \
/ ' = = = = = = = \ " L.='.::'`:|:|db|:|:'`::.`=.L \" =======` \\ \n \
| . - - - . . - - . | _ : = = ' | : | 88 | : | ` = = : _ | . - - . . - - - . | \ n \
| | : | _ . = ' / = = = = = = = | : - - : | = = = = = = = \ \ ` = . _ | : | | \ n \
| | _ , = ' | | = = . = . = = | : - - : | = = . = . = = | | ` = . _ | | \ n \
| _ : = ' _______ | | | | | | | : - - : | | | | | | | _______ ` = : _ | \ n \
| | | | | | | : - - : | | | | | | | \ n \
' ' - - - - - - - | : - - : | - - - - - - - ' ' \ n \
' : = = : ' \ n \
" ;
# define MAXHONOR 9
char * HONORIFIC [ ] = { " Great " , " Mighty " , " Wise " , " Benevolent " , " Merciful " , " Just " , " Sublime " ,
" Glorious " , " Serene " , " Majestic " } ;
2020-06-15 10:24:12 -04:00
void completedterm ( void ) ;
int inputiexpr ( void ) ;
2020-06-14 02:04:08 -04:00
Boolean planyear ( void ) ;
2020-06-15 10:24:12 -04:00
void printdeposed ( void ) ;
2020-06-14 02:04:08 -04:00
void printgreeting ( void ) ;
void printlandprice ( void ) ;
void printstatus ( void ) ;
void printyearrept ( void ) ;
Boolean scanyes ( char * prompt ) ;
void setlandprice ( void ) ;
int Year = 0 ;
int Population = INITPOP ;
int Grain = INITGRAIN ;
int Land = INITLAND ;
int consctl ;
int foodgrain , landsale , plantland ;
2020-06-15 10:24:12 -04:00
int harvyield , landprice , newpop , plaguedeath , popfed , ratgrain , starvedeath , starvepct ;
2020-06-14 02:04:08 -04:00
int totstarved = 0 , totstarvepct = 0 ;
2020-06-15 10:24:12 -04:00
Boolean terminated = FALSE ;
2020-06-14 02:04:08 -04:00
void
main ( void )
{
consctl = open ( " /dev/consctl " , OWRITE ) ;
if ( consctl = = - 1 ) exits ( " can't open consctl: %r \n " ) ;
srand ( time ( 0 ) ) ;
print ( MSGSPLASH ) ;
if ( scanyes ( " Would you like instructions? " ) = = TRUE ) print ( MSGHELP ) ;
printgreeting ( ) ;
printstatus ( ) ;
setlandprice ( ) ;
printlandprice ( ) ;
2020-06-15 10:24:12 -04:00
do
2020-06-14 02:04:08 -04:00
{
2020-06-15 10:24:12 -04:00
+ + Year ;
if ( planyear ( ) = = FALSE ) terminated = TRUE ;
else
2020-06-14 02:04:08 -04:00
{
Grain = Grain + ( landsale * landprice ) - ( plantland / 2 ) - foodgrain ;
Land = Land - landsale ;
harvyield = nrand ( 5 ) + 1 ;
switch ( nrand ( 5 ) + 1 )
{
case 1 :
ratgrain = Grain ;
break ;
case 3 :
ratgrain = Grain / 3 ;
break ;
case 5 :
ratgrain = Grain / 5 ;
break ;
default :
ratgrain = 0 ;
}
Grain = Grain + ( plantland * harvyield ) - ratgrain ;
newpop = ( nrand ( 5 ) + 1 ) * ( 20 * Land + Grain ) / Population / 100 + 1 ;
popfed = foodgrain / 20 ;
starvedeath = ( ( popfed < Population ) ? ( Population - popfed ) : 0 ) ;
totstarved = totstarved + starvedeath ;
starvepct = 100 * starvedeath / Population ;
2020-06-15 10:24:12 -04:00
if ( starvepct > 45 )
{
printgreeting ( ) ;
print ( " You have starved %d of your subjects in one year! \n " , starvedeath ) ;
printdeposed ( ) ;
terminated = TRUE ;
}
else
{
totstarvepct = totstarvepct + starvepct ;
Population = Population + newpop - starvedeath ;
plaguedeath = ( ( nrand ( 100 ) < 15 ) ? ( Population / 2 ) : 0 ) ;
Population = Population - plaguedeath ;
printgreeting ( ) ;
printyearrept ( ) ;
2020-06-14 02:04:08 -04:00
2020-06-15 10:24:12 -04:00
if ( Year = = MAXYEARS ) completedterm ( ) ;
}
2020-06-14 02:04:08 -04:00
}
2020-06-15 10:24:12 -04:00
} while ( Year < MAXYEARS & & terminated = = FALSE ) ;
print ( MSGDIV ) ;
2020-06-14 02:04:08 -04:00
exits ( 0 ) ;
}
2020-06-15 10:24:12 -04:00
void
completedterm ( void )
{
int avgstarvepct = totstarvepct / MAXYEARS ;
int landperperson = Land / Population ;
int likeassassination = Population * 0.8 * frand ( ) ;
printgreeting ( ) ;
print ( " In your %d-year reign, %d people died of starvation, an average of %d people per year. \n " , MAXYEARS , totstarved , avgstarvepct ) ;
print ( " You started with %d acres per person and ended with %d acres per person. \n " , INITLAND / INITPOP , landperperson ) ;
if ( avgstarvepct > 33 | | landperperson < 7 ) printdeposed ( ) ;
else if ( avgstarvepct > 10 | | landperperson < 9 ) print ( " Your heavy-handed performance smacks of Nero and Ivan IV. Your (surviving) people find you an unpleasant ruler, and, frankly, hate your guts! " ) ;
else if ( avgstarvepct > 3 | | landperperson < 10 )
{
print ( " Your performance could have been better, but wasn't too bad. " ) ;
if ( likeassassination > 0 ) print ( " %d %s would like to see you assassinated, but we all have our trivial problems. \n " , likeassassination , ( likeassassination = = 1 ? " person " : " people " ) ) ;
}
else print ( " A fantastic performance! Charlemagne, Disraeli, and Jefferson combined could not have done better! " ) ;
}
int
inputiexpr ( void )
{
char buf [ 80 ] ;
int buflen = 80 ;
int result = 0 ;
int ch , rix , wix , p , o , n [ 40 ] ;
char op [ 39 ] ;
if ( fgets ( buf , buflen , stdin ) ! = NULL )
{
if ( buf [ strlen ( buf ) - 1 ] ! = ' \n ' ) while ( ( ch = getchar ( ) ) ! = ' \n ' & & ch ! = EOF ) ;
rix = wix = 0 ;
while ( buf [ rix ] ! = ' \0 ' )
{
if ( strchr ( " 0123456789+-*/ " , buf [ rix ] ) ! = 0 )
{
if ( rix > wix ) buf [ wix ] = buf [ rix ] ;
+ + wix ;
}
+ + rix ;
}
buf [ wix ] = ' \0 ' ;
p = sscanf ( buf , " %d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d%c%d " ,
& n [ 0 ] , & op [ 0 ] , & n [ 1 ] , & op [ 1 ] , & n [ 2 ] , & op [ 2 ] , & n [ 3 ] , & op [ 3 ] , & n [ 4 ] , & op [ 4 ] , & n [ 5 ] , & op [ 5 ] , & n [ 6 ] , & op [ 6 ] , & n [ 7 ] , & op [ 7 ] , & n [ 8 ] , & op [ 8 ] , & n [ 9 ] , & op [ 9 ] ,
& n [ 10 ] , & op [ 10 ] , & n [ 11 ] , & op [ 11 ] , & n [ 12 ] , & op [ 12 ] , & n [ 13 ] , & op [ 13 ] , & n [ 14 ] , & op [ 14 ] , & n [ 15 ] , & op [ 15 ] , & n [ 16 ] , & op [ 16 ] , & n [ 17 ] , & op [ 17 ] , & n [ 18 ] , & op [ 18 ] , & n [ 19 ] , & op [ 19 ] ,
& n [ 20 ] , & op [ 20 ] , & n [ 21 ] , & op [ 21 ] , & n [ 22 ] , & op [ 22 ] , & n [ 23 ] , & op [ 23 ] , & n [ 24 ] , & op [ 24 ] , & n [ 25 ] , & op [ 25 ] , & n [ 26 ] , & op [ 26 ] , & n [ 27 ] , & op [ 27 ] , & n [ 28 ] , & op [ 28 ] , & n [ 29 ] , & op [ 29 ] ,
& n [ 30 ] , & op [ 30 ] , & n [ 31 ] , & op [ 31 ] , & n [ 32 ] , & op [ 32 ] , & n [ 33 ] , & op [ 33 ] , & n [ 34 ] , & op [ 34 ] , & n [ 35 ] , & op [ 35 ] , & n [ 36 ] , & op [ 36 ] , & n [ 37 ] , & op [ 37 ] , & n [ 38 ] , & op [ 38 ] , & n [ 39 ] ) ;
if ( p > 0 )
{
result = n [ 0 ] ;
for ( o = 0 ; o < ( int ) ( p / 2 ) ; + + o )
{
switch ( op [ o ] )
{
case ' + ' :
result = result + n [ o + 1 ] ;
break ;
case ' - ' :
result = result - n [ o + 1 ] ;
break ;
case ' * ' :
result = result * n [ o + 1 ] ;
break ;
case ' / ' :
result = result / n [ o + 1 ] ;
break ;
}
}
}
}
return result ;
}
2020-06-14 02:04:08 -04:00
Boolean
planyear ( void )
{
2020-06-15 10:24:12 -04:00
Boolean play = TRUE ;
Plancmd cmd ;
foodgrain = landsale = planland = 0 ;
do
{
cmd = planmenu ( ) ;
switch ( cmd )
{
case BUY :
2020-06-14 02:04:08 -04:00
2020-06-15 10:24:12 -04:00
break ;
case SELL :
break ;
case FEED :
break ;
case PLANT :
break ;
case RESET :
foodgrain = landsale = planland = 0 ;
break ;
case EXEC :
break ;
case CALC :
ezintcalc ( ) ;
break ;
case QUIT :
play = FALSE ;
break ;
}
} while ( cmd ! = EXEC & & cmd ! = QUIT ) ;
return play ;
}
void
printdeposed ( void )
{
print ( " Due to this extreme mismanagement you have not only been deposed and executed, but you have also been declared National Fink! \n " ) ;
2020-06-14 02:04:08 -04:00
}
void
printgreeting ( void )
{
print ( MSGDIV ) ;
print ( " O %s One, I beg to report, \n " , HONORIFIC [ nrand ( MAXHONOR + 1 ) ] ) ;
}
void
printlandprice ( void )
{
print ( " The price of land is %d bushels of grain per acre. \n " , landprice ) ;
}
void
printstatus ( void )
{
print ( " The population is %d. \n " , Population ) ;
print ( " You own %d acres. \n " , Land ) ;
print ( " You have %d bushels of grain. \n " , Grain ) ;
}
void
printyearrept ( void )
{
2020-06-15 10:24:12 -04:00
print ( " In Year %d, \n " , Year ) ;
2020-06-14 02:04:08 -04:00
print ( " %d bushels were harvested per acre, for a total harvest of %d bushels. \n " ,
harvyield , plantland * harvyield ) ;
if ( ratgrain > 0 ) print ( " Rats ate %d bushels of grain. \n " , ratgrain ) ;
if ( newpop > 0 ) print ( " The population increased by %d. \n " , newpop ) ;
}
Boolean
scanyes ( char * prompt )
{
int in = 0 ;
if ( write ( consctl , " rawon " , 5 ) ! = 5 ) exits ( " \n can't turn off echo \n " ) ;
while ( in ! = ' y ' & & in ! = ' n ' )
{
print ( " %s [y/n] " , prompt ) ;
in = getchar ( ) ;
if ( in = = EOF ) exits ( " \n error reading terminal input \n " ) ;
print ( " %c \n " , in ) ;
}
if ( write ( consctl , " rawoff " , 6 ) ! = 6 ) exits ( " \n can't turn on echo \n " ) ;
print ( " \n " ) ;
return ( in = = ' y ' ? TRUE : FALSE ) ;
}
void
setlandprice ( void )
{
landprice = nrand ( 10 ) + 17 ;
}