diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/README.md new file mode 100644 index 00000000..ac389318 --- /dev/null +++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/README.md @@ -0,0 +1,18 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +1. Command-Line MiniScript: +Download for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as: +``` + miniscript stockmarket.ms +``` + +2. Mini Micro: +Download Mini Micro from https://miniscript.org/MiniMicro/, launch, and then click the top disk slot and chose "Mount Folder..." Select the folder containing the MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` + load "stockmarket" + run +``` diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/qubit.ms b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/qubit.ms new file mode 100644 index 00000000..3074be2d --- /dev/null +++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/qubit.ms @@ -0,0 +1,361 @@ +print " "*33 + "QUBIC" +print " "*15 + "Creative Computing Morristown New Jersey" +print; print; print + +getYesNo = function(prompt) + while true + yn = input(prompt + "? ").lower + " " + if yn[0] == "y" then return "yes" + if yn[0] == "n" then return "no" + print "Incorrect answer. Please type 'yes' or 'no'" + end while +end function + +// Data defining "lines" as sets of board indexes which form 4-in-a-row: +ma = [null, + [null, 1,2,3,4], // 1 + [null, 5,6,7,8], // 2 + [null, 9,10,11,12], // 3 + [null, 13,14,15,16], // 4 + [null, 17,18,19,20], // 5 + [null, 21,22,23,24], // 6 + [null, 25,26,27,28], // 7 + [null, 29,30,31,32], // 8 + [null, 33,34,35,36], // 9 + [null, 37,38,39,40], // 10 + [null, 41,42,43,44], // 11 + [null, 45,46,47,48], // 12 + [null, 49,50,51,52], // 13 + [null, 53,54,55,56], // 14 + [null, 57,58,59,60], // 15 + [null, 61,62,63,64], // 16 + [null, 1,17,33,49], // 17 + [null, 5,21,37,53], // 18 + [null, 9,25,41,57], // 19 + [null, 13,29,45,61], // 20 + [null, 2,18,34,50], // 21 + [null, 6,22,38,54], // 22 + [null, 10,26,42,58], // 23 + [null, 14,30,46,62], // 24 + [null, 3,19,35,51], // 25 + [null, 7,23,39,55], // 26 + [null, 11,27,43,59], // 27 + [null, 15,31,47,63], // 28 + [null, 4,20,36,52], // 29 + [null, 8,24,40,56], // 30 + [null, 12,28,44,60], // 31 + [null, 16,32,48,64], // 32 + [null, 1,5,9,13], // 33 + [null, 17,21,25,29], // 34 + [null, 33,37,41,45], // 35 + [null, 49,53,57,61], // 36 + [null, 2,6,10,14], // 37 + [null, 18,22,26,30], // 38 + [null, 34,38,42,46], // 39 + [null, 50,54,58,62], // 40 + [null, 3,7,11,15], // 41 + [null, 19,23,27,31], // 42 + [null, 35,39,43,47], // 43 + [null, 51,55,59,63], // 44 + [null, 4,8,12,16], // 45 + [null, 20,24,28,32], // 46 + [null, 36,40,44,48], // 47 + [null, 52,56,60,64], // 48 + [null, 1,6,11,16], // 49 + [null, 17,22,27,32], // 50 + [null, 33,38,43,48], // 51 + [null, 49,54,59,64], // 52 + [null, 13,10,7,4], // 53 + [null, 29,26,23,20], // 54 + [null, 45,42,39,36], // 55 + [null, 61,58,55,52], // 56 + [null, 1,21,41,61], // 57 + [null, 2,22,42,62], // 58 + [null, 3,23,43,63], // 59 + [null, 4,24,44,64], // 60 + [null, 49,37,25,13], // 61 + [null, 50,38,26,14], // 62 + [null, 51,39,27,15], // 63 + [null, 52,40,28,16], // 64 + [null, 1,18,35,52], // 65 + [null, 5,22,39,56], // 66 + [null, 9,26,43,60], // 67 + [null, 13,30,47,64], // 68 + [null, 49,34,19,4], // 69 + [null, 53,38,23,8], // 70 + [null, 57,42,27,12], // 71 + [null, 61,46,31,16], // 72 + [null, 1,22,43,64], // 73 + [null, 16,27,38,49], // 74 + [null, 4,23,42,61], // 75 + [null, 13,26,39,52]] // 76 + +// "opening book", i.e. spots that are generally good to hold if available +ya = [null, 1,49,52,4,13,61,64,16,22,39,23,38,26,42,27,43] + +showBoard = function + for i in range(1,9); print; end for + for i in range(1, 4) + print + for j in range(1, 4) + str = " " * j + for k in range(1, 4) + q = 16 * i + 4 * j + k - 20 + if xa[q] == 5 then + str += "(M)" + else if xa[q] == 1 then + str += "(Y)" + else + str += "( )" + end if + str += " " + end for + print str + // print (makes display too tall for the screen) + end for + print + end for +end function + +clearFractions = function + for i in range(1, 64) + if xa[i] == 1/8 then xa[i] = 0 + end for +end function + +checkForLines = function + for s in range(1, 76) + j1 = ma[s][1]; + j2 = ma[s][2]; + j3 = ma[s][3]; + j4 = ma[s][4]; + la[s] = xa[j1] + xa[j2] + xa[j3] + xa[j4] + end for +end function + +doPlayerMove = function + clearFractions + while true + print + inp = input("Your move? ") + if inp == "0" then + showBoard + continue + end if + if inp == "1" then exit + ok = true + if inp.len != 3 then + ok = false + else + i = inp[0].val + j = inp[1].val + k = inp[2].val + ok = (0 < i < 5) and (0 < j < 5) and (0 < k < 5) + end if + if not ok then + print "Incorrect move, retype it--" + else + m = 16 * i + 4 * j + k - 20 + if xa[m] != 0 then + print "That square is used, try again." + else + xa[m] = 1 + break + end if + end if + end while +end function + +selectMove = function(lineIndex, valueToReplace) + if lineIndex % 4 <= 1 then a = 1 else a = 2 + for j in range(a, 5 - a, 5 - 2 * a) + if xa[ma[lineIndex][j]] == valueToReplace then + xa[ma[lineIndex][j]] = 5 + m = ma[lineIndex][j] + print "Machine takes " + squareName(m) + return true + end if + end for + return false +end function + +doComputerMove = function + // look for lines with two M's and two blanks; add 1/8 to the blank spots + for i in range(1, 76) + la[i] = xa[ma[i][1]] + xa[ma[i][2]] + xa[ma[i][3]] + xa[ma[i][4]] + l = la[i] + if l == 10 then + for j in range(1, 4) + if (xa[ma[i][j]] == 0) then xa[ma[i][j]] = 1/8 + end for + end if + end for + // ...and if we now find lines containing 4 such spots, or 1 M and 3 such spots, + // then pick one of those spots for our move + checkForLines + for i in range(1, 76) + if la[i] == 4/8 or la[i] == 5 + 3/8 then + selectMove i, 1/8 + return true + end if + end for + + // now look for lines containing 2 Y's, and mark (with 1/8) the blank spots + clearFractions + for i in range(1, 76) + la[i] = xa[ma[i][1]] + xa[ma[i][2]] + xa[ma[i][3]] + xa[ma[i][4]] + l = la[i] + if l == 2 then + for j in range(1, 4) + if (xa[ma[i][j]] == 0) then xa[ma[i][j]] = 1 / 8 + end for + end if + end for + // ...and again, if we find 4 such spots in a row, or 1 player move plus + // 3 marked spots, then pick one of those + checkForLines + for i in range(1, 76) + if la[i] == 4/8 or la[i] == 1 + 3/8 then + selectMove 1/8 + return true + end if + end for + + // do mysterious stuff that depends on the order of lines in ma + // in ways I don't understand + for k in range(1, 18) + p = 0 + for i in range(4 * k - 3, 4 * k) + for j in range(1, 4) + p += xa[ma[i][j]] + end for + end for + if p == 4 or p == 9 then + for i in range(4 * k - 3, 4 * k) + if selectMove(1/8) then return true + end for + s = 0 + end if + end for + + // look for certain "good" spots in our ya array that are still available + clearFractions + found = false + for z in range(1, 17) + if xa[ya[z]] == 0 then + found = true + break + end if + end for + if not found then + // getting desperate, look for any open spot + for i in range(1, 64) + if xa[i] == 0 then + xa[i] = 5 + print "Machine likes " + squareName(i) + return true + end if + end for + print "The game is a draw." + return false + end if + m = ya[z] + xa[m] = 5 + print "Machine moves to " + squareName(m) + return true +end function + +squareName = function(m) + k1 = floor((m - 1) / 16) + 1 + j2 = m - 16 * (k1 - 1) + k2 = floor((j2 - 1) / 4) + 1 + k3 = m - (k1 - 1) * 16 - (k2 - 1) * 4 + return str(k1) + k2 + k3 +end function + +doOneGame = function + globals.xa = [null] + [0] * 64 // board state + globals.la = [null] + [0] * 76 // line data + skipFirst = getYesNo("Do you want to move first") == "no" + while true + if skipFirst then + skipFirst = false + else + doPlayerMove + end if + checkForLines + machineDone = false + // take three passes over the straight lines in the board + for j in range(1, 3) + for i in range(1, 76) + // first pass: check for player win + if j == 1 then + if la[i] != 4 then continue; + print "You win as follows" + " (line " + i + ")" + for j in range(1, 4) + print squareName(ma[i][j]) + end for + return + end if + // second pass: check for machine able to win + if j == 2 then + if la[i] != 15 then continue; + for j in range(1, 4) + m = ma[i][j] + if (xa[m] != 0) then continue; + xa[m] = 5 + break + end for + print "Machine moves to " + squareName(m) + ", and wins as follows" + for j in range(1, 4) + print squareName(ma[i][j]) + end for + return + end if + // third pass: check for player about to win + if j == 3 then + if la[i] != 3 then continue + for j in range(1, 4) + m = ma[i][j] + if xa[m] != 0 then continue + xa[m] = 5 + print "Nice try, machine moves to " + squareName(m) + machineDone = true + end for + break + end if + end for + end for + if (machineDone) then continue + + if not doComputerMove then break + end while +end function + + +// Main program +if getYesNo("Do you want instructions") == "yes" then + print + print "The game is tic-tac-toe in a 4 x 4 x 4 cube." + print "Each move is indicated by a 3 digit number, with each" + print "digit between 1 and 4 inclusive. The digits indicate the" + print "level, row, and column, respectively, of the occupied" + print "place. " + print + print "To print the playing board, type 0 (zero) as your move." + print "The program will print the board with your moves indi-" + print "cated with a (Y), the machine's moves with an (M), and" + print "unused squares with a ( )." // "output is on paper." + print + print "To stop the program run, type 1 as your move." + print + print +end if +while true + doOneGame + print + if getYesNo("Do you want to try another game") == "no" then break +end while + + + diff --git a/88_3-D_Tic-Tac-Toe/README.md b/88_3-D_Tic-Tac-Toe/README.md index 969de3d8..2ab13480 100644 --- a/88_3-D_Tic-Tac-Toe/README.md +++ b/88_3-D_Tic-Tac-Toe/README.md @@ -15,6 +15,8 @@ There are at least two bugs from the original BASIC: 1. Code should only allow player to input valid 3D coordinates where every digit is between 1 and 4, but the original code allows any value between 111 and 444 (such as 297, for instance). 2. If the player moves first and the game ends in a draw, the original program will still prompt the player for a move instead of calling for a draw. +Also note that while the file is called qubit.bas (with a "T"), the title shown in the program listing is "QUBIC" (with "C")... and the sample output shows "TIC TAC TOE" instead of either of these. + --- As published in Basic Computer Games (1978): diff --git a/88_3-D_Tic-Tac-Toe/javascript/qubit.js b/88_3-D_Tic-Tac-Toe/javascript/qubit.js index 0057619f..6f1cbe64 100644 --- a/88_3-D_Tic-Tac-Toe/javascript/qubit.js +++ b/88_3-D_Tic-Tac-Toe/javascript/qubit.js @@ -193,7 +193,7 @@ function select_move() { } if (j > 5 - a) return false; - xa[ma[i][j]] = s; + xa[ma[i][j]] = 5; m = ma[i][j]; print("MACHINE TAKES"); show_square(m);