Kingdom is a multi-player resource-management game in which each player governs a village over five years (twenty seasons), balancing population, money, and corn while defending against floods, starvation, and thieves. Each turn players allocate workers to three jobs—dyke mending, planting, and defence—then deal with randomly triggered disasters. The program stores per-player state in parallel arrays (M, C, Q, D, N, Z, X, T) and uses string slicing on N$(A,11) to pack both a player’s name and gender code into a single dimensioned string. A notable optimisation at line 8000 pre-builds a 22-line screen image string in FAST mode before the game begins. The listing includes an embedded note at line 9005 acknowledging that the program crashes at line 470.
Program Analysis
Program Structure
The program is divided into a title/intro section, initialisation, a main game loop, and several subroutines:
- Lines 1–57: Title screen, rules display, player registration (
GOSUB 7000), and array initialisation. - Lines 100–630: Main seasonal loop.
Scycles 1–4 (seasons);Ycounts years 1–5. The outer loop at line 170 iterates over players (P). - Lines 640–730: End-of-game winner announcement.
- Lines 1000–1110: Flood/dyke subroutine.
- Lines 2000–2180: Thieves/defence subroutine.
- Lines 3000–3040: Starvation subroutine.
- Lines 4000–4220: Corn-buying subroutine.
- Lines 5000–5140: Corn-selling subroutine.
- Lines 7000–7190: Player registration loop.
- Lines 8000–8050: Pre-build screen background string in
FASTmode. - Lines 9000–9010:
SAVEandRUN.
Data Model
All per-player state is held in parallel numeric arrays dimensioned to A (number of players). The packed name/gender string array N$(A,11) uses the 11th character as a gender flag (‘M’ or ‘F’), with characters 1–10 holding the name proper. Slices like N$(P)(TO 10) and N$(P)(11) exploit ZX81-style string slicing to read back name and gender independently.
| Array | Meaning | Initial value |
|---|---|---|
M(A) | Money ($) | 1000 |
Q(A) | Population | 1000 |
C(A) | Corn (sacks) | 2500 |
D(A) | Corn planted this spring | — |
Z(A) | Flood casualties (display) | 0 |
X(A) | Starvation casualties (display) | 0 |
T(A) | Thief casualties (display) | 0 |
N(A) | New arrivals this season | — |
U(A) | Player age | — |
Seasonal / Year Loop
S is incremented each iteration of the outer player loop preamble (line 115) and wraps back to 0 at S=4 (line 150). Y is only incremented when S=1 (Spring, line 140), giving a clean year counter. The game ends when Y=5 at line 630.
Disaster Subroutines
Three randomly triggered disasters are evaluated each season per player. Each is called conditionally based on the player’s labour allocation:
- Floods (1000): Triggered if dyke workers (
A1) are fewer thanQ(P)/2.2. A randomK(5–14) killsK*10people, destroysK*15sacks of corn, and fines the player money ifK>8. A 1-in-3 chance of no event provides a random reprieve. - Thieves (2000): Triggered if defenders (
A3) are fewer thanQ(P)/2.2. Deducts people, corn, and money. Has a bug: usesT(the loop variable) instead ofRNDin the reprieve check at line 2010. - Starvation (3000): Triggered if corn planted is less than twice the population. Deaths equal the shortfall, capped at the total population.
Corn Economy
At the end of each season, corn is updated as C(P) = (C(P)/1.2) + D(P)*3 (line 535), meaning planted corn triples but existing stocks decay. If the total corn is below Q(P)*2, subroutine 4000 forces the player to buy corn at a random rate ($15–$19 per sack). If surplus exists, subroutine 5000 offers selling at $5–$9 per sack. Money grows automatically at 9% per season (line 580).
Screen Techniques
The program uses PRINT AT extensively for layout and scrolls the screen with a FOR/SCROLL/NEXT loop (22 iterations) rather than CLS, to avoid screen flicker between game phases. The subroutine at line 8000 pre-builds a 22-line background string M$ in FAST mode using inverse characters and ASCII art, then prints it in one statement at line 470 (PRINT AT 0,0;M$).
Centring of numeric output at lines 240–280 is achieved with a formula: TAB 15-(((LEN(STR$ value))+N)/2), where N accounts for the label length. This is an elegant approach to dynamic text centering without knowing the number’s width in advance.
Player Title Logic
Lines 190–200 determine the player’s title for display. The logic uses gender (character 11 of N$) and age (U(P)) to assign King/Queen/Prince/Princess. However, line 200 contains a bug: it tests N$(P)="F" against the full 11-character string rather than N$(P)(11)="F", so the Queen title will never be displayed correctly.
Input Validation
Labour allocations (lines 335, 375, 410) are validated with IF INT A1 <> A1 THEN GOTO to reject fractional inputs. The total labour check at line 412 ensures workers assigned don’t exceed population, looping back to re-display if over-allocated. The corn planting input (line 425) checks it doesn’t exceed available stocks.
Bugs and Anomalies
- Line 11 / lines 10–12:
LET Y=0is inside aFOR F=10 TO 21loop with noPRINTorSCROLL, so it serves only to resetY(the year counter) 12 times on the title screen — the loop body appears to be a remnant of a screen-clear attempt. - Line 200: Condition
N$(P)="F"tests the entire 11-character name string against a single character, so the Queen title is never triggered. - Line 280: The corn display is missing
C(P)— the format string prints" SACKS OF CORN."but the corn value itself is not included in thePRINTstatement. - Line 415: Inside the labour-overflow loop (lines 414–416),
IF INT A3<>A3 THEN GOTO 410is a stray validation check that has no effect since the loop is only entered after valid integer input. - Line 2010: Uses
T(the loop control variable from line 2030 if previously run, otherwise 0) instead ofRNDfor the 1-in-3 reprieve, making the thieves event deterministic rather than random. - Line 2088:
PRINT EXP 10,16;is clearly a typo forPRINT AT 10,16;, and would cause a syntax or runtime error. - Lines 5040–5070: The sell subroutine prints a prompt but never actually inputs a value —
A$is used at lines 5050 and 5070 but is never assigned by anINPUTstatement in this subroutine, so it retains whatever value it last held. - Line 7160:
INPUT H$appears twice (lines 7150 and 7160), requiring the player to confirm twice. - Line 9005: An inline
REMnote from the author states “THIS PROGRAM CRASHES REPORT CODE 5/470”, referencing a crash at line 470 (PRINT AT 0,0;M$), likely due toM$being too long for a singlePRINTstatement. - Line 705:
POKE 16418,0resets the system variable controlling the cursor position — an unusual direct memory write in an otherwise pure-BASIC program.
Content
Source Code
1 PRINT AT 3,7;"*****************"
2 PRINT AT 4,7;"* *"
3 PRINT AT 5,7;"* K I N G D O M *"
4 PRINT AT 6,7;"* *"
5 PRINT AT 7,7;"*****************"
6 PRINT AT 10,0;"YOU HAVE TO GOVERN A VILLAGE";AT 12,0;"FOR A PERIOD OF FIVE YEARS.YOU";AT 14,0;"MUST TRY TO KEEP ALIVE AS MANY"
7 PRINT AT 16,0;"PEOPLE AS POSSIBLE.THEY WILL DO";AT 18,0;"ONE OF THREE JOBS.";AT 20,0;"YOU MUST PROTECT THEM AGAINST.."
8 PRINT AT 21,5;"PRESS ANY KEY TO CONTINUE"
9 IF INKEY$="" THEN GOTO 9
10 FOR F=10 TO 21
11 LET Y=0
12 NEXT F
13 PRINT AT 10,0;"...(A)>=FLOODS";AT 11,0;"...(B)>=STARVATION";AT 12,0;"...(C)>=THIEVES";AT 14,0;"YOU HAVE TO BE AS RICH AS POSS.";AT 16,0;"AT THE END OF THE FIVE YEARS";AT 18,0;"AND THE RICHEST WINS."
14 PRINT AT 21,5;"PRESS ANY KEY TO CONTINUE"
15 IF INKEY$="" THEN GOTO 15
16 FOR F=10 TO 21
17 PRINT AT F,0;" "
18 NEXT F
19 PRINT AT 10,0;"HOW MANY PLAYERS? ";
20 INPUT A
21 PRINT A
22 DIM N$(A,11)
23 DIM U(A)
24 GOSUB 7000
34 PRINT AT 21,5;"PRESS ANY KEY TO START"
35 IF INKEY$="" THEN GOTO 35
36 FOR F=1 TO 22
37 SCROLL
38 NEXT F
39 GOSUB 8000
40 DIM M(A)
41 DIM C(A)
42 DIM Q(A)
43 FOR F=1 TO A
44 LET M(F)=1000
45 LET Q(F)=1000
46 LET C(F)=2500
47 NEXT F
48 DIM D(A)
49 DIM N(A)
50 DIM Z(A)
51 DIM X(A)
52 DIM T(A)
53 FOR F=1 TO A
54 LET Z(F)=0
55 LET X(F)=0
56 LET T(F)=0
57 NEXT F
100 REM START
105 LET S=0
115 LET S=S+1
120 IF S=1 THEN LET Y$="SPRING"
125 IF S=2 THEN LET Y$="SUMMER"
130 IF S=3 THEN LET Y$="AUTUMN"
135 IF S=4 THEN LET Y$="WINTER"
140 IF S=1 THEN LET Y=Y+1
150 IF S=4 THEN LET S=0
170 FOR P=1 TO A
175 LET N(P)=INT (RND*10)
176 LET Q(P)=Q(P)+N(P)
180 PRINT AT 0,9;Y$;" YEAR ";Y
190 IF N$(P)(11)="M" AND U(P)>18 THEN PRINT "KING ";N$(P)( TO 10)
193 IF N$(P)(11)="F" AND U(P)<=18 THEN PRINT "PRINCESS ";N$(P)( TO 10)
195 IF N$(P)(11)="M" AND U(P)<=18 THEN PRINT "PRINCE ";N$(P)( TO 10)
200 IF N$(P)="F" AND U(P)>18 THEN PRINT "QUEEN ";N$(P)( TO 10)
201 PRINT
202 PRINT N(P);" PEOPLE CAME TO THE VILLAGE."
203 PRINT
210 PRINT TAB 9;"CASUALTIES:"
211 PRINT " STARVED . FLOODS . THIEVES"
212 PRINT TAB 3;X(P);TAB 12;Z(P);TAB 22;T(P)
214 PRINT "********************************"
220 PRINT TAB 10;"YOU HAVE:"
240 PRINT TAB 15-(((LEN (STR$ M(P)))+2)/2);"$";M(P);","
260 PRINT TAB 15-(((LEN (STR$ Q(P)))+8)/2);Q(P);" PEOPLE,"
280 PRINT TAB 15-(((LEN (STR$ C(P)))+15)/2);" SACKS OF CORN."
290 PRINT "********************************"
300 PRINT "LABOR ARRANGEMENT:"
320 PRINT "(A) MENDING THE DYKE ";
330 INPUT A1
335 IF INT A1<>A1 THEN GOTO 330
340 PRINT A1
360 PRINT "(B) PLANTING CORN "
370 INPUT A2
375 IF INT A2<>A2 THEN GOTO 370
380 PRINT A2
400 PRINT "(C) DEFENDING THE VILLAGE "
409 INPUT A3
410 IF INT A3<>A3 THEN GOTO 409
411 PRINT A3
412 IF A1+A2+A3<=Q(P) THEN GOTO 420
413 PRINT AT 21,5;"TOO MANY PEOPLE"
414 FOR F=1 TO 22
415 IF INT A3<>A3 THEN GOTO 410
416 NEXT F
417 GOTO 180
420 IF Y$<>"SPRING" THEN GOTO 430
422 PRINT "HOW MANY SACKS OF CORN ARE TO";" BE PLANTED? ";
423 INPUT D(P)
424 PRINT D(P)
425 IF D(P)>C(P) THEN GOTO 422
426 LET C(P)=C(P)-D(P)
427 IF D(P)/10>A2 THEN LET D(P)=A2*10
430 PRINT AT 21,5;"PRESS ANY KEY TO CONTINUE"
440 IF INKEY$="" THEN GOTO 440
450 FOR F=1 TO 22
460 SCROLL
465 NEXT F
466 FAST
470 PRINT AT 0,0;M$
490 PRINT AT 8,14;"******";AT 9,14;"* *";AT 10,14;"* ++ *";AT 11,14;"* *";AT 12,14;"******"
500 PRINT AT 10,27;"T"
501 LET T(P)=0
502 LET Z(P)=0
503 LET X(P)=0
504 SLOW
510 IF A1<Q(P)/2.2 THEN GOSUB 1000
520 IF A3<Q(P)/2.2 THEN GOSUB 2000
530 IF D(P)<Q(P)*2 THEN GOSUB 3000
535 LET C(P)=(C(P)/1.2)+D(P)*3
540 IF C(P)+D(P)<Q(P)*2 THEN GOSUB 4000
550 IF C(P)+D(P)>Q(P)*2 THEN GOSUB 5000
560 LET Q(P)=Q(P)*1.2
565 LET Q(P)=INT (Q(P))
575 LET C(P)=INT (C(P))
580 LET M(P)=M(P)*1.09
583 LET M(P)=INT (M(P))
590 FOR F=1 TO 22
600 SCROLL
610 NEXT F
611 IF M(P)<0 THEN LET M(P)=0
612 IF C(P)<0 THEN LET C(P)=0
613 IF Q(P)<0 THEN LET Q(P)=0
620 NEXT P
630 IF Y<5 THEN GOTO 115
640 PRINT AT 0,0;"NOW FOR THE WINNER....."
644 LET W$=""
645 LET W=0
650 FOR F=1 TO A
660 PRINT N$(F)( TO 10);" WITH $";M(F);","
680 IF M(F)>W THEN LET W$=N$(F)( TO 10)
690 IF M(F)>W THEN LET W=M(F)
700 NEXT F
705 POKE 16418,0
710 PRINT AT 20,0,"CONGRATULATIONS",W$;" YOU ARE THE WINNER OF THE GAME WITH $";W
730 GOTO 10000
\n1000 REM DYKE
\n1010 IF INT (RND*3)+1=1 THEN RETURN
\n1020 LET K=INT (RND*10)+5
\n1030 FOR F=3 TO K+3
\n1040 FOR G=0 TO 21
\n1050 PRINT AT G,F;CHR$ 8
\n1060 NEXT G
\n1070 IF K*10>Q(P) THEN LET K=INT (Q(P)/10)
\n1080 LET Q(P)=Q(P)-K*10
\n1090 IF K>8 THEN LET M(P)=M(P)-((K-8)*100)
\n1095 LET Z(P)=K*10
\n1100 LET C(P)=C(P)-K*15
\n1110 RETURN
\n2000 REM DEF
\n2010 IF INT (T*3)+1=1 THEN RETURN
\n2020 LET K=INT (RND*10)+5
\n2025 IF K*6>Q(P) THEN LET K=INT (Q(P)/6)
\n2030 FOR F=27 TO 16 STEP -1
\n2040 PRINT AT 10,F;"T "
\n2050 NEXT F
\n2060 FOR F=1 TO K
\n2070 PRINT AT 10,16;"\. "
\n2080 PRINT EXP 10,16;"\' "
\n2090 PRINT AT 10,16;"\ '"
\n2100 PRINT AT 10,16;"\ ."
\n2110 NEXT F
\n2120 FOR F=16 TO 27
\n2130 PRINT AT 10,F;" T"
\n2140 NEXT F
\n2150 LET Q(P)=Q(P)-K*6
\n2151 LET T(P)=K*6
\n2160 LET C(P)=C(P)-K*25
\n2170 LET M(P)=M(P)-K*15
\n2180 RETURN
\n3000 REM STAR
\n3010 LET K=ABS (D(P)-(Q(P)*2))
\n3015 IF K>Q(P) THEN LET K=Q(P)
\n3020 LET Q(P)=Q(P)-(INT (K))
\n3035 LET X(P)=K
\n3040 RETURN
\n4000 REM BUY
\n4010 LET K=INT (RND*5)+15
\n4020 FOR F=1 TO 22
\n4030 SCROLL
\n4040 NEXT F
\n4050 PRINT AT 0,0;"YOU HAVEN/T GOT ENOUGH CORN TO FEED ";"YOUR VILLAGE-YOU MUST BUY SOME..."
\n4060 PRINT
\n4070 PRINT "CURRENT BUYING RATE = ";K
\n4080 PRINT
\n4090 PRINT "YOU HAVE $";M(P)
\n4100 PRINT
\n4110 PRINT "THE MOST YOU CAN HAVE ARE ";INT (M(P)/K)
\n4120 PRINT "SACKS"
\n4140 PRINT "HOW MANY DO YOU WANT TO BUY?";
\n4150 INPUT I
\n4160 IF I>(M(P)/K) THEN GOTO 4140
\n4170 PRINT I
\n4180 PRINT
\n4190 PRINT "THAT WILLCOST $ ";I*K
\n4200 LET M(P)=M(P)-(K*I)
\n4210 LET C(P)=C(P)+1
\n4220 RETURN
\n5000 REM SELL
\n5010 FOR F=1 TO 22
\n5020 SCROLL
\n5030 NEXT F
\n5040 PRINT AT 0,0;"YOU HAVE A SURPLUS OF CORN.DO YOU";"WANT TO SELL ANY? IF SO, SPECIFY THE AMOUNT."
\n5050 IF A$(1)="N" THEN RETURN
\n5070 LET K=VAL A$
\n5071 IF K<=C(P) THEN GOTO 5080
\n5072 PRINT
\n5073 PRINT "YOU ONLY HAVE ";INT (C(P));" SACKS."
\n5074 IF INKEY$="" THEN GOTO 5074
\n5075 GOTO 5000
\n5080 LET J=INT (RND*5)+5
\n5090 PRINT K;" SACKS OF CORN AT"
\n5100 PRINT "$";J;" A SACK,WILL MAKE "
\n5110 PRINT "$";K*J
\n5120 LET M(P)=M(P)+K*J
\n5130 LET C(P)=C(P)-K
\n5140 RETURN
\n7000 FOR F=1 TO A
\n7010 CLS
\n7020 PRINT "PLAYER ";F
\n7030 PRINT
\n7040 PRINT "YOUR NAME PLEASE: "
\n7050 INPUT N$(F)
\n7051 PRINT N$(F)
\n7052 PRINT
\n7060 PRINT "YOUR AGE? ";
\n7070 INPUT U(F)
\n7080 PRINT U(F)
\n7090 PRINT
\n7100 PRINT "ARE MALE(M) OR FEMALE(F)? ";
\n7110 INPUT N$(F)(11)
\n7120 PRINT N$(F)(11)
\n7130 PRINT
\n7140 PRINT "O.K.? ";
\n7150 INPUT H$
\n7160 INPUT H$
\n7170 IF H$="NO" OR H$="NO" THEN GOTO 7010
\n7180 NEXT F
\n7190 RETURN
\n8000 FAST
\n8005 LET M$=""
\n8010 FOR F=1 TO 22
\n8020 LET M$=M$+"%A%A%A; % ; ;//////"
\n8030 NEXT F
\n8040 SLOW
\n8050 RETURN
\n9000 SAVE "1014%9"
\n9005 REM THIS PROGRAM CRASHES REPORT CODE 5/470
\n9010 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
