Hammurabi

Published May 30, 2006
Advertisement
My Hammurabi source and binaries

Yesterday was Memorial Day, and I didn't have anything to do, so I decided to dig into the game Hammurabi.

Original BASIC Source for Hammurabi

This game was written in line number BASIC, which is what I started out on those many years ago. ("those many years ago"=="18 years ago" and thanks for asking.)

I had to type in the BASIC source, which took around an hour or so.

But, of course, I have no interpreter for line number BASIC (and do not want one), so what is a programmer to do?

Naturally, I decided to port the game to C. I fired up VC++2005, made myself a main function, copied and pasted the BASIC source as comments into the main function, and set about the task of "translating" each line of BASIC into lines of C.

The result:

[SOURCE]/*	Hammurabi Version 1.0.0 ("Faithful Port")    Copyright (C) 2006  Ernest S. Pazera    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA	Contact information:		ernestpazera@msn.com	"Original" game and source taken from:		BASIC Computer Games (Microcomputer Edition)		Edited by David H. Ahl		ISBN:0-89480-052-3	Version History:		1.0.0: 			Initial Release 			29MAY2006			The initial version is a "Faithful Port", which means that I did the very best I could			to duplicate the functionality of the original BASIC program in equivalent C code.			Variable names are as in the original code. Most of the functionality was easily replicable			with printf and scanf. The three GOSUBs had to be implemented as functions. 			Natually, there are a lot of gotos, all of the variables are global, */#include "stdio.h"#include "conio.h"#include "stdlib.h"/*	This comes from a BASIC game,	so naturally all of the variables	are global and have esoteric names.*/int d1;//total deathsint p1;//total starvation percentageint z;//year numberint p;//current populationint s;//current number of bushels of grainint h;//harvestint e;//grain eaten by ratsint y;//grain per acreint a;//acresint i;//new populationint q;//input variable, grain fed to peopleint d;//deaths, input variableint c;//random numbers, fed populationint l;//acres per personint n;//beep loop//gosubs are best implemented as functionsvoid gosub710();//not enough grainvoid gosub720();//not enough landvoid gosub800();//generate a random number in c(1-5)int main(int argc,char* argv[]){	//10 PRINT TAB(32);"HAMURABI"	printf("                                HAMURABI\n");	//20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"	printf("               CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");	//30 PRINT:PRINT:PRINT	printf("\n\n\n");	//80 PRINT "TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA"	printf("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\n");	//90 PRINT "FOR A TEN YEAR TERM OF OFFICE.":PRINT	printf("FOR A TEN YEAR TERM OF OFFICE.\n\n");	//95 D1=0:P1=0	d1=0;p1=0;	//100 Z=0:P=95:S=2800:H=3000:E-H-S	z=0;p=95;s=2800;h=3000;e=h-s;	//110 Y=3:A=H/Y:I=5:Q=1	y=3;a=h/y;i=5;q=1;line210:	//210 D=0	d=0;line215:	//215 PRINT:PRINT:PRINT "HAMURABI: I BEG TO REPORT TO YOU,":Z=Z+1	printf("\n\nHAMURABI: I BEG TO REPORT TO YOU,\n");z++;	//217 PRINT "IN YEAR";Z;",";D;"PEOPLE STARVED,";I;"CAME TO THE CITY,"	printf("IN YEAR %d, %d PEOPLE STARVED, %d CAME TO THE CITY,\n",z,d,i);	//218 P=P+I	p+=i;	//227 IF Q>0 THEN 230	if(q>0) goto line230;	//228 P=INT(P/2)	p/=2;	//229 PRINT "A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED."	printf("A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED.\n");line230:	//230 PRINT "POPULATION IS NOW";P	printf("POPULATION IS NOW %d.\n",p);	//232 PRINT "THE CITY NOW OWNS";A;"ACRES."	printf("THE CITY NOW OWNS %d ACRES.\n",a);	//235 PRINT "YOU HARVESTED";Y;"BUSHELS PER ACRE."	printf("YOU HARVESTED %d BUSHELS PER ACRE.\n",y);	//250 PRINT "RATS ATE";E;"BUSHELS."	printf("RATS ATE %d BUSHELS.\n",e);	//260 PRINT "YOU HOW HAVE";S;"BUSHELS IN STORE.":PRINT	printf("YOU HOW HAVE %d BUSHELS IN STORE.\n\n",s);	//270 IF Z=11 THEN 860	if(z==11) goto line860;	//310 C=INT(10*RND(1)):Y=C+17	c=rand()%10;y=c+17;	//312 PRINT "LAND IS TRADING AT";Y;"BUSHELS PER ACRE."	printf("LAND IS TRADING AT %d BUSHELS PER ACRE.\n",y);line320:	//320 PRINT "HOW MANY ACRES DO YOU WISH TO BUY";	printf("HOW MANY ACRES DO YOU WISH TO BUY?");	//321 INPUT Q:IF Q<0 THEN 850	scanf("%d",&q);if(q<0) goto line850;	//322 IF Y*Q	if((y*q)goto line330;	//323 GOSUB 710	gosub710();	//324 GOTO 320	goto line320;line330:	//330 IF Q=0 THEN 340	if(q==0) goto line340;	//331 A=A+Q:S=S-Y*Q:C=0	a+=q;s-=(y*q);c=0;	//334 GOTO 400	goto line400;line340:	//340 PRINT "HOW MANY ACRES DO YOU WISH TO SELL";	printf("HOW MANY ACRES DO YOU WISH TO SELL?");	//341 INPUT Q:IF Q<0 THEN 850	scanf("%d",&q);if(q<0) goto line850;	//342 IF Q	if(qgoto line350;	//343 GOSUB 720	gosub720();	//344 GOTO 340	goto line340;line350:	//350 A=A-Q:S=S+Y*Q:C=0	a-=q;s+=(y*q);c=0;line400:	//400 PRINT	printf("\n");line410:	//410 PRINT "HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE";	printf("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE?");	//411 INPUT Q	scanf("%d",&q);	//412 IF Q<0 THEN 850	if(q<0) goto line850;	//418 REM *** TRYING TO USE MORE GRAIN THAN IS IN SILOS?	//420 IF Q<=S THEN 430	if(q<=s) goto line430;	//421 GOSUB 710	gosub710();	//422 GOTO 410	goto line410;line430:	//430 S=S-Q:C=1:PRINT	s-=q;c=1;printf("\n");line440:	//440 PRINT "HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED";	printf("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED?");	//441 INPUT D: IF D=0 THEN 511	scanf("%d",&d);	//442 IF D<0 THEN 850	if(d<0) goto line850;	//444 REM *** TRYING TO PLANT MORE ACRES THAN YOU OWN?	//445 IF D<=A THEN 450	if(d<=a) goto line450;	//446 GOSUB 720	gosub720();	//447 GOTO 440	goto line440;	//449 REM *** ENOUGH GRAIN FOR SEED?line450:	//450 IF INT(D/2)<=S THEN 455	if((d/2)goto
line455;
//452 GOSUB 710
gosub710();
//453 GOTO 440
goto line440;

//454 REM *** ENOUGH PEOPLE TO TEND THE CROPS?
line455:
//455 IF D<10*P THEN 510
//BUG: Obviously, 1 unit of population can work 10 acres.
//Change: Changed code to allow maximum efficiency.
if(d<=(10*p)) goto line510;
//460 PRINT "BUT YOU HAVE ONLY";P;"PEOPLE TO TEND THE FIELDS! NOW THEN,"
printf("BUT YOU HAVE ONLY %d PEOPLE TO TEND THE FIELDS! NOW THEN,\n",p);
//470 GOTO 440
goto line440;

line510:
//510 S=S-INT(D/2)
s-=(d>>1);
//511 GOSUB 800
gosub800();
//512 REM *** A BOUNTIFUL HARVEST!
//515 Y=C:H=D*Y:E=0
y=c;h=d*y;e=0;
//521 GOSUB 800
gosub800();
//522 IF INT(C/2)<>C/2 THEN 530
if((c&1)==1) goto line530;
//523 REM *** RATS ARE RUNNING WILD!!
//525 E=INT(S/2)
e=s>>1;

line530:
//530 S=S-E+H
s=s-e+h;
//531 GOSUB 800
gosub800();
//532 REM *** LET'S HAVE SOME BABIES
//533 I=INT(C*(20*A+S)/P/100+1)
i=(c*(20*a+s)/p/100)+1;
//539 REM *** HOW MANY PEOPLE HAD FULL TUMMIES?
//540 C=INT(Q/20)
c=q/20;
//541 REM *** HORROR, A 15% CHANCE OF PLAGUE
//542 Q=INT(10*(2*RND(1)-.3))
q=10*((2*(rand()%100)-30)/100);
//550 IF P
if(pgoto
line210;
//551 REM *** STARVE ENOUGH FOR IMPEACHMENT?
//552 D=P-C:IF D>.45*P THEN 560
d=p-c;if(d>(45*p/100)) goto line560;
//553 P1=((Z-1)*P1+D*100/P)/Z
p1=((z-1)*p1+d*100/p)/z;
//555 P=C:D1=D1+D:GOTO 215
p=c;d1+=d;goto line215;

line560:
//560 PRINT:PRINT "YOU STARVED";D;"PEOPLE IN ONE YEAR!!!"
printf("\nYOU STARVED %d PEOPLE IN ONE YEAR!!!\n",d);

line565:
//565 PRINT "DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY"
printf("DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\n");
//566 PRINT "BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE"
printf("BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\n");
//567 PRINT "ALSO BEEN DECLARED NATIONAL FINK!!!!":GOTO 990
printf("ALSO BEEN DECLARED NATIONAL FINK!!!!\n");goto line990;

line850:
//850 PRINT:PRINT "HAMURABI: I CANNOT DO WHAT YOU WISH."
printf("\nHAMURABI: I CANNOT DO WHAT YOU WISH.\n");
//855 PRINT "GET YOURSELF ANOTHER STEWARD!!!"
printf("GET YOURSELF ANOTHER STEWARD!!!\n");
//857 GOTO 990
goto line990;

line860:
//860 PRINT "IN YOUR 10-YEAR TERM OF OFFICE,";P1;"PERCENT OF THE"
printf("IN YOUR 10-YEAR TERM OF OFFICE, %d PERCENT OF THE\n",p1);
//862 PRINT "POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF"
printf("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF\n");
//865 PRINT D1;"PEOPLE DIED!!":L=A/P
printf("%d PEOPLE DIED!!\n",d1);l=a/p;
//870 PRINT "YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH"
printf("YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH\n");
//875 PRINT L;"ACRES PER PERSON.":PRINT
printf("%d ACRES PER PERSON.\n\n",l);
//880 IF P1>33 THEN 565
if(p1>33) goto line565;
//885 IF L<7 THEN 565
if(l<7) goto line565;
//890 IF P1>10 THEN 940
if(p1>10) goto line940;
//892 IF L<9 THEN 940
if(l<9) goto line940;
//895 IF P1>3 THEN 960
if(p1>3) goto line960;
//896 IF L<10 THEN 960
if(l<10) goto line960;
//900 PRINT "A FANTASTIC PERFORMANCE!!! CHARLEMAGNE, DISRAELI, AND"
printf("A FANTASTIC PERFORMANCE!!! CHARLEMAGNE, DISRAELI, AND\n");
//905 PRINT "JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!":GOTO 990
printf("JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\n");goto line990;

line940:
//940 PRINT "YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVARN IV."
printf("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVARN IV.\n");
//945 PRINT "THE PEOPLE (REMAINING) FIND YOU AND UNPLEASANT RULE, AND,"
printf("THE PEOPLE (REMAINING) FIND YOU AND UNPLEASANT RULE, AND,\n");
//950 PRINT "FRANKLY, HATE YOUR GUTS!!":GOTO 990
printf("FRANKLY, HATE YOUR GUTS!!\n");goto line990;

line960:
//960 PRINT "YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT"
printf("YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\n");
//965 PRINT "REALLY WASN'T TOO BAD AT ALL. ";INT(P*.8(RND(1));"PEOPLE"
printf("REALLY WASN'T TOO BAD AT ALL. %d PEOPLE\n",rand()%((p*8)/10));
//970 PRINT "DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR"
printf("DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\n");
//975 PRINT "TRIVIAL PROBLEMS."
printf("TRIVIAL PROBLEMS.\n");

line990:
//990 PRINT: FOR N=1 TO 10:PRINT CHR$(7);:NEXT N
printf("\n");for(n=1;n<=10;n++) printf("\x07");
//995 PRINT "SO LONG FOR NOW.":PRINT
printf("SO LONG FOR NOW.\n\n");
//999 END
return(0);
}

void gosub710()
{
//710 PRINT "HAMURABI: THINK AGAIN. YOU HAVE ONLY"
printf("HAMURABI: THINK AGAIN. YOU HAVE ONLY\n");
//711 PRINT S;"BUSHELS OF GRAIN. NOW THEN,"
printf("%d BUSHELS OF GRAIN. NOW THEN,\n",s);
//712 RETURN
}

void gosub720()
{
//720 PRINT "HAMURABI: THINK AGAIN. YOU OWN ONLY";A;"ACRES. NOW THEN,"
printf("HAMURABI: THINK AGAIN. YOU OWN ONLY %d ACRES. NOW THEN,\n",a);
//730 RETURN
}

void gosub800()
{
//800 C=INT(RND(1)*5)+1
c=(rand()%5)+1;
//801 RETURN
}
[/SOURCE]

It winds up approximately as ugly as the original BASIC source. Cryptic global variables, some of which are reused for entirely different purposed. There are gotos and gosubs, magic number constants, and all manner of evil ickiness. The labels and function calls are based on line number, and are completely useless descriptively speaking.

"I can do better."

[SOURCE]/*	Hammurabi Version 1.0.1 ("Less Cryptic")    Copyright (C) 2006  Ernest S. Pazera    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA	Contact information:		ernestpazera@msn.com	"Original" game and source taken from:		BASIC Computer Games (Microcomputer Edition)		Edited by David H. Ahl		ISBN:0-89480-052-3	Version History:		1.0.1:			Less Cryptic			29MAY2006			Globals have been given descriptive names.			Functions have been given useful names.			Labels have been given useful names.			Recycled variables have been noted as overloaded, for later disambiguation.			Removed BASIC source from comments.			Added GameOverGood, GameTitle, GameInitialize.			Added gotos at the end of each game state, to facilitate moving the states into functions.			Now seeding random number generator during GameInitialize.			Some disambiquation flags for plague flag, price per acre and yield per acre.			Magic numbers have either vanished or been given TODO markers.		1.0.0: 			Faithful Port			29MAY2006			The initial version is a "Faithful Port", which means that I did the very best I could			to duplicate the functionality of the original BASIC program in equivalent C code.			Variable names are as in the original code. Most of the functionality was easily replicable			with printf and scanf. The three GOSUBs had to be implemented as functions. 			Natually, there are a lot of gotos, all of the variables are global, */#include "stdio.h"#include "conio.h"#include "stdlib.h"#include "time.h"enum{	INITIAL_POPULATION = 95,	INITIAL_POPULATION_INCREASE = 5,	INITIAL_BUSHELS = 2800,	INITIAL_HARVEST = 3000,	INITIAL_BUSHELS_YIELD_ACRE = 3,	INITIAL_YEAR = 0,	FINAL_YEAR = 10,	PRICE_PER_ACRE_MINIMUM = 17,	PRICE_PER_ACRE_MAXIMUM = 26,	ACRES_PER_BUSHEL_PLANTED = 2,	ACRES_PLANTED_PER_PERSON = 10,	BUSHELS_EATEN_PER_PERSON = 20,	IMPEACHMENT_PERCENTAGE = 45,	PERCENTAGE_STARVED_LOSE = 33,	PERCENTAGE_STARVED_BAD = 10,	PERCENTAGE_STARVED_MEDIOCRE = 3,	ACRES_PER_PERSON_LOSE = 7,	ACRES_PER_PERSON_BAD = 9,	ACRES_PER_PERSON_MEDIOCRE = 10,	ASSASSINATION_PERCENTAGE = 80};/*	This comes from a BASIC game,	so naturally all of the variables	are global and have esoteric names.*/int total_deaths;//total deathsint overall_percentage_starved;//total starvation percentageint current_year;//year numberint current_population;//current populationint current_bushels;//current number of bushelsint bushels_harvested;//harvestint bushels_destroyed;//bushels eaten by ratsint bushels_per_acre;//bushels per acre **OVERLOADED**int current_acres;//acresint population_increase;//new populationint bushels_eaten;//acres purchased, acres sold, grain fed to people, plague flag **OVERLOADED**int current_deaths;//deaths, acres planted **OVERLOADED**int random_number;//random numbers, fed population **OVERLOADED**int acres_per_person;//acres per personint beep_count;//beep loop//gosubs are best implemented as functionsvoid NotEnoughGrain();//not enough grainvoid NotEnoughAcres();//not enough landvoid GenerateRandomNumber();//generate a random number in random_number(1-5)int main(int argc,char* argv[]){	goto GameTitle;GameTitle:	printf("                                HAMURABI\n");	printf("               CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");	printf("\n\n\n");	goto GameInitialize;GameInitialize:	srand((unsigned int)time(0));	printf("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\n");	printf("FOR A TEN YEAR TERM OF OFFICE.\n\n");	total_deaths=0;	overall_percentage_starved=0;	current_year=INITIAL_YEAR;	current_population=INITIAL_POPULATION;	current_bushels=INITIAL_BUSHELS;	bushels_harvested=INITIAL_HARVEST;	bushels_destroyed=bushels_harvested-current_bushels;	bushels_per_acre=INITIAL_BUSHELS_YIELD_ACRE;//TODO: yield, not price	current_acres=bushels_harvested/bushels_per_acre;//TODO: yield, not price	population_increase=INITIAL_POPULATION_INCREASE;	bushels_eaten=1;//TODO: this is the plague flag	goto NoDeaths;NoDeaths:	current_deaths=0;	goto StartOfTurn;StartOfTurn:	printf("\n\nHAMURABI: I BEG TO REPORT TO YOU,\n");current_year++;	printf("IN YEAR %d, %d PEOPLE STARVED, %d CAME TO THE CITY,\n",current_year,current_deaths,population_increase);	current_population+=population_increase;	if(bushels_eaten>0) goto TurnReport;//TODO: this is the plague flag	//TODO: fix it so that the effects of a plague are modifiable	current_population/=2;	printf("A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED.\n");	goto TurnReport;TurnReport:	printf("POPULATION IS NOW %d.\n",current_population);	printf("THE CITY NOW OWNS %d ACRES.\n",current_acres);	printf("YOU HARVESTED %d BUSHELS PER ACRE.\n",bushels_per_acre);//TODO: yield, not price	printf("RATS ATE %d BUSHELS.\n",bushels_destroyed);	printf("YOU HOW HAVE %d BUSHELS IN STORE.\n\n",current_bushels);	if(current_year>FINAL_YEAR) goto GameOverDecideFate;	random_number=rand()%(PRICE_PER_ACRE_MAXIMUM-PRICE_PER_ACRE_MINIMUM+1);	bushels_per_acre=random_number+PRICE_PER_ACRE_MINIMUM;//TODO: this is price, not yield	printf("LAND IS TRADING AT %d BUSHELS PER ACRE.\n",bushels_per_acre);//TODO: price, not yield	goto PurchaseAcresPrompt;PurchaseAcresPrompt:	printf("HOW MANY ACRES DO YOU WISH TO BUY?");	scanf("%d",&bushels_eaten);if(bushels_eaten<0) goto GameOverBadInput;	if((bushels_per_acre*bushels_eaten)goto
PurchaseAcres;//TODO: price, not yield
NotEnoughGrain();
goto PurchaseAcresPrompt;

PurchaseAcres:
if(bushels_eaten==0) goto SellAcresPrompt;
current_acres+=bushels_eaten;
current_bushels-=(bushels_per_acre*bushels_eaten);//TODO: price, not yield
random_number=0;
goto DoneBuyingAndSelling;

SellAcresPrompt:
printf("HOW MANY ACRES DO YOU WISH TO SELL?");
scanf("%d",&bushels_eaten);
if(bushels_eaten<0) goto GameOverBadInput;
if(bushels_eatengoto SellAcres;
NotEnoughAcres();
goto SellAcresPrompt;

SellAcres:
current_acres-=bushels_eaten;
current_bushels+=(bushels_per_acre*bushels_eaten);//TODO: price, not yield
random_number=0;
goto DoneBuyingAndSelling;

DoneBuyingAndSelling:
printf("\n");
goto BushelsEatenPrompt;

BushelsEatenPrompt:
printf("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE?");
scanf("%d",&bushels_eaten);
if(bushels_eaten<0) goto GameOverBadInput;
//TRYING TO USE MORE GRAIN THAN IS IN SILOS?
if(bushels_eaten<=current_bushels) goto BushelsEaten;
NotEnoughGrain();
goto BushelsEatenPrompt;

BushelsEaten:
current_bushels-=bushels_eaten;
random_number=1;
printf("\n");
goto AcresPlanetedPrompt;

AcresPlanetedPrompt:
printf("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED?");
scanf("%d",&current_deaths);
if(current_deaths<0) goto GameOverBadInput;
//TRYING TO PLANT MORE ACRES THAN YOU OWN?
if(current_deaths<=current_acres) goto EnoughBushelsForPlanting;
NotEnoughAcres();
goto AcresPlanetedPrompt;


EnoughBushelsForPlanting:
//ENOUGH GRAIN FOR SEED?
if((current_deaths/ACRES_PER_BUSHEL_PLANTED)goto EnoughPeopleForPlanting;
NotEnoughGrain();
goto AcresPlanetedPrompt;

EnoughPeopleForPlanting:
//ENOUGH PEOPLE TO TEND THE CROPS?
if(current_deaths<=(ACRES_PLANTED_PER_PERSON*current_population)) goto DoHarvest;
printf("BUT YOU HAVE ONLY %d PEOPLE TO TEND THE FIELDS! NOW THEN,\n",current_population);
goto AcresPlanetedPrompt;

DoHarvest:
current_bushels-=(current_deaths/ACRES_PER_BUSHEL_PLANTED);
GenerateRandomNumber();
//A BOUNTIFUL HARVEST!
bushels_per_acre=random_number;//TODO: yield, not price
bushels_harvested=current_deaths*bushels_per_acre;//TODO: yield, not price
bushels_destroyed=0;
GenerateRandomNumber();
//TODO: a better way of making the rats happen 40% of the time
if((random_number&1)==1) goto EndOfTurn;
//RATS ARE RUNNING WILD!!
//TODO: a better way to customize how much of the food the rats will eat
bushels_destroyed=current_bushels/2;
goto EndOfTurn;

EndOfTurn:
current_bushels=current_bushels-bushels_destroyed+bushels_harvested;
GenerateRandomNumber();
//LET'S HAVE SOME BABIES
population_increase=(random_number*(20*current_acres+current_bushels)/current_population/100)+1;//TODO: this formula is too complicated
//HOW MANY PEOPLE HAD FULL TUMMIES?
random_number=bushels_eaten/BUSHELS_EATEN_PER_PERSON;
//HORROR, A 15% CHANCE OF PLAGUE
bushels_eaten=10*((2*(rand()%100)-30)/100);//TODO: this is the plague flag, and this formula is too complicated
if(current_populationgoto NoDeaths;
//STARVE ENOUGH FOR IMPEACHMENT?
current_deaths=current_population-random_number;
if(current_deaths>(IMPEACHMENT_PERCENTAGE*current_population/100)) goto Impeachment;
overall_percentage_starved=((current_year-INITIAL_YEAR-1)*overall_percentage_starved+current_deaths*100/current_population)/(current_year-INITIAL_YEAR);//TODO: this formula is too complicated
current_population=random_number;
total_deaths+=current_deaths;
goto StartOfTurn;

Impeachment:
printf("\nYOU STARVED %d PEOPLE IN ONE YEAR!!!\n",current_deaths);
goto GameOverLose;

GameOverLose:
printf("DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\n");
printf("BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\n");
printf("ALSO BEEN DECLARED NATIONAL FINK!!!!\n");
goto ExitGame;

GameOverBadInput:
printf("\nHAMURABI: I CANNOT DO WHAT YOU WISH.\n");
printf("GET YOURSELF ANOTHER STEWARD!!!\n");
goto ExitGame;

GameOverDecideFate:
printf("IN YOUR 10-YEAR TERM OF OFFICE, %d PERCENT OF THE\n",overall_percentage_starved);
printf("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF\n");
printf("%d PEOPLE DIED!!\n",total_deaths);
acres_per_person=current_acres/current_population;
printf("YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH\n");
printf("%d ACRES PER PERSON.\n\n",acres_per_person);
if(overall_percentage_starved>PERCENTAGE_STARVED_LOSE) goto GameOverLose;
if(acres_per_persongoto GameOverLose;
if(overall_percentage_starved>PERCENTAGE_STARVED_BAD) goto GameOverBad;
if(acres_per_persongoto GameOverBad;
if(overall_percentage_starved>PERCENTAGE_STARVED_MEDIOCRE) goto GameOverMediocre;
if(acres_per_persongoto GameOverMediocre;
goto GameOverGood;

GameOverGood:
printf("A FANTASTIC PERFORMANCE!!! CHARLEMAGNE, DISRAELI, AND\n");
printf("JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\n");
goto ExitGame;

GameOverBad:
printf("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVARN IV.\n");
printf("THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER AND,\n");
printf("FRANKLY, HATE YOUR GUTS!!\n");
goto ExitGame;

GameOverMediocre:
printf("YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\n");
printf("REALLY WASN'T TOO BAD AT ALL. %d PEOPLE\n",rand()%((current_population*ASSASSINATION_PERCENTAGE)/100));//TODO: this calculation is too complex
printf("DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\n");
printf("TRIVIAL PROBLEMS.\n");
goto ExitGame;

ExitGame:
printf("\n");for(beep_count=1;beep_count<=10;beep_count++) printf("\x07");
printf("SO LONG FOR NOW.\n\n");

return(0);
}

void NotEnoughGrain()
{
printf("HAMURABI: THINK AGAIN. YOU HAVE ONLY\n");
printf("%d BUSHELS OF GRAIN. NOW THEN,\n",current_bushels);
}

void NotEnoughAcres()
{
printf("HAMURABI: THINK AGAIN. YOU OWN ONLY %d ACRES. NOW THEN,\n",current_acres);
}

void GenerateRandomNumber()
{
random_number=(rand()%5)+1;
}
[/SOURCE]

Still a lot of gotos, but at least the names of things are more meaningful. You can see a couple of TODO lines as I went through here.

"Still, I can do better."

[SOURCE]/*	Hammurabi Version 1.0.2 ("")    Copyright (C) 2006  Ernest S. Pazera    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA	Contact information:		ernestpazera@msn.com	"Original" game and source taken from:		BASIC Computer Games (Microcomputer Edition)		Edited by David H. Ahl		ISBN:0-89480-052-3	Version History:		1.0.2:			29MAY2006			Switched from gotos to game states.			Disambiguated variables.			Scoped variables locally where possible.			Moved to C++, but only for using enumerations without first specifying the keyword 'enum'.		1.0.1:			Less Cryptic			29MAY2006			Globals have been given descriptive names.			Functions have been given useful names.			Labels have been given useful names.			Recycled variables have been noted as overloaded, for later disambiguation.			Removed BASIC source from comments.			Added GameOverGood, GameTitle, GameInitialize.			Added gotos at the end of each game state, to facilitate moving the states into functions.			Now seeding random number generator during GameInitialize.			Some disambiquation flags for plague flag, price per acre and yield per acre.			Magic numbers have either vanished or been given TODO markers.		1.0.0: 			Faithful Port			29MAY2006			The initial version is a "Faithful Port", which means that I did the very best I could			to duplicate the functionality of the original BASIC program in equivalent C code.			Variable names are as in the original code. Most of the functionality was easily replicable			with printf and scanf. The three GOSUBs had to be implemented as functions. 			Natually, there are a lot of gotos, all of the variables are global, */#include "stdio.h"#include "conio.h"#include "stdlib.h"#include "time.h"enum state_t{	STATE_GAMETITLE,	STATE_GAMEINITIALIZE,	STATE_NODEATHS,	STATE_STARTOFTURN,	STATE_TURNREPORT,	STATE_PURCHASEACRESPROMPT,	STATE_PURCHASEACRES,	STATE_SELLACRESPROMPT,	STATE_SELLACRES,	STATE_DONEBUYINGANDSELLING,	STATE_BUSHELSEATENPROMPT,	STATE_BUSHELSEATEN,	STATE_ACRESPLANTEDPROMPT,	STATE_ENOUGHBUSHELSFORPLANTING,	STATE_ENOUGHPEOPLEFORPLANTING,	STATE_DOHARVEST,	STATE_ENDOFTURN,	STATE_IMPEACHMENT,	STATE_GAMEOVERLOSE,	STATE_GAMEOVERBADINPUT,	STATE_GAMEOVERDECIDEFATE,	STATE_GAMEOVERGOOD,	STATE_GAMEOVERBAD,	STATE_GAMEOVERMEDIOCRE,	STATE_EXITGAME,	STATE_COUNT};enum{	INITIAL_POPULATION = 95,	INITIAL_POPULATION_INCREASE = 5,	INITIAL_BUSHELS = 2800,	INITIAL_HARVEST = 3000,	INITIAL_BUSHELS_YIELD_ACRE = 3,	INITIAL_YEAR = 0,	FINAL_YEAR = 10,	PRICE_PER_ACRE_MINIMUM = 17,	PRICE_PER_ACRE_MAXIMUM = 26,	ACRES_PER_BUSHEL_PLANTED = 2,	ACRES_PLANTED_PER_PERSON = 10,	BUSHELS_EATEN_PER_PERSON = 20,	IMPEACHMENT_PERCENTAGE = 45,	PERCENTAGE_STARVED_LOSE = 33,	PERCENTAGE_STARVED_BAD = 10,	PERCENTAGE_STARVED_MEDIOCRE = 3,	ACRES_PER_PERSON_LOSE = 7,	ACRES_PER_PERSON_BAD = 9,	ACRES_PER_PERSON_MEDIOCRE = 10,	ASSASSINATION_PERCENTAGE = 80,	BUSHEL_YIELD_PER_ACRE_MINIMUM = 1,	BUSHEL_YIELD_PER_ACRE_MAXIMUM = 5,	PERCENT_CHANCE_RATS = 40,	PERCENT_CHANCE_PLAGUE = 15};/*	This comes from a BASIC game,	so naturally all of the variables	are global and have esoteric names.*/int total_deaths;//total deathsint overall_percentage_starved;//total starvation percentageint current_year;//year numberint current_population;//current populationint current_bushels;//current number of bushelsint bushels_harvested;//harvestint bushels_destroyed;//bushels eaten by ratsint bushels_yield_per_acre;//bushels yield per acreint bushels_price_per_acre;//bushels price per acreint current_acres;//acresint population_increase;//new populationint bushels_eaten;//grain fed to peopleint acres_purchased;//acres purchasedint acres_sold;//acres sold int current_deaths;//deathsint acres_planted;//acres plantedstate_t state;//game statevoid NotEnoughGrain();void NotEnoughAcres();int GenerateRandomNumber(int minimum,int maximum);//game state functionsstate_t GameTitle();state_t GameInitialize();state_t NoDeaths();state_t StartOfTurn();state_t TurnReport();state_t PurchaseAcresPrompt();state_t PurchaseAcres();state_t SellAcresPrompt();state_t SellAcres();state_t DoneBuyingAndSelling();state_t BushelsEatenPrompt();state_t BushelsEaten();state_t AcresPlantedPrompt();state_t EnoughBushelsForPlanting();state_t EnoughPeopleForPlanting();state_t DoHarvest();state_t EndOfTurn();state_t Impeachment();state_t GameOverLose();state_t GameOverBadInput();state_t GameOverDecideFate();state_t GameOverGood();state_t GameOverBad();state_t GameOverMediocre();state_t ExitGame();int main(int argc,char* argv[]){	for(state = STATE_GAMETITLE;state!=STATE_COUNT;)	{		switch(state)		{		case STATE_GAMETITLE:			{				state = GameTitle();			}break;		case STATE_GAMEINITIALIZE:			{				state = GameInitialize();			}break;		case STATE_NODEATHS:			{				state = NoDeaths();			}break;		case STATE_STARTOFTURN:			{				state = StartOfTurn();			}break;		case STATE_TURNREPORT:			{				state = TurnReport();			}break;		case STATE_PURCHASEACRESPROMPT:			{				state = PurchaseAcresPrompt();			}break;		case STATE_PURCHASEACRES:			{				state = PurchaseAcres();			}break;		case STATE_SELLACRESPROMPT:			{				state = SellAcresPrompt();			}break;		case STATE_SELLACRES:			{				state = SellAcres();			}break;		case STATE_DONEBUYINGANDSELLING:			{				state = DoneBuyingAndSelling();			}break;		case STATE_BUSHELSEATENPROMPT:			{				state = BushelsEatenPrompt();			}break;		case STATE_BUSHELSEATEN:			{				state = BushelsEaten();			}break;		case STATE_ACRESPLANTEDPROMPT:			{				state = AcresPlantedPrompt();			}break;		case STATE_ENOUGHBUSHELSFORPLANTING:			{				state = EnoughBushelsForPlanting();			}break;		case STATE_ENOUGHPEOPLEFORPLANTING:			{				state = EnoughPeopleForPlanting();			}break;		case STATE_DOHARVEST:			{				state = DoHarvest();			}break;		case STATE_ENDOFTURN:			{				state = EndOfTurn();			}break;		case STATE_IMPEACHMENT:			{				state = Impeachment();			}break;		case STATE_GAMEOVERLOSE:			{				state = GameOverLose();			}break;		case STATE_GAMEOVERBADINPUT:			{				state = GameOverBadInput();			}break;		case STATE_GAMEOVERDECIDEFATE:			{				state = GameOverDecideFate();			}break;		case STATE_GAMEOVERGOOD:			{				state = GameOverGood();			}break;		case STATE_GAMEOVERBAD:			{				state = GameOverBad();			}break;		case STATE_GAMEOVERMEDIOCRE:			{				state = GameOverMediocre();			}break;		case STATE_EXITGAME:			{				state = ExitGame();			}break;		default:			{				state=STATE_COUNT;			}break;		}	}	return(0);}void NotEnoughGrain(){	printf("HAMURABI: THINK AGAIN. YOU HAVE ONLY\n");	printf("%d BUSHELS OF GRAIN. NOW THEN,\n",current_bushels);}void NotEnoughAcres(){	printf("HAMURABI: THINK AGAIN. YOU OWN ONLY %d ACRES. NOW THEN,\n",current_acres);}int GenerateRandomNumber(int minimum,int maximum){	return((rand()%(maximum-minimum+1))+minimum);}state_t GameTitle()//{	printf("                                HAMURABI\n");	printf("               CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");	printf("\n\n\n");	return(STATE_GAMEINITIALIZE);}state_t GameInitialize(){	srand((unsigned int)time(0));	printf("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\n");	printf("FOR A TEN YEAR TERM OF OFFICE.\n\n");	total_deaths=0;	overall_percentage_starved=0;	current_year=INITIAL_YEAR;	current_population=INITIAL_POPULATION;	current_bushels=INITIAL_BUSHELS;	bushels_harvested=INITIAL_HARVEST;	bushels_destroyed=bushels_harvested-current_bushels;	bushels_yield_per_acre=INITIAL_BUSHELS_YIELD_ACRE;	current_acres=bushels_harvested/bushels_yield_per_acre;	population_increase=INITIAL_POPULATION_INCREASE;	return(STATE_NODEATHS);}state_t NoDeaths(){	current_deaths=0;	return(STATE_STARTOFTURN);}state_t StartOfTurn(){	bool plague_flag=false;	if(current_year>INITIAL_YEAR)	{		plague_flag=GenerateRandomNumber(1,100)<=PERCENT_CHANCE_PLAGUE;	}	printf("\n\nHAMURABI: I BEG TO REPORT TO YOU,\n");	current_year++;	printf("IN YEAR %d, %d PEOPLE STARVED, %d CAME TO THE CITY,\n",current_year,current_deaths,population_increase);	current_population+=population_increase;	if(!plague_flag) return(STATE_TURNREPORT);	//TODO: fix it so that the effects of a plague are modifiable	current_population/=2;	printf("A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED.\n");	return(STATE_TURNREPORT);}state_t TurnReport(){	printf("POPULATION IS NOW %d.\n",current_population);	printf("THE CITY NOW OWNS %d ACRES.\n",current_acres);	printf("YOU HARVESTED %d BUSHELS PER ACRE.\n",bushels_yield_per_acre);	printf("RATS ATE %d BUSHELS.\n",bushels_destroyed);	printf("YOU HOW HAVE %d BUSHELS IN STORE.\n\n",current_bushels);	if(current_year>FINAL_YEAR) return(STATE_GAMEOVERDECIDEFATE);	bushels_price_per_acre=GenerateRandomNumber(PRICE_PER_ACRE_MINIMUM,PRICE_PER_ACRE_MAXIMUM);	printf("LAND IS TRADING AT %d BUSHELS PER ACRE.\n",bushels_price_per_acre);	return(STATE_PURCHASEACRESPROMPT);}state_t PurchaseAcresPrompt(){	printf("HOW MANY ACRES DO YOU WISH TO BUY?");	scanf("%d",&acres_purchased);if(acres_purchased<0) return(STATE_GAMEOVERBADINPUT);	if((bushels_price_per_acre*acres_purchased)return
(STATE_PURCHASEACRES);
NotEnoughGrain();
return(STATE_PURCHASEACRESPROMPT);
}

state_t PurchaseAcres()
{
if(acres_purchased==0) return(STATE_SELLACRESPROMPT);
current_acres+=acres_purchased;
current_bushels-=(bushels_price_per_acre*acres_purchased);
return(STATE_DONEBUYINGANDSELLING);
}

state_t SellAcresPrompt()
{
printf("HOW MANY ACRES DO YOU WISH TO SELL?");
scanf("%d",&acres_sold);
if(acres_sold<0) return(STATE_GAMEOVERBADINPUT);
if(acres_soldreturn(STATE_SELLACRES);
NotEnoughAcres();
return(STATE_SELLACRESPROMPT);
}

state_t SellAcres()
{
current_acres-=acres_sold;
current_bushels+=(bushels_price_per_acre*acres_sold);
return(STATE_DONEBUYINGANDSELLING);
}

state_t DoneBuyingAndSelling()
{
printf("\n");
return(STATE_BUSHELSEATENPROMPT);
}

state_t BushelsEatenPrompt()
{
printf("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE?");
scanf("%
0 likes 1 comments

Comments

johnhattan
May 30, 2006 09:58 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement

Latest Entries

Music To My Ears

1714 views

Getting There...

1977 views

Guess Chess

1876 views

iPhone JetLag

1827 views

iPhone JetLag

1670 views
Advertisement