From 5a886283aafb06bd750a4aa59b0fee7e9167ede6 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 10 Jul 2023 21:24:15 -0700 Subject: [PATCH 01/11] MiniScript versions of Acey Ducey, Amazing, Animal, and Awari. --- .../01_Acey_Ducey/MiniScript/README.md | 16 ++ .../01_Acey_Ducey/MiniScript/aceyducey.ms | 59 +++++++ .../02_Amazing/MiniScript/README.md | 18 +++ .../02_Amazing/MiniScript/amazing.ms | 108 +++++++++++++ .../03_Animal/MiniScript/README.md | 16 ++ .../03_Animal/MiniScript/animal.ms | 90 +++++++++++ .../04_Awari/MiniScript/README.md | 16 ++ .../04_Awari/MiniScript/awari.ms | 146 ++++++++++++++++++ 01_Acey_Ducey/README.md | 5 +- 02_Amazing/README.md | 4 + 10 files changed, 477 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md create mode 100644 00_Alternate_Languages/01_Acey_Ducey/MiniScript/aceyducey.ms create mode 100644 00_Alternate_Languages/02_Amazing/MiniScript/README.md create mode 100644 00_Alternate_Languages/02_Amazing/MiniScript/amazing.ms create mode 100644 00_Alternate_Languages/03_Animal/MiniScript/README.md create mode 100644 00_Alternate_Languages/03_Animal/MiniScript/animal.ms create mode 100644 00_Alternate_Languages/04_Awari/MiniScript/README.md create mode 100644 00_Alternate_Languages/04_Awari/MiniScript/awari.ms diff --git a/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md b/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md new file mode 100644 index 00000000..a15b86d9 --- /dev/null +++ b/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md @@ -0,0 +1,16 @@ +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 aceyducey.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 BASIC program. Then, at the Mini Micro command prompt, enter: + + load "aceyducey" + run diff --git a/00_Alternate_Languages/01_Acey_Ducey/MiniScript/aceyducey.ms b/00_Alternate_Languages/01_Acey_Ducey/MiniScript/aceyducey.ms new file mode 100644 index 00000000..c00684ce --- /dev/null +++ b/00_Alternate_Languages/01_Acey_Ducey/MiniScript/aceyducey.ms @@ -0,0 +1,59 @@ +print " "*26 + "Acey Ducey Card Game" +print " "*15 + "Creative Computing Morristown, New Jersey" +print +print +print "Acey-ducey is played in the following manner." +print "The dealer (computer) deals two cards face up." +print "You have an option to bet or not bet depending" +print "on whether or not you feel the card will have" +print "a value between the first two." +print "If you do not want to bet, input a 0." + +cards = range(2,10) + ["Jack", "Queen", "King", "Ace"] + +while true + money = 100 + + while true + print "You now have " + money + " dollars." + print + print "Here are your next two cards:" + while true + A = floor(rnd * cards.len) + B = floor(rnd * cards.len) + if B > A then break + end while + print cards[A] + print cards[B] + bet = input("What is your bet? ").val + while bet > money + print "Sorry, my friend, but you bet too much." + print "You have only " + money + " dollars to bet." + bet = input("What is your bet? ").val + end while + if bet == 0 then + print "Chicken!!" + continue + end if + C = floor(rnd * cards.len) + print cards[C] + + if C <= A or C >= B then + print "Sorry, you lose." + money -= bet + if money <= 0 then break + else + print "You win!!!" + money += bet + end if + end while + + print + print + print "Sorry, friend, but you blew your wad." + print; print + again = input("Try again (yes or no)? ").lower + if again and again[0] == "n" then break +end while + +print "O.K., hope you had fun!" \ No newline at end of file diff --git a/00_Alternate_Languages/02_Amazing/MiniScript/README.md b/00_Alternate_Languages/02_Amazing/MiniScript/README.md new file mode 100644 index 00000000..a93e33d1 --- /dev/null +++ b/00_Alternate_Languages/02_Amazing/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 amazing.ms + +Note that because this program imports "listUtil", you will need to have a the standard MiniScript libraries somewhere in your import path. + +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 BASIC program. Then, at the Mini Micro command prompt, enter: + + load "amazing" + run diff --git a/00_Alternate_Languages/02_Amazing/MiniScript/amazing.ms b/00_Alternate_Languages/02_Amazing/MiniScript/amazing.ms new file mode 100644 index 00000000..3c358979 --- /dev/null +++ b/00_Alternate_Languages/02_Amazing/MiniScript/amazing.ms @@ -0,0 +1,108 @@ +import "listUtil" +print " "*28 + "Amazing Program" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print; print +while true + inp = input("What and your width and length? ") + inp = inp.replace(",", " ") + fields = inp.split + h = fields[0].val; v = fields[-1].val + if h > 1 and v > 1 then break + print "Meaningless dimensions. Try again." +end while + +// order: keeps track of the order in which each cell was +// visited as we built the maze. 0 means not explored yet. Indexed in [column][row] order. +// (This is W in the original BASIC program.) +order = list.init2d(h,v, 0) + +// walls: keeps track of the walls below and to the right of each cell: +// 0: walls below and to the right +// 1: wall to the right +// 2: wall below +// 3: neither wall +// (This is V in the original BASIC program.) +// Note that a wall to the right can be removed from a +// valid entry by adding 2; a wall below can be removed +// by adding 1. +walls = list.init2d(h,v, 0) +print +print +print +print + +// pick an exit at the top of the maze, +// and print the maze top +x = floor(rnd * h) +for i in range(0, h-1) + if i == x then print ". ","" else print ".--","" +end for +print "." + +// walk from our starting position (by the exit) around +// the maze, clearing a wall on each step +c = 1 // current step number +order[x][0] = c; c += 1 +r = x; s = 0 // [r][s] is our current position in the maze +while true + // collect the set of directions we can move in + dirs = [] + if r > 0 and order[r-1][s] == 0 then dirs.push "left" + if s > 0 and order[r][s-1] == 0 then dirs.push "up" + if r+1 < h and order[r+1][s] == 0 then dirs.push "right" + if s+1 < v and order[r][s+1] == 0 then dirs.push "down" + if not dirs then + //print "Uh-oh, I'm stuck at " + r + "," + s + // couldn't find any directions for this cell; + // find the next already-explored cell + while true + r += 1 + if r >= h then + r = 0 + s += 1 + if s >= v then s = 0 + end if + if order[r][s] != 0 then break + end while + continue + end if + + // pick a random available direction; move there, + // clearing the wall in between and updating order + d = dirs.any + if d == "left" then + walls[r-1][s] += 2 + r = r-1 + else if d == "up" then + walls[r][s-1] += 1 + s = s-1 + else if d == "right" then + walls[r][s] += 2 + r = r+1 + else if d == "down" then + walls[r][s] += 1 + s = s+1 + end if + + //print "At step " + c + ", at " + r + "," + s + order[r][s] = c + c += 1 + if c > h*v then break +end while + +// pick an exit at the bottom of the maze +x = floor(rnd * h) +walls[x][v-1] += 1 + +// print the (rest of the) maze +for j in range(0, v-1) + print "I", "" + for i in range(0, h-1) + if walls[i][j] < 2 then print " I", "" else print " ", "" + end for + print + for i in range(0, h-1) + if walls[i][j] % 2 == 0 then print ":--", "" else print ": ", "" + end for + print "." +end for diff --git a/00_Alternate_Languages/03_Animal/MiniScript/README.md b/00_Alternate_Languages/03_Animal/MiniScript/README.md new file mode 100644 index 00000000..cb7892f6 --- /dev/null +++ b/00_Alternate_Languages/03_Animal/MiniScript/README.md @@ -0,0 +1,16 @@ +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 animal.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 BASIC program. Then, at the Mini Micro command prompt, enter: + + load "animal" + run diff --git a/00_Alternate_Languages/03_Animal/MiniScript/animal.ms b/00_Alternate_Languages/03_Animal/MiniScript/animal.ms new file mode 100644 index 00000000..5aafdddb --- /dev/null +++ b/00_Alternate_Languages/03_Animal/MiniScript/animal.ms @@ -0,0 +1,90 @@ +print " "*32 + "Animal" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "Play 'Guess the Animal'" +print +print "Think of an animal and the computer will try to guess it." +print + +// Ask a yes/no question, and return "Y" or "N". +getYesNo = function(prompt) + while true + inp = input(prompt + "? ").upper + if inp and (inp[0] == "Y" or inp[0] == "N") then return inp[0] + print "Please answer Yes or No." + end while +end function + +// Our data is stored as a list of little maps. +// Answers have only an "answer" key. +// Questions have a "question" key, plus "ifYes" and "ifNo" +// keys which map to the index of the next question or answer. +data = [ + {"question":"Does it swim", "ifYes":1, "ifNo":2}, + {"answer":"fish"}, + {"answer":"bird"}] + +// List all known animals. +listKnown = function + print; print "Animals I already know are:" + for item in data + if item.hasIndex("answer") then print (item.answer + " "*17)[:17], "" + end for + print; print +end function + +// Ask the question at curIndex, and handle the user's response. +doQuestion = function + q = data[curIndex] + if getYesNo(q.question) == "Y" then + globals.curIndex = q.ifYes + else + globals.curIndex = q.ifNo + end if +end function + +// Check the answer at curIndex. If incorrect, get a new question +// to put at that point in our data. +checkAnswer = function + node = data[curIndex] + inp = getYesNo("Is it a " + node.answer) + if inp == "Y" then + print "Why not try another animal?" + else + actual = input("The animal you were thinking of was a? ").lower + print "Please type in a question that would distinguish a" + print actual + " from a " + node.answer + q = {} + q.question = input + q.question = q.question[0].upper + q.question[1:] - "?" + data[curIndex] = q + k = data.len + data.push node // old answer at index k + data.push {"answer":actual} // new answer at index k+1 + if getYesNo("For a " + actual + " the answer would be") == "Y" then + data[curIndex].ifYes = k+1 + data[curIndex].ifNo = k + else + data[curIndex].ifNo = k+1 + data[curIndex].ifYes = k + end if + end if +end function + +// Main loop. (Press Control-C to break.) +while true + while true + inp = input("Are you thinking of an animal? ").upper + if inp == "LIST" then listKnown + if inp and inp[0] == "Y" then break + end while + curIndex = 0 + while true + if data[curIndex].hasIndex("question") then + doQuestion + else + checkAnswer + break + end if + end while +end while diff --git a/00_Alternate_Languages/04_Awari/MiniScript/README.md b/00_Alternate_Languages/04_Awari/MiniScript/README.md new file mode 100644 index 00000000..269d1215 --- /dev/null +++ b/00_Alternate_Languages/04_Awari/MiniScript/README.md @@ -0,0 +1,16 @@ +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 awari.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 BASIC program. Then, at the Mini Micro command prompt, enter: + + load "awari" + run diff --git a/00_Alternate_Languages/04_Awari/MiniScript/awari.ms b/00_Alternate_Languages/04_Awari/MiniScript/awari.ms new file mode 100644 index 00000000..e01c2d6c --- /dev/null +++ b/00_Alternate_Languages/04_Awari/MiniScript/awari.ms @@ -0,0 +1,146 @@ +print " "*34 + "Awari" +print " "*15 + "Creative Computing Morristown, New Jersey" + +// Keep a list of the opening moves (up to 8) of previously lost or drawn games. +// These will be used to penalize repeating the same moves again. +badGames = [] + +printQty = function(qty) + print (" " + qty)[-2:], " " +end function + +printBoard = function + print; print " ", "" + for i in range(12, 7); printQty board[i]; end for + print; printQty board[13] + print " " * 6, ""; printQty board[6] + print; print " ", "" + for i in range(0, 5); printQty board[i]; end for + print; print +end function + +// Redistribute the stones starting at position. +// If the last one ends by itself, opposite some nonzero +// stones on the other side, then capture them into homePos. +// Return true if the last stone ended at homePos, false otherwise. +moveStones = function(board, position, homePos) + p = board[position]; board[position] = 0 + while p + position = (position + 1) % 14 + board[position] += 1 + p -= 1 + end while + if board[position] == 1 and position != 6 and position != 13 and board[12-position] then + board[homePos] += board[12-position] + 1 + board[position] = 0 + board[12-position] = 0 + end if + globals.gameOver = board[0:6].sum == 0 or board[7:13].sum == 0 + return position == homePos +end function + +// Get the player move. Note that the player inputs their move as a number +// from 1-6, but we return it as an actual board position index 0-6. +getPlayerMove = function(prompt="Your move") + while true + pos = input(prompt + "? ").val + if 0 < pos < 7 and board[pos-1] then return pos - 1 + print "Illegal move." + end while +end function + +getComputerMove = function + // Copy the board for safekeeping + boardCopy = board[:] + bestScore = -99; bestMove = 0 + for j in range(7, 12) + if board[j] == 0 then continue // can't move from an empty spot + // suppose we move at position j... + moveStones board, j, 13 + // consider each possible response the player could make + bestPlayerScore = 0 + for i in range(0, 5) + if board[i] == 0 then continue + landPos = board[i] + i // figure the landing position + score = floor(landPos / 14); landPos %= 14 + if board[landPos] == 0 and landPos != 6 and landPos != 13 then + score += board[12 - landPos] // points for capturing stones + end if + if score > bestPlayerScore then bestPlayerScore = score + end for + // figure our own score as our points, minus player points, minus best player score + ourScore = board[13] - board[6] - bestPlayerScore + if gameMoves.len < 8 then + // subtract 2 points if current series of moves is in our bad-games list + proposed = gameMoves + [j] + for badGame in badGames + if badGame[:proposed.len] == proposed then ourScore -= 2 + end for + end if + if ourScore > bestScore then + bestScore = ourScore + bestMove = j + end if + // restore the board + globals.board = boardCopy[:] + end for + print char(42+bestMove) // (labels computer spots as 1-6 from right to left) + return bestMove +end function + +// The game is over when either side has 0 stones left. +isGameOver = function + return board[0:6].sum == 0 or board[7:13].sum == 0 +end function + +// Play one game to completion. +playOneGame = function + // The board is represented as a list of 13 numbers. + // Position 6 is the player's home; 13 is the computer's home. + globals.board = [3]*14; board[13] = 0; board[6] = 0 + // Also keep a list of the moves in the current game + globals.gameMoves = [] + print; print + while true + // Player's turn + printBoard + pos = getPlayerMove + gameMoves.push pos + if moveStones(board, pos, 6) then + if gameOver then break + printBoard + pos = getPlayerMove("Again") + gameMoves.push pos + moveStones board, pos, 6 + end if + if gameOver then break + // Computer's turn + printBoard; print "My move is ", "" + pos = getComputerMove + gameMoves.push pos + if moveStones(board, pos, 13) then + if gameOver then break + printBoard; print "...followed by ", "" + pos = getComputerMove + gameMoves.push pos + moveStones board, pos, 13 + end if + if gameOver then break + end while + printBoard + print; print "GAME OVER" + delta = board[6] - board[13] + if delta < 0 then + print "I win by " + (-delta) + " points" + return + end if + if delta == 0 then print "Drawn game" else print "You win by " + delta + " points" + if gameMoves.len > 8 then gameMoves = gameMoves[:8] + if badGames.indexOf(gameMoves) == null then badGames.push gameMoves +end function + +// Main loop +while true + playOneGame + print; print +end while diff --git a/01_Acey_Ducey/README.md b/01_Acey_Ducey/README.md index 26856f71..0fabfb08 100644 --- a/01_Acey_Ducey/README.md +++ b/01_Acey_Ducey/README.md @@ -15,10 +15,13 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- Entering a negative bet allows you to gain arbitrarily large amounts of money upon losing the round. #### Porting Notes -(please note any difficulties or challenges in porting here) +- The assignment `N = 100` in line 100 has no effect; variable `N` is not used anywhere else in the program. #### External Links - Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp diff --git a/02_Amazing/README.md b/02_Amazing/README.md index b53cbbf5..b8e4b9b4 100644 --- a/02_Amazing/README.md +++ b/02_Amazing/README.md @@ -13,6 +13,10 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- The input dimensions are checked for values of 1, but not for values of 0 or less. Such inputs will cause the program to break. + #### Porting Notes **2022-01-04:** patched original source in [#400](https://github.com/coding-horror/basic-computer-games/pull/400) to fix a minor bug where a generated maze may be missing an exit, particularly at small maze sizes. From d9b3d473438f7274d48e15e50c42fa1deada4d09 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 11 Jul 2023 07:50:40 -0700 Subject: [PATCH 02/11] Added MiniScript implementation of bagels. --- .../05_Bagels/MiniScript/README.md | 16 ++++ .../05_Bagels/MiniScript/bagels.ms | 83 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 00_Alternate_Languages/05_Bagels/MiniScript/README.md create mode 100644 00_Alternate_Languages/05_Bagels/MiniScript/bagels.ms diff --git a/00_Alternate_Languages/05_Bagels/MiniScript/README.md b/00_Alternate_Languages/05_Bagels/MiniScript/README.md new file mode 100644 index 00000000..91c9fda2 --- /dev/null +++ b/00_Alternate_Languages/05_Bagels/MiniScript/README.md @@ -0,0 +1,16 @@ +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 bagels.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 BASIC program. Then, at the Mini Micro command prompt, enter: + + load "bagels" + run diff --git a/00_Alternate_Languages/05_Bagels/MiniScript/bagels.ms b/00_Alternate_Languages/05_Bagels/MiniScript/bagels.ms new file mode 100644 index 00000000..93b33b01 --- /dev/null +++ b/00_Alternate_Languages/05_Bagels/MiniScript/bagels.ms @@ -0,0 +1,83 @@ +print " "*33 + "BAGELS" +print " "*15 + "Creative Computing Morristown, New Jersey"; print; print +// *** BAGELS Number Guessing Game +// *** Original source unknown but suspected to be +// *** Lawrence Hall of Science, U.C. Berkely + +print; print; print +inp = input("Would you like the rules (yes or no)? ") +if not inp or inp[0].lower != "n" then + print; print "I am thinking of a three-digit number. Try to guess" + print "my number and I will give you clues as follows:" + print " PICO - one digit correct but in the wrong position" + print " FERMI - one digit correct and in the right position" + print " BAGELS - no digits correct" +end if + +pickNumber = function + // pick three unique random digits + while true + actual = [floor(10*rnd), floor(10*rnd), floor(10*rnd)] + if actual[0] != actual[1] and actual[0] != actual[2] and actual[1] != actual[2] then break + end while + //print "DEBUG: actual=" + actual + print; print "O.K. I have a number in mind." + return actual +end function + +getGuess = function(guessNum) + isNotDigit = function(c); return c < "0" or c > "9"; end function + while true + inp = input("Guess #" + guessNum + "? ") + if inp.len != 3 then + print "Try guessing a three-digit number." + else if inp[0] == inp[1] or inp[0] == inp[2] or inp[1] == inp[2] then + print "Oh, I forgot to tell you that the number I have in mind" + print "has no two digits the same." + else if isNotDigit(inp[0]) or isNotDigit(inp[1]) or isNotDigit(inp[2]) then + print "What?" + else + return [inp[0].val, inp[1].val, inp[2].val] + end if + end while +end function + +doOneGame = function + actual = pickNumber + for guessNum in range(1, 20) + guess = getGuess(guessNum) + picos = 0; fermis = 0 + for i in [0,1,2] + if guess[i] == actual[i] then + fermis += 1 + else if actual.indexOf(guess[i]) != null then + picos += 1 + end if + end for + if fermis == 3 then + print "YOU GOT IT!!!" + globals.score += 1 + return + else if picos or fermis then + print "PICO " * picos + "FERMI " * fermis + else + print "BAGELS" + end if + end for + print "Oh well." + print "That's twenty guesses. My number was " + actual.join("") +end function + +// main loop +score = 0 +while true + doOneGame + print + inp = input("Play again (yes or no)? ") + if not inp or inp[0].upper != "Y" then break +end while +if score then + print; print "A " + score + " point BAGELS buff!!" +end if +print "Hope you had fun. Bye." + From 5bca164c49fd2dba668448b97db9b47184f4d98e Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 11 Jul 2023 10:27:49 -0700 Subject: [PATCH 03/11] Added MiniScript version of 06_Banner. --- .../06_Banner/MiniScript/README.md | 16 ++++ .../06_Banner/MiniScript/banner.ms | 89 +++++++++++++++++++ 06_Banner/README.md | 4 + 3 files changed, 109 insertions(+) create mode 100644 00_Alternate_Languages/06_Banner/MiniScript/README.md create mode 100644 00_Alternate_Languages/06_Banner/MiniScript/banner.ms diff --git a/00_Alternate_Languages/06_Banner/MiniScript/README.md b/00_Alternate_Languages/06_Banner/MiniScript/README.md new file mode 100644 index 00000000..0ec35b38 --- /dev/null +++ b/00_Alternate_Languages/06_Banner/MiniScript/README.md @@ -0,0 +1,16 @@ +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 banner.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 BASIC program. Then, at the Mini Micro command prompt, enter: + + load "banner" + run diff --git a/00_Alternate_Languages/06_Banner/MiniScript/banner.ms b/00_Alternate_Languages/06_Banner/MiniScript/banner.ms new file mode 100644 index 00000000..d5d57e18 --- /dev/null +++ b/00_Alternate_Languages/06_Banner/MiniScript/banner.ms @@ -0,0 +1,89 @@ +blockWidth = input("Horizontal? ").val +if blockWidth <= 1 then blockWidth = 3 + +blockHeight = input("Vertical? ").val +if blockHeight <= 1 then blockHeight = 5 + +inp = input("Centered? ").upper +centered = inp and inp[0] > "P" + +printChar = input("Character (type 'all' if you want character being printed)? ") + +statement = input("Statement: ").upper + +//input("Set page") // <-- opportunity to set your pin-feed printer before proceeding! + +// Define the character data. For each character, we have 7 numbers +// which are the 9-bit binary representation of each row, plus one. +data = {} +data[" "] = [0,0,0,0,0,0,0] +data["!"] = [1,1,1,384,1,1,1] +data["?"] = [5,3,2,354,18,11,5] +data["."] = [1,1,129,449,129,1,1] +data["*"] = [69,41,17,512,17,41,69] +data["="] = [41,41,41,41,41,41,41] +data["0"] = [57,69,131,258,131,69,57] +data["1"] = [0,0,261,259,512,257,257] +data["2"] = [261,387,322,290,274,267,261] +data["3"] = [66,130,258,274,266,150,100] +data["4"] = [33,49,41,37,35,512,33] +data["5"] = [160,274,274,274,274,274,226] +data["6"] = [194,291,293,297,305,289,193] +data["7"] = [258,130,66,34,18,10,8] +data["8"] = [69,171,274,274,274,171,69] +data["9"] = [263,138,74,42,26,10,7] +data["A"] = [505,37,35,34,35,37,505] +data["B"] = [512,274,274,274,274,274,239] +data["C"] = [125,131,258,258,258,131,69] +data["D"] = [512,258,258,258,258,131,125] +data["E"] = [512,274,274,274,274,258,258] +data["F"] = [512,18,18,18,18,2,2] +data["G"] = [125,131,258,258,290,163,101] +data["H"] = [512,17,17,17,17,17,512] +data["I"] = [258,258,258,512,258,258,258] +data["J"] = [65,129,257,257,257,129,128] +data["K"] = [512,17,17,41,69,131,258] +data["L"] = [512,257,257,257,257,257,257] +data["M"] = [512,7,13,25,13,7,512] +data["N"] = [512,7,9,17,33,193,512] +data["O"] = [125,131,258,258,258,131,125] +data["P"] = [512,18,18,18,18,18,15] +data["Q"] = [125,131,258,258,322,131,381] +data["R"] = [512,18,18,50,82,146,271] +data["S"] = [69,139,274,274,274,163,69] +data["T"] = [2,2,2,512,2,2,2] +data["U"] = [128,129,257,257,257,129,128] +data["V"] = [64,65,129,257,129,65,64] +data["W"] = [256,257,129,65,129,257,256] +data["X"] = [388,69,41,17,41,69,388] +data["Y"] = [8,9,17,481,17,9,8] +data["Z"] = [386,322,290,274,266,262,260] + +for c in statement + if not data.hasIndex(c) then continue + + // Print character c in giant sideways banner-style! + for datum in data[c] + if datum then datum -= 1 // remove spurious +1 + if printChar.upper != "ALL" then c = printChar + + for lineRepeat in range(blockWidth-1) + if centered then print " " * (34 - 4.5*blockHeight), "" + + for bitPos in range(9,0) + if bitAnd(datum, 2^bitPos) then charToPrint=c else charToPrint=" " + print charToPrint * blockHeight, "" + end for // next bitPos + + print + wait 0.01 // put in a small pause so it's not too fast to see! + end for // next lineRepeat (repeating line according to entered Y value) + + end for // next datum (row of this character) + + // Add a little space after each character + for i in range(1, 2 * blockWidth) + print + wait 0.01 + end for +end for // next character in the message diff --git a/06_Banner/README.md b/06_Banner/README.md index 3acbf7fc..f01b876d 100644 --- a/06_Banner/README.md +++ b/06_Banner/README.md @@ -15,5 +15,9 @@ http://www.vintage-basic.net/games.html #### Porting Notes +- The "SET PAGE" input, stored in `O$`, has no effect. It was probably meant as an opportunity for the user to set their pin-feed printer to the top of the page before proceeding. + +- The data values for each character are the bit representation of each horizontal row of the printout (vertical column of a character), plus one. Perhaps because of this +1, the original code (and some of the ports here) are much more complicated than they need to be. + (please note any difficulties or challenges in porting here) From 82fd99b1bf702afe3b228b932f8d59a50dea58bd Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 11 Jul 2023 17:11:28 -0700 Subject: [PATCH 04/11] Added MiniScript version of 07_Basketball --- .../07_Basketball/MiniScript/README.md | 16 + .../07_Basketball/MiniScript/basketball.ms | 299 ++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100644 00_Alternate_Languages/07_Basketball/MiniScript/README.md create mode 100644 00_Alternate_Languages/07_Basketball/MiniScript/basketball.ms diff --git a/00_Alternate_Languages/07_Basketball/MiniScript/README.md b/00_Alternate_Languages/07_Basketball/MiniScript/README.md new file mode 100644 index 00000000..408b7495 --- /dev/null +++ b/00_Alternate_Languages/07_Basketball/MiniScript/README.md @@ -0,0 +1,16 @@ +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 basketball.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 BASIC program. Then, at the Mini Micro command prompt, enter: + + load "basketball" + run diff --git a/00_Alternate_Languages/07_Basketball/MiniScript/basketball.ms b/00_Alternate_Languages/07_Basketball/MiniScript/basketball.ms new file mode 100644 index 00000000..d152cb10 --- /dev/null +++ b/00_Alternate_Languages/07_Basketball/MiniScript/basketball.ms @@ -0,0 +1,299 @@ +print " "*31 + "Basketball" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "This is Dartmouth College basketball. You will be Dartmouth" +print " captain and playmaker. Call shots as follows: 1. Long" +print " (30 ft.) jump shot; 2. Short (15 ft.) jump shot; 3. Lay" +print " up; 4. Set shot." +print "Both teams will use the same defense. Call defense as" +print "follows: 6. Press; 6.5 Man-to-Man; 7. Zone; 7.5 None." +print "To change defense, just type 0 as your next shot." + +inputDefense = function(prompt) + while true + globals.defense = input(prompt).val + if defense >= 6 then break + end while +end function + +// Do the center jump; return US or THEM who gets the ball. +centerJump = function + print "Center Jump" + if rnd < 0.6 then + print opponent + " controls the tap." + return THEM + else + print "Dartmouth controls the tap." + return US + end if +end function + +inputShot = function + while true + globals.shotType = input("Your shot (0-4): ") + if shotType == "0" then + inputDefense "Your new defensive alignment is? " + continue + end if + globals.shotType = shotType.val + if 1 <= shotType <= 4 then return + end while +end function + +endFirstHalf = function + print " ***** End of first half *****"; print + print "Score: Dartmouth: " + score[US] + " " + opponent + ": " + score[THEM] + print; print + globals.inControl = centerJump +end function + +checkGameOver = function + print + if score[0] != score[1] then + print " ***** END OF GAME *****" + print "Final score: Dartmouth: " + score[US] + " " + opponent + ": " + score[THEM] + print + return true + else + print " ***** End of Second Half *****" + print "Score at end of regulation time:" + print " Dartmouth: " + score[US] + " " + opponent + ": " + score[THEM] + print + print "Begin two minute overtime period" + return false + end if +end function + +scoreBasket = function(who = null) + if who == null then who = inControl + score[who] += 2 + printScore +end function + +printScore = function + print "Score: " + score[1] + " to " + score[0] + print "Time: " + timer +end function + +// Logic for a Dartmouth jump shot. Return true to continue as Dartmouth, +// false to pass the ball to the opponent. +dartmouthJumpShot = function + if rnd <= 0.341 * defense / 8 then + print "Shot is good." + scoreBasket + return false + end if + + if rnd < 0.682 * defense / 8 then + print "Shot is off target." + if defense/6 * rnd > 0.45 then + print "Rebound to " + opponent + return false + end if + print "Dartmouth controls the rebound." + if rnd <= 0.4 then + globals.shotType = 3 + (rnd > 0.5) + return true + end if + if defense == 6 and rnd < 0.6 then + print "Pass stolen by " + opponent + ", easy layup." + scoreBasket THEM + return true + end if + print "Ball passed back to you." + return true + end if + + if rnd < 0.782 * defense/8 then + print "Shot is blocked. Ball controlled by ", "" + if rnd > 0.5 then + print opponent + "." + return false + else + print "Dartmouth." + return true + end if + end if + + if rnd > 0.843 * defense/8 then + print "Charging foul. Dartmouth loses ball." + else + print "Shooter is fouled. Two shots." + doFoulShots US + end if + return false +end function + +// Logic for an opponent jump shot. Return true to continue as opponent, +// false to pass the ball to Dartmouth. +opponentJumpShot = function + if rnd <= 0.35 * defense / 8 then + print "Shot is good." + scoreBasket + return false + end if + + if 8 / defense * rnd <= 0.75 then + print "Shot is off rim." + return opponentMissed + end if + + if 8 / defense * rnd <= 0.9 then + print "Player fouled. Two shots." + doFoulShots THEM + return false + end if + print "Offensive foul. Dartmouth's ball." + return false +end function + +// Do a Dartmouth set shot or lay-up. Return true to continue as Dartmouth, +// false to pass the ball to the opponent. +dartmouthSetOrLay = function + if 7 / defense * rnd <= 0.4 then + print "Shot is good. Two points." + scoreBasket + else if 7 / defense * rnd <= 0.7 then + print "Shot is off the rim." + if rnd < 0.667 then + print opponent + " controls the rebound." + return false + end if + print "Dartmouth controls the rebound." + if rnd < 0.4 then return true + print "Ball passed back to you." + return true + else if 7 / defense * rnd < 0.875 then + print "Shooter fouled. Two shots." + doFoulShots US + else if 7 / defense * rnd < 0.925 then + print "Shot blocked. " + opponent + "'s ball." + else + print "Charging foul. Dartmouth loses the ball." + end if + return false +end function + +// Do an opponent set shot or lay-up. Return true to continue as opponent, +// false to pass the ball to Dartmouth. +opponentSetOrLay = function + if 7 / defense * rnd <= 0.413 then + print "Shot is missed." + return opponentMissed + else + print "Shot is good." + scoreBasket + return false + end if +end function + +// Handle opponent missing a shot -- return true to continue as opponent, +// false to pass the ball to Dartmouth. +opponentMissed = function + if defense / 6 * rnd <= 0.5 then + print "Dartmouth controls the rebound." + return false + else + print opponent + " controls the rebound." + if defense == 6 and rnd <= 0.75 then + print "Ball stolen. Easy lay up for Dartmouth." + scoreBasket US + return true + end if + if rnd <= 0.5 then + print "Pass back to " + opponent + " guard." + return true + end if + globals.shotType = 4 - (rnd > 0.5) + return true + end if +end function + +playOneSide = function + print + while true + globals.timer += 1 + if timer == 50 then return endFirstHalf + if time == 92 then + print " *** Two minutes left in the game ***"; print + end if + if shotType == 1 or shotType == 2 then + print "Jump Shot" + if inControl == US then + if dartmouthJumpShot then continue else break + else + if opponentJumpShot then continue else break + end if + else // (if shot type >= 3) + if shotType > 3 then print "Set shot." else print "Lay up." + if inControl == US then + if dartmouthSetOrLay then continue else break + else + if opponentSetOrLay then continue else break + end if + end if + end while + globals.inControl = 1 - globals.inControl +end function + +doFoulShots = function(who) + if rnd > 0.49 then + if rnd > 0.75 then + print "Both shots missed." + else + print "Shooter makes one shot and misses one." + score[who] += 1 + end if + else + print "Shooter makes both shots." + score[who] += 2 + end if + printScore +end function + +opponentPlay = function + print + while true + globals.timer += 1 + if timer == 50 then return endFirstHalf + if time == 92 then + print " *** Two minutes left in the game ***"; print + end if + if shotType == 1 or shotType == 2 then + print "Jump Shot" + if opponentJumpShot then continue else break + else // (if shot type >= 3) + if shotType > 3 then print "Set shot." else print "Lay up." + if opponentSetOrLay then continue else break + end if + end while + globals.inControl = US +end function + +// Constants +THEM = 0 +US = 1 + +// Main program +inputDefense "Your starting defense will be? " +print +opponent = input("Choose your opponent? ") +score = [0,0] // score for each team (US and THEM) +gameOver = false +inControl = centerJump +timer = 0 +while not gameOver + print + if inControl == US then + inputShot + playOneSide + else + shotType = ceil(10 / 4 * rnd + 1) + playOneSide + end if + if timer >= 100 then + if checkGameOver then break + timer = 93 + dartmouthHasBall = centerJump + end if +end while From 85ee2c387542704088a1db1d4b8a9de0865969e9 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 12 Jul 2023 07:23:30 -0700 Subject: [PATCH 05/11] Added MiniScript version of 08_Batnum; also updated a couple of READMEs. --- .../08_Batnum/MiniScript/README.md | 16 +++ .../08_Batnum/MiniScript/batnum.ms | 109 ++++++++++++++++++ 08_Batnum/README.md | 4 + 09_Battle/README.md | 2 +- 4 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/08_Batnum/MiniScript/README.md create mode 100644 00_Alternate_Languages/08_Batnum/MiniScript/batnum.ms diff --git a/00_Alternate_Languages/08_Batnum/MiniScript/README.md b/00_Alternate_Languages/08_Batnum/MiniScript/README.md new file mode 100644 index 00000000..2a7ed1b4 --- /dev/null +++ b/00_Alternate_Languages/08_Batnum/MiniScript/README.md @@ -0,0 +1,16 @@ +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 batnum.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 BASIC program. Then, at the Mini Micro command prompt, enter: + + load "batnum" + run diff --git a/00_Alternate_Languages/08_Batnum/MiniScript/batnum.ms b/00_Alternate_Languages/08_Batnum/MiniScript/batnum.ms new file mode 100644 index 00000000..d1019717 --- /dev/null +++ b/00_Alternate_Languages/08_Batnum/MiniScript/batnum.ms @@ -0,0 +1,109 @@ +print " "*33 + "Batnum" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "This program is a 'Battle of Numbers' game, where the" +print "computer is your opponent." +print +print "The game starts with an assumed pile of objects. You" +print "and your opponent alternately remove objects from the pile." +print "Winning is defined in advance as taking the last object or" +print "not. You can also specify some other beginning conditions." +print "Don't use zero, however, in playing the game." +print "Enter a negative number for new pile size to stop playing." +print + +options = {} +getOptions = function + while true + options.pileSize = input("Enter pile size? ").val + if options.pileSize != 0 and options.pileSize == floor(options.pileSize) then break + end while + if options.pileSize < 0 then return + + while true + winOption = input("Enter win option - 1 to take last, 2 to avoid last: ") + if winOption == "1" or winOption == "2" then break + end while + options.takeLast = (winOption == "1") + + while true + minMax = input("Enter min and max? ").replace(",", " ").split + if minMax.len < 2 then continue + options.minTake = minMax[0].val + options.maxTake = minMax[-1].val + if options.minTake >= 1 and options.minTake < options.maxTake then break + end while + + while true + startOpt = input("Enter start option - 1 computer first, 2 you first: ") + if startOpt == "1" or startOpt == "2" then break + end while + options.computerFirst = (startOpt == "1") +end function + +computerTurn = function + // Random computer play (not in original program): + take = options.minTake + floor(rnd * (options.maxTake - options.minTake)) + + // Proper (smart) computer play + q = pile + if not options.takeLast then q -= 1 + take = q % (options.minTake + options.maxTake) + if take < options.minTake then take = options.minTake + if take > options.maxTake then take = options.maxTake + + if take >= pile then + if options.takeLast then + print "Computer takes " + pile + " and wins." + else + print "Computer takes " + pile + " and loses." + end if + globals.gameOver = true + else + globals.pile -= take + print "Computer takes " + take + " and leaves " + pile + end if +end function + +playerTurn = function + while true + print; take = input("Your move? ").val + if take == 0 then + print "I told you not to use zero! Computer wins by forfeit." + globals.gameOver = true + return + end if + if options.minTake <= take <= options.maxTake and take <= pile then break + print "Illegal move, reenter it" + end while + if take >= pile then + if options.takeLast then + print "Congratulations, you win." + else + print "Tough luck, you lose." + end if + globals.gameOver = true + else + globals.pile -= take + //print "You take " + take + ", leaving " + pile // (not in original program) + end if +end function + +while true + getOptions + if options.pileSize < 0 then break + pile = options.pileSize + gameOver = false + + print; print + + if options.computerFirst then computerTurn + while not gameOver + playerTurn + if gameOver then break + computerTurn + end while + + for i in range(1,10); print; end for +end while +print "OK, bye!" \ No newline at end of file diff --git a/08_Batnum/README.md b/08_Batnum/README.md index 84052986..bb74a4ec 100644 --- a/08_Batnum/README.md +++ b/08_Batnum/README.md @@ -19,6 +19,10 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- Though the instructions say "Enter a negative number for new pile size to stop playing," this does not actually work. + #### Porting Notes (please note any difficulties or challenges in porting here) diff --git a/09_Battle/README.md b/09_Battle/README.md index 04286452..1f011a46 100644 --- a/09_Battle/README.md +++ b/09_Battle/README.md @@ -13,7 +13,7 @@ The first thing you should learn is how to locate and designate positions on the The second thing you should learn about is the splash/hit ratio. “What is a ratio?” A good reply is “It’s a fraction or quotient.” Specifically, the spash/hit ratio is the number of splashes divided by the number of hits. If you had 9 splashes and 15 hits, the ratio would be 9/15 or 3/5, both of which are correct. The computer would give this splash/hit ratio as .6. -The main objective and primary education benefit of BATTLE comes from attempting to decode the bas guys’ fleet disposition code. To do this, you must make a comparison between the coded matrix and the actual matrix which you construct as you play the game. +The main objective and primary education benefit of BATTLE comes from attempting to decode the bad guys’ fleet disposition code. To do this, you must make a comparison between the coded matrix and the actual matrix which you construct as you play the game. The original author of both the program and these descriptive notes is Ray Westergard of Lawrence Hall of Science, Berkeley, California. From e8212bc2f3512fb7a00c0d1cccecdb0201e2b6a5 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 12 Jul 2023 16:29:11 -0700 Subject: [PATCH 06/11] Initial implementation of 09_Battle in MiniScript. --- 09_Battle/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/09_Battle/README.md b/09_Battle/README.md index 1f011a46..29d2622e 100644 --- a/09_Battle/README.md +++ b/09_Battle/README.md @@ -28,4 +28,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -(please note any difficulties or challenges in porting here) +- The original game has no way to re-view the fleet disposition code once it scrolls out of view. Ports should consider allowing the user to enter "?" at the "??" prompt, to reprint the disposition code. (This is added by the MiniScript port under Alternate Languages, for example.) \ No newline at end of file From 47309445324246c54693b62977d127e4883c6f51 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 12 Jul 2023 16:49:01 -0700 Subject: [PATCH 07/11] Actually added MiniScript implementation of 09_Battle this time. --- .../09_Battle/MiniScript/README.md | 18 ++ .../09_Battle/MiniScript/battle.ms | 157 ++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 00_Alternate_Languages/09_Battle/MiniScript/README.md create mode 100644 00_Alternate_Languages/09_Battle/MiniScript/battle.ms diff --git a/00_Alternate_Languages/09_Battle/MiniScript/README.md b/00_Alternate_Languages/09_Battle/MiniScript/README.md new file mode 100644 index 00000000..16b06b72 --- /dev/null +++ b/00_Alternate_Languages/09_Battle/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). + +NOTE: One feature has been added to the original game. At the "??" prompt, instead of entering coordinates, you can enter "?" (a question mark) to reprint the fleet disposition code. + +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 battle.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 BASIC program. Then, at the Mini Micro command prompt, enter: + + load "battle" + run diff --git a/00_Alternate_Languages/09_Battle/MiniScript/battle.ms b/00_Alternate_Languages/09_Battle/MiniScript/battle.ms new file mode 100644 index 00000000..e082b25b --- /dev/null +++ b/00_Alternate_Languages/09_Battle/MiniScript/battle.ms @@ -0,0 +1,157 @@ +print " "*33 + "Battle" +print " "*15 + "Creative Computing Morristown, New Jersey" +// -- BATTLE WRITTEN BY RAY WESTERGARD 10/70 +// COPYRIGHT 1971 BY THE REGENTS OF THE UNIV. OF CALIF. +// PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY +// Converted to MiniScript by Joe Strout, July 2023. + +import "listUtil" + +setup = function + // prepare the shield with the bad guys' ships + globals.field = list.init2d(6,6, 0) // matrix of enemy ships -- 0th row/column unused + for shipType in [1,2,3] + for ship in [1,2] + while not addShip(shipType, ship) + // keep trying until we successfully add it! + end while + end for + end for + + // prepare another matrix to keep track of where we have hit + globals.hits = list.init2d(6,6, 0) + + // and some some info per ship (ID) and ship type + globals.shipHitsLeft = [null, 2, 2, 3, 3, 4, 4] // hits left till each ship is sunk + globals.sunkPerType = [0] * 3 // counts how many of each type were sunk + + // finally, keep track of hits and splashes + globals.splashCount = 0 + globals.hitCount = 0 +end function + +// Try to add the given ship to field. +// Return true on success, false on failure. +addShip = function(shipType, shipNum) + size = 5 - shipType + x = floor(rnd * 6) + y = floor(rnd * 6) + direction = floor(rnd * 4) + if direction == 0 then + dx = 1; dy = 0 + else if direction == 1 then + dx = 1; dy = 1 + else if direction == 2 then + dx = 0; dy = 1 + else + dx = -1; dy = 1 + end if + // First make sure our placement doesn't go out of bounds + if not (0 <= x + dx * size <= 5) then return false + if not (0 <= y + dy * size <= 5) then return false + // Then, make sure it's not blocked by another ship + for i in range(0, size-1) + px = x + dx * i // (point under consideration) + py = y + dy * i + // make sure where we want to place the ship is still empty + if field[px][py] then return false + // if placing a ship diagonally, don't allow it to cross + // another ship on the other diagonal + if i > 0 and dx and dy then + adjacent1 = field[px-dx][py] + adjacent2 = field[px][py-dy] + if adjacent1 and adjacent1 == adjacent2 then return false + end if + end for + // Looks like it's all clear, so fill it in! + id = 9 - 2 * shipType - shipNum; + for i in range(0, size-1) + field[x + dx * i][y + dy * i] = id + end for + return true +end function + +// Print the "encoded" fleet disposition. This is just the regular field, +// but rotated and flipped. +printField = function + print + print "The following code of the bad guys' fleet disposition" + print "has been captured but not decoded:" + print + for i in range(0,5) + for j in range(0,5) + print field[5-j][i], " " + end for + print + end for +end function + +doOneTurn = function + while true + xy = input("??").replace(",", " ") + if xy == "?" then; printField; continue; end if // (not in original game) + x = xy[0].val; y = xy[-1].val + if xy.len < 2 or x != floor(x) or x < 1 or x > 6 or y != floor(y) or y < 1 or y > 6 then + print "Invalid input. Try again." + continue + end if + break + end while + row = x - 1 // (minus one since our matrix is 0-based instead of 1-based) + col = y - 1 + shipId = field[row][col] + if shipId == 0 then + // fall through to 'end if' below + else if shipHitsLeft[shipId] == 0 then + print "There used to be a ship at that point, but you sank it." + else if hits[row][col] then + print "You already put a hole in ship number " + shipId + " at that point." + else + hits[row][col] = shipId + print "A direct hit on ship number " + shipId + globals.hitCount += 1 + shipHitsLeft[shipId] -= 1 + if shipHitsLeft[shipId] == 0 then + shipType = floor((shipId-1) / 2) // get ship type, 0-2 + sunkPerType[shipType] += 1 + print "And you sunk it. Hurray for the good guys." + print "So far, the bad guys have lost" + print sunkPerType[0] + " destroyer(s), " + sunkPerType[1] + + " cruiser(s), and " + sunkPerType[2] + " aircraft carrier(s)." + print "Your current splash/hit ratio is " + (splashCount / hitCount) + end if + return + end if + print "Splash! Try again." + globals.splashCount += 1 +end function + +playOneGame = function + setup + printField + print + print "De-code it and use it if you can" + print "but keep the de-coding method a secret." + print + print "START GAME" + + while true + doOneTurn + if sunkPerType.sum == 6 then break + end while + + print + print "You have totally wiped out the bad guys' fleet" + print "with a final splash/hit ratio of " + (splashCount / hitCount) + if splashCount == 0 then + print "Congratulations -- a direct hit every time." + end if +end function + +// Main loop +while true + playOneGame + print + print "****************************" + print +end while From 67f0527692856014d699879a6e2945b449c1802d Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 17 Jul 2023 16:25:18 -0700 Subject: [PATCH 08/11] Initial work on the blackjack game. Still need to handle splits and insurance. --- .../10_Blackjack/MiniScript/README.md | 16 ++ .../10_Blackjack/MiniScript/blackjack.ms | 258 ++++++++++++++++++ 10_Blackjack/README.md | 11 +- 3 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/10_Blackjack/MiniScript/README.md create mode 100644 00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms diff --git a/00_Alternate_Languages/10_Blackjack/MiniScript/README.md b/00_Alternate_Languages/10_Blackjack/MiniScript/README.md new file mode 100644 index 00000000..449006a9 --- /dev/null +++ b/00_Alternate_Languages/10_Blackjack/MiniScript/README.md @@ -0,0 +1,16 @@ +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 blackjack.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 BASIC program. Then, at the Mini Micro command prompt, enter: + + load "blackjack" + run diff --git a/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms b/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms new file mode 100644 index 00000000..bbbb9257 --- /dev/null +++ b/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms @@ -0,0 +1,258 @@ +import "listUtil" +print " "*31 + "Black Jack" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +fna = function(q); return q - 11*(q >= 22); end function +P = [[]]*15 // P(i,j) is the jth card in hand i +Q = [0]*15 // Q(i) is the total value of hand i +C = [] // the deck being dealt from +D = [] // the discard pile +T = [0]*8 // total $ for each player +S = [0]*7 // total $ won/lost this hand for each player +B = [0]*15 // bet for each hand +Z = [0]*7 // insurance for each player + +reshuffle = function + print "Reshuffling" + globals.C = D + globals.D = [] + C.shuffle +end function + +// Function to draw a card from the deck. +getCard = function // line 100 + if not C then reshuffle + return C.pop +end function + +// Function to evaluate the given hand. Total is usually put into +// Q(handNum). Totals have the following meaning: +// 2-10...Hard 2-10 +// 11-21...Soft 11-21 +// 22-32...Hard 11-21 +// 33+ or -1...Busted +evalHand = function(handNum) // line 300 + result = 0 + for card in P[handNum] + result = addCardToTotal(result, card) + end for + return result +end function + +// Function to add a card into a total hand value. +addCardToTotal = function(total, card) // line 500 + x1 = card; if x1 > 10 then x1 = 10 + q1 = total + x1 + if total < 11 then + if card == 1 then return total + 11 // (ace) + return q1 + 11 * (q1 >= 11) + end if + total = q1 + (total <= 21 and q1 >= 21) + if total >= 33 then total = -1 + return total +end function + +// Print one of those totals as it should appear to the user. +displayTotal = function(total) + return total - 11 * (total >= 22) +end function + +printCard = function(cardNum) + s = cardNames[cardNum] + print " " + (s+" ")[:2], " " +end function + +printCardV2 = function(cardNum) + s = cardNames[cardNum] + print " " + (" " + s)[-2:], " " +end function + +getYesNo = function(prompt) + while true + inp = input(prompt).upper + if inp and (inp[0] == "Y" or inp[0] == "N") then return inp[0] + end while +end function + +getNumber = function(prompt, minVal=0, maxVal=500) + while true + result = input(prompt).val + if result == floor(result) and minVal <= result <= maxVal then return result + end while +end function + +// Get one of a list of one-letter (uppercase) options. +getOption = function(prompt, options) + while true + result = input(prompt).upper + if result and options.indexOf(result[0]) != null then return result[0] + print "Type " + options[:-1].join(", ") + " or " + options[-1] + " please" + end while +end function + +getBets = function + print "Bets:" + for i in range(0, numPlayers-1) + B[i] = getNumber("# " + (i+1) + "? ", 1, 500) + end for +end function + +playOneRound = function + globals.Z = [0] * numPlayers + globals.S = [0] * numPlayers + if C.len < (numPlayers+1) * 2 then reshuffle + getBets + print "PLAYER ", "" + for i in range(0, numPlayers-1) + print i+1, " " + P[i] = [] + end for + print "DEALER" + P[numPlayers] = [] + for row in [1,2] + print " ", "" + for i in range(0, numPlayers) + P[i].push getCard + if row == 1 or i < numPlayers then printCard P[i][-1] + end for + print + end for + // Test for insurance + if P[numPlayers][0] == 1 and getYesNo("Any insurance? ") == "Y" then + print "Insurance Bets" + for i in range(0, numPlayers-1) + Z[i] = getNumber("# " + (i+1) + "? ", 0, B[i]/2) + S[i] = Z[i] * (3 * (P[numPlayers][1] >= 10) - 1) // ?!? + end for + end if + // Test for dealer blackjack + dealerCard0 = P[numPlayers][0] + dealerCard1 = P[numPlayers][1] + if (dealerCard0==1 and dealerCard1 > 9) or + (dealerCard0 > 9 and dealerCard1==1) then + print; print "Dealer has a " + cardNames[dealerCard1] + " in the hole for Blackjack" + for i in range(0, numPlayers) + Q[i] = evalHand(i) + end for + else + // no dealer blackjack + // now play the hands + for i in range(0, numPlayers-1) + playHand i + end for + Q[numPlayers] = evalHand(numPlayers) // (evaluate dealer hand) + // Test for playing the dealer's hand... we only do so if + // there are any player hands with cards left. + anyLeft = false + for i in range(0, numPlayers-1) + if P[i] or P[i+8] then anyLeft = true + end for + if not anyLeft then + print "Dealer had a " + cardNames[P[numPlayers][1]] + " concealed." + else + // Play dealer's hand. + dispTotal = displayTotal(Q[numPlayers]) + print "Dealer has a " + cardNames[P[numPlayers][1]] + " concealed" + + " for a total of " + dispTotal + "." + while Q[numPlayers] > 0 and dispTotal <= 16 + if P[numPlayers].len == 2 then print "Draws ", "" + card = getCard + print cardNames[card], " " + P[numPlayers].push card + Q[numPlayers] = evalHand(numPlayers) + dispTotal = displayTotal(Q[numPlayers]) + end while + if P[numPlayers].len > 2 then print " ---Total is " + dispTotal + print + end if + end if + tallyResults +end function + +playHand = function(handNum) + while P[handNum] + choice = getOption("Player " + (handNum % 8 + 1) + "? ", ["H", "S", "D", "/"]) + if choice == "S" then // player wants to stand + Q[handNum] = evalHand(handNum) + if Q[handNum] == 21 then + print "Blackjack" + S[handNum] += 1.5 * B[handNum] + B[handNum] = 0 + discardHand handNum + end if + break + else if choice == "D" then // player wants to double down + print "Not yet supported!" + else if choice == "H" then // player wants to hit + Q[handNum] = evalHand(handNum) + card = getCard + print "Received a " + cardNames[card] + P[handNum].push card + Q[handNum] = evalHand(handNum) + if Q[handNum] < 0 then + print "...busted" + discardHand handNum + end if + else if choice == "/" then // player wants to split + print "Not yet supported!" + end if + end while +end function + +discardHand = function(handNum) + while P[handNum] + D.push P[handNum].pop + end while + Q[handNum] = 0 +end function + +tallyResults = function + dealerTotal = displayTotal(evalHand(numPlayers)) + for i in range(0, numPlayers-1) + playerHandATotal = displayTotal(evalHand(i)) + playerHandBTotal = displayTotal(evalHand(i+8)) + // calculate S[i], which is the $ won/lost for player i + S[i] = S[i] + B[i]*sign(playerHandATotal - dealerTotal) + B[i+8]*sign(playerHandBTotal - dealerTotal) + B[i+8] = 0 + s = "Player " + (i+1) + " " + s += ["loses", "pushes", "wins"][sign(S[i])+1] + if S[i] != 0 then s += " " + abs(S[i]) + T[i] += S[i] + T[numPlayers] -= S[i] + s = (s + " "*20)[:20] + " Total = " + T[i] + print s + discardHand i + discardHand i+8 + end for + print "Dealer's total = " + T[numPlayers] + print +end function + +// Main program starts here // (Line 1500) +// Initialize +cardNames = "N A 2 3 4 5 6 7 8 9 10 J Q K".split +inputs = "H,S,D,/," +D = range(1,13) * 4 + +yesNo = getYesNo("Do you want instructions? ") +if yesNo[0] == "Y" then + print "This is the game of 21. As many as 7 players may play the" + print "game. On each deal, bets will be asked for, and the" + print "players' bets should be typed in. The cards will then be" + print "dealt, and each player in turn plays his hand. The" + print "first response should be either 'D', indicating that the" + print "player is doubling down, 'S', indicating that he is" + print "standing, 'H', indicating he wants another card, or '/'," + print "indicating that he wants to split his cards. After the" + print "initial response, all further responses should be 'S' or" + print "'H', unless the cards were split, in which case doubling" + print "down is again permitted. In order to collect for" + print "blackjack, the initial response should be 'S'." +end if +numPlayers = getNumber("Number of players? ", 1, 7) +print +// main loop! +while true + playOneRound +end while diff --git a/10_Blackjack/README.md b/10_Blackjack/README.md index dcbe53bb..ebed2a88 100644 --- a/10_Blackjack/README.md +++ b/10_Blackjack/README.md @@ -15,6 +15,15 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html + #### Porting Notes -(please note any difficulties or challenges in porting here) +The program makes extensive use of the assumption that a boolean expression evaluates to **-1** for true. This was the case in some classic BASIC environments but not others; and it is not the case in [JS Basic](https://troypress.com/wp-content/uploads/user/js-basic/index.html), leading to nonsensical results. In an environment that uses **1** instead of **-1** for truth, you would need to negate the boolean expression in the following lines: + - 570 + - 590 + - 2220 + - 2850 + - 3100 + - 3400 + - 3410 + - 3420 From e0a417bf8ac5d0695b2ff7fce726a94a9ece40fb Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 19 Jul 2023 18:14:30 -0700 Subject: [PATCH 09/11] Finished the blackjack port to MiniScript. --- .../10_Blackjack/MiniScript/blackjack.ms | 175 ++++++++++-------- 1 file changed, 99 insertions(+), 76 deletions(-) diff --git a/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms b/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms index bbbb9257..98bb0b90 100644 --- a/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms +++ b/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms @@ -4,37 +4,34 @@ print " "*15 + "Creative Computing Morristown, New Jersey" print; print; print fna = function(q); return q - 11*(q >= 22); end function -P = [[]]*15 // P(i,j) is the jth card in hand i -Q = [0]*15 // Q(i) is the total value of hand i -C = [] // the deck being dealt from -D = [] // the discard pile -T = [0]*8 // total $ for each player -S = [0]*7 // total $ won/lost this hand for each player -B = [0]*15 // bet for each hand -Z = [0]*7 // insurance for each player +hands = [[]]*15 // hands(i,j) is the jth card in hand i (P) +handValue = [0]*15 // total value of each hand (Q) +deck = [] // the deck being dealt from (C) +playerMoney = [0]*8 // total $ for each player (T) +roundWinnings = [0]*7 // total $ won/lost this hand for each player (S) +betPerHand = [0]*15 // bet for each hand (B) reshuffle = function print "Reshuffling" - globals.C = D - globals.D = [] - C.shuffle + globals.deck = range(1,13)*4 + deck.shuffle end function // Function to draw a card from the deck. getCard = function // line 100 - if not C then reshuffle - return C.pop + if not deck then reshuffle + return deck.pop end function // Function to evaluate the given hand. Total is usually put into -// Q(handNum). Totals have the following meaning: +// handValue(handNum). Totals have the following meaning: // 2-10...Hard 2-10 // 11-21...Soft 11-21 // 22-32...Hard 11-21 // 33+ or -1...Busted evalHand = function(handNum) // line 300 result = 0 - for card in P[handNum] + for card in hands[handNum] result = addCardToTotal(result, card) end for return result @@ -42,6 +39,7 @@ end function // Function to add a card into a total hand value. addCardToTotal = function(total, card) // line 500 + if total < 0 then return total // (already busted) x1 = card; if x1 > 10 then x1 = 10 q1 = total + x1 if total < 11 then @@ -79,6 +77,7 @@ getNumber = function(prompt, minVal=0, maxVal=500) while true result = input(prompt).val if result == floor(result) and minVal <= result <= maxVal then return result + print "Please enter a number from " + minVal + " to " + maxVal end while end function @@ -94,117 +93,143 @@ end function getBets = function print "Bets:" for i in range(0, numPlayers-1) - B[i] = getNumber("# " + (i+1) + "? ", 1, 500) + betPerHand[i] = getNumber("# " + (i+1) + "? ", 1, 500) end for end function playOneRound = function - globals.Z = [0] * numPlayers - globals.S = [0] * numPlayers - if C.len < (numPlayers+1) * 2 then reshuffle + globals.roundWinnings = [0] * numPlayers + if deck.len < (numPlayers+1) * 2 then reshuffle getBets print "PLAYER ", "" for i in range(0, numPlayers-1) print i+1, " " - P[i] = [] + hands[i] = [] end for print "DEALER" - P[numPlayers] = [] + hands[numPlayers] = [] for row in [1,2] print " ", "" for i in range(0, numPlayers) - P[i].push getCard - if row == 1 or i < numPlayers then printCard P[i][-1] + hands[i].push getCard + if row == 1 or i < numPlayers then printCard hands[i][-1] end for print end for + dealerCard0 = hands[numPlayers][0] + dealerCard1 = hands[numPlayers][1] // Test for insurance - if P[numPlayers][0] == 1 and getYesNo("Any insurance? ") == "Y" then + if dealerCard0 == 1 and getYesNo("Any insurance? ") == "Y" then print "Insurance Bets" for i in range(0, numPlayers-1) - Z[i] = getNumber("# " + (i+1) + "? ", 0, B[i]/2) - S[i] = Z[i] * (3 * (P[numPlayers][1] >= 10) - 1) // ?!? + insurance = getNumber("# " + (i+1) + "? ", 0, betPerHand[i]/2) + roundWinnings[i] = insurance * (3 * (dealerCard1 >= 10) - 1) end for end if // Test for dealer blackjack - dealerCard0 = P[numPlayers][0] - dealerCard1 = P[numPlayers][1] if (dealerCard0==1 and dealerCard1 > 9) or (dealerCard0 > 9 and dealerCard1==1) then print; print "Dealer has a " + cardNames[dealerCard1] + " in the hole for Blackjack" for i in range(0, numPlayers) - Q[i] = evalHand(i) + handValue[i] = evalHand(i) end for else // no dealer blackjack + if dealerCard0 == 1 or dealerCard0 >= 10 then + print; print "No dealer Blackjack." + end if // now play the hands for i in range(0, numPlayers-1) playHand i end for - Q[numPlayers] = evalHand(numPlayers) // (evaluate dealer hand) + handValue[numPlayers] = evalHand(numPlayers) // (evaluate dealer hand) // Test for playing the dealer's hand... we only do so if // there are any player hands with cards left. anyLeft = false for i in range(0, numPlayers-1) - if P[i] or P[i+8] then anyLeft = true + if hands[i] or hands[i+8] then anyLeft = true end for if not anyLeft then - print "Dealer had a " + cardNames[P[numPlayers][1]] + " concealed." + print "Dealer had a " + cardNames[hands[numPlayers][1]] + " concealed." else // Play dealer's hand. - dispTotal = displayTotal(Q[numPlayers]) - print "Dealer has a " + cardNames[P[numPlayers][1]] + " concealed" + + dispTotal = displayTotal(handValue[numPlayers]) + print "Dealer has a " + cardNames[hands[numPlayers][1]] + " concealed" + " for a total of " + dispTotal + "." - while Q[numPlayers] > 0 and dispTotal <= 16 - if P[numPlayers].len == 2 then print "Draws ", "" + while handValue[numPlayers] > 0 and dispTotal <= 16 card = getCard + if hands[numPlayers].len == 2 then print "Draws ", "" print cardNames[card], " " - P[numPlayers].push card - Q[numPlayers] = evalHand(numPlayers) - dispTotal = displayTotal(Q[numPlayers]) + hands[numPlayers].push card + handValue[numPlayers] = evalHand(numPlayers) + dispTotal = displayTotal(handValue[numPlayers]) end while - if P[numPlayers].len > 2 then print " ---Total is " + dispTotal + if hands[numPlayers].len > 2 then + if handValue[numPlayers] < 0 then print " ---Busted" else print " ---Total is " + dispTotal + end if print end if end if tallyResults end function -playHand = function(handNum) - while P[handNum] - choice = getOption("Player " + (handNum % 8 + 1) + "? ", ["H", "S", "D", "/"]) +playHand = function(handNum, prompt=null, allowSplit=true) + if not prompt then prompt = "Player " + (handNum % 8 + 1) + while hands[handNum] + options = ["H", "S", "D"] + ["/"] * allowSplit + choice = getOption(prompt + "? ", options) if choice == "S" then // player wants to stand - Q[handNum] = evalHand(handNum) - if Q[handNum] == 21 then + handValue[handNum] = evalHand(handNum) + if handValue[handNum] == 21 and hands[handNum].len == 2 then print "Blackjack" - S[handNum] += 1.5 * B[handNum] - B[handNum] = 0 + roundWinnings[handNum] += 1.5 * betPerHand[handNum] + betPerHand[handNum] = 0 discardHand handNum end if break - else if choice == "D" then // player wants to double down - print "Not yet supported!" - else if choice == "H" then // player wants to hit - Q[handNum] = evalHand(handNum) + else if choice == "D" or choice == "H" then // hit or double down + handValue[handNum] = evalHand(handNum) + if choice == "D" then betPerHand[handNum] *= 2 card = getCard - print "Received a " + cardNames[card] - P[handNum].push card - Q[handNum] = evalHand(handNum) - if Q[handNum] < 0 then - print "...busted" + print "Received a " + cardNames[card], " " + hands[handNum].push card + handValue[handNum] = evalHand(handNum) + if handValue[handNum] < 0 then + print "...busted", "" discardHand handNum end if - else if choice == "/" then // player wants to split - print "Not yet supported!" + print + if choice == "D" then break + else if choice == "/" then // split + card1 = hands[handNum][0]; if card1 > 10 then card1 = 10 + card2 = hands[handNum][1]; if card2 > 10 then card2 = 10 + if card1 != card2 then + print "Splitting not allowed." + continue + end if + hand2 = handNum + 8 + hands[hand2] = [hands[handNum].pop] + betPerHand[hand2] = betPerHand[handNum] + card = getCard + print "First hand receives a " + cardNames[card] + hands[handNum].push card + card = getCard + print "Second hand receives a " + cardNames[card] + hands[hand2].push card + if card1 != 1 then + // Now play the two hands + playHand handNum, "Hand 1", false + playHand hand2, "Hand 2", false + end if + break end if + allowSplit = false end while end function discardHand = function(handNum) - while P[handNum] - D.push P[handNum].pop - end while - Q[handNum] = 0 + hands[handNum] = [] + handValue[handNum] = 0 end function tallyResults = function @@ -212,31 +237,28 @@ tallyResults = function for i in range(0, numPlayers-1) playerHandATotal = displayTotal(evalHand(i)) playerHandBTotal = displayTotal(evalHand(i+8)) - // calculate S[i], which is the $ won/lost for player i - S[i] = S[i] + B[i]*sign(playerHandATotal - dealerTotal) + B[i+8]*sign(playerHandBTotal - dealerTotal) - B[i+8] = 0 + // calculate roundWinnings[i], which is the $ won/lost for player i + roundWinnings[i] = roundWinnings[i] + betPerHand[i]*sign(playerHandATotal - dealerTotal) + betPerHand[i+8]*sign(playerHandBTotal - dealerTotal) + betPerHand[i+8] = 0 s = "Player " + (i+1) + " " - s += ["loses", "pushes", "wins"][sign(S[i])+1] - if S[i] != 0 then s += " " + abs(S[i]) - T[i] += S[i] - T[numPlayers] -= S[i] - s = (s + " "*20)[:20] + " Total = " + T[i] + s += ["loses", "pushes", "wins"][sign(roundWinnings[i])+1] + if roundWinnings[i] != 0 then s += " " + abs(roundWinnings[i]) + playerMoney[i] += roundWinnings[i] + playerMoney[numPlayers] -= roundWinnings[i] + s = (s + " "*25)[:25] + "Total = " + playerMoney[i] print s discardHand i discardHand i+8 end for - print "Dealer's total = " + T[numPlayers] + print "Dealer's total = " + playerMoney[numPlayers] print end function // Main program starts here // (Line 1500) // Initialize -cardNames = "N A 2 3 4 5 6 7 8 9 10 J Q K".split -inputs = "H,S,D,/," -D = range(1,13) * 4 +cardNames = "n A 2 3 4 5 6 7 8 9 10 J Q K".split -yesNo = getYesNo("Do you want instructions? ") -if yesNo[0] == "Y" then +if getYesNo("Do you want instructions? ") == "Y" then print "This is the game of 21. As many as 7 players may play the" print "game. On each deal, bets will be asked for, and the" print "players' bets should be typed in. The cards will then be" @@ -249,6 +271,7 @@ if yesNo[0] == "Y" then print "'H', unless the cards were split, in which case doubling" print "down is again permitted. In order to collect for" print "blackjack, the initial response should be 'S'." + print end if numPlayers = getNumber("Number of players? ", 1, 7) print From 980330cd3925fd81b99dae7a77d69ab02753ba78 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 19 Jul 2023 20:38:23 -0700 Subject: [PATCH 10/11] Bug fixes and tweaks to MiniScript blackjack. --- .../10_Blackjack/MiniScript/blackjack.ms | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms b/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms index 98bb0b90..6c44cf7c 100644 --- a/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms +++ b/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms @@ -17,8 +17,8 @@ reshuffle = function deck.shuffle end function -// Function to draw a card from the deck. -getCard = function // line 100 +// Function to draw a card from the deck (reshuffling if needed) +getCard = function if not deck then reshuffle return deck.pop end function @@ -29,7 +29,7 @@ end function // 11-21...Soft 11-21 // 22-32...Hard 11-21 // 33+ or -1...Busted -evalHand = function(handNum) // line 300 +evalHand = function(handNum) result = 0 for card in hands[handNum] result = addCardToTotal(result, card) @@ -38,7 +38,7 @@ evalHand = function(handNum) // line 300 end function // Function to add a card into a total hand value. -addCardToTotal = function(total, card) // line 500 +addCardToTotal = function(total, card) if total < 0 then return total // (already busted) x1 = card; if x1 > 10 then x1 = 10 q1 = total + x1 @@ -46,7 +46,7 @@ addCardToTotal = function(total, card) // line 500 if card == 1 then return total + 11 // (ace) return q1 + 11 * (q1 >= 11) end if - total = q1 + (total <= 21 and q1 >= 21) + total = q1 + (total <= 21 and q1 > 21) if total >= 33 then total = -1 return total end function @@ -56,16 +56,7 @@ displayTotal = function(total) return total - 11 * (total >= 22) end function -printCard = function(cardNum) - s = cardNames[cardNum] - print " " + (s+" ")[:2], " " -end function - -printCardV2 = function(cardNum) - s = cardNames[cardNum] - print " " + (" " + s)[-2:], " " -end function - +// Get a yes/no response from the user getYesNo = function(prompt) while true inp = input(prompt).upper @@ -73,6 +64,7 @@ getYesNo = function(prompt) end while end function +// Get a number, within a given range, from the user getNumber = function(prompt, minVal=0, maxVal=500) while true result = input(prompt).val @@ -112,7 +104,9 @@ playOneRound = function print " ", "" for i in range(0, numPlayers) hands[i].push getCard - if row == 1 or i < numPlayers then printCard hands[i][-1] + if row == 1 or i < numPlayers then + print " " + (cardNames[hands[i][-1]] + " ")[:2], " " + end if end for print end for @@ -185,6 +179,8 @@ playHand = function(handNum, prompt=null, allowSplit=true) roundWinnings[handNum] += 1.5 * betPerHand[handNum] betPerHand[handNum] = 0 discardHand handNum + else + print "Total is " + displayTotal(handValue[handNum]) end if break else if choice == "D" or choice == "H" then // hit or double down @@ -195,11 +191,13 @@ playHand = function(handNum, prompt=null, allowSplit=true) hands[handNum].push card handValue[handNum] = evalHand(handNum) if handValue[handNum] < 0 then - print "...busted", "" + print "...Busted" discardHand handNum + roundWinnings[handNum] = -betPerHand[handNum] + betPerHand[handNum] = 0 end if - print - if choice == "D" then break + prompt = "Hit" + if choice == "D" then; print; break; end if else if choice == "/" then // split card1 = hands[handNum][0]; if card1 > 10 then card1 = 10 card2 = hands[handNum][1]; if card2 > 10 then card2 = 10 From dbd37d1c5b8cfd7b37758709936441b5e220f56f Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 19 Jul 2023 20:50:49 -0700 Subject: [PATCH 11/11] Updated README for command-line MiniScript. --- 00_Alternate_Languages/10_Blackjack/MiniScript/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/00_Alternate_Languages/10_Blackjack/MiniScript/README.md b/00_Alternate_Languages/10_Blackjack/MiniScript/README.md index 449006a9..5b04b3a0 100644 --- a/00_Alternate_Languages/10_Blackjack/MiniScript/README.md +++ b/00_Alternate_Languages/10_Blackjack/MiniScript/README.md @@ -9,6 +9,8 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript blackjack.ms +But note that the current release (1.2.1) of command-line MiniScript does not properly flush the output buffer when line breaks are suppressed, as this program does when prompting for your next action after a Hit. So, method 2 (below) is recommended for now. + 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 BASIC program. Then, at the Mini Micro command prompt, enter: