R.T.Russell Home Page

Appendix E - Answers to the Exercises




In all of these answers please bear in mind that programming is a very subjective art - if what you got worked, that's right, even if it's different from the answers given here. Rather than use these answers as a right / wrong comparison, see how they differ from yours and why. If you're floundering with a problem or stuck for ideas, have a peep, it's not an exam but rather a learning process.

Chapter 3

1) Modify the first program to read "BB4W" instead of "BBC".

REM My first program
PRINT "BBB   BBB     44   W   W"
PRINT "B  B  B  B   4 4   W   W"
PRINT "BBB   BBB   4  4   W W W"
PRINT "B  B  B  B  44444  W W W"
PRINT "BBB   BBB      4   WW WW"
END
2) Insert TABs into the print statements to print BB4W starting at row 10, column 10 in the output window.
REM My first program
PRINT TAB(10,10);"BBB   BBB     44   W   W"
PRINT TAB(10,11);"B  B  B  B   4 4   W   W"
PRINT TAB(10,12);"BBB   BBB   4  4   W W W"
PRINT TAB(10,13);"B  B  B  B  44444  W W W"
PRINT TAB(10,14);"BBB   BBB      4   WW WW"
END

Chapter 4

1) Modify the area program to give the circumference of a circle 3.14159*diameter.

REM Circumference of a circle
Diameter=5
Circumference=3.14159*Diameter
PRINT "The circumference is ";Circumference
END
2) Print the area of a rectangle, when given the width and height.
REM Area of a rectangle
Width=5
Height=10
Area=Width*Height
PRINT "The area is ";Area
END
3) Assign a string variable to contain your name and output:
Hello, xxxx
where xxxx is, of course, your name.
REM Print my name
Name$="Justin Time"
PRINT "Hello, ";Name$
END
Chapter 5

1) Modify the circle program to use PI instead of 3.14159. Save it.
REM Area of a circle
Radius=5
Area=PI*Radius^2
PRINT "The area of your circle is ";Area
END
2) Write a program that uses RND to simulate two six-sided dice being thrown. Print the results for each die and the total.

Two dice have a range of 2 to 12, but the probabilities of the different totals are not equal. For example there are five ways of getting a total of 6 (1+5, 2+4, 3+3, 4+2, 5+1) but only one way of getting a total of 12 (6+6). For this reason you must treat each die as a separate entity:
REM Tumblin' Dice
Die1%=RND(6)
Die2%=RND(6)
PRINT "Total ";Die1%+Die2%
END
3) Verify that the following formula is true:
LOG(X)=LN(X)/LN(10)
The easiest way at this stage is to print the results and compare them visually.
REM Verify LOG(X)=LN(X)/LN(10)
X=1.234
PRINT LOG(X)
PRINT LN(X)/LN(10)
END
Chapter 6

1) Set a string to hold the days of the week like this:
"Sun Mon TuesWed ThurFri Sat"
All names are 4 characters in length including a space if necessary. Given a number for a day, use MID$ to extract the correct abbreviation for the day.

Each string is 4 characters long, so each name will start at position 1, 5, 9 etc. If we take the day number Sunday = 1 etc. and subtract 1 from it then multiply by 4, we get a sequence that goes 0, 4, 8 ... To complete the formula, add an offset of 1. The total calculation needs brackets to override the operator precedence.
(DayNumber-1)*4+1
REM Day name
Day$="Sun Mon TuesWed ThurFri Sat "
DayNum=3
DayName$=MID$(Day$,(DayNum-1)*4+1,4)
PRINT "Day number ";DayNum;" is ";DayName$
END
2) Set a string to hold your first name. Use MID$ and ASC to find the ASCII codes of the letters in the name.
REM ASCII Codes in My Name
Name$="Peter"
PRINT MID$(Name$,1,1);" has code ";
PRINT ASC(MID$(Name$,1,1))
PRINT MID$(Name$,2,1);" has code ";
PRINT ASC(MID$(Name$,2,1))
PRINT MID$(Name$,3,1);" has code ";
PRINT ASC(MID$(Name$,3,1))
PRINT MID$(Name$,4,1);" has code ";
PRINT ASC(MID$(Name$,4,1))
PRINT MID$(Name$,5,1);" has code ";
PRINT ASC(MID$(Name$,5,1))
END
I hope you used copy and paste for this one. You could also pull each letter out to a separate string like this:
Letter$=MID$(Name$,1,1)
PRINT Letter$;" has code ";ASC(Letter$)
3) Set three strings to hold your first name, second name (if you haven't got one, make it up) and surname. Use LEFT$ to find your initials and concatenation to create a new string in the format "R. T. Russell".
REM Initials
First$="Johann"
Second$="Sebastian"
Surname$="Bach"
Name$=LEFT$(First$,1)+". "
Name$=Name$+LEFT$(Second$,1)+". "
Name$=Name$+Surname$
PRINT Name$
END
Chapter 7

1) Examine the different MODEs in the help file, try printing text in MODEs 1 to 6 to get the feel for what they look like.

A bit open ended this one, the easiest way is to cut and paste three lines several times:
REM Different MODES
MODE 1
PRINT "Hello, World"
WAIT 200
MODE 2
PRINT "Hello, World"
WAIT 200
MODE 3
PRINT "Hello, World"
WAIT 200
MODE 4
PRINT "Hello, World"
WAIT 200
MODE 5
PRINT "Hello, World"
WAIT 200
MODE 6
PRINT "Hello, World"
WAIT 200
END
2) Modify the Changing colours program to produce new random colours by using three RND(255) statements in the call on lines 2 and 5.
REM Changing colours
COLOUR 3,RND(255),RND(255),RND(255)
REM Now we've set the colour change to it
COLOUR 3
PRINT "Hello, World"
COLOUR 3,RND(255),RND(255),RND(255)
PRINT "Hello, World"
COLOUR 0
END
With the window still open, RUN this several times to get different colours.

Chapter 8

1) The volume of a cylinder is PI*Radius^2*Length. Write a program that will ask for radius and length then give the volume.
REM Volume of a cylinder
INPUT "Enter the radius " Radius
INPUT "Enter the length " Length
Volume=PI*Radius^2*Length
PRINT "The volume is ";Volume
END
2) Have a program prompt to enter your full name. Print the number of characters (including spaces) in the name.
REM Length of name
INPUT LINE "Enter your name, please " Name$
PRINT "Thank you ";Name$
PRINT "Your name has ";LEN(Name$);" characters."
END
Chapter 9

Below is a sample output from a two runs of a program that acts as a simple calculator:
Enter first number: 5
Enter second number: 6
Enter 1 to add or 2 to subtract: 1
5 + 6 = 11
>RUN
Enter first number: 45
Enter second number: 55
Enter 1 to add or 2 to subtract: 2
45 - 55 = -10
Can you write the program that produces the above screen? Allow one INPUT for each number, one INPUT for the operations. Use IF to select the correct PRINT statement and result, then another INPUT to ask for another go. Extra marks if you expand to include multiply and divide.

This is the first solution.
REM Basic calculator
INPUT "Enter first number " Num1
INPUT "Enter second number " Num2
INPUT "Enter 1 to add or 2 to subtract: " Op%
IF Op%=1 THEN
  PRINT Num1;" + ";Num2;" = ";Num1 + Num2
ENDIF
IF Op%=2 THEN
  PRINT Num1;" - ";Num2;" = ";Num1 - Num2
ENDIF
END
After this the second one is easy.
REM Basic calculator
INPUT "Enter first number " Num1
INPUT "Enter second number " Num2
PRINT "Enter 1 to add, 2 to subtract"
INPUT " 3 to multiply, 4 to divide: " Op%
IF Op%=1 THEN
  PRINT Num1;" + ";Num2;" = ";Num1 + Num2
ENDIF
IF Op%=2 THEN
  PRINT Num1;" - ";Num2;" = ";Num1 - Num2
ENDIF
IF Op%=3 THEN
  PRINT Num1;" * ";Num2;" = ";Num1 * Num2
ENDIF
IF Op%=4 THEN
  PRINT Num1;" / ";Num2;" = ";Num1 / Num2
ENDIF
IF Op%<1 OR Op%>4 THEN
  PRINT "Sorry, invalid operation."
ENDIF
END
Chapter 10

Recreate an executive decision maker. Generate a random number 1 to 6 and print a message depending on the result:
1 - Hire a yes man
2 - Fire someone
3 - Delegate
4 - Cancel all overtime
5 - Give yourself a rise
6 - Raid the pension fund
REM Decision maker
PRINT "Here is your decision for the day"
Dec%=RND(6)
CASE Dec% OF
  WHEN 1 : PRINT "Hire a yes man"
  WHEN 2 : PRINT "Fire someone"
  WHEN 3 : PRINT "Delegate"
  WHEN 4 : PRINT "Cancel all overtime"
  WHEN 5 : PRINT "Give yourself a rise"
  WHEN 6 : PRINT "Raid the pension fund"
ENDCASE
END
Chapter 11

1) Write a program with a FOR loop to print the 5 times table. Each line should be in the format:
1 * 5 = 5
2 * 5 = 10
...
12 * 5 = 60
REM 5 times table
FOR I%=1 TO 12
  PRINT I%;" * 5 = ";I%*5
NEXT I%
END
2) Use two nested FOR loops to draw a rectangle on the screen by using a line like PRINT TAB(X,Y);"*"
REM Print a rectangle
INPUT "Enter Width " Width%
INPUT "Enter Height " Height%
CLS
FOR Y%=1 TO Height%
  FOR X%=1 TO Width%
    PRINT TAB(X%,Y%);"*"
  NEXT X%
NEXT Y%
END
Or, instead of clearing the screen, you could just offset the rectangle:
REM Print a rectangle
INPUT "Enter Width " Width%
INPUT "Enter Height " Height%
FOR Y%=1 TO Height%
  FOR X%=1 TO Width%
    PRINT TAB(X%+5,Y%+5);"*"
  NEXT X%
NEXT Y%
END
Chapter 12

1) Produce a program that will ask for a string and print the ASCII code of the first character. Have the program stop if the string entered is empty ("").
REM Find the code
REPEAT
  INPUT "Enter a string " MyString$
  IF LEN(MyString$) > 0 THEN
    A$=LEFT$(MyString$,1)
    PRINT A$;" has ASCII code ";ASC(A$)
  ENDIF
UNTIL LEN(MyString$)=0
END
2) Write a program that will ask for a number. Add this number to a running total. Repeat until the number entered is 0. Print the result.
REM Totalizer
Total=0
REPEAT
  INPUT "Enter a number " Num
  Total+=Num
UNTIL Num=0
PRINT "Total entered = ";Total
END
Chapter 13

1) Modify the number filter program to accept one (and only one) decimal point in the number. If you're feeling ambitious, add a further modification to intercept backspace and delete the last character, if any, from the string. You'll need to print a space after the string to erase the character from the screen.

Picking up the keypresses is no problem, we need a flag to indicate that the string has had a decimal point entered. When deleting the final character, we have to check if it's a point and reset the flag accordingly.
REM Number filter
Total$=""
DP%=FALSE
PRINT "Type your number or Enter to finish"
REPEAT
  Key%=GET
  REM Check for numeric characters
  IF CHR$(Key%)>="0" AND CHR$(Key%)<="9" THEN
    Total$=Total$+CHR$(Key%)
  PRINT TAB(0,1);Total$;
  ENDIF
  REM Check for decimal point
  IF CHR$(Key%)="." AND NOT DP% THEN
    Total$=Total$+CHR$(Key%)
    DP%=TRUE
    PRINT TAB(0,1);Total$;
  ENDIF
  REM Action backspace only if there's
  REM something to delete
  IF Key%=8 AND LEN(Total$)> 0 THEN
    REM If last character is a point,
    REM reset flag the DP flag
    IF RIGHT$(Total$,1)="." DP%=FALSE
    Total$=LEFT$(Total$)
    REM Print string with trailing space
    REM to erase deleted character
    PRINT TAB(0,1);Total$;" ";
    PRINT TAB(0,1);Total$;
  ENDIF
  UNTIL Key%=13
PRINT '"You entered: ";VAL(Total$)
END
2) Make a simple drawing program. Use X% and Y% in a TAB statement to plot an 'X' on the screen. When you press the arrow keys, adjust X% or Y% according to the key pressed. For example, if you press left, decrease X%, down - increase Y%. Plot an 'X' at the new position so you can leave a trail on the screen. Restrict the area in which you can draw to a 20 * 20 grid.

We restrict the cursor to a grid of 20*20 so there's no problem going off the edge of the screen. The program loops forever, press ESC to get out.

There are two possible commands here GET and INKEY, the first program is the solution using GET.
REM Sketch
X%=10
Y%=10
REM Print X in starting place
PRINT TAB(X%,Y%);"X"
REPEAT
  Key%=GET
  REM Move cursor in direction after checking
  REM we're still in limits
  CASE Key% OF
    WHEN 139: IF Y% > 0 THEN Y%-=1
    WHEN 137: IF X% < 19 THEN X%+=1
    WHEN 138: IF Y% < 19 THEN Y%+=1
    WHEN 136: IF X% > 0 THEN X%-=1
  ENDCASE
  REM Print X in new position
  PRINT TAB(X%,Y%);"X"
UNTIL FALSE
END
Here is the solution using INKEY. If you coded it this way, you probably discovered the importance of a WAIT command to stop the 'X' zipping from one side of the screen to the other.
REM X-A-Sketch
X%=10
Y%=10
REM Print X in starting place
PRINT TAB(X%,Y%);"X"
REPEAT
  REM Move cursor in direction after checking
  REM we're still in limits
  IF INKEY(-58) AND Y% > 0 THEN Y%-=1
  IF INKEY(-122) AND X% < 19 THEN X%+=1
  IF INKEY(-42) AND Y% < 19 THEN Y%+=1
  IF INKEY(-26) AND X% > 0 THEN X%-=1
  REM Small delay to stop too many prints
  WAIT 20
  REM Print X in new position
  PRINT TAB(X%,Y%);"X"
UNTIL FALSE
END
Chapter 14

Here are the figures for the first six months' sales of triple fruit chocolate covered syrup and treacle flavour ice lollies from one local newsagent:
January   105
February  261
March     482
April     195
May       347
June      626
Set an array to hold these values. Then add to the program so it loops through the values to find and print:

a) the month number for the lowest sales;
b) the month for the highest sales;
c) the total sales.

You can use the same FOR loop to achieve all three or do them separately: your choice.

Modify the program to have an array of month names, initialize it and adapt the above program to display real names for the months.


This is looks a lot but it's not too bad if you break it down and follow the examples.
REM Lolly sales
DIM Sales%(6), Month$(12)
REM Initialise
Sales%() = 0,105,261,482,195,347,626
Month$() = "","January","February", \
\ "March","April","May","June", \
\ "July","August","September", \
\ "October","November","December"
REM Set result variables
LowestSale% = 9999
LowestMonth% = 0
HighestSale% = -9999
HighestMonth% = 0
Total% = 0
REM Now find the data
FOR I%=1 TO 6
  IF Sales%(I%) < LowestSale% THEN
    LowestSale%=Sales%(I%)
    LowestMonth%=I%
  ENDIF
  IF Sales%(I%) > HighestSale% THEN
    HighestSale%=Sales%(I%)
    HighestMonth%=I%
  ENDIF
  Total%+=Sales%(I%)
NEXT I%
REM Print the results
LoMon$=Month$(LowestMonth%)
HiMon$=Month$(HighestMonth%)
PRINT "The lowest sales were in ";LoMon$
PRINT "The highest sales were in ";HiMon$
PRINT "The total sales were ";Total%
END
Chapter 15

1) If you wanted to store the grades for five subjects for a pupil along with their first name and surname, can you suggest a structure that would do this?
DIM Pupil{FirstName$, Surname$, Grades%(5)}
2) Write a program that declares such a structure and prompts for the information. Calculate the average grade and print the results.
REM Pupil Report
DIM Pupil{FirstName$, Surname$, Grades%(5)}
REM Collect information
INPUT "Enter first name " Pupil.FirstName$
INPUT "Enter surname " Pupil.Surname$
FOR I%=1 TO 5
  PRINT "Enter grade for subject ";I%;
  INPUT " " Pupil.Grades%(I%)
NEXT I%
Total=0
FOR I%=1 TO 5
  Total+=Pupil.Grades%(I%)
NEXT I%
REM Print a report card
PRINT
PRINT "Name: ";Pupil.Surname$;", ";
PRINT Pupil.FirstName$
PRINT "Average grade: ";Total/5
PRINT
END
3) If you had 20 pupils in a class, how would you make an array of the above structure?

There are two methods:
DIM Pupil{(20) FirstName$, Surname$, \
\              Grades%(5)}
or:
DIM Pupil{FirstName$, Surname$, Grades%(5)}
DIM Class{(20)}=Pupil{}
Chapter 16

1) Modify the PROC_ScreenSetup to accept the background and foreground colour.
REM Passing a value to a PROC
PROC_ScreenSetup(5, "First screen", 0, 130)
INPUT A$
PROC_ScreenSetup(10, "Second screen", 1, 135)
INPUT A$
REM Restore original colours
PROC_ScreenSetup(0, "", 0, 128+15)
END
DEF PROC_ScreenSetup(Col%,Title$,Fore%,Back%)
COLOUR Back%
COLOUR Fore%
CLS
PRINT TAB(Col%);Title$
ENDPROC
2) Write and test PROC_Greater(A%,B%) which compares A% and B%. If the A% > B%, do nothing, if B% > A%, exchange the two values using a local variable. You'll need to pass by reference so the calling program can print the results.
REM Exchange two variables
INPUT "Enter value 1 " Num1%
INPUT "Enter value 2 " Num2%
PROC_Greater(Num1%, Num2%)
PRINT Num1%;" is greater than ";Num2%
END
DEF PROC_Greater(RETURN A%, RETURN B%)
LOCAL Temp%
REM If greater number is last, swop them
IF B% > A% THEN
  Temp% = B%
  B% = A%
  A% = Temp%
ENDIF
ENDPROC
Chapter 17

1) It's a very useful function that waits for the user to press y (yes) or n (no) in response to a prompt and returns either TRUE or FALSE. It should, of course, check for case.
REM FN_YesNo
PRINT "Are you sure you want to exit (Y/N)?"
IF FN_YesNo THEN
  PRINT "Fine by me, bye."
ELSE
  PRINT "Sorry, show's over anyway."
ENDIF
END
DEF FN_YesNo
LOCAL Reply$, Return%
REPEAT
  Reply$=GET$
UNTIL INSTR("YyNn",Reply$)<>0
IF Reply$="Y" OR Reply$="y" THEN
  Return%=TRUE
ELSE
  Return%=FALSE
ENDIF
=Return%
2) Write a function FN_Lower that accepts a string. It goes through each character in the string and converts all uppercase letters to lowercase. Other characters are left as they are. Return the converted string.
REM FN_Lower
INPUT "Enter a string to convert " MyString$
LoString$=FN_Lower(MyString$)
PRINT "Converted string: ";LoString$
END
DEF FN_Lower(Convert$)
LOCAL C$, Code%, Return$, I%
Return$=""
FOR I%=1 TO LEN(Convert$)
  REM Get character to work with into
  REM temporary variable, saves code
  C$ = MID$(Convert$,I%,1)
  REM Test character to see if uppercase
  IF C$>="A" AND C$ <= "Z" THEN
    REM It is, so convert it
    REM Get code for character - offset 'A'
    Code%=ASC(C$)-ASC("A")
    REM Add value to offset for 'a'
    C$=CHR$(ASC("a")+Code%)
  ENDIF
  REM Now add character to return string
  Return$+=C$
NEXT I%
=Return$
You could also use MID$ to replace the characters in the passed string, like this:
DEF FN_Lower(Convert$)
LOCAL C$, Code%, I%
FOR I%=1 TO LEN(Convert$)
  REM Get character to work with into
  REM temporary variable, saves code
  C$ = MID$(Convert$,I%,1)
  REM Test character to see if uppercase
  IF C$ >= "A" AND C$ <= "Z" THEN
    REM It is, so convert it
    REM Get code for character - offset 'A'
    Code%=ASC(C$)-ASC("A")
    REM Add value to offset for 'a'
    MID$(Convert$,I%,1)=CHR$(ASC("a")+Code%)
  ENDIF
NEXT I%
=Convert$
Chapter 18

1) Make the alien walk back across the screen, right to left when it has reached the right-hand side.
REM Walking alien
MODE 6
OFF
VDU 23,240,153,189,219,126,36,60,36,36
PRINT TAB(0,10);CHR$(240)
FOR I%=1 TO 19
  PRINT TAB(I%-1,10);" "
  PRINT TAB(I%,10);CHR$(240)
  WAIT 25
NEXT I%
FOR I%=19 TO 0 STEP -1
  PRINT TAB(I%+1,10);" "
  PRINT TAB(I%,10);CHR$(240)
  WAIT 25
NEXT I%
ON
END
2) Create another alien with its arms pointing down. Use character 241. Modify the animation from 1) to alternate aliens as it moves across the screen.
I% MOD 2
will tell you if I% is an odd or even number.
REM Walking alien
MODE 6
OFF
VDU 23,240,153,189,219,126,36,60,36,36
VDU 23,241,24,60,219,255,165,189,36,36
PRINT TAB(0,10);CHR$(240)
FOR I%=1 TO 19
  PRINT TAB(I%-1,10);" "
  IF I% MOD 2 = 0 THEN
    PRINT TAB(I%,10);CHR$(240)
  ELSE
    PRINT TAB(I%,10);CHR$(241)
  ENDIF
  WAIT 25
NEXT I%
FOR I%=19 TO 0 STEP -1
  PRINT TAB(I%+1,10);" "
  IF I% MOD 2 = 0 THEN
    PRINT TAB(I%,10);CHR$(240)
  ELSE
    PRINT TAB(I%,10);CHR$(241)
  ENDIF
  WAIT 25
NEXT I%
ON
END
Chapter 19

1) Create a sound effect that uses short bursts of hiss to generate a noise like a machine gun.

... or a helicopter depending on how you feel.

REM Machine gun
 
FOR I%=1 TO 5
  SOUND 0,-15,4,1
  SOUND 0,0,0,1
  SOUND 0,-15,4,1
  SOUND 0,0,0,1
NEXT I%
END
2) Here is an incomplete game ...

The missing lines should look something like this:

REM Read character in front of player
Ch%=GET(CarX%,1)
REM Off road, lose a life
IF Ch%<>220 THEN
  SOUND 0,-15,4,5
  Lives%-=1
  WAIT 5
ENDIF
REM Detect player movement
IF INKEY(-26) AND CarX%>5 CarX%-=1
IF INKEY(-122) AND CarX%<34 CarX%+=1
If you think it's too easy, change the WAIT 20 line at the top of the main loop or make the road three characters wide.
My best score is 561 ...

Chapter 20

1) I'm sure you can see lots of improvements here, try adding two more commands, one to completely clear the grid and one to fill it. You could use C and F to do this.

The main problem to be aware of here is how to integrate the new options with the existing program. Looking at the pseudo-code, we can see that there are three routines to change:

PROC_DrawMainScreen, we need to display the new options so the user knows they're there.

FN_GetUserAction, allow the user to enter two codes, taking care of upper and lower cases and assign an action code.

PROC_ProcessAction, deal with the new actions. All that is required here is to loop through each row and column in the grid, setting or clearing each cell as the choice dictates. Once finished, we need to call PROC_DrawCharacter which will refresh the screen.

Rather than reproduce the whole program, here are the updated routines.

REM *****************************************
REM PROC_DrawMainScreen - prints title & help
DEF PROC_DrawMainScreen
REM Set background colour
COLOUR 128+7
CLS
COLOUR 0
REM Print title
PRINT TAB(15,0);"Character Generator"
PRINT TAB(15,1);STRING$(19,"=")
REM Print help instructions
PRINT TAB(1,3);"Instructions:"
PRINT TAB(1,4);"Use arrow keys to move cursor."
PRINT TAB(1,5);"Space to toggles selected cell."
PRINT TAB(1,6);"C clears grid, F fills it"
PRINT TAB(1,7);"X or ESC to exits."
ENDPROC
REM *****************************************
REM FN_GetUserAction - returns an action code
DEF FN_GetUserAction
LOCAL Key%,Code%
REPEAT
  REM Wait for keypress
  Key%=GET
  REM Translate key press to action code
  CASE Key% OF
    WHEN 139: Code%=1
    WHEN 137: Code%=2
    WHEN 138: Code%=3
    WHEN 136: Code%=4
    WHEN 32: Code%=5
    WHEN 67 OR 99: Code%=6
    WHEN 70 OR 102: Code%=7
    WHEN 88: Code%=999
    WHEN 120: Code%=999
    OTHERWISE Code%=0
  ENDCASE
UNTIL Code%<>0
=Code%
REM *****************************************
REM PROC_ProcessAction - actions a valid code
DEF PROC_ProcessAction(Code%)
LOCAL Row%,Col%
CASE Code% OF
  WHEN 1: PROC_MoveCursor(1)
  WHEN 2: PROC_MoveCursor(2)
  WHEN 3: PROC_MoveCursor(3)
  WHEN 4: PROC_MoveCursor(4)
  WHEN 5:
    IF Grid%(Cursor.Col%,Cursor.Row%)=1 THEN
      Grid%(Cursor.Col%,Cursor.Row%)=0
    ELSE
      Grid%(Cursor.Col%,Cursor.Row%)=1
    ENDIF
    PROC_DrawCharacter
  WHEN 6:
    FOR Row%=1 TO 8
      FOR Col%=1 TO 8
        Grid%(Row%,Col%)=0
      NEXT Col%
    NEXT Row%
    PROC_DrawCharacter
  WHEN 7:
    FOR Row%=1 TO 8
      FOR Col%=1 TO 8
        Grid%(Row%,Col%)=1
      NEXT Col%
    NEXT Row%
    PROC_DrawCharacter
  WHEN 999:
    REM Set exit flag
    Exit=TRUE
ENDCASE
PROC_DrawCursor
ENDPROC
2) It's nice to be able to reverse engineer characters too, given the row totals. Modify the project to allow the user to enter a total for the row he's currently on. Then redisplay the character.

This threatens to be a little more complicated. Obviously, there will be modifications to the above three routines again, but how do we achieve the translation of a number into cells of the grid? Let's write the pseudo-code. First we need to get a value to work with:
REPEAT
  Prompt for Row Value
  Get a value for the current row
UNTIL Row Value is valid
Now we have to convert it into binary. Start with a value of 128, the value of the highest bit in an eight bit number, and compare the row value with it. If the row value is greater than or equal to 128, the top bit must be set so we subtract 128 from the row value and set the correct cell in the grid. After this take the value of the next bit down (64) and try again. We keep going until we have done all eight bits. This looks like a job for a FOR loop to me. Here's what we are trying to achieve:
Set Column Value to 128
FOR each column
  IF Row Value >= Column Value THEN
    Set Grid cell at Row, Column
    Subtract Column Value from Row Value
  ELSE
    Reset Grid cell at Row, Column
  ENDIF
  Half Column Value
NEXT column
Draw Character
If we write all this into the Process Action routine, it starts getting a little ungainly. We'll give the action a new routine, GetRowValue. We're going to need local variables for the Row Value, Column Value, and a loop counter, Column. This is the complete routine, I added it to the bottom of the program:
REM *****************************************
REM PROC_GetRowValue - gets a value for row
DEF PROC_GetRowValue
LOCAL RowValue%,ColValue%, Col%
REM Get a valid value
REPEAT
  PRINT TAB(1,25);SPC(30);TAB(1,25);
  INPUT "Enter value for row: " RowValue%
UNTIL RowValue%>=0 AND RowValue%<=255
PRINT TAB(1,25);SPC(30)
REM Convert the number into binary
ColValue%=128
FOR Col%=1 TO 8
  IF RowValue%>=ColValue% THEN
    Grid%(Col%,Cursor.Row%)=1
    RowValue%-=ColValue%
  ELSE
    Grid%(Col%,Cursor.Row%)=0
  ENDIF
  ColValue%=ColValue%/2
NEXT Col%
PROC_DrawCharacter
ENDPROC
Of course there are also the other three routines. Here they are:
REM *****************************************
REM PROC_DrawMainScreen - prints title & help
DEF PROC_DrawMainScreen
REM Set background colour
COLOUR 128+7
CLS
COLOUR 0
REM Print title
PRINT TAB(15,0);"Character Generator"
PRINT TAB(15,1);STRING$(19,"=")
REM Print help instructions
PRINT TAB(1,3);"Instructions:"
PRINT TAB(1,4);"Use arrow keys to move cursor."
PRINT TAB(1,5);"Space toggles selected cell."
PRINT TAB(1,6);"C clears grid, F fills it"
PRINT TAB(1,7);"V enters a row value"
PRINT TAB(1,8);"Press X or ESC to exit."
ENDPROC
REM *****************************************
REM FN_GetUserAction - returns an action code
DEF FN_GetUserAction
LOCAL Key%,Code%
REPEAT
  REM Wait for keypress
  Key%=GET
  REM Translate key press to action code
  CASE Key% OF
    WHEN 139: Code%=1
    WHEN 137: Code%=2
    WHEN 138: Code%=3
    WHEN 136: Code%=4
    WHEN 32: Code%=5
    WHEN 67 OR 99: Code%=6
    WHEN 70 OR 102: Code%=7
    WHEN 86 OR 118: Code%=8
    WHEN 88: Code%=999
    WHEN 120: Code%=999
    OTHERWISE Code%=0
  ENDCASE
UNTIL Code%<>0
=Code%
REM *****************************************
REM PROC_ProcessAction - actions a valid code
DEF PROC_ProcessAction(Code%)
LOCAL Row%,Col%
CASE Code% OF
  WHEN 1: PROC_MoveCursor(1)
  WHEN 2: PROC_MoveCursor(2)
  WHEN 3: PROC_MoveCursor(3)
  WHEN 4: PROC_MoveCursor(4)
  WHEN 5:
    IF Grid%(Cursor.Col%,Cursor.Row%)=1 THEN
      Grid%(Cursor.Col%,Cursor.Row%)=0
    ELSE
      Grid%(Cursor.Col%,Cursor.Row%)=1
    ENDIF
    PROC_DrawCharacter
  WHEN 6:
    FOR Row%=1 TO 8
      FOR Col%=1 TO 8
        Grid%(Row%,Col%)=0
      NEXT Col%
    NEXT Row%
    PROC_DrawCharacter
  WHEN 7:
    FOR Row%=1 TO 8
      FOR Col%=1 TO 8
        Grid%(Row%,Col%)=1
      NEXT Col%
    NEXT Row%
    PROC_DrawCharacter
  WHEN 8: PROC_GetRowValue
  WHEN 999:
    REM Set exit flag
    Exit=TRUE
ENDCASE
PROC_DrawCursor
ENDPROC

Left CONTENTS

HOME Right


Best viewed with Any Browser Valid HTML 3.2!
© Peter Nairn 2006