Skip to content

Watch the distribution

Watch a fixed-scale chart change as rolls arrive.

  • The Craft

Watch the shares change instead of waiting for a finished table. A face can keep the same count while its share shrinks, because another face has just increased the total.

Continue from Compare shares. This version uses a fixed batch of twelve. It updates after every roll; Q stops early and keeps the partial result. At completion it returns to BASIC. RUN starts fresh.

Replace lines 30, 450, 460, 1050. Add lines 430, 435, 470, 480, 720, 725, 1020, 1140, 1150, 1170. There are no lines to delete.

changes.bas
  30 LET n=0: LET b=12: LET done=0: LET h$="####################": LET z$="                    "
 430 GO SUB 1000
 435 PRINT AT 19,1;"Rolling... Q stops this batch."
 450 LET d=INT (RND*6)+1: LET t(d)=t(d)+1: LET n=n+1: LET done=done+1
 460 GO SUB 1100
 470 LET k$=INKEY$
 480 IF k$="q" OR k$="Q" THEN GO TO 600
 720 PRINT AT 19,1;"Samples vary; no fairness proof."
 725 IF done<b THEN PRINT AT 19,1;"Stopped early. Counts kept.     "
1020 PRINT AT 2,1;"Bars 0-100%; rounded to 5%."
1050 PRINT AT row,2;j;AT row+1,5;CHR$ 91;AT row+1,26;CHR$ 93
1140 LET width=INT (20*t(j)/n+0.5)
1150 PRINT AT row+1,6; INK 5;h$( TO width);z$( TO 20-width)
1170 PRINT AT 20,1;"Batch ";done;" / ";b;"     "
Complete program at this stage
dice-roller.bas
  10 BORDER 0: PAPER 0: INK 7: BRIGHT 0: CLS
  20 RANDOMIZE : DIM t(6)
  30 LET n=0: LET b=12: LET done=0: LET h$="####################": LET z$="                    "
 430 GO SUB 1000
 435 PRINT AT 19,1;"Rolling... Q stops this batch."
 440 FOR i=1 TO b
 450 LET d=INT (RND*6)+1: LET t(d)=t(d)+1: LET n=n+1: LET done=done+1
 460 GO SUB 1100
 470 LET k$=INKEY$
 480 IF k$="q" OR k$="Q" THEN GO TO 600
 490 NEXT i
 600 GO SUB 1000: GO SUB 1100
 720 PRINT AT 19,1;"Samples vary; no fairness proof."
 725 IF done<b THEN PRINT AT 19,1;"Stopped early. Counts kept.     "
 750 STOP
1000 CLS : PRINT AT 0,9; INK 5; BRIGHT 1;"DICE ROLLER"
1020 PRINT AT 2,1;"Bars 0-100%; rounded to 5%."
1030 PRINT AT 4,1; INK 5;"FACE  COUNT   NOW%"
1040 FOR j=1 TO 6: LET row=5+2*(j-1)
1050 PRINT AT row,2;j;AT row+1,5;CHR$ 91;AT row+1,26;CHR$ 93
1080 NEXT j: PRINT AT 18,1;"Fair model: about 16.7% each."
1090 RETURN
1100 PRINT AT 1,1;"Rolls ";n;"   "
1110 FOR j=1 TO 6
1120 LET row=5+2*(j-1): LET pc=INT (1000*t(j)/n+0.5)/10
1130 PRINT AT row,7;t(j);"    ";AT row,15;pc;"   "
1140 LET width=INT (20*t(j)/n+0.5)
1150 PRINT AT row+1,6; INK 5;h$( TO width);z$( TO 20-width)
1160 NEXT j
1170 PRINT AT 20,1;"Batch ";done;" / ";b;"     "
1180 RETURN

RUN and watch the chart form. Each row has twenty possible filled cells, representing a fixed scale from zero to 100%. Try another RUN and hold Q during rolling. The result should say it stopped early; the counts must still add up to the total shown.

Move the display into the loop

Line 430 draws the frame before rolling. Line 450 counts a roll and increases done, the amount of work completed in this batch. Line 460 calls the display routine. The first calculation therefore has n equal to one, not zero.

INKEY$ reads the currently held key as a string, or an empty string when no key is down. Lines 470–480 accept q or Q and jump to the result at 600. IF runs the statements after THEN only when its condition is true. OR accepts either letter case; GO TO 600 continues at the result routine instead of the next loop iteration. The program checks between display updates, so stopping is not instantaneous while BASIC is printing.

The result redraw includes every counted roll. Line 725 compares done with b to distinguish an early stop from a completed batch. We keep all the counts already made; there is no unfinished roll to subtract.

Share a fixed scale

Line 1140 calculates INT (20*t(j)/n+0.5). It converts the share into a width from zero to twenty cells, rounding to the nearest cell. Each cell represents five percentage points. A share of 25% fills five cells; 100% fills all twenty.

h$ holds twenty hash characters and z$ holds twenty spaces. A string is text, and its name ends in $. h$(TO width) takes the first width characters. When width is zero, that slice is empty. z$(TO 20-width) supplies the unfilled part. Together they always print twenty characters, erasing any longer bar from the previous update. CHR$ 91 and CHR$ 93 print the surrounding brackets.

Small nonzero shares can round to no filled cells. Keep the numeric column: the coarse bar gives a quick comparison, while the number gives more detail. The percentage is rounded separately to one decimal place.

Face two has occurred twice in four rolls. The next roll is a six. What happens to face two's count, percentage and bar?

Show the explanation

Its count stays at two. Its share falls from 50% to 40%, and its bar shrinks from ten cells to eight. Every share uses the new total, even though only the face-six tally increased. That is why the display recalculates all six rows.

The header is drawn once during rolling. The updating routine overwrites the total, six counts, shares and bars without clearing the whole screen. This keeps the layout in place while the data changes.

If a bar never shrinks, inspect the spaces printed after its hashes. If a larger count looks like an extra digit has survived, inspect the spaces after numeric output. Redrawing text means replacing its old footprint as well as printing the new value.

Keyboard notes

INKEY$ uses N in extended mode. CHR$ uses U in extended mode. OR is Symbol Shift with U. TO inside a string slice is the same token used in a FOR loop; here it separates the slice bounds.

Sources

Steven Vickers, edited by Robin Bradbeer, ZX Spectrum BASIC Programming, second edition (Sinclair Research, 1983), chapter 8, chapter 12, chapter 14, chapter 15, chapter 18.