Friday, May 27, 2011

Forth for Enlightenment, part six of ten, Backwords too

One of the problems that had yet to be solved in the previous post is creating a new puzzle. And, the cat was let out of the bag, in that the HP-28 has no way to write into the middle of a string. However, we have already created a function, REV, that changes a string. Further, if the string starts out with no duplicate characters, it stays having no duplicates. So one idea is to call it a bunch of times with random reversals. The idea is to call the function often enough to randomize the string, but not so often as to take too long. After some experimentation, 30 calls was settled on.


« 1 30 START
RAND 8 * 2 + FLOOR REV
NEXT
» 'SHFL' STO

You can test this function by keying in the string "abcdefghi" and pushing the user defined key under 'SHFL'. This function takes about 18 seconds to run. It's too long. Most people can wait about 7 seconds before they start thinking about something else. At 18 seconds, they're thinking about getting a cup of coffee. I don't drink coffee.

Back in 1988, i had an 7.16 MHz 8088 based PC clone (switch selectable to 4.77 MHz). There were two C compilers. Microsoft C 5.0, and Borland's Turbo C. Turbo C seemed like it was infinitely faster. But timing tests showed that it was only three times faster at compiling programs. The expectation was that Borland must have been at least ten times faster. But here's what was really going on. Compiling a program that took 20 seconds in Microsoft's compiler would take about 7 seconds to compile with Borland's Turbo C. It turned out that typical C program files acted exactly this way. For larger projects, there were multiple files, and each turned out to take about 7 seconds to compile with Turbo C. When modifications were made to a program, typically only one file would be edited, and the compiler was smart enough to compile only the edited files. The developer experience was that Turbo C was always quick, while Microsoft C was always slow. It was worse than this, though. Turbo C really understood the new ANSI (now ISO) C standard, where Microsoft C 5.0 would only happily ignore the new syntax. And i encountered real working C code that would actually crash the Microsoft C compiler. Microsoft could refund me the more than three times higher cost any time now, and i wouldn't be quite so pissed off.

All this to say that while this solution is quick to write, it isn't very satisfactory. However, i went on to write the rest of the game.


« CLLCD
"abcdefghi" SHFL
1 'BMV' STO
WHILE DUP "abcdefghi" ≠ REPEAT
BMV 1 DISP 'BMV' 1 STO+ DUP 2 DISP
DO UNTIL KEY END STR→ REV
END
2 DISP
"You win" 3 DISP
'BMV' PURGE
» 'BACK' STO

After you enter this program, you can run it by clicking on the user key labeled 'BACK'. It clears the screen first, and after what seems like forever, it puts up the new random puzzle. It then waits for single key presses. When it gets a digit between 1 and 9, it reverses that many letters, checks to see if you won, and if not, waits for the next key. You might notice that there is a symbol on the top of the screen that says that a program is running, even though it's waiting for you. When you finish the game (that is, when you win), it prints "You win". You can quit a game by pressing the "ON" button. It will probably leave the current puzzle string on the stack.

A closer look at the program shows that it starts with the solution and passes it to SHFL. It creates the variable BMV, with the value 1. This is the count of moves so far. It might have meant "Backwords MoVes". It then loops until the string is the solution string. It displays the current puzzle and the current move. The DO UNTIL KEY END is an idiom to get a character for input. The KEY function does not wait for a key press. There isn't a built-in function to wait for a character. So you must provide the wait loop yourself. The key comes back as a string. What was needed was a number. The STR→ function converts the string into a number. It wasn't my first guess for a function that might do that. It's passed to REV without any error checking. I mean, you could press anything. If you press the SOLV button, it turns out that STR→ can't convert that to anything. The machine beeps, prints "Bad Argument Type" on the screen and stops. There's lots of crap on the stack, too. Not very graceful. If you press the zero key, the first character is duplicated in the string. Pressing the '1' key reverses one character, which is to say that it does nothing. But it does increment your move count. So, confine your entries to 2 through 9. Back in the day, i might have performed better data entry checking. Call me lazy.

Next up is a diversion about playing this game.