 ## 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 "BBC BASIC" 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 BBC BASIC 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.
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?
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

### HOME   