hammurabi-p9/hammurabi.c

331 lines
10 KiB
C
Raw Normal View History

2020-06-14 06:04:08 +00: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 14:24:12 +00:00
typedef enum {BUY, SELL, FEED, PLANT, RESET, EXEC, CALC, QUIT} Plancmd;
2020-06-14 06:04:08 +00: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 14:24:12 +00:00
void completedterm(void);
int inputiexpr(void);
2020-06-14 06:04:08 +00:00
Boolean planyear(void);
2020-06-15 14:24:12 +00:00
void printdeposed(void);
2020-06-14 06:04:08 +00: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 14:24:12 +00:00
int harvyield, landprice, newpop, plaguedeath, popfed, ratgrain, starvedeath, starvepct;
2020-06-14 06:04:08 +00:00
int totstarved = 0, totstarvepct = 0;
2020-06-15 14:24:12 +00:00
Boolean terminated = FALSE;
2020-06-14 06:04:08 +00: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 14:24:12 +00:00
do
2020-06-14 06:04:08 +00:00
{
2020-06-15 14:24:12 +00:00
++ Year;
if(planyear() == FALSE) terminated = TRUE;
else
2020-06-14 06:04:08 +00: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 14:24:12 +00: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 06:04:08 +00:00
2020-06-15 14:24:12 +00:00
if(Year == MAXYEARS) completedterm();
}
2020-06-14 06:04:08 +00:00
}
2020-06-15 14:24:12 +00:00
} while(Year < MAXYEARS && terminated == FALSE);
print(MSGDIV);
2020-06-14 06:04:08 +00:00
exits(0);
}
2020-06-15 14:24:12 +00: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 06:04:08 +00:00
Boolean
planyear(void)
{
2020-06-15 14:24:12 +00:00
Boolean play = TRUE;
Plancmd cmd;
foodgrain = landsale = planland = 0;
do
{
cmd = planmenu();
switch(cmd)
{
case BUY:
2020-06-14 06:04:08 +00:00
2020-06-15 14:24:12 +00: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 06:04:08 +00: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 14:24:12 +00:00
print("In Year %d,\n", Year);
2020-06-14 06:04:08 +00: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("\ncan't turn off echo\n");
while(in != 'y' && in != 'n')
{
print("%s [y/n] ", prompt);
in = getchar();
if(in == EOF) exits("\nerror reading terminal input\n");
print("%c\n", in);
}
if(write(consctl, "rawoff", 6) != 6) exits("\ncan't turn on echo\n");
print("\n");
return (in == 'y' ? TRUE : FALSE);
}
void
setlandprice(void)
{
landprice = nrand(10) + 17;
}