Check

Developer(s): Dale F Lipinski
Date: 198
Type: Cassette
Platform(s): TS 1000
Tags: Home

Check is a checkbook balancing program that stores up to 207 transaction entries and 207 payee names in parallel arrays, encoding check numbers and dates together into single floating-point values using a base-1,000,000 scheme. Each transaction record in the two-dimensional array A() packs the payee index combined with the check number, the reconciliation status combined with the date, and the amount in cents as integer. The program supports four main functions: entry input, search (by date, check number, account name, or outstanding items), reconciliation, and an edit mode accessed via option 6. A machine language presence check at line 2595 using USR 32736 tests whether a specific ROM or utility is loaded before proceeding. Amounts are stored as integer cents internally and divided by 100 for display, avoiding floating-point precision issues on dollar values.


Program Analysis

Program Structure

The program is organized into several logical sections accessed via a main menu at line 60–160:

  1. Initialization (lines 2300–2690): Sets up all constants, dimensions arrays, and prompts for starting check number and balance.
  2. Main Menu (lines 60–160): Displays current balance and date, offers options 1 (input entry), 2 (search), 3 (reconcile), 6 (edit).
  3. Entry Input (lines 170–1020): Collects payee name, check number, date, and amount; stores them in arrays.
  4. Reconciliation (lines 1030–1550): Searches by check number or deposit, marks items reconciled, and computes outstanding bank statement balance.
  5. Search (lines 1590–2140): Searches by date, check number, account name, or outstanding status; doubles as the edit entry point for option 6.
  6. Display Subroutine (lines 2190–2290): Common record display used by search and reconcile routines.
  7. Save/Quit (lines 2700–2860): Handles full-array warnings, tape save with data preserved, and a final unused PRINT PEEK at line 2860.

Constant Initialization and Naming

The initialization subroutine at line 2300 defines all numeric constants as single-letter variables to save memory and speed up execution. This is a classic ZX81 BASIC optimization:

VariableValueRole
B207Max entries / max payee names
A0Zero constant
C1One constant
D2Two / array column index
E3Three / array column index
G5Five / row for AT positioning
I7Seven
K9Nine
L10Ten
M207Payee name array size
N2Current entry count pointer
O28Lower bound for valid digit CODE check
P39Upper bound for valid digit CODE check
Q2Current payee name count pointer
R1E6Packing base (1,000,000)
Sreconciled markerComputed from (L*L+O+C)*R = 129,000,000

Data Encoding Scheme

The most technically interesting aspect of this program is how it packs multiple values into single floating-point array cells using base 1,000,000 (R = 1E6). The array A(N, 3) stores three fields per transaction:

  • A(W,C) — encodes payee index × 1,000,000 + check number. The check number is extracted with A(W,C) - INT(A(W,C)/R)*R (i.e., modulo 1,000,000), and the payee index is INT(A(W,C)/R).
  • A(W,D) — encodes reconciliation marker × 1,000,000 + date. The reconciliation flag S = 129,000,000 is added to the date when an item is reconciled (line 1570). An item is outstanding when INT(A(W,D)/R)*R = S is false (i.e., the high part is 0).
  • A(W,E) — stores the amount in integer cents (dollars × 100).

Deposits are identified by a payee index of 1 (the reserved A$(1) = "DEPOSIT" entry) and stored with A(W,C) = R (i.e., index 1 × 1,000,000 + 0).

Balance and Amount Handling

The variable BA holds the running balance in integer cents throughout (BA = BA * 100 at line 2655). Deposits add to BA, checks subtract. The display consistently uses BA/100 or X/100 to present dollar values. The reconciliation routine at lines 1440–1500 computes BAL as the sum of all outstanding items and prints the implied bank statement balance as (BA - BAL) / 100.

Input Validation

Numeric input is validated by checking CODE Z$ against the character code range for digits. On the ZX81, digits ‘0’–’9′ have codes 28–37. The bounds O = 28 and P = 39 (slightly generous upper bound) are used in guards like:

IF CODE Z$<=O OR CODE Z$>=P THEN GOTO ...

This rejects non-digit input but allows ENTER (code 0, handled separately by checking CODE Z$ = A, i.e., = 0, meaning the user pressed ENTER and the system returned an empty string).

Edit Mode (Option 6)

Edit mode is accessed by entering “6” at the main menu and routes through the search subroutine. When a record is found and confirmed wrong (HI = D, i.e., = 2), control jumps to line 182 which reverses the financial effect of the old entry (removing its amount from BA and zeroing the record fields) before re-entering new data. The variable HI is used as a flag: it is set to 0 (A) normally and 2 (D) when the user indicates a record needs correction.

Machine Language Check

Line 2595 executes USR 32736 and compares the result to 40059. Address 32736 is near the top of the ZX81’s 32KB ROM space, and this appears to be a check for the presence of a specific ROM version or utility. If the check fails, the program prints a small error marker ("? ") but continues executing regardless.

Payee Name Deduplication

When a new payee name is entered, lines 870–910 scan the existing A$() array for a match. If found, the existing index W is reused; if not, the name is appended at position Q and Q is incremented. The encoded check number field then becomes R * W + check_number, linking the transaction to its payee by index.

Capacity Limits and Overflow Handling

The arrays are dimensioned for 207 entries (B = 207) and 207 payee names (M = 207). Lines 742–757 check these limits before accepting new data, and lines 2700–2720 display appropriate warnings when either limit is reached. When full, the program routes to the save/quit prompt rather than continuing to accept entries.

Notable Bugs and Anomalies

  • Line 155 routes option “6” to GOSUB 1590 (search), the same as option “2”. This is intentional — search is the entry point for edit mode, with behavior diverging based on R$ = "6".
  • Line 780 is referenced by GOTO 780 implicitly via line 750’s IF CODE Z$=A THEN GOTO 780, but the label is actually line 782. There is no line 780; line 782 is the next line after 750’s conditional, so after falling through line 750 (when the condition is true), execution would naturally reach 782 — but since GOTO 780 targets a non-existent line, the interpreter will run from the next line after 780, which is 782. This is a deliberate technique.
  • Line 2860 (PRINT PEEK 16386 - PEEK 16412 + 256*(PEEK 16387-PEEK 16413)-50) is unreachable dead code, likely a debugging remnant that computed available memory.
  • The prompt string O$ at line 2594 reads “INFO DELETED–ENTER CORRECT INFO” but deletions are actually implemented by zeroing array fields rather than physically removing records, so deleted entries remain in the array as zero-valued placeholders.

Content

Appears On

Related Products

Related Articles

Related Content

Image Gallery

Check

Source Code

   7 SAVE "CHEC%K"
  10 FAST 
  20 GOSUB 2300
  30 CLS 
  40 PRINT D$;AT A,K-C;"TODAYS ";F$,"ENTER IN THIS ORDER.","YEAR MONTH DAY",,"USE ONLY SIX DIGITS TOTAL"
  50 INPUT DA
  60 CLS 
  70 PRINT "% % % %P%R%O%G%R%A%M% %B%Y% %D%A%L%E% %F% %L%I%P%I%N%S%K%I% % % ";"% % : CHECK BOOK :% : DATE :% : ";DA;TAB L+L+K;" :% % ";M$;"BALANCE $ ";BA/100;TAB A;"LAST ";G$;LC,M$
  80 PRINT "NOTE: IF AT ANY TIME YOU LOSE","'''''''' CONTROL AND GET THE PROGRAM";TAB G;"PRESS %G%O%T%O 60 %E%N%T%E%R.",M$;,,,,C$,,"1= INPUT ENTRY",,"2= SEARCH",,"3= RECONCILE",,"6= ";N$,,E$
  95 LET HI=C
 100 INPUT R$
 120 IF R$="0" THEN GOTO 2730
 130 IF R$="1" THEN GOTO 170
 140 IF R$="2" THEN GOSUB 1590
 150 IF R$="3" THEN GOSUB 1030
 155 IF R$="6" THEN GOSUB 1590
 160 GOTO 60
 170 REM 
 180 CLS 
 181 IF R$<>"6" THEN GOTO 190
 182 IF (INT (A(W,C)/R))=C THEN LET BA=BA-A(W,E)
 183 LET A(W,D)=A
 184 IF (INT (A(W,C)/R))>=D THEN LET BA=BA+A(W,E)
 185 LET A(W,E)=A
 186 LET A(W,C)=A
 187 CLS 
 188 PRINT TAB I;N$,O$
 190 PRINT C$,,"1= CHECK ENTRY",,"5= ";A$(C),,,E$
 210 INPUT Z$
 225 IF R$="6" AND Z$="0" THEN CLS 
 226 IF R$="6" AND Z$="0" THEN PRINT "YOU MUST ENTER VALUES TO AN EDIT"
 227 IF R$="6" AND Z$="0" THEN GOTO 190
 230 IF Z$="0" THEN GOTO 60
 240 IF Z$="1" THEN GOSUB 330
 250 IF Z$="5" THEN GOSUB 270
 260 GOTO 170
 270 REM 
 280 CLS 
 290 LET Y$=A$(C)
 300 LET Y=A
 310 GOSUB 490
 320 RETURN 
 330 REM 
 340 CLS 
 350 PRINT D$;H$;"NAME?",,,C$,,M$
 370 INPUT Y$
 385 IF CODE Y$=A THEN GOTO 340
 386 IF R$="6" AND Y$="0" THEN GOTO 340
 390 IF Y$="0" THEN RETURN 
 400 CLS 
 410 PRINT G$;LC+C;,,,,TAB A;J$,M$
 430 INPUT Z$
 450 IF CODE Z$=A THEN LET Y=LC+C
 460 IF CODE Z$=A THEN GOTO 500
 470 IF CODE Z$<=O OR CODE Z$>=P THEN GOTO 400
 480 IF CODE Z$<>A THEN LET Y=VAL Z$
 490 REM 
 500 CLS 
 510 IF Y$=A$(C) THEN PRINT A$(C)
 520 PRINT F$;DA,,,,J$,C$,,M$
 540 INPUT Z$
 560 IF CODE Z$=A THEN LET Z=DA
 570 IF CODE Z$=A THEN GOTO 610
 580 IF Z$="0" THEN RETURN 
 590 IF CODE Z$<=O OR CODE Z$>=P THEN GOTO 500
 600 IF CODE Z$<>A THEN LET Z=VAL Z$
 610 CLS 
 620 PRINT D$;"AMOUNT?",M$
 640 INPUT Z$
 660 IF CODE Z$<=O OR CODE Z$>=P THEN GOTO 610
 670 LET X=(VAL Z$)*100
 680 CLS 
 690 PRINT Y$;TAB A;F$;Z,,G$;Y,,"$ ";X/100;TAB A,,,,K$,M$
 700 IF Y$<>A$(C) AND BA-X<A THEN PRINT "%O%V%E%R%D%R%A%F%T",,M$
 720 INPUT Z$
 740 IF Y$<>A$(C) AND BA-X<A THEN RETURN 
 742 IF N>=B THEN GOTO 752
 744 IF Q-C>=M THEN GOTO 752
 750 IF CODE Z$=A THEN GOTO 780
 752 CLS 
 755 PRINT "INFO %N%O%T ENTERED  ",,,
 756 IF Q-C>=M THEN GOTO 2705
 757 IF N>=B THEN GOTO 2710
 760 IF Y$=A$(C) THEN GOTO 510
 770 GOTO 350
 782 IF R$="6" THEN LET NN=N
 784 IF R$="6" THEN LET N=W
 790 IF Y$<>A$(C) THEN GOTO 840
 800 LET AA=R
 810 LET BA=BA+X
 820 LET W=C
 830 GOTO 920
 840 LET BA=BA-X
 850 IF Y>LC THEN LET LC=Y
 860 LET A$(Q)=Y$
 870 FOR W=D TO Q-C
 880 IF A$(Q)=A$(W) THEN GOTO 902
 890 NEXT W
 900 LET Q=Q+C
 910 LET AA=R*W
 920 LET A(N,C)=AA+Y
 930 LET A(N,D)=R+Z
 940 LET A(N,E)=X
 942 IF R$="6" THEN LET N=NN-C
 950 LET N=N+C
 955 PRINT AT G,L;"INFO ENTERED",M$;L$
 956 IF R$="6" THEN PRINT AT G+C,E;N$;"      CORRECTION",M$
 957 PRINT ,,"BALANCE = $";BA/100
 970 INPUT Z$
 980 IF Z$="1" THEN COPY 
 990 IF N-C>=B OR Q-C>=M THEN GOTO 2705
 992 IF R$="6" THEN LET R$="0"
 994 IF R$="0" THEN RETURN 
 1000 IF CODE Z$=A AND Y$=A$(C) THEN GOTO 500
 1010 IF CODE Z$=A OR Z$="1" THEN GOTO 340
 1020 RETURN 
 1030 REM 
 1040 CLS 
 1050 PRINT "ENTER ";G$;"TO BE RECONCILED";,,C$,,M$;E$
 1070 INPUT Y$
 1077 IF CODE Y$<=O OR CODE Y$>=P THEN GOTO 1040
 1080 IF Y$="0" THEN GOTO 1180
 1090 LET Z=VAL Y$
 1092 FOR W=D TO N
 1094 CLS 
 1095 IF A(W,C)-(INT (A(W,C)/R)*R)=Z THEN GOSUB 2190
 1100 IF A(W,C)-(INT (A(W,C)/R)*R)=Z THEN PRINT AT G,A;M$;K$
 1105 IF A(W,C)-(INT (A(W,C)/R)*R)<>Z THEN NEXT W
 1115 IF W>=N THEN PRINT "NOT FOUND"
 1116 IF W>=N THEN GOTO 1050
 1120 INPUT Z$
 1130 IF Z$="0" THEN NEXT W
 1160 GOSUB 1560
 1170 GOTO 1040
 1180 CLS 
 1190 PRINT AT A,A;"ENTER ";A$(C);AT A,G+K;"TO BE RECONCILED. ENTER BY DATE",,,,C$,,M$;E$
 1210 INPUT Y$
 1218 IF CODE Y$<=O OR CODE Y$>=P THEN GOTO 1180
 1220 IF Y$="0" THEN GOTO 1320
 1230 LET Z=VAL Y$
 1235 FOR W=D TO N
 1240 CLS 
 1242 IF INT (A(W,C)/R)<>C THEN NEXT W
 1245 IF INT (A(W,C)/R)=C AND A(W,D)-(INT (A(W,D)/R)*R)=Z THEN GOSUB 2190
 1250 IF INT (A(W,C)/R)=C AND A(W,D)-(INT (A(W,D)/R)*R)=Z THEN PRINT AT G,A;M$;K$
 1255 IF A(W,D)-(INT (A(W,D)/R)*R)<>Z THEN NEXT W
 1265 IF W>=N THEN PRINT AT L,G;"NOT FOUND"
 1270 IF W>=N THEN GOTO 1190
 1275 INPUT Z$
 1290 IF Z$="0" THEN NEXT W
 1300 GOSUB 1560
 1310 GOTO 1180
 1320 LET Z=S
 1330 FOR W=D TO N
 1340 CLS 
 1345 IF (INT (A(W,D)/R)*R)<>Z THEN GOSUB 2190
 1350 IF (INT (A(W,D)/R)*R)<>Z THEN PRINT AT G,A;"OUTSTANDING ITEMS         ",M$;C$;"           ","5= SKIP OUTSTANDING ITEMS LIST",L$(O+P TO ),M$;E$
 1355 IF (INT (A(W,D)/R)*R)=Z THEN NEXT W
 1357 IF W>=N THEN GOTO 1440
 1370 INPUT Z$
 1390 IF Z$="0" THEN RETURN 
 1400 IF Z$="5" OR W=N-D THEN GOTO 1440
 1410 NEXT W
 1440 LET BAL=A
 1450 FOR X=C TO N-C
 1460 IF (INT (A(X,D)/R)*R)<>S AND (INT (A(X,C)/R))=C THEN LET BAL=BAL+A(X,E)
 1470 IF (INT (A(X,D)/R)*R)<>S AND (INT (A(X,C)/R))<>C THEN LET BAL=BAL-A(X,E)
 1480 NEXT X
 1490 CLS 
 1500 PRINT "BANK STATEMENT IS $ ";(BA-BAL)/100;TAB A;M$;L$
 1520 INPUT Z$
 1530 IF Z$="1" THEN COPY 
 1550 RETURN 
 1560 REM 
 1570 LET A(W,D)=(A(W,D)-(INT (A(W,D)/R)*R))+S
 1580 RETURN 
 1590 REM 
 1600 CLS 
 1610 IF R$="6" THEN PRINT AT A,K;N$
 1615 PRINT AT C,L;"SEARCH",M$;C$,,"1= BY ";F$,,"2= BY ";G$,"3= BY ";H$,,"4= BY OUTSTANDING ITEM",E$
 1617 IF R$="6" THEN PRINT AT I,A;E$,"BE SURE TO COPY ALL INFO THAT ISCHANGED"
 1630 INPUT Z$
 1650 IF CODE Z$<=O OR CODE Z$>=P THEN GOTO 1600
 1660 IF Z$="0" THEN RETURN 
 1662 IF Z$="4" AND R$="6" THEN GOTO 1600
 1663 IF R$="6" THEN GOTO 1730
 1665 IF Z$="4" THEN GOTO 2080
 1670 PRINT ,,"0= SPECIFIC ITEM","%E%N%T%E%R= ALL ITEMS",E$
 1690 INPUT Y$
 1720 IF CODE Y$=A THEN GOTO 2150
 1730 PRINT ,,D$;"ITEM?"
 1750 INPUT Y$
 1765 IF Z$="3" THEN GOTO 1970
 1770 IF CODE Y$<=O OR CODE Y$>=P THEN GOTO 1600
 1780 IF Z$="1" THEN GOTO 1820
 1790 IF Z$="2" THEN GOTO 1900
 1810 GOTO 1600
 1820 REM 
 1830 LET Z=VAL Y$
 1840 FOR W=C TO N-D
 1850 REM 
 1860 IF A(W,D)-(INT (A(W,D)/R)*R)=Z THEN GOSUB 2190
 1865 IF HI=A AND R$="6" THEN GOTO 182
 1870 NEXT W
 1885 CLS 
 1887 PRINT AT C,E+E;"END"
 1890 GOTO 1610
 1900 REM 
 1910 LET Z=VAL Y$
 1920 FOR W=D TO N-C
 1930 IF A(W,C)-(INT (A(W,C)/R)*R)=Z THEN GOSUB 2190
 1935 IF HI=A AND R$="6" THEN GOTO 182
 1940 NEXT W
 1955 CLS 
 1957 PRINT "END"
 1960 GOTO 1610
 1970 LET A$(Q)=Y$
 1980 FOR X=C TO N-C
 1990 IF A$(Q)=A$(X) THEN GOTO 2020
 1995 IF HI=A AND R$="6" THEN GOTO 182
 2000 NEXT X
 2005 CLS 
 2007 PRINT "END"
 2010 GOTO 1610
 2020 LET Z=X*R
 2030 FOR W=D TO N-C
 2040 IF (INT (A(W,C)/R)*R)=Z THEN GOSUB 2190
 2050 NEXT W
 2055 CLS 
 2057 PRINT "END"
 2060 GOTO 1610
 2070 REM 
 2080 LET Z=S
 2090 FOR W=D TO N-C
 2100 REM 
 2110 IF (INT (A(W,D)/R)*R)<>Z THEN GOSUB 2190
 2120 IF R$="3" THEN RETURN 
 2125 IF Z$="0" THEN GOTO 1600
 2130 NEXT W
 2135 CLS 
 2137 PRINT "END"
 2140 GOTO 1610
 2150 FOR W=D TO N-C
 2160 GOSUB 2190
 2165 IF HI=D THEN GOTO 2175
 2170 NEXT W
 2175 CLS 
 2177 PRINT AT C,E+E;"END"
 2180 GOTO 1610
 2190 REM 
 2200 CLS 
 2210 LET T=INT (A(W,D)/R)
 2220 IF T=C THEN LET T=A
 2230 PRINT F$;A(W,D)-(INT (A(W,D)/R)*R);TAB O;W,G$;A(W,C)-(INT (A(W,C)/R)*R),,H$;A$(INT (A(W,C)/R));TAB A;"$ ";(A(W,E)/100);TAB A,,"%  DENOTES RECONCILED ITEM",L$
 2235 IF INT (A(W,D)/R)*R=S THEN PRINT AT A,O-D;"% "
 2240 IF R$="3" THEN RETURN 
 2245 IF R$="6" THEN PRINT AT G+C,A;"PRESS 0 %E%N%T%E%R IF NOT CORRECT";AT I+D,A;M$;N$,"DELETION"
 2260 INPUT Z$
 2265 LET HI=A
 2270 IF Z$="1" THEN COPY 
 2275 IF Z$="0" THEN LET HI=D
 2285 IF HI=A AND R$="6" THEN GOTO 182
 2290 RETURN 
 2300 REM 
 2310 LET B=207
 2320 LET A=B-B
 2330 LET C=B/B
 2340 LET D=C+C
 2350 LET E=D+C
 2360 LET G=E+D
 2370 LET I=G+D
 2380 LET K=I+D
 2390 LET L=K+C
 2400 LET M=207
 2410 LET N=D
 2420 LET O=L+L+I
 2430 LET P=O+L+C
 2440 LET Q=D
 2450 LET R=1E6
 2460 LET S=(L*L+O+C)*R
 2470 DIM A(B,E)
 2480 DIM A$(M,22)
 2490 LET C$="0= NO ENTRY "
 2500 LET D$="WHAT IS THE "
 2510 LET E$="% %E%N%T%E%R% %A%N%S%W%E%R% %N%U%M%B%E%R% "
 2520 LET F$="DATE "
 2530 LET G$="CHECK NO. "
 2540 LET H$="ACCOUNT "
 2550 LET I$="PRESS %E%N%T%E%R IF THIS IS CORRECT  "
 2560 LET J$=I$+"IF NOT ENTER NUMBER"
 2570 LET K$=I$+"PRESS 0 %E%N%T%E%R IF NOT CORRECT"
 2580 LET L$="PRESS 0 %E%N%T%E%R TO RETURN         PRESS 1 %E%N%T%E%R TO COPY           PRESS %E%N%T%E%R TO CONTINUE"
 2590 LET M$="''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''"
 2592 LET N$="EDIT MODE"
 2594 LET O$="INFO DELETED--ENTER CORRECT INFO"+M$
 2595 IF USR 32736=40059 THEN PRINT "?% % % "
 2600 PRINT D$;"FIRST ";G$,"TO BE USED IN THIS PROGRAM?"
 2620 INPUT LC
 2630 LET LC=LC-C
 2640 PRINT ,,"WHAT IS THE BEGINNG BALANCE?"
 2650 INPUT BA
 2655 LET BA=BA*100
 2660 LET A(C,C)=R
 2670 LET A(C,D)=S
 2680 LET A$(C)="DEPOSIT"
 2690 RETURN 
 2700 CLS 
 2705 IF Q>=M-C THEN PRINT "NO ROOM FOR ";H$;"NAME"
 2710 IF N>=B-C OR Q>=M-C THEN PRINT "CHECK BOOK IS FULL",M$
 2720 GOTO 2740
 2730 CLS 
 2740 PRINT "ARE YOU FINISHED?",M$;"0= YES",,"1= NO",,E$
 2760 INPUT Z$
 2780 IF Z$<>"0" THEN GOTO 60
 2800 PRINT ,,M$;"PLUG TAPE RECORDER IN.","START RECORDING.","PRESS %E%N%T%E%R",,M$
 2810 INPUT Z$
 2830 IF CODE Z$<>A THEN GOTO 60
 2840 SAVE "CHEC%K"
 2850 GOTO 30
 2860 PRINT PEEK 16386-PEEK 16412+256*(PEEK 16387-PEEK 16413)-50

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top