This is the big one. The original author of BASIC Games to JavaScript seems to have stopped at Awari, and I’m curious as to why and what the challenges will be.

Awari is also known as Kalah or Mancala.

jny3woz

My first problem with the conversion has been getting the original BASIC code to run in the first place. The lack of spacing between words is the first problem – the code in the book removes virtually all spaces, even those between keywords.

15 FORI=0TON-1:READF(I):NEXTI

PC-Basic does not support such a compact form, so spaces around keywords need to be added.

15 FOR I=0 TO N-1:READ F(I):NEXT I

The next issue is that the game fails to run in the PC-BASIC emulator, saying:

FOR without NEXT in 230

What’s happening there? Here’s an excerpt.

215 FOR I=0 TO 5:IF B(I)<>0 THEN 230
220 NEXT I
225 RETURN
230 FOR I=7 TO 12:IF B(I)<>0 THEN LETE=1:RETURN
235 GOTO 220

It took a while to understand what’s supposed to happen there. Line 230 is attempting the to abandon the 215 FOR loop, and to repurpose its NEXT statement on a new FOR loop at 230.

PC-BASIC doesn’t like such shoddy behaviour. The solution here is to supply the second FOR loop with its own NEXT statement, returning once it’s done.

235 NEXT I:RETURN

This gets the original game working but somehow after saving it, the text file ends up being corrupt.

After spending far too long attempting to troubleshoot this issue, I finally check the documentation which says:

  • If ,A is specified, the program will be saved in plain text format.
  • If ,P is specified, the program will be saved in protected format. When a protected program is loaded in GW-BASIC, it cannot be LISTed or SAVEd in non-protected format.
  • If neither is specified, the program will be saved in tokenised format.

What looked to be corrupted, was instead the tokenised save format, and was immediately saved by specifying ,A for plain text.

The conversion

After all of that PC-BASIC work, I can finally get to the state of converting the BASIC code to work as JavaScript code instead. Because all of the GOTOs are not done in a structured language, the code needs to be reorganised so that it works with no GOTO statements.

As the conversion process can be quite complex, I keep several different save file. I don’t fully know what I’m doing here with such a complex process, so need to be able to step backwards while exploring the techniques involved.

Removing unneeded line numbers

To start making sense of the BASIC code, I remove mark off the lines that are gone to using THEN, GOTO, and GOSUB. Removing the unmarked lines allows me to more easily understand how the code it supposed to be structured.

Removing statements inessential to the code flow

Because most of the unmarked lines have no effect on the structure of the code, I’m going to remove most of those to help me figure out the structure more clearly. I can add the original code back in later on, for reference purposes.

Remove some line numbers, by applying structure to the code

Some of the code can now be restructured using structured techniques, allowing many line numbers to be removed. For example, with:

100 PRINT"AGAIN";
110 INPUT M:IF M<7 THEN IF M>0 THEN LET M=M-1:GOTO 130
120 PRINT"ILLEGAL MOVE":GOTO 100
130 IF B(M)=0 GOTO 120

The 100 is returning you back for more input, so the AGAIN part can be moved down to the illegal section. We can then put things in a do/while loop, and check for both the correct input and valid selection, where you can only select a pit that actually contains stones.

do {
    INPUT M
    if (M>0 && M<7 && B(M)!==0) {
        LET M=M-1
    } else {
        PRINT"ILLEGAL MOVE"
        PRINT"AGAIN";
    }
} while (M<=0 || M>=7);

All line numbers are now removed from that section, but it’s not always that easy. Get the easy wins done first.

Use named functions, and continue unravelling the code

Moving other parts of code out to named functions helps to make sense of large blocks of code.

function showBoard() {
    ...
}
function showBowl() {
    ...
}
function computerTurn() {
    ...
}

After that organising, the rest of the remaining line numbers can be removed.

Include the original code beneath each function

Now the original code can be included in sections, as comments below each function, so that the full details can be fleshed out.

function seedStones() {
    p = b(m);
    for (p = p; p >= 1; p -= 1) {
        m = m + 1;
        if (m > 13) {
            m = m - 14;
        }
        b(m) = b(m) + 1;
    }
    if (b(m) === 1) {
        if (m !== 6 && m !== 13) {
            if (b(12 - m) > 0) {
                b(h) = b(h) + b(12 - m) + 1;
                b(m) = 0;
                b(12 - m) = 0;
                return;
            }
        }
    }
    return;
}
// 600 LET P=B(M):LET B(M)=0
// 605 FOR P=P TO 1 STEP-1:LET M=M+1:IF M>13 THEN LET M=M-14
// 610 LET B(M)=B(M)+1:NEXT P
// 615 IF B(M)=1 THEN IF M<>6 THEN IF M<>13 THEN IF B(12-M) THEN GOTO 625
// 620 RETURN
// 625 LET B(H)=B(H)+B(12-M)+1:LET B(M)=0:LET B(12-M)=0:RETURN

The old commented code can then be removed when everything works.

ReadLine requires a command dispatcher pattern

Lastly, areas requiring user input need to be dealt with, by assigning a state before stopping and waiting for input. The only trouble is that the same input is used by multiple places, so careful manipulation of state is required:

function getMove() {
    if (state === "playerMove") {
        state = "waitingForPlayerMove";
    }
    if (state === "secondPlayerMove") {
        state = "waitingForSecondMove";
    }
    con.readLine(commandHandler);
}

The command handler can now return execution back to the appropriate location, and the converted code now works without any problems.

Finishing things off

The final work on converting the Awari game is to play through as much of it that I can, to try and be sure that all parts of the code have been tested.

This one was a challenging conversion, but has demonstrated to me that if I can do this one, the rest can also be done too. I know now that it’s time now for me to take up the mantle and carry on the the once-abandoned work with converting the rest of the games.

The example code for the converted Awari can be found at http://codepen.io/pmw57/details/NpLxmR

Advertisements