├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── NEWS ├── README ├── README.markdown ├── configure.ac ├── doc └── HMRABI ├── headers └── city.h └── src ├── Makefile.am ├── city.c └── main.c /AUTHORS: -------------------------------------------------------------------------------- 1 | Brian L. Troutwine -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010 Brian L. Troutwine 4 | 5 | Permission is hereby granted, free of charge, to any person 6 | obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without 8 | restriction, including without limitation the rights to use, 9 | copy, modify, merge, publish, distribute, sublicense, and/or 10 | sell copies of the Software, and to permit persons to whom the 11 | Software is furnished to do so, subject to the following 12 | conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the 16 | Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 19 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 20 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 21 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 22 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | Please peruse the outputs of 'git log'. 2 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006, 2007 Free Software Foundation, Inc. 6 | 7 | This file is free documentation; the Free Software Foundation gives 8 | unlimited permission to copy, distribute and modify it. 9 | 10 | Basic Installation 11 | ================== 12 | 13 | Briefly, the shell commands `./configure; make; make install' should 14 | configure, build, and install this package. The following 15 | more-detailed instructions are generic; see the `README' file for 16 | instructions specific to this package. 17 | 18 | The `configure' shell script attempts to guess correct values for 19 | various system-dependent variables used during compilation. It uses 20 | those values to create a `Makefile' in each directory of the package. 21 | It may also create one or more `.h' files containing system-dependent 22 | definitions. Finally, it creates a shell script `config.status' that 23 | you can run in the future to recreate the current configuration, and a 24 | file `config.log' containing compiler output (useful mainly for 25 | debugging `configure'). 26 | 27 | It can also use an optional file (typically called `config.cache' 28 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 29 | the results of its tests to speed up reconfiguring. Caching is 30 | disabled by default to prevent problems with accidental use of stale 31 | cache files. 32 | 33 | If you need to do unusual things to compile the package, please try 34 | to figure out how `configure' could check whether to do them, and mail 35 | diffs or instructions to the address given in the `README' so they can 36 | be considered for the next release. If you are using the cache, and at 37 | some point `config.cache' contains results you don't want to keep, you 38 | may remove or edit it. 39 | 40 | The file `configure.ac' (or `configure.in') is used to create 41 | `configure' by a program called `autoconf'. You need `configure.ac' if 42 | you want to change it or regenerate `configure' using a newer version 43 | of `autoconf'. 44 | 45 | The simplest way to compile this package is: 46 | 47 | 1. `cd' to the directory containing the package's source code and type 48 | `./configure' to configure the package for your system. 49 | 50 | Running `configure' might take a while. While running, it prints 51 | some messages telling which features it is checking for. 52 | 53 | 2. Type `make' to compile the package. 54 | 55 | 3. Optionally, type `make check' to run any self-tests that come with 56 | the package. 57 | 58 | 4. Type `make install' to install the programs and any data files and 59 | documentation. 60 | 61 | 5. You can remove the program binaries and object files from the 62 | source code directory by typing `make clean'. To also remove the 63 | files that `configure' created (so you can compile the package for 64 | a different kind of computer), type `make distclean'. There is 65 | also a `make maintainer-clean' target, but that is intended mainly 66 | for the package's developers. If you use it, you may have to get 67 | all sorts of other programs in order to regenerate files that came 68 | with the distribution. 69 | 70 | 6. Often, you can also type `make uninstall' to remove the installed 71 | files again. 72 | 73 | Compilers and Options 74 | ===================== 75 | 76 | Some systems require unusual options for compilation or linking that the 77 | `configure' script does not know about. Run `./configure --help' for 78 | details on some of the pertinent environment variables. 79 | 80 | You can give `configure' initial values for configuration parameters 81 | by setting variables in the command line or in the environment. Here 82 | is an example: 83 | 84 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 85 | 86 | *Note Defining Variables::, for more details. 87 | 88 | Compiling For Multiple Architectures 89 | ==================================== 90 | 91 | You can compile the package for more than one kind of computer at the 92 | same time, by placing the object files for each architecture in their 93 | own directory. To do this, you can use GNU `make'. `cd' to the 94 | directory where you want the object files and executables to go and run 95 | the `configure' script. `configure' automatically checks for the 96 | source code in the directory that `configure' is in and in `..'. 97 | 98 | With a non-GNU `make', it is safer to compile the package for one 99 | architecture at a time in the source code directory. After you have 100 | installed the package for one architecture, use `make distclean' before 101 | reconfiguring for another architecture. 102 | 103 | Installation Names 104 | ================== 105 | 106 | By default, `make install' installs the package's commands under 107 | `/usr/local/bin', include files under `/usr/local/include', etc. You 108 | can specify an installation prefix other than `/usr/local' by giving 109 | `configure' the option `--prefix=PREFIX'. 110 | 111 | You can specify separate installation prefixes for 112 | architecture-specific files and architecture-independent files. If you 113 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 114 | PREFIX as the prefix for installing programs and libraries. 115 | Documentation and other data files still use the regular prefix. 116 | 117 | In addition, if you use an unusual directory layout you can give 118 | options like `--bindir=DIR' to specify different values for particular 119 | kinds of files. Run `configure --help' for a list of the directories 120 | you can set and what kinds of files go in them. 121 | 122 | If the package supports it, you can cause programs to be installed 123 | with an extra prefix or suffix on their names by giving `configure' the 124 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 125 | 126 | Optional Features 127 | ================= 128 | 129 | Some packages pay attention to `--enable-FEATURE' options to 130 | `configure', where FEATURE indicates an optional part of the package. 131 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 132 | is something like `gnu-as' or `x' (for the X Window System). The 133 | `README' should mention any `--enable-' and `--with-' options that the 134 | package recognizes. 135 | 136 | For packages that use the X Window System, `configure' can usually 137 | find the X include and library files automatically, but if it doesn't, 138 | you can use the `configure' options `--x-includes=DIR' and 139 | `--x-libraries=DIR' to specify their locations. 140 | 141 | Specifying the System Type 142 | ========================== 143 | 144 | There may be some features `configure' cannot figure out automatically, 145 | but needs to determine by the type of machine the package will run on. 146 | Usually, assuming the package is built to be run on the _same_ 147 | architectures, `configure' can figure that out, but if it prints a 148 | message saying it cannot guess the machine type, give it the 149 | `--build=TYPE' option. TYPE can either be a short name for the system 150 | type, such as `sun4', or a canonical name which has the form: 151 | 152 | CPU-COMPANY-SYSTEM 153 | 154 | where SYSTEM can have one of these forms: 155 | 156 | OS KERNEL-OS 157 | 158 | See the file `config.sub' for the possible values of each field. If 159 | `config.sub' isn't included in this package, then this package doesn't 160 | need to know the machine type. 161 | 162 | If you are _building_ compiler tools for cross-compiling, you should 163 | use the option `--target=TYPE' to select the type of system they will 164 | produce code for. 165 | 166 | If you want to _use_ a cross compiler, that generates code for a 167 | platform different from the build platform, you should specify the 168 | "host" platform (i.e., that on which the generated programs will 169 | eventually be run) with `--host=TYPE'. 170 | 171 | Sharing Defaults 172 | ================ 173 | 174 | If you want to set default values for `configure' scripts to share, you 175 | can create a site shell script called `config.site' that gives default 176 | values for variables like `CC', `cache_file', and `prefix'. 177 | `configure' looks for `PREFIX/share/config.site' if it exists, then 178 | `PREFIX/etc/config.site' if it exists. Or, you can set the 179 | `CONFIG_SITE' environment variable to the location of the site script. 180 | A warning: not all `configure' scripts look for a site script. 181 | 182 | Defining Variables 183 | ================== 184 | 185 | Variables not defined in a site shell script can be set in the 186 | environment passed to `configure'. However, some packages may run 187 | configure again during the build, and the customized values of these 188 | variables may be lost. In order to avoid this problem, you should set 189 | them in the `configure' command line, using `VAR=value'. For example: 190 | 191 | ./configure CC=/usr/local2/bin/gcc 192 | 193 | causes the specified `gcc' to be used as the C compiler (unless it is 194 | overridden in the site shell script). 195 | 196 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 197 | an Autoconf bug. Until the bug is fixed you can use this workaround: 198 | 199 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 200 | 201 | `configure' Invocation 202 | ====================== 203 | 204 | `configure' recognizes the following options to control how it operates. 205 | 206 | `--help' 207 | `-h' 208 | Print a summary of the options to `configure', and exit. 209 | 210 | `--version' 211 | `-V' 212 | Print the version of Autoconf used to generate the `configure' 213 | script, and exit. 214 | 215 | `--cache-file=FILE' 216 | Enable the cache: use and save the results of the tests in FILE, 217 | traditionally `config.cache'. FILE defaults to `/dev/null' to 218 | disable caching. 219 | 220 | `--config-cache' 221 | `-C' 222 | Alias for `--cache-file=config.cache'. 223 | 224 | `--quiet' 225 | `--silent' 226 | `-q' 227 | Do not print messages saying which checks are being made. To 228 | suppress all normal output, redirect it to `/dev/null' (any error 229 | messages will still be shown). 230 | 231 | `--srcdir=DIR' 232 | Look for the package's source code in directory DIR. Usually 233 | `configure' can determine that directory automatically. 234 | 235 | `configure' also accepts some other, not widely useful, options. Run 236 | `configure --help' for more details. 237 | 238 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = src -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | 2010-06-28 2 | 3 | * Added autotools build infrastructure. (BLT) 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.markdown -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Hamurabi: Classic BASIC gaming. 2 | 3 | An MIT licensed, C99 implementation of the classic BASIC game 4 | hamurabi. Useful for boostrapping build systems, dreaming of a 5 | life that can never be. 6 | 7 | ## What you get. 8 | 9 | For history's sake, the HMRABBI by Peter Turnbull is 10 | included. Of primary interest are going to be: 11 | 12 | * main.c :: User interaction, state machine. 13 | * city.{c,h} :: City structure, manipulation functions. 14 | 15 | This being a quick hack, comments are minimal but it shouldn't 16 | be _too_ hard to untangle. The primary goal in the translation 17 | was to separate user I/O from the core computations. In some 18 | sense this is not yet complete: the state machine is not yet 19 | separated from user I/O. Still, it is now _far_ simpler to 20 | swap out the command-driven interface with, say, ncurses or a 21 | socket. 22 | 23 | As with any translation, there was some leeway taken. If I 24 | went too far, report it as a bug! 25 | 26 | ## What I'll think is nifty. 27 | 28 | There's certainly possibility for improvement. Here's a list 29 | of things I'd readily accept: 30 | 31 | * Curses interface, 32 | * documentation (source comments or otherwise) and 33 | * Debian package infrastructure. 34 | 35 | If it's not on the list, send me a patch: I'll probably like 36 | it! -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([hamurabi], [0.0.2], [brian@troutwine.us]) 2 | AM_INIT_AUTOMAKE([-Wall -Werror]) 3 | 4 | AC_PROG_CC_C99 5 | 6 | AC_CHECK_HEADERS([stdint.h errno.h limits.h]) 7 | 8 | AC_CONFIG_HEADERS([config.h]) 9 | AC_CONFIG_FILES([Makefile src/Makefile]) 10 | AC_OUTPUT -------------------------------------------------------------------------------- /doc/HMRABI: -------------------------------------------------------------------------------- 1 | 10 REM *** CONVERTED FROM THE ORIGINAL FOCAL PROGRAM AND MODIFIED 2 | 20 REM *** FOR EDUSYSTEM 70 BY DAVID AHL, DIGITAL 3 | 30 REM *** MODIFIED FOR 8K MICROSOFT BASIC BY PETER TURNBULL 4 | 80 PRINT "TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA" 5 | 85 PRINT "SUCCESSFULLY FOR A 10-YR TERM OF OFFICE.":PRINT 6 | 90 REM RANDOMIZE REMOVED 7 | 95 D1=0:P1=0 8 | 110 Z=0:P=95:S=2800:H=3000:E=H-S 9 | 120 Y=3:A=H/Y:I=5:Q=1 10 | 210 D=0 11 | 215 PRINT:PRINT:PRINT "HAMURABI: I BEG TO REPORT TO YOU,":Z=Z+1 12 | 217 PRINT "IN YEAR"Z","D"PEOPLE STARVED,"I"CAME TO THE CITY." 13 | 218 P=P+I 14 | 227 IF Q>0 THEN 230 15 | 228 P=INT(P/2) 16 | 229 PRINT "A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED." 17 | 230 PRINT "POPULATION IS NOW"P 18 | 232 PRINT "THE CITY NOW OWNS"A"ACRES." 19 | 235 PRINT "YOU HARVESTED"Y"BUSHELS PER ACRE." 20 | 250 PRINT "RATS ATE"E"BUSHELS." 21 | 260 PRINT "YOU NOW HAVE"S"BUSHELS IN STORE.":PRINT 22 | 270 IF Z=11 THEN 860 23 | 310 C=INT(10*RND(1)):Y=C+17 24 | 312 PRINT "LAND IS TRADING AT"Y"BUSHELS PER ACRE." 25 | 320 PRINT "HOW MANY ACRES DO YOU WISH TO BUY"; 26 | 321 INPUT Q:IF Q<0 THEN 850 27 | 322 IF Y*Q<=S THEN 330 28 | 323 GOSUB 710 29 | 324 GOTO 320 30 | 330 IF Q=0 THEN 340 31 | 331 A=A+Q:S=S-Y*Q:C=0 32 | 334 GOTO 400 33 | 340 PRINT "HOW MANY ACRES DO YOU WISH TO SELL"; 34 | 341 INPUT Q:IF Q<0 THEN 850 35 | 342 IF QC/2 THEN 530 69 | 523 REM *** THE RATS ARE RUNNING WILD!! 70 | 525 E=INT(S/C) 71 | 530 S=S-E+H 72 | 531 GOSUB 800 73 | 532 REM *** LET'S HAVE SOME BABIES 74 | 533 I=INT(C*(20*A+S)/P/100+1) 75 | 539 REM *** HOW MANY PEOPLE HAD FULL TUMMIES? 76 | 540 C=INT(Q/20) 77 | 541 REM *** HORRORS, A 15% CHANCE OF PLAGUE 78 | 542 Q=INT(10*(2*RND(1)-.3)) 79 | 550 IF P.45*P THEN 560 82 | 553 P1=((Z-1)*P1+D*100/P)/Z 83 | 555 P=C:D1=D1+D:GOTO 215 84 | 560 PRINT:PRINT "YOU STARVED"D"PEOPLE IN ONE YEAR!!!" 85 | 565 PRINT "DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY" 86 | 566 PRINT "BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE" 87 | 567 PRINT "ALSO BEEN DECLARED 'NATIONAL FINK' !!":GOTO 990 88 | 710 PRINT "HAMURABI: THINK AGAIN. YOU HAVE ONLY" 89 | 711 PRINT S"BUSHELS OF GRAIN. NOW THEN," 90 | 712 RETURN 91 | 720 PRINT "HAMURABI: THINK AGAIN. YOU OWN ONLY"A"ACRES. NOW THEN," 92 | 730 RETURN 93 | 800 C=INT(RND(1)*5)+1 94 | 801 RETURN 95 | 850 PRINT:PRINT "HAMURABI: I CANNOT DO WHAT YOU WISH." 96 | 855 PRINT "GET YOURSELF ANOTHER STEWARD!!!!!" 97 | 857 GOTO 990 98 | 860 PRINT "IN YOUR 10-YEAR TERM OF OFFICE,"P1"PERCENT OF THE" 99 | 862 PRINT "POPULATION STARVED PER YEAR ON AVERAGE, I.E., A TOTAL OF" 100 | 865 PRINT D1"PEOPLE DIED!!":L=A/P 101 | 870 PRINT "YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH" 102 | 875 PRINT L"ACRES PER PERSON.":PRINT 103 | 880 IF P1>33 THEN 565 104 | 885 IF L<7 THEN 565 105 | 890 IF P1>10 THEN 940 106 | 892 IF L<9 THEN 940 107 | 895 IF P1>3 THEN 960 108 | 896 IF L<10 THEN 960 109 | 900 PRINT "A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND" 110 | 905 PRINT "JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!":GOTO 990 111 | 940 PRINT "YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV." 112 | 945 PRINT "THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND," 113 | 950 PRINT "FRANKLY, HATE YOUR GUTS!":GOTO 990 114 | 960 PRINT "YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT" 115 | 965 PRINT "REALLY WASN'T TOO BAD AT ALL. "; 116 | 966 PRINT INT(P*.8*RND(1));"PEOPLE WOULD" 117 | 970 PRINT "DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR" 118 | 975 PRINT "TRIVIAL PROBLEMS." 119 | 990 PRINT:FOR N=1 TO 10:PRINT CHR$(7);:NEXT N 120 | 995 PRINT "SO LONG FOR NOW.":PRINT 121 | 999 END 122 | -------------------------------------------------------------------------------- /headers/city.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License 3 | 4 | Copyright (c) 2010 Brian L. Troutwine 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated 8 | documentation files (the "Software"), to deal in the 9 | Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, 12 | and to permit persons to whom the Software is furnished to 13 | do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall 16 | be included in all copies or substantial portions of the 17 | Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 20 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 21 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 22 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 23 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #ifndef __CITY_H 30 | #define __CITY_H 31 | 32 | #define RAND(N) (uint16_t)((double)rand() / ((double)RAND_MAX + 1) * N) 33 | 34 | typedef struct _st city_st; 35 | typedef enum _resp { 36 | OKAY, /* Is there a problem here? There's no problem here. */ 37 | EACREAGE, /* Insufficient acres in city. */ 38 | EPOP, /* Insufficient population in city. */ 39 | EBUSHELS, /* Insufficient bushels in city storage. */ 40 | ESTARVE /* More than 45% of people starved in a year. */ 41 | } resp; 42 | 43 | city_st *new_city_st(); 44 | void free_city_st(city_st *cty); 45 | void add_migrants(city_st *cty); 46 | void rats(city_st *cty); 47 | uint16_t plague(city_st *cty); 48 | uint16_t starvation(city_st *cty); 49 | uint16_t births(city_st *cty); 50 | resp step(city_st *cty); 51 | resp buy_acres(city_st *cty, const uint16_t amnt); 52 | resp sell_acres(city_st *cty, const uint16_t amnt); 53 | resp feed_populace(city_st *cty, const uint16_t amnt); 54 | resp plant_seed(city_st *cty, const uint16_t amnt); 55 | 56 | uint16_t population(const city_st *cty); 57 | uint16_t acres(const city_st *cty); 58 | uint16_t yield(const city_st *cty); 59 | uint16_t pests(const city_st *cty); 60 | uint16_t bushels(const city_st *cty); 61 | uint16_t trade_val(const city_st *cty); 62 | uint16_t starved(const city_st *cty); 63 | uint16_t migrated(const city_st *cty); 64 | uint16_t tot_died(const city_st *cty); 65 | uint16_t avg_starved(const city_st *cty); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = hamurabi 2 | AM_CPPFLAGS = -I$(top_srcdir)/headers 3 | hamurabi_SOURCES = main.c city.c -------------------------------------------------------------------------------- /src/city.c: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License 3 | 4 | Copyright (c) 2010 Brian L. Troutwine 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated 8 | documentation files (the "Software"), to deal in the 9 | Software without restriction, including without limitation 10 | the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, 12 | and to permit persons to whom the Software is furnished to 13 | do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall 16 | be included in all copies or substantial portions of the 17 | Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 20 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 21 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 22 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 23 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 24 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 25 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 26 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | 29 | #include 30 | #include 31 | 32 | #include "city.h" 33 | 34 | struct _st { 35 | uint16_t population; 36 | uint16_t starved; 37 | uint16_t migrated; 38 | uint16_t bushels; 39 | uint16_t acres; 40 | uint16_t yield; 41 | uint16_t pests; 42 | uint16_t trade_val; 43 | uint16_t avg_starved; 44 | uint16_t tot_died; 45 | uint16_t fed; 46 | uint16_t planted; 47 | }; 48 | 49 | city_st *new_city_st() { 50 | city_st *cty = (city_st *) malloc(sizeof(city_st)); 51 | 52 | cty->population = 95; 53 | cty->migrated = 5; 54 | cty->starved = 0; 55 | cty->bushels = 2800; 56 | cty->acres = 1000; 57 | cty->yield = 3; 58 | cty->pests = 200; 59 | cty->trade_val = 17+RAND(10); 60 | cty->avg_starved = 0; 61 | cty->tot_died = 0; 62 | cty->fed = 0; 63 | cty->planted = 0; 64 | 65 | return cty; 66 | } 67 | 68 | void free_city_st(city_st *cty) { 69 | free(cty); 70 | } 71 | 72 | void add_migrants(city_st *cty) { 73 | cty->population += cty->migrated; 74 | cty->migrated = 0; 75 | } 76 | 77 | void rats(city_st *cty) { 78 | cty->pests = cty->bushels / (RAND(5)+2); 79 | } 80 | 81 | uint16_t plague(city_st *cty) { 82 | uint16_t died = cty->population / (RAND(4)+2); 83 | cty->population -= died; 84 | return died; 85 | } 86 | 87 | uint16_t starvation(city_st *cty) { 88 | /* 20 bushels of grain are needed for each citizen to 89 | live. */ 90 | cty->starved = cty->population - (cty->fed/20); 91 | return cty->starved; 92 | } 93 | 94 | uint16_t births(city_st *cty) { 95 | /* For each two people living at the end of the year, one 96 | child is born. Carrying capacity of city is 6000. */ 97 | uint16_t pop = cty->population; 98 | return pop*(1 - pop/6000); 99 | } 100 | 101 | resp step(city_st *cty) { 102 | uint16_t died = 0; 103 | died += starvation(cty); 104 | if (died > cty->population * 0.45) 105 | return ESTARVE; 106 | cty->avg_starved = 0.1*died + 0.9*cty->avg_starved; // EMA 107 | 108 | if (RAND(15) == 0) 109 | died += plague(cty); 110 | cty->tot_died += died; 111 | 112 | cty->population += births(cty); 113 | 114 | cty->migrated = 0.1*RAND(cty->population); 115 | cty->trade_val = 17+RAND(10); 116 | cty->yield = RAND(10)+1; 117 | 118 | cty->bushels += cty->yield*cty->planted; 119 | rats(cty); 120 | return OKAY; 121 | } 122 | 123 | resp buy_acres(city_st *cty, const uint16_t amnt) { 124 | if (cty->trade_val*amnt > cty->bushels) 125 | return EBUSHELS; 126 | cty->bushels -= (cty->trade_val)*amnt; 127 | cty->acres += amnt; 128 | return OKAY; 129 | } 130 | 131 | resp sell_acres(city_st *cty, const uint16_t amnt) { 132 | if (amnt > cty->acres) 133 | return EACREAGE; 134 | cty->bushels += (cty->trade_val)*amnt; 135 | cty->acres -= amnt; 136 | return OKAY; 137 | } 138 | 139 | resp feed_populace(city_st *cty, const uint16_t amnt) { 140 | if (amnt >= cty->bushels) 141 | return EBUSHELS; 142 | cty->bushels -= amnt; 143 | cty->fed = amnt; 144 | return OKAY; 145 | } 146 | 147 | resp plant_seed(city_st *cty, const uint16_t amnt) { 148 | if (amnt > cty->acres) 149 | return EACREAGE; 150 | else if (amnt > cty->bushels) 151 | return EBUSHELS; 152 | else if (amnt > 10*cty->population) 153 | return EPOP; 154 | 155 | cty->bushels -= amnt; 156 | cty->planted = amnt; 157 | return OKAY; 158 | } 159 | 160 | uint16_t population(const city_st *cty) { 161 | return cty->population; 162 | } 163 | 164 | uint16_t acres(const city_st *cty) { 165 | return cty->acres; 166 | } 167 | 168 | uint16_t yield(const city_st *cty) { 169 | return cty->yield; 170 | } 171 | 172 | uint16_t pests(const city_st *cty) { 173 | return cty->pests; 174 | } 175 | 176 | uint16_t bushels(const city_st *cty) { 177 | return cty->bushels; 178 | } 179 | 180 | uint16_t trade_val(const city_st *cty) { 181 | return cty->trade_val; 182 | } 183 | 184 | uint16_t starved(const city_st *cty) { 185 | return cty->starved; 186 | } 187 | 188 | uint16_t migrated(const city_st *cty) { 189 | return cty->migrated; 190 | } 191 | 192 | uint16_t tot_died(const city_st *cty) { 193 | return cty->tot_died; 194 | } 195 | 196 | uint16_t avg_starved(const city_st *cty) { 197 | return cty->avg_starved; 198 | } 199 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | This an ancient game. Have a gander at this: 3 | 4 | 10 REM *** CONVERTED FROM THE ORIGINAL FOCAL PROGRAM AND MODIFIED 5 | 20 REM *** FOR EDUSYSTEM 70 BY DAVID AHL, DIGITAL 6 | 30 REM *** MODIFIED FOR 8K MICROSOFT BASIC BY PETER TURNBULL 7 | 8 | Well, now it has been transliterated from the BASIC to C. 9 | 10 | The MIT License 11 | 12 | Copyright (c) 2010 Brian L. Troutwine 13 | 14 | Permission is hereby granted, free of charge, to any person 15 | obtaining a copy of this software and associated 16 | documentation files (the "Software"), to deal in the 17 | Software without restriction, including without limitation 18 | the rights to use, copy, modify, merge, publish, 19 | distribute, sublicense, and/or sell copies of the Software, 20 | and to permit persons to whom the Software is furnished to 21 | do so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall 24 | be included in all copies or substantial portions of the 25 | Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 28 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 29 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 30 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 31 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 32 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 33 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 34 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 35 | */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | 44 | #include "city.h" 45 | 46 | uint16_t input(void); 47 | 48 | void retire(); 49 | void storm_out(); 50 | void ejected(); 51 | void game_end(const city_st *cty); 52 | void nero_end(); 53 | void not_so_bad_end(const city_st *cty); 54 | 55 | uint16_t input(void) { 56 | const uint16_t inp_size = 10; 57 | char input[inp_size], *endptr; 58 | assert( fgets(input, inp_size, stdin) ); 59 | errno = 0; 60 | uint16_t q = (uint16_t) strtol(input, &endptr, inp_size); 61 | if ((errno == ERANGE && (q == LONG_MAX || q == LONG_MIN)) 62 | || (errno != 0 && q == 0)) { 63 | perror("strtol"); 64 | exit(EXIT_FAILURE); 65 | } 66 | if (endptr == input) { 67 | fprintf(stderr, "No digits were found\n"); 68 | exit(EXIT_FAILURE); 69 | } 70 | return q; 71 | } 72 | 73 | /* 74 | Client functions 75 | 76 | Someday I dream of being in curses. 77 | */ 78 | void retire() { 79 | printf("So long for now.\n"); 80 | exit(EXIT_SUCCESS); 81 | } 82 | 83 | void storm_out() { 84 | printf("Hamurabi: I cannot do what you wish.\n"); 85 | printf("Get yourself another steward!!!!!\n"); 86 | retire(); 87 | } 88 | 89 | void ejected() { 90 | printf("Due to this extreme mismanagement you have not only\n"); 91 | printf("been impeached and thrown out of office but you have\n"); 92 | printf("also been declared 'National Fink' !!\n"); 93 | retire(); 94 | } 95 | 96 | void game_end(const city_st *cty) { 97 | uint16_t l = (uint16_t) (acres(cty)/(population(cty))); 98 | printf("In your 10-year term of office %d percent of the\n", 99 | avg_starved(cty)); 100 | printf("population starved per year on average, i.e., a total of\n"); 101 | printf("%d people died!!\n\n", tot_died(cty)); 102 | printf("You started with 10 acres per person and ended with\n"); 103 | printf("%d acres per person.\n\n", l); 104 | 105 | if ((avg_starved(cty)>33) || (l<7)) ejected(); 106 | if ((avg_starved(cty)>10) || (l<9)) nero_end(); 107 | if ((avg_starved(cty)>3) || (l<10)) not_so_bad_end(cty); 108 | } 109 | 110 | void nero_end() { 111 | printf("Your heavy handed performance smacks of Nero and Ivan IV.\n"); 112 | printf("The people (remaining) find you an unpleasant ruler, and,\n"); 113 | printf("frankly, hate your guts!\n"); 114 | retire(); 115 | } 116 | 117 | void not_so_bad_end(const city_st *cty) { 118 | printf("Your performance could have been somewhat better, but\n"); 119 | printf("really wasn't too bad at all. "); 120 | printf("%d people would ", RAND(population(cty))); 121 | printf("dearly like to see you assassinated but we all have our\n"); 122 | printf("trivial problems.\n"); 123 | retire(); 124 | } 125 | 126 | int main(void) { 127 | puts("Try your hand at governing Ancient Sumeria\n" 128 | "successfully for a 10 year term of office.\n"); 129 | 130 | city_st *cty = new_city_st(); 131 | uint16_t inp; 132 | 133 | for (uint16_t year=0; year < 11; year++) { 134 | printf("Hamurabi: I beg to report to you,\nin year %d, ", year); 135 | printf("%d people starved %d came to the city.\n", 136 | starved(cty), migrated(cty)); 137 | 138 | add_migrants(cty); 139 | 140 | if (RAND(2) == 1) { 141 | printf("A horrible plague struck! Many people have died!\n"); 142 | plague(cty); 143 | } 144 | 145 | printf("\nPopulation is now %d\n", population(cty)); 146 | printf("The city now owns %d acres\n", acres(cty)); 147 | printf("You have harvested %d bushels per acre.\n", 148 | yield(cty)); 149 | printf("Rats ate %d bushels.\n\n", 150 | pests(cty)); 151 | printf("You now have %d bushels in store.\n\n", 152 | bushels(cty)); 153 | printf("Land is trading at %d bushels per acre.\n", 154 | trade_val(cty)); 155 | buy_acres: 156 | printf("How many acres do you wish to buy?\n"); 157 | inp = input(); 158 | if (inp < 0) storm_out(); 159 | else if (inp == 0) goto sell_acres; 160 | if (buy_acres(cty, inp) != 0) { 161 | printf("Hamurabi: Think again. You have only %d", 162 | bushels(cty)); 163 | printf(" bushels of grain. Now then,\n"); 164 | goto buy_acres; 165 | } 166 | goto feed_people; 167 | 168 | sell_acres: 169 | printf("How many acres do you wish to sell?\n"); 170 | inp = input(); 171 | if (inp < 0) storm_out(); 172 | else if (inp == 0) goto feed_people; 173 | if (sell_acres(cty, inp) != 0) { 174 | printf("Hamurabi: Think again. You have only %d acres.", 175 | acres(cty)); 176 | printf(" Now then,\n"); 177 | goto sell_acres; 178 | } 179 | 180 | feed_people: 181 | printf("How many bushels do you wish to feed your people?\n"); 182 | printf("(No starvation: %d bushels.)\n", 183 | population(cty)*20); 184 | inp = input(); 185 | if (inp < 0) storm_out(); 186 | else if (inp == 0) goto plant_seed; 187 | if (feed_populace(cty, inp) != 0) { 188 | printf("Hamurabi: Think again. We only have %d bushels.", 189 | bushels(cty)); 190 | printf(" Now then,\n"); 191 | goto feed_people; 192 | } 193 | 194 | plant_seed: 195 | printf("How many acres do you wish to plant with seed?\n"); 196 | printf("(MAX: %d acres)\n", 10*population(cty)); 197 | inp = input(); 198 | if (inp < 0) storm_out(); 199 | else if (inp == 0) goto progress; 200 | switch(plant_seed(cty, inp)) { 201 | case EACREAGE: { 202 | printf("Hamurabi: Think again. You have only %d acres.", 203 | acres(cty)); 204 | printf(" Now then,\n"); 205 | goto plant_seed; 206 | } break; 207 | case EPOP: { 208 | printf("But you only have %d people to tend the fields.", 209 | population(cty)); 210 | printf(" Now then,\n"); 211 | goto plant_seed; 212 | } break; 213 | case EBUSHELS: { 214 | printf("Hamurabi: Think again. We only have %d bushels.", 215 | bushels(cty)); 216 | printf(" Now then,\n"); 217 | goto plant_seed; 218 | } break; 219 | case ESTARVE: 220 | case OKAY: break; 221 | } 222 | 223 | progress: 224 | if (step(cty) == ESTARVE) { 225 | printf("You starved %d people in one year!!!\n", 226 | starved(cty)); 227 | ejected(); 228 | } 229 | 230 | } 231 | 232 | game_end(cty); 233 | free_city_st(cty); 234 | } 235 | --------------------------------------------------------------------------------