From 8440a1e30c43a132b15efb3591428819acfcc152 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 13:18:27 -0700 Subject: [PATCH 001/377] fixed typo in 78_Sive_Wave/README.md --- 78_Sine_Wave/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/78_Sine_Wave/README.md b/78_Sine_Wave/README.md index 32789d048..c5c340f3c 100644 --- a/78_Sine_Wave/README.md +++ b/78_Sine_Wave/README.md @@ -1,6 +1,6 @@ ### Sine Wave -Did you ever go to a computer show and see a bunch of CRT terminals just sitting there waiting forlornly for someone to give a demo on them. It was one of those moments when I was at DEC that I decided there should be a little bit of background activity. And why not plot with words instead of the usual X’s? Thus SINE WAVE was born and lives on in dozens on different versions. At least those CRTs don’t look so lifeless anymore. +Did you ever go to a computer show and see a bunch of CRT terminals just sitting there waiting forlornly for someone to give a demo on them. It was one of those moments when I was at DEC that I decided there should be a little bit of background activity. And why not plot with words instead of the usual X’s? Thus SINE WAVE was born and lives on in dozens of different versions. At least those CRTs don’t look so lifeless anymore. --- From 60a6b290f45102353a0274b7af979bd4d7f97e7c Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 17:14:31 -0700 Subject: [PATCH 002/377] Added 91_Train port to MiniScript --- .../91_Train/MiniScript/README.md | 3 ++ .../91_Train/MiniScript/train.ms | 28 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 00_Alternate_Languages/91_Train/MiniScript/README.md create mode 100644 00_Alternate_Languages/91_Train/MiniScript/train.ms diff --git a/00_Alternate_Languages/91_Train/MiniScript/README.md b/00_Alternate_Languages/91_Train/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/91_Train/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/91_Train/MiniScript/train.ms b/00_Alternate_Languages/91_Train/MiniScript/train.ms new file mode 100644 index 000000000..27ce5b98f --- /dev/null +++ b/00_Alternate_Languages/91_Train/MiniScript/train.ms @@ -0,0 +1,28 @@ +// TRAIN +// +// Converted from BASIC to MiniScript by Ryushinaka and Joe Strout + +while true + print "TRAIN" + print "CREATIVE COMPUTER MORRISTOWN, NEW JERSEY" + print "" + print "TIME - SPEED DISTANCE EXERCISE" + + carSpeed = floor(25*rnd + 40) + difference = floor(15*rnd + 5) + trainSpeed = floor(19*rnd + 20) + print " A car traveling " + carSpeed + " MPH can make a certain trip in" + print difference + " hours less than a train traveling at " + trainSpeed + " MPH." + answer = input("How long does the trip take by car? ").val + carTime = difference*trainSpeed/(carSpeed-trainSpeed) + error = round(abs((carTime-answer)*100/answer)) + if error < 5 then + print "GOOD! Answer within " + error + " PERCENT." + else + print "Sorry. You were off by " + floor(error) + " percent." + print "Correct answer is " + round(carTime, 1) + " hours." + end if + + answer = input("Another problem (YES or NO)? ") + if not answer or answer[0].upper != "Y" then break +end while From 8cea6c14662878b0ec4d8645539bb5dfa72a344e Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 17:27:00 -0700 Subject: [PATCH 003/377] Added 87_3-D_Plot in MiniScript --- .../87_3-D_Plot/MiniScript/3dplot.ms | 26 +++++++++++++++++++ .../87_3-D_Plot/MiniScript/README.md | 3 +++ 2 files changed, 29 insertions(+) create mode 100644 00_Alternate_Languages/87_3-D_Plot/MiniScript/3dplot.ms create mode 100644 00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md diff --git a/00_Alternate_Languages/87_3-D_Plot/MiniScript/3dplot.ms b/00_Alternate_Languages/87_3-D_Plot/MiniScript/3dplot.ms new file mode 100644 index 000000000..0cf1e5169 --- /dev/null +++ b/00_Alternate_Languages/87_3-D_Plot/MiniScript/3dplot.ms @@ -0,0 +1,26 @@ +// 3dPlot +// +// Converted from BASIC to MiniScript by Joe Strout + +print " "*32 + "3D PLOT" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print +e = 2.71828 + +fna = function(z) + return 30 * e^(-z*z/100) +end function + +for x in range(-30, 30, 1.5) + lastZ = 0 + y1 = 5 * floor(sqrt(900-x*x)/5) + for y in range(y1, -y1, -5) + z = floor(25+fna(sqrt(x*x+y*y))-.7*y) + if z > lastZ then + print " "*(z-lastZ) + "*", "" + lastZ = z + end if + end for + print + wait 0.1 // (optional) +end for diff --git a/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md b/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). From 78af0d3069dc3902fb5309db6d8ead72a78cc763 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 17:33:37 -0700 Subject: [PATCH 004/377] Added MiniScript version of 78_Sine_Wave --- .../78_Sine_Wave/MiniScript/README.md | 3 +++ .../78_Sine_Wave/MiniScript/sinewave.ms | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md create mode 100644 00_Alternate_Languages/78_Sine_Wave/MiniScript/sinewave.ms diff --git a/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md b/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/78_Sine_Wave/MiniScript/sinewave.ms b/00_Alternate_Languages/78_Sine_Wave/MiniScript/sinewave.ms new file mode 100644 index 000000000..da3e99a77 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/MiniScript/sinewave.ms @@ -0,0 +1,15 @@ +print " "*30 + "SINE WAVE" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print; print; print +// Remarkable program by David Ahl, ported +// from BASIC to MiniScript by Joe Strout + +B = 0 +// start long loop +for t in range(0, 40, 0.25) + A = floor(26 + 25*sin(t)) + print " "*A, "" + if not B then print "CREATIVE" else print "COMPUTING" + B = not B + wait 0.01 +end for From 095617f944471a89eb69a8caf57fc72eb73f0e3b Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 18:06:27 -0700 Subject: [PATCH 005/377] Added MiniScript port of 32_Diamond --- .../32_Diamond/MiniScript/README.md | 3 +++ .../32_Diamond/MiniScript/diamond.ms | 23 +++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 00_Alternate_Languages/32_Diamond/MiniScript/README.md create mode 100644 00_Alternate_Languages/32_Diamond/MiniScript/diamond.ms diff --git a/00_Alternate_Languages/32_Diamond/MiniScript/README.md b/00_Alternate_Languages/32_Diamond/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/32_Diamond/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/32_Diamond/MiniScript/diamond.ms b/00_Alternate_Languages/32_Diamond/MiniScript/diamond.ms new file mode 100644 index 000000000..8166b570a --- /dev/null +++ b/00_Alternate_Languages/32_Diamond/MiniScript/diamond.ms @@ -0,0 +1,23 @@ +// Diamond +// +// Ported from BASIC to MiniScript by Joe Strout + +print " "*33 + "DIAMOND" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print +print "For a pretty diamond pattern," +maxw = input("type in an odd number between 5 and 21: ").val +s = "CC" + "!" * maxw +columns = floor(68/maxw) +for row in range(1, columns) + for w in range(1, maxw, 2) + range(maxw-2, 1, -2) + print " "*(maxw-w)/2, "" + for column in range(1, columns) + print s[:w], "" + if column < columns then print " "*(maxw-w), "" + end for + print + wait 0.01 + end for +end for + From 2c42d39bfd6b335c68a637f37956b511f77a7db8 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 18:26:53 -0700 Subject: [PATCH 006/377] Added MiniScript port of 33_Dice --- .../33_Dice/MiniScript/README.md | 3 ++ .../33_Dice/MiniScript/dice.ms | 53 +++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 00_Alternate_Languages/33_Dice/MiniScript/README.md create mode 100644 00_Alternate_Languages/33_Dice/MiniScript/dice.ms diff --git a/00_Alternate_Languages/33_Dice/MiniScript/README.md b/00_Alternate_Languages/33_Dice/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/33_Dice/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/33_Dice/MiniScript/dice.ms b/00_Alternate_Languages/33_Dice/MiniScript/dice.ms new file mode 100644 index 000000000..38b41ef34 --- /dev/null +++ b/00_Alternate_Languages/33_Dice/MiniScript/dice.ms @@ -0,0 +1,53 @@ +// Dice +// +// Danny Freidus +// Ported from BASIC to MiniScript by Joe Strout + +print " "*34 + "DICE" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print +print "This program simulates the rolling of a" +print "pair of dice." +print "You enter the number of times you want the computer to" +print "'roll' the dice. Watch out, very large numbers take" +print "a long time. In particular, numbers over 5000." + +// Function to do one run of the simulation. +runOnce = function + // Clear the array we'll use to hold the counts + counts = [0] * 13 + // Loop the desired number of times + x = input("How many rolls? ").val + for s in range(1, x) + // roll two dice and find the sum + die1 = ceil(6 * rnd) + die2 = ceil(6 * rnd) + sum = die1 + die2 + // update the count for that sum + counts[sum] += 1 + end for + print + + // print a table showing how many times each sum was rolled + print "Total Spots Number of Times" + for v in range(2, 12) + // (the [-6:] trick below right-aligns the number) + print (" " + v)[-6:] + " "*10 + counts[v] + end for + print; print +end function + +// Get a yes/no (or at least y/n) response from the user. +askYesNo = function(prompt) + while true + answer = input(prompt).lower[:1] + if answer == "y" or answer == "n" then return answer + end while +end function + +// main loop +while true + print + runOnce + if askYesNo("Try again? ") == "n" then break +end while From 921a03f9e25d11d21e786015f65a359a22c1641e Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 18:41:49 -0700 Subject: [PATCH 007/377] Added MiniScript port of 52_Kinema --- .../52_Kinema/MiniScript/README.md | 3 ++ .../52_Kinema/MiniScript/kinema.ms | 40 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 00_Alternate_Languages/52_Kinema/MiniScript/README.md create mode 100644 00_Alternate_Languages/52_Kinema/MiniScript/kinema.ms diff --git a/00_Alternate_Languages/52_Kinema/MiniScript/README.md b/00_Alternate_Languages/52_Kinema/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/52_Kinema/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/52_Kinema/MiniScript/kinema.ms b/00_Alternate_Languages/52_Kinema/MiniScript/kinema.ms new file mode 100644 index 000000000..9fb27071a --- /dev/null +++ b/00_Alternate_Languages/52_Kinema/MiniScript/kinema.ms @@ -0,0 +1,40 @@ +// Kinema +// +// Ported from BASIC to MiniScript by Joe Strout + +print " "*33 + "KINEMA" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print + +checkAnswer = function(prompt, correctValue) + answer = input(prompt).val + right = abs((answer - correctValue)/answer) < 0.15 + if right then + print "Close enough!" + else + print "Not even close...." + end if + print "Correct answer is " + correctValue + return right +end function + +doOneRun = function + print; print + rightCount = 0 + V = 5 + floor(35*rnd) + print "A ball is thrown upwards at " + V + " meters per second." + print + rightCount += checkAnswer("How high will it go (in meters)? ", 0.05 * V^2) + rightCount += checkAnswer("How long until it returns (in seconds)? ", V/5) + t = 1 + floor(2*V*rnd)/10 + rightCount += checkAnswer("What will its velocity be after " + t + + " seconds? ", V-10*t) + print + print rightCount + " right out of 3." + if rightCount >= 2 then print " Not bad." +end function + +// main loop (press control-C to break out) +while true + doOneRun +end while From a0171e37aceeddfa48454b3ada60268826cfa904 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 18:58:46 -0700 Subject: [PATCH 008/377] added MiniScript port of 92_Trap --- .../92_Trap/MiniScript/README.md | 3 + .../92_Trap/MiniScript/trap.ms | 69 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 00_Alternate_Languages/92_Trap/MiniScript/README.md create mode 100644 00_Alternate_Languages/92_Trap/MiniScript/trap.ms diff --git a/00_Alternate_Languages/92_Trap/MiniScript/README.md b/00_Alternate_Languages/92_Trap/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/92_Trap/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/92_Trap/MiniScript/trap.ms b/00_Alternate_Languages/92_Trap/MiniScript/trap.ms new file mode 100644 index 000000000..443839463 --- /dev/null +++ b/00_Alternate_Languages/92_Trap/MiniScript/trap.ms @@ -0,0 +1,69 @@ +// TRAP +// STEVE ULLMAN, 8-1-72 +// Ported to MiniScript by Ryushinaka and Joe Strout, 2023 + +print "TRAP" +print "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print "" + +// constants: +G = 6 // number of guesses +N = 100 // range of numbers + +// Get a yes/no (or at least y/n) response from the user. +askYesNo = function(prompt) + while true + answer = input(prompt).lower[:1] + if answer == "y" or answer == "n" then return answer + end while +end function + +if askYesNo("Instructions? ") == "y" then + print "I am thinking of a number between 1 and " + N + print "Try to guess my number. On each guess, " + print "you are to enter 2 numbers, trying to trap" + print "my number between the two numbers. I will" + print "tell you if you have trapped my number, if my" + print "number is larger than your two numbers, or if" + print "my number is smaller than your two numbers." + print "If you want to guess one single number, type" + print "your guess for both your trap numbers." + print "You get " + G + " guesses to get my number." + print +end if + +doOneGame = function + computers_number = ceil(N*rnd) + + for Q in range(1,G) + print "" + while true + guess = input("Guess #" + Q + ": ").replace(" ","") + guess = guess.split(",") + if guess.len == 2 then break + print "Enter your guess like: 30,40" + end while + A = guess[0].val + B = guess[1].val + + if A == computers_number and B == computers_number then + print "You got it!!!" + return + else if A <= computers_number and B >= computers_number then + print "You have trapped my number." + else if A > computers_number and B > computers_number then + print "My number is smaller than your trap numbers." + else if A < computers_number and B < computers_number then + print "My number is larger than your trap numbers." + end if + end for + print "Sorry, that's " + G + " guesses. The number was " + computers_number +end function + +// main loop +while true + print + doOneGame + print + if askYesNo("Try Again? ") == "n" then break +end while From 0f85e3da49c5f4b3e1194886ae469d61f4836769 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 22:46:33 -0700 Subject: [PATCH 009/377] Ported 54_Letter to MiniScript --- .../54_Letter/MiniScript/README.md | 3 ++ .../54_Letter/MiniScript/letter.ms | 44 +++++++++++++++++++ .../92_Trap/MiniScript/trap.ms | 6 +-- 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 00_Alternate_Languages/54_Letter/MiniScript/README.md create mode 100644 00_Alternate_Languages/54_Letter/MiniScript/letter.ms diff --git a/00_Alternate_Languages/54_Letter/MiniScript/README.md b/00_Alternate_Languages/54_Letter/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/54_Letter/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/54_Letter/MiniScript/letter.ms b/00_Alternate_Languages/54_Letter/MiniScript/letter.ms new file mode 100644 index 000000000..78a32b3bc --- /dev/null +++ b/00_Alternate_Languages/54_Letter/MiniScript/letter.ms @@ -0,0 +1,44 @@ +// Letter Guessing Game +// Ported to MiniScript by Joe Strout, 2023 + +print " "*33 + "LETTER" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print + +print "Letter Guessing Game"; print +print "I'll think of a letter of the alphabet, A to Z." +print "Try to guess my letter and I'll give you clues" +print "as to how close you're getting to my letter." + +// Function to play one round of the game +playOneGame = function + letter = char(65 + floor(rnd * 26)) + guesses = 0 + print; print "OK, I have a letter. Start guessing." + while true + print; guess = input("What is your guess? ")[:1].upper + guesses = guesses + 1 + if guess == letter then + print; print "You got it in " + guesses + " guesses!!" + if guesses > 5 then + print "But it shouldn't take more than 5 guesses!" + else + print "Good job !!!!!" + print char(7) * 15 + end if + return + else if guess < letter then + print "Too low. Try a higher letter." + else + print "Too high. Try a lower letter." + end if + end while +end function + +// main loop -- press Control-C to exit +while true + print + playOneGame + print + print "Let's play again....." +end while diff --git a/00_Alternate_Languages/92_Trap/MiniScript/trap.ms b/00_Alternate_Languages/92_Trap/MiniScript/trap.ms index 443839463..687a7a1ea 100644 --- a/00_Alternate_Languages/92_Trap/MiniScript/trap.ms +++ b/00_Alternate_Languages/92_Trap/MiniScript/trap.ms @@ -2,9 +2,9 @@ // STEVE ULLMAN, 8-1-72 // Ported to MiniScript by Ryushinaka and Joe Strout, 2023 -print "TRAP" -print "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" -print "" +print " "*34 + "TRAP" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print // constants: G = 6 // number of guesses From 099368a2691ceacf5a6cd3ae6f6f9678daea64ce Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 22:57:52 -0700 Subject: [PATCH 010/377] Ported 66_Number to MiniScript --- .../66_Number/MiniScript/README.md | 3 ++ .../66_Number/MiniScript/number.ms | 44 +++++++++++++++++++ 66_Number/README.md | 2 +- 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/66_Number/MiniScript/README.md create mode 100644 00_Alternate_Languages/66_Number/MiniScript/number.ms diff --git a/00_Alternate_Languages/66_Number/MiniScript/README.md b/00_Alternate_Languages/66_Number/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/66_Number/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/66_Number/MiniScript/number.ms b/00_Alternate_Languages/66_Number/MiniScript/number.ms new file mode 100644 index 000000000..23d88de34 --- /dev/null +++ b/00_Alternate_Languages/66_Number/MiniScript/number.ms @@ -0,0 +1,44 @@ +// Number Game +// originally by Tom Adametx +// Ported from BASIC to MiniScript by Joe Strout, 2023 + +print " "*33 + "NUMBER" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print + +print "You have 100 points. By guessing numbers from 1 to 5, you" +print "can gain or lose points depending on how close you get to" +print "a random number selected by the computer."; print +print "You occasionally will get a jackpot which will double(!)" +print "your point count. You win when you get to 500 points." +print + +P = 100 +fnr = function; return ceil(5*rnd); end function +while true + guess = input("Guess a number from 1 to 5: ").val + R = fnr + S = fnr + T = fnr + U = fnr + V = fnr + if guess == R then + P = P - 5 + else if guess == S then + P = P + 5 + else if guess == T then + P = P+P + print "You hit the jackpot!!!" + else if guess == U then + P = P + 1 + else if guess == V then + P = P - floor(P*0.5) + else if guess > 5 then + continue + end if + if P > 500 then + print "!!!!You win!!!! with " + P + " points." + exit + end if + print "You have " + P + " points."; print +end while diff --git a/66_Number/README.md b/66_Number/README.md index 43d97db3b..2df37b6b7 100644 --- a/66_Number/README.md +++ b/66_Number/README.md @@ -15,4 +15,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -(please note any difficulties or challenges in porting here) +Contrary to the description, the computer picks *five* random numbers per turn, not one. You are not rewarded based on how close your guess is to one number, but rather to which of these five random numbers (if any) it happens to match exactly. From 0a1bea9e036b8a8ecf2d80dcbf9123f2bb9ee52a Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 28 Jan 2023 23:08:55 -0700 Subject: [PATCH 011/377] Added MiniScript port of 64_Nicomachus --- .../64_Nicomachus/MiniScript/README.md | 3 ++ .../64_Nicomachus/MiniScript/nicomachus.ms | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 00_Alternate_Languages/64_Nicomachus/MiniScript/README.md create mode 100644 00_Alternate_Languages/64_Nicomachus/MiniScript/nicomachus.ms diff --git a/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md b/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/64_Nicomachus/MiniScript/nicomachus.ms b/00_Alternate_Languages/64_Nicomachus/MiniScript/nicomachus.ms new file mode 100644 index 000000000..ebbc394b7 --- /dev/null +++ b/00_Alternate_Languages/64_Nicomachus/MiniScript/nicomachus.ms @@ -0,0 +1,45 @@ +// Nicomachus +// originally by David Ahl +// Ported from BASIC to MiniScript by Joe Strout, 2023 + +print " "*33 + "NICOMA" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print +print "Boomerang puzzle from Arithmetica of Nicomachus -- A.D. 90!" + +// Get a yes/no (or at least y/n) response from the user. +askYesNo = function(prompt) + while true + answer = input(prompt) + a1 = answer.lower[:1] + if a1 == "y" or a1 == "n" then return a1 + print "Eh? I don't understand '" + answer + "' Try 'yes' or 'no'." + end while +end function + +doOne = function + print + print "Please think of a number between 1 and 100." + A = input("Your number divided by 3 has a remainder of: ").val + B = input("Your number divided by 5 has a remainder of: ").val + C = input("Your number divided by 7 has a remainder of: ").val + print + print "Let me think a moment..." + print + wait 1.5 + D = 70*A + 21*B + 15*C + D = D % 105 // gets the remainder after dividing by 105 + yesNo = askYesNo("Your number was " + D + ", right? ") + if yesNo == "y" then + print "How about that!" + else + print "I feel your arithmetic is in error." + end if +end function + +// Main loop -- press Control-C to break +while true + doOne + print + print "Let's try another." +end while From 98b61acfcf602f14db6caaea45d065f269ec0a14 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 31 Jan 2023 20:45:30 -0700 Subject: [PATCH 012/377] Added MiniScript version of 31_Depth_Charge. --- .../31_Depth_Charge/MiniScript/README.md | 3 + .../31_Depth_Charge/MiniScript/depthcharge.ms | 116 ++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md create mode 100644 00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms diff --git a/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md b/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms b/00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms new file mode 100644 index 000000000..eeb813d11 --- /dev/null +++ b/00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms @@ -0,0 +1,116 @@ +// Depth Charge +// Originally by Dana Noftle (1978) +// Translated from BASIC to MiniScript by Ryushinaka and Joe Strout (2023) + +askYesNo = function(prompt) + while true + answer = input(prompt).lower[:1] + if answer == "y" or answer == "n" then return answer + end while +end function + +showWelcome = function + print + print " "*34 + "Depth Charge" + print " "*15 + "Creative Computing Morristown, New Jersey" + print +end function + +setup = function + while true + globals.size = input("Dimension of search area? ").val + if size > 0 then break + end while + + globals.numCharges = ceil(log(size,2)) + if numCharges == 0 then globals.numCharges = 1 // ensure we have at least 1 shot + + print "You are the captain of the destroyer USS Computer." + print "An enemy sub has been causing you trouble. Your" + print "mission is to destroy it. You have " + numCharges + " shots." + print "Specify depth charge explosion point with a" + print "trio of numbers -- the first two are the" + print "surface coordinates; the third is the depth." +end function + +showShotResult = function(shot,location) + result = "Sonar reports shot was " + if shot[1] > location[1] then + result = result + "north" + else if shot[1] < location[1] then + result = result + "south" + end if + + if shot[0] > location[0] then + result = result + "east" + else if shot[0] < location[0] then + result = result + "west" + end if + + if shot[1] != location[1] or shot[0] != location[0] then + result = result + " and " + end if + + if shot[2] > location[2] then + result = result + "too low." + else if shot[2] < location[2] then + result = result + "too high." + else + result = result + "depth OK." + end if + + print result +end function + +getShot = function + shotPos = [0,0,0] + while true + rawGuess = input("Enter coordinates: ").split(" ") + if rawGuess.len == 3 then + shotPos[0] = rawGuess[0].val + shotPos[1] = rawGuess[1].val + shotPos[2] = rawGuess[2].val + return shotPos + else + print "Please enter coordinates separated by spaces" + print "Example: 3 2 1" + end if + end while +end function + + +playGame = function + print "Good luck!" + print + + subPos = [floor(rnd*size), floor(rnd*size), floor(rnd*size)] + + // For debugging, you can give away the answer: + print "(Sub is hidden at: " + subPos.join(" ") + ")" + + for c in range(1, numCharges) + print "Trial " + c + + shot = getShot + + if shot[0] == subPos[0] and shot[1] == subPos[1] and shot[2] == subPos[2] then + print "B O O M ! ! You found it in " + c + " tries!" + return + else + showShotResult(shot,subPos) + end if + end for + + print "You have been torpedoed! Abandon ship!" + print "The submarine was at " + subPos.join(" ") + "." +end function + +showWelcome +setup +while true + playGame + if askYesNo("Another game (Y or N): ") == "n" then + print "OK. Hope you enjoyed yourself." + break + end if +end while From 512157f808d7d2c17916118cdfacaa1a4a3c6290 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 31 Jan 2023 20:46:20 -0700 Subject: [PATCH 013/377] Removed debugging line from Depth Charge (MiniScript port). --- .../31_Depth_Charge/MiniScript/depthcharge.ms | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms b/00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms index eeb813d11..3607cb805 100644 --- a/00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms +++ b/00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms @@ -86,7 +86,7 @@ playGame = function subPos = [floor(rnd*size), floor(rnd*size), floor(rnd*size)] // For debugging, you can give away the answer: - print "(Sub is hidden at: " + subPos.join(" ") + ")" + //print "(Sub is hidden at: " + subPos.join(" ") + ")" for c in range(1, numCharges) print "Trial " + c From 8bedf02e211ec124f99de6b8b01e60b6d8cfa9d3 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 31 Jan 2023 21:11:07 -0700 Subject: [PATCH 014/377] Added MiniScript port of 41_Guess. --- .../41_Guess/MiniScript/README.md | 3 + .../41_Guess/MiniScript/guess.ms | 59 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 00_Alternate_Languages/41_Guess/MiniScript/README.md create mode 100644 00_Alternate_Languages/41_Guess/MiniScript/guess.ms diff --git a/00_Alternate_Languages/41_Guess/MiniScript/README.md b/00_Alternate_Languages/41_Guess/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/41_Guess/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/41_Guess/MiniScript/guess.ms b/00_Alternate_Languages/41_Guess/MiniScript/guess.ms new file mode 100644 index 000000000..496426ce4 --- /dev/null +++ b/00_Alternate_Languages/41_Guess/MiniScript/guess.ms @@ -0,0 +1,59 @@ +setup = function + print " "*33 + "GUESS" + print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + print; print; print + print "This is a number guessing game. I'll think" + print "of a number between 1 and any limit you want." + print "Then you have to guess what it is." + print + while true + globals.limit = input("What limit do you want? ").val + if limit > 1 then break + print "Please enter a number greater than 1." + end while + globals.par = floor(log(limit, 2)) + 1 +end function + +printGap = function + for i in range(1, 5) + print + end for +end function + +doOneGame = function + rightAnswer = ceil(rnd * limit) + print "I'm thinking of a number between 1 and " + limit + print "Now you try to guess what it is." + guess = 0 + while true + guess = guess + 1 + num = input("Your guess: ").val + if num <= 0 then + printGap + setup + return + end if + if num == rightAnswer then + print "That's it! You got it in " + guess + " tries." + if guess < par then + print "Very good." + else if guess == par then + print "Good." + else + print "You should have been able to get it in only " + par + "." + end if + printGap + return + end if + if num > rightAnswer then + print "Too high. Try a smaller answer." + else + print "Too low. Try a bigger answer." + end if + end while +end function + +setup +while true + doOneGame +end while \ No newline at end of file From a2721f422aeef1052471578144a603862888ce41 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 31 Jan 2023 21:46:09 -0700 Subject: [PATCH 015/377] Added MiniScript port of 29_Craps. --- .../29_Craps/MiniScript/README.md | 3 + .../29_Craps/MiniScript/craps.ms | 87 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 00_Alternate_Languages/29_Craps/MiniScript/README.md create mode 100644 00_Alternate_Languages/29_Craps/MiniScript/craps.ms diff --git a/00_Alternate_Languages/29_Craps/MiniScript/README.md b/00_Alternate_Languages/29_Craps/MiniScript/README.md new file mode 100644 index 000000000..f52e8746d --- /dev/null +++ b/00_Alternate_Languages/29_Craps/MiniScript/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). diff --git a/00_Alternate_Languages/29_Craps/MiniScript/craps.ms b/00_Alternate_Languages/29_Craps/MiniScript/craps.ms new file mode 100644 index 000000000..900ba5d43 --- /dev/null +++ b/00_Alternate_Languages/29_Craps/MiniScript/craps.ms @@ -0,0 +1,87 @@ +// Craps +// Ported from BASIC to MiniScript by Joe Strout (2023) + +print " "*33 + "CRAPS" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print + +print "2,3,12 are losers; 4,5,6,8,9,10 are points; 7,11 are natural winners." +winnings = 0 + +rollDice = function + wait 0.5 // (a small delay makes the game more dramatic) + return ceil(rnd*6) + ceil(rnd*6) +end function + +doOneBet = function + while true + wager = input("Input the amount of your wager: ").val + if wager > 0 then break + end while + print "I will now throw the dice." + result = 0 // 1 if we win, 2 if win double, -1 if we lose + roll = rollDice + if roll == 7 or roll == 11 then + print roll + "- natural....a winner!!!!" + print roll + " pays even money, you win " + wager + " dollars" + result = 1 + else if roll == 2 then + print "2- snake eyes....you lose." + print "You lose " + wager + " dollars." + result = -1 + else if roll == 3 or roll == 12 then + print roll + " - craps...you lose." + print "You lose " + wager + " dollars." + result = -1 + else + point = roll + print point + " is the point. I will roll again" + while true + roll = rollDice + if roll == 7 then + print "7 - craps. You lose." + print "You lose $" + wager + result = -1 + break + else if roll == point then + print roll + "- a winner.........CONGRATS!!!!!!!!" + print roll + " at 2 to 1 odds pays you...let me see..." + + (2*wager) + " dollars" + result = 2 + break + else + print roll + " - no point. I will roll again" + end if + end while + end if + globals.winnings += wager * result +end function + +// Main loop. +while true + doOneBet + + while true + // Why you have to enter 5 to continue is anyone's guess, + // but that's what the original program did. + again = input(" If you want to play again print 5 if not print 2: ") + if again == "5" or again == "2" then break + end while + + if winnings < 0 then + print "You are now under $" + (-winnings) + else if winnings > 0 then + print "You are now ahead $" + winnings + else + print "You are now even at 0" + end if + if again != "5" then break +end while + +if winnings < 0 then + print "Too bad, you are in the hole. Come again." +else if winnings > 0 then + print "Congratulations---You came out a winner. Come again!" +else + print "Congrtulations---You came out even, not bad for an amateur" +end if From 846be86481c02fbae4460aa50a13612132f614ca Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Fri, 17 Feb 2023 07:52:45 +1100 Subject: [PATCH 016/377] Configure project --- 77_Salvo/csharp/Salvo.csproj | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/77_Salvo/csharp/Salvo.csproj b/77_Salvo/csharp/Salvo.csproj index d3fe4757c..51470ec9f 100644 --- a/77_Salvo/csharp/Salvo.csproj +++ b/77_Salvo/csharp/Salvo.csproj @@ -2,8 +2,16 @@ Exe net6.0 - 10 + 11 enable enable + + + + + + + + From e6425221bf3f63342d8f087de27c9190e8427906 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Sun, 19 Feb 2023 19:58:24 +1100 Subject: [PATCH 017/377] Create program structure --- 77_Salvo/csharp/Game.cs | 18 +++++++++++++++++ 77_Salvo/csharp/Program.cs | 6 ++++++ 77_Salvo/csharp/Resources/Resource.cs | 29 +++++++++++++++++++++++++++ 77_Salvo/csharp/Resources/Title.txt | 5 +++++ 4 files changed, 58 insertions(+) create mode 100644 77_Salvo/csharp/Game.cs create mode 100644 77_Salvo/csharp/Program.cs create mode 100644 77_Salvo/csharp/Resources/Resource.cs create mode 100644 77_Salvo/csharp/Resources/Title.txt diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs new file mode 100644 index 000000000..e3efb88c6 --- /dev/null +++ b/77_Salvo/csharp/Game.cs @@ -0,0 +1,18 @@ +namespace Salvo; + +internal class Game +{ + private readonly IReadWrite _io; + private readonly IRandom _random; + + public Game(IReadWrite io, IRandom random) + { + _io = io; + _random = random; + } + + internal void Play() + { + _io.Write(Streams.Title); + } +} \ No newline at end of file diff --git a/77_Salvo/csharp/Program.cs b/77_Salvo/csharp/Program.cs new file mode 100644 index 000000000..d1fa1a27a --- /dev/null +++ b/77_Salvo/csharp/Program.cs @@ -0,0 +1,6 @@ +global using Games.Common.IO; +global using Games.Common.Randomness; +global using static Salvo.Resources.Resource; +using Salvo; + +new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); diff --git a/77_Salvo/csharp/Resources/Resource.cs b/77_Salvo/csharp/Resources/Resource.cs new file mode 100644 index 000000000..0cc550343 --- /dev/null +++ b/77_Salvo/csharp/Resources/Resource.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace Salvo.Resources; + +internal static class Resource +{ + internal static class Streams + { + public static Stream Title => GetStream(); + } + + internal static class Prompts + { + } + + private static string GetPrompt([CallerMemberName] string? name = null) => GetString($"{name}Prompt"); + + private static string GetString([CallerMemberName] string? name = null) + { + using var stream = GetStream(name); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + private static Stream GetStream([CallerMemberName] string? name = null) => + Assembly.GetExecutingAssembly().GetManifestResourceStream($"{typeof(Resource).Namespace}.{name}.txt") + ?? throw new Exception($"Could not find embedded resource stream '{name}'."); +} \ No newline at end of file diff --git a/77_Salvo/csharp/Resources/Title.txt b/77_Salvo/csharp/Resources/Title.txt new file mode 100644 index 000000000..6b2ba9b31 --- /dev/null +++ b/77_Salvo/csharp/Resources/Title.txt @@ -0,0 +1,5 @@ + Salvo + Creative Computing Morristown, New Jersey + + + From e5530d67c8e2f00503a5b4e2f969915d8c2a7734 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Sun, 26 Feb 2023 23:40:45 +1100 Subject: [PATCH 018/377] Transliterate logic --- 77_Salvo/csharp/Game.cs | 411 +++++++++++++++++++++++++++++++++++++ 77_Salvo/csharp/Program.cs | 1 + 2 files changed, 412 insertions(+) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index e3efb88c6..e7a7f818b 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -1,3 +1,5 @@ +using Games.Common.Randomness; + namespace Salvo; internal class Game @@ -14,5 +16,414 @@ public Game(IReadWrite io, IRandom random) internal void Play() { _io.Write(Streams.Title); + +L1040: var AA = new float[11,11]; + var BA = new float[11,11]; + var CA = new int[8]; + var DA = new int[8]; + var EA = new int[13]; + var FA = new int[13]; + var GA = new int[13]; + var HA = new float[13]; + var KA = new int[11,11]; +L1050: var Z8 = 0; +L1060: for (var W = 1; W <= 12; W++) + { +L1070: EA[W] = -1; +L1080: HA[W] = -1; + } +L1100: for (var X = 1; X <= 10; X++) + { +L1110: for (var Y = 1; Y <= 10; Y++) + { +L1120: BA[X,Y] = 0; + } + } +L1150: for (var X = 1; X <= 12; X++) + { +L1160: FA[X]=0; +L1170: GA[X]=0; + } +L1190: for (var X = 1; X <= 10; X++) + { +L1200: for (var Y = 1; Y <= 10; Y++) + { +L1210: AA[X,Y]=0; + } + } +L1240: for (var K = 4; K >= 1; K--) + { +L1250: var U6=0; +L1260: var (X, Y, V, V2) = L2910(); +L1270: int FNA(int K) => (5-K)*3-2*K/4+Math.Sign(K-1)-1; +L1280: int FNB(int K) => K+K/4-Math.Sign(K-1); +L1290: if (V+V2+V*V2 == 0) { goto L1260; } +L1300: if (Y+V*FNB(K)>10) { goto L1260; } +L1310: if (Y+V*FNB(K)<1) { goto L1260; } +L1320: if (X+V2*FNB(K)>10) { goto L1260; } +L1330: if (X+V2*FNB(K)<1) { goto L1260; } +L1340: U6=U6+1; +L1350: if (U6>25) { goto L1190; } +L1360: for (var Z = 0; Z <= FNB(K); Z++) + { +L1370: FA[Z+FNA(K)]=X+V2*Z; +L1380: GA[Z+FNA(K)]=Y+V*Z; + } +L1400: var U8=FNA(K); +L1405: if (U8>U8+FNB(K)) { goto L1460; } +L1410: for (var Z2 = U8; Z2 <= U8+FNB(K); Z2++) + { +L1415: if (U8<2) { continue; } +L1420: for (var Z3 = 1; Z3 <= U8-1; Z3++) + { +L1430: if (Math.Sqrt((FA[Z3]-FA[Z2])*(FA[Z3]-FA[Z2]) + (GA[Z3]-GA[Z2])*(GA[Z3]-GA[Z2])) < 3.59) { goto L1260; } + } + } +L1460: for (var Z = 0; Z <= FNB(K); Z++) + { +L1470: AA[FA[Z+U8],GA[Z+U8]]=.5F+Math.Sign(K-1)*(K-1.5F); + } + } +L1500: _io.WriteLine("ENTER COORDINATES FOR..."); +L1510: _io.WriteLine("BATTLESHIP"); +L1520: for (var X = 1; X <= 5; X++) + { + var (Y, Z) = _io.Read2Numbers(""); + BA[(int)Y, (int)Z] = 3; +L1540: BA[(int)Y, (int)Z] = 3; + } +L1560: _io.WriteLine("CRUISER"); +L1570: for (var X = 1; X <= 3; X++) + { + var (Y, Z) = _io.Read2Numbers(""); +L1590: BA[(int)Y, (int)Z]=2; + } +L1610: _io.WriteLine("DESTROYER"); +L1620: for (var X = 1; X <= 2; X++) + { + var (Y, Z) = _io.Read2Numbers(""); +L1640: BA[(int)Y, (int)Z]=1; + } +L1660: _io.WriteLine("DESTROYER"); +L1670: for (var X = 1; X <= 2; X++) + { + var (Y, Z) = _io.Read2Numbers(""); +L1690: BA[(int)Y, (int)Z]=.5F; + } +L1710: var JS = _io.ReadString("DO YOU WANT TO START"); +L1730: if (JS != "WHERE ARE YOUR SHIPS?") { goto L1890; } +L1740: _io.WriteLine("BATTLESHIP"); +L1750: for (var Z = 1; Z <= 5; Z++) + { +L1760: _io.WriteLine($" {FA[Z]} {GA[Z]} "); + } +L1780: _io.WriteLine("CRUISER"); +L1790: _io.WriteLine($" {FA[6]} {GA[6]} "); +L1800: _io.WriteLine($" {FA[7]} {GA[7]} "); +L1810: _io.WriteLine($" {FA[8]} {GA[8]} "); +L1820: _io.WriteLine("DESTROYER"); +L1830: _io.WriteLine($" {FA[9]} {GA[9]} "); +L1840: _io.WriteLine($" {FA[10]} {GA[10]} "); +L1850: _io.WriteLine("DESTROYER"); +L1860: _io.WriteLine($" {FA[11]} {GA[11]} "); +L1870: _io.WriteLine($" {FA[12]} {GA[12]} "); +L1880: goto L1710; +L1890: var C=0; +L1900: var KS = _io.ReadString("DO YOU WANT TO SEE MY SHOTS"); +L1920: _io.WriteLine(); +L1930: if (JS != "YES") { goto L2620; } +L1950: if (JS != "YES") { goto L1990; } +L1960: C=C+1; +L1970: _io.WriteLine(); +L1980: _io.WriteLine($"TURN {C}"); +L1990: var A=0; +L2000: for (var W = .5F; W <= 3; W += .5F) + { +L2010: for (var X = 1; X <= 10; X++) + { +L2020: for (var Y = 1; Y <= 10; Y++) + { +L2030: if (BA[X,Y] == W) { goto L2070; } + } + } +L2060: continue; +L2070: A=A+(int)(W+.5F); + } +L2090: for (var W = 1; W <= 7; W++) + { +L2100: CA[W] = 0; +L2110: DA[W] = 0; +L2120: FA[W] = 0; +L2130: GA[W] = 0; + } +L2150: var P3=0; +L2160: for (var X = 1; X <= 10; X++) + { +L2170: for (var Y = 1; Y <= 10; Y++) + { +L2180: if (AA[X,Y]>10) { continue; } +L2190: P3=P3+1; + } + } +L2220: _io.WriteLine($"YOU HAVE {A} SHOTS."); +L2230: if (P3 >= A) { goto L2260; } +L2240: _io.WriteLine("YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES."); +L2250: goto L2890; +L2260: if (A != 0) { goto L2290; } +L2270: _io.WriteLine("I HAVE WON."); +L2280: return; +L2290: for (var W = 1; W <= A; W++) + { +L2300: var (X, Y) = _io.Read2Numbers(""); +L2310: if (X != (int)X) { goto L2370; } +L2320: if (X > 10) { goto L2370; } +L2330: if (X < 1) { goto L2370; } +L2340: if (Y != (int)Y) { goto L2370; } +L2350: if (Y > 10) { goto L2370; } +L2360: if (Y >= 1) { goto L2390; } +L2370: _io.WriteLine("ILLEGAL, ENTER AGAIN."); +L2380: goto L2300; +L2390: if (AA[(int)X,(int)Y]>10) + { + _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {AA[(int)X,(int)Y]-10}"); + goto L2300; + } +L2400: CA[W]=(int)X; +L2410: DA[W]=(int)Y; + } +L2460: for (var W = 1; W <= A; W++) + { +L2470: if (AA[CA[W],DA[W]] == 3) + { + _io.WriteLine("YOU HIT MY BATTLESHIP."); + goto L2510; + } +L2480: if (AA[CA[W],DA[W]] == 2) + { + _io.WriteLine("YOU HIT MY CRUISER."); + goto L2510; + } +L2490: if (AA[CA[W],DA[W]] == 1) + { + _io.WriteLine("YOU HIT MY DESTROYER."); + goto L2510; + } +L2500: if (AA[CA[W],DA[W]] == .5F) + { + + _io.WriteLine("YOU HIT MY DESTROYER."); + goto L2510; + } +L2510: AA[CA[W],DA[W]] = 10+C; + } +L2620: A = 0; +L2630: if (JS == "YES") { goto L2670; } +L2640: C = C + 1; +L2650: _io.WriteLine(); +L2660: _io.WriteLine($"TURN {C}"); +L2670: A = 0; +L2680: for (var W = .5F; W <= 3; W += .5F) + { +L2690: for (var X = 1; X <= 10; X++) + { +L2700: for (var Y = 1; Y <= 10; Y++) + { +L2710: if (AA[X,Y] == W) { goto L2750; } + } + } +L2740: continue; +L2750: A = A + (int)(W+.5F); + } +L2770: P3=0; +L2780: for (var X = 1; X <= 10; X++) + { +L2790: for (var Y = 1; Y <= 10; Y++) + { +L2800: if (AA[X,Y]>10) { continue; } +L2810: P3=P3+1; + } + } +L2840: _io.WriteLine($"I HAVE {A} SHOTS."); +L2850: if (P3>A) { goto L2880; } +L2860: _io.WriteLine("I HAVE MORE SHOTS THAN BLANK SQUARES."); +L2870: goto L2270; +L2880: if (A != 0) { goto L2960; } +L2890: _io.WriteLine("YOU HAVE WON."); +L2900: return; + + (int, int, int, int) L2910() + { + var X = _random.Next(1, 11); + var Y = _random.Next(1, 11); + var V = _random.Next(-1, 2); + var V2 = _random.Next(-1, 2); + + return (X, Y, V, V2); + } + +L2960: for (var W = 1; W <= 12; W++) + { +L2970: if (HA[W]>0) { goto L3800; } + } +L3000: var w=0; +L3010: var R3=0; +L3020: var (x, y, v, v2) = L2910(); +L3030: //RESTORE + var index = 0; +L3040: var R2=0; +L3050: R3=R3+1; +L3060: if (R3>100) { goto L3010; } +L3070: if (x>10) { goto L3110; } +L3080: if (x>0) { goto L3120; } +L3090: x = 1 + (int)(_random.NextFloat() * 2.5F); +L3100: goto L3120; +L3110: x = 10 - (int)(_random.NextFloat() * 2.5F); +L3120: if (y>10) { goto L3160; } +L3130: if (y>0) { goto L3270; } +L3140: y=1+(int)(_random.NextFloat() * 2.5F); +L3150: goto L3270; +L3160: y=10-(int)(_random.NextFloat() * 2.5F); +L3170: goto L3270; +L3180: FA[w]=x; +L3190: GA[w]=y; +L3200: if (w==A) { goto L3380; } +L3210: if (R2==6) { goto L3030; } +L3240: //DATA 1,1,-1,1,1,-3,1,1,0,2,-1,1 + var data = new[] { 1,1,-1,1,1,-3,1,1,0,2,-1,1 }; +L3220: //READ X1,Y1 + var (X1, Y1) = (data[index++], data[index++]); +L3230: R2=R2+1; +L3250: x=x+X1; +L3260: y=y+Y1; +L3270: if (x>10) { goto L3210; } +L3280: if (x<1) { goto L3210; } +L3290: if (y>10) { goto L3210; } +L3300: if (y<1) { goto L3210; } +L3310: if (BA[x,y]>10) { goto L3210; } +L3320: for (var Q9 = 1; Q9 <= w; Q9++) + { +L3330: if (FA[Q9] != x) { continue; } +L3340: if (GA[Q9] == y) { goto L3210; } + } +L3360: w=w+1; +L3370: goto L3180; +L3380: if (KS != "YES") { goto L3420; } +L3390: for (var Z5 = 1; Z5 <= A; Z5++) + { +L3400: _io.WriteLine($" {FA[Z5]} {GA[Z5]}"); + } +L3420: for (var W = 1; W <= A; W++) + { +L3430: if (BA[FA[W],GA[W]] == 3) + { + _io.WriteLine("I HIT YOUR BATTLESHIP"); + } + else if (BA[FA[W],GA[W]] == 2) + { + _io.WriteLine("I HIT YOUR CRUISER"); + } + else if (BA[FA[W],GA[W]] == 1) + { + _io.WriteLine("I HIT YOUR DESTROYER"); + } + else if (BA[FA[W],GA[W]] == .5F) + { + _io.WriteLine("I HIT YOUR DESTROYER"); + } + else + { + BA[FA[W],GA[W]]=10+C; + continue; + } +L3570: for (var Q = 1; Q <= 12; Q++) + { +L3580: if (EA[Q] != -1) { continue; } +L3590: EA[Q]=10+C; +L3600: HA[Q]=BA[FA[W],GA[W]]; +L3610: var M3=0; +L3620: for (var M2 = 1; M2 <= 12; M2++) + { +L3630: if (HA[M2] != HA[Q]) { continue; } +L3640: M3=M3+1; + } +L3660: if (M3 != (int)(HA[Q]+.5F)+1+(int)(HA[Q]+.5F)/3) { goto L3470; } +L3670: for (var M2 = 1; M2 <= 12; M2++) + { +L3680: if (HA[M2] != HA[Q]) { continue; } +L3690: EA[M2] = -1; +L3700: HA[M2] = -1; + } +L3720: goto L3470; + } +L3740: _io.WriteLine("PROGRAM ABORT:"); +L3750: for (var Q = 1; Q <= 12; Q++) + { +L3760: _io.WriteLine($"EA[{Q}] = {EA[Q]}"); +L3770: _io.WriteLine($"HA[{Q}] = {HA[Q]}"); + } + return; +L3470: BA[FA[W],GA[W]]=10+C; + } +L3490: goto L1950; +L3800: //REM************************USINGEARRAY +L3810: for (var R = 1; R <= 10; R++) + { +L3820: for (var S = 1; S <= 10; S++) + { + KA[R,S]=0; + } + } +L3860: for (var U = 1; U <= 12; U++) + { +L3870: if (EA[U]<10) { continue; } +L3880: for (var R = 1; R <= 10; R++) + { +L3890: for (var S = 1; S <= 10; S++) + { +L3900: if (BA[R,S]<10) { goto L3930; } +L3910: KA[R,S]=-10000000; +L3920: continue; +L3930: for (var M = Math.Sign(1-R); M <= Math.Sign(10-R); M++) + { +L3940: for (var N = Math.Sign(1-S); N <= Math.Sign(10-S); N++) + { +L3950: if (N+M+N*M==0) { continue; } +L3960: if (BA[R+M,S+N] != EA[U]) { continue; } +L3970: KA[R,S]=KA[R,S]+EA[U]-S*(int)(HA[U]+.5F); + } + } + } + } + } +L4030: for (var R = 1; R <= A; R++) + { +L4040: FA[R]=R; +L4050: GA[R]=R; + } +L4070: for (var R = 1; R <= 10; R++) + { +L4080: for (var S = 1; S <= 10; S++) + { +L4090: var Q9=1; +L4100: for (var M = 1; M <= A; M++) + { +L4110: if (KA[FA[M],GA[M]]>=KA[FA[Q9],GA[Q9]]) { continue; } +L4120: Q9=M; + } +L4131: if (R>A) { goto L4140; } +L4132: if (R==S) { goto L4210; } +L4140: if (KA[R,S] Date: Tue, 28 Feb 2023 11:37:54 +1300 Subject: [PATCH 019/377] started work on a rust implementation of super star trek --- 84_Super_Star_Trek/rust/Cargo.toml | 8 ++++++ 84_Super_Star_Trek/rust/src/main.rs | 34 ++++++++++++++++++++++ 84_Super_Star_Trek/rust/src/model.rs | 43 ++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 84_Super_Star_Trek/rust/Cargo.toml create mode 100644 84_Super_Star_Trek/rust/src/main.rs create mode 100644 84_Super_Star_Trek/rust/src/model.rs diff --git a/84_Super_Star_Trek/rust/Cargo.toml b/84_Super_Star_Trek/rust/Cargo.toml new file mode 100644 index 000000000..1ec696335 --- /dev/null +++ b/84_Super_Star_Trek/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs new file mode 100644 index 000000000..673b6700f --- /dev/null +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -0,0 +1,34 @@ +use model::{Galaxy, GameStatus, Pos, Quadrant}; + +mod model; + +fn main() { + let mut galaxy = Galaxy::generate_new(); + // create the model + // start the loop + loop { + view(&galaxy); + galaxy = wait_for_command(&galaxy); + } + // rather than using a loop, recursion and passing the ownership might be better +} + +fn view(model: &Galaxy) { + match model.game_status { + GameStatus::ShortRangeScan => { + let quadrant = &model.quadrants[model.enterprise.sector.as_index()]; + render_quadrant(&model.enterprise.sector, quadrant) + } + } +} + +fn render_quadrant(enterprise_sector: &Pos, quadrant: &Quadrant) { + +} + +fn wait_for_command(galaxy: &Galaxy) -> Galaxy { + // listen for command from readline + // handle bad commands + // update model + Galaxy::generate_new() +} \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs new file mode 100644 index 000000000..9ca501898 --- /dev/null +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -0,0 +1,43 @@ + +pub struct Galaxy { + pub quadrants: Vec, + pub enterprise: Enterprise, + pub game_status: GameStatus +} + +pub struct Pos(u8, u8); + +impl Pos { + pub fn as_index(&self) -> usize { + (self.0 * 8 + self.1).into() + } +} + +pub struct Quadrant { + pub stars: Vec, + pub star_bases: Vec, + pub klingons: Vec +} + +pub struct Klingon { + pub sector: Pos +} + +pub struct Enterprise { + pub quadrant: Pos, + pub sector: Pos, +} + +pub enum GameStatus { + ShortRangeScan +} + +impl Galaxy { + pub fn generate_new() -> Self { + Galaxy { + quadrants: Vec::new(), + enterprise: Enterprise { quadrant: Pos(0,0), sector: Pos(0,0) }, + game_status: GameStatus::ShortRangeScan + } + } +} \ No newline at end of file From 92b4d60e84da5f0c310c22a1a4550352623cfb5a Mon Sep 17 00:00:00 2001 From: Christopher Date: Tue, 28 Feb 2023 12:36:29 +1300 Subject: [PATCH 020/377] work aligning with mvu, along with a render quadrant view function --- 84_Super_Star_Trek/rust/src/main.rs | 56 ++++++++++++++++++--------- 84_Super_Star_Trek/rust/src/model.rs | 3 +- 84_Super_Star_Trek/rust/src/update.rs | 15 +++++++ 84_Super_Star_Trek/rust/src/view.rs | 35 +++++++++++++++++ 4 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 84_Super_Star_Trek/rust/src/update.rs create mode 100644 84_Super_Star_Trek/rust/src/view.rs diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 673b6700f..86bc2d85d 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,34 +1,54 @@ -use model::{Galaxy, GameStatus, Pos, Quadrant}; +use std::io::stdin; + +use model::{Galaxy, GameStatus}; +use update::Message; mod model; +mod view; +mod update; fn main() { let mut galaxy = Galaxy::generate_new(); - // create the model - // start the loop loop { - view(&galaxy); - galaxy = wait_for_command(&galaxy); + view::view(&galaxy); + let command = wait_for_command(&galaxy.game_status); + galaxy = update::update(command, galaxy) } - // rather than using a loop, recursion and passing the ownership might be better } -fn view(model: &Galaxy) { - match model.game_status { - GameStatus::ShortRangeScan => { - let quadrant = &model.quadrants[model.enterprise.sector.as_index()]; - render_quadrant(&model.enterprise.sector, quadrant) +fn wait_for_command(game_status: &GameStatus) -> Message { + let stdin = stdin(); + loop { + match game_status { + _ => { + println!("Command?"); + let mut buffer = String::new(); + if let Ok(_) = stdin.read_line(&mut buffer) { + let text = buffer.trim_end(); + if let Some(msg) = as_message(text, game_status) { + return msg + } + print_command_help(); + } + } } } } -fn render_quadrant(enterprise_sector: &Pos, quadrant: &Quadrant) { - +fn as_message(text: &str, game_status: &GameStatus) -> Option { + if text == "" { + return None + } + match game_status { + _ => { + match text { + "SRS" => Some(Message::RequestShortRangeScan), + _ => None + } + } + } } -fn wait_for_command(galaxy: &Galaxy) -> Galaxy { - // listen for command from readline - // handle bad commands - // update model - Galaxy::generate_new() +fn print_command_help() { + println!("valid commands are just SRS at the mo") } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 9ca501898..2a03bbd95 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -5,7 +5,8 @@ pub struct Galaxy { pub game_status: GameStatus } -pub struct Pos(u8, u8); +#[derive(PartialEq)] +pub struct Pos(pub u8, pub u8); impl Pos { pub fn as_index(&self) -> usize { diff --git a/84_Super_Star_Trek/rust/src/update.rs b/84_Super_Star_Trek/rust/src/update.rs new file mode 100644 index 000000000..cf30c83ed --- /dev/null +++ b/84_Super_Star_Trek/rust/src/update.rs @@ -0,0 +1,15 @@ +use crate::model::{Galaxy, GameStatus}; + +pub enum Message { + RequestShortRangeScan +} + +pub fn update(message: Message, model: Galaxy) -> Galaxy { + match message { + Message::RequestShortRangeScan => + Galaxy { + game_status: GameStatus::ShortRangeScan, + ..model + } + } +} \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs new file mode 100644 index 000000000..2f6bdf223 --- /dev/null +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -0,0 +1,35 @@ +use crate::model::{Galaxy, GameStatus, Quadrant, Pos, Klingon}; + + +pub fn view(model: &Galaxy) { + match model.game_status { + GameStatus::ShortRangeScan => { + let quadrant = &model.quadrants[model.enterprise.sector.as_index()]; + render_quadrant(&model.enterprise.sector, quadrant) + } + } +} + +fn render_quadrant(enterprise_sector: &Pos, quadrant: &Quadrant) { + println!("{:-^33}", ""); + for y in 0..=7 { + for x in 0..=7 { + let pos = Pos(x, y); + if &pos == enterprise_sector { + print!("<*> ") + } else if quadrant.stars.contains(&pos) { + print!(" * ") + } else if quadrant.star_bases.contains(&pos) { + print!(">!< ") + } else if let Some(_) = find_klingon(&pos, &quadrant.klingons) { + print!("+K+ ") + } + } + print!("\n") + } + println!("{:-^33}", ""); +} + +fn find_klingon<'a>(sector: &Pos, klingons: &'a Vec) -> Option<&'a Klingon> { + klingons.into_iter().find(|k| &k.sector == sector) +} \ No newline at end of file From c35736c5c8cc61f9bf070e65ab776f73fa92b297 Mon Sep 17 00:00:00 2001 From: Christopher Date: Tue, 28 Feb 2023 13:28:08 +1300 Subject: [PATCH 021/377] enterprise now starts in a random quadrant and empty sector --- 84_Super_Star_Trek/rust/Cargo.toml | 1 + 84_Super_Star_Trek/rust/src/main.rs | 7 ++- 84_Super_Star_Trek/rust/src/model.rs | 85 +++++++++++++++++++++++++++- 84_Super_Star_Trek/rust/src/view.rs | 21 +++---- 4 files changed, 97 insertions(+), 17 deletions(-) diff --git a/84_Super_Star_Trek/rust/Cargo.toml b/84_Super_Star_Trek/rust/Cargo.toml index 1ec696335..3b1d02f52 100644 --- a/84_Super_Star_Trek/rust/Cargo.toml +++ b/84_Super_Star_Trek/rust/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +rand = "0.8.5" diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 86bc2d85d..20cd7ea36 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,4 +1,4 @@ -use std::io::stdin; +use std::io::{stdin, stdout, Write}; use model::{Galaxy, GameStatus}; use update::Message; @@ -18,10 +18,13 @@ fn main() { fn wait_for_command(game_status: &GameStatus) -> Message { let stdin = stdin(); + let mut stdout = stdout(); loop { match game_status { _ => { - println!("Command?"); + print!("Command? "); + let _ = stdout.flush(); + let mut buffer = String::new(); if let Ok(_) = stdin.read_line(&mut buffer) { let text = buffer.trim_end(); diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 2a03bbd95..4468e6f9f 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -1,3 +1,4 @@ +use rand::Rng; pub struct Galaxy { pub quadrants: Vec, @@ -14,9 +15,14 @@ impl Pos { } } +#[derive(PartialEq)] +pub enum SectorStatus { + Empty, Star, StarBase, Klingon +} + pub struct Quadrant { pub stars: Vec, - pub star_bases: Vec, + pub star_base: Option, pub klingons: Vec } @@ -35,10 +41,83 @@ pub enum GameStatus { impl Galaxy { pub fn generate_new() -> Self { + let quadrants = Self::generate_quadrants(); + + let mut rng = rand::thread_rng(); + let enterprise_quadrant = Pos(rng.gen_range(0..8), rng.gen_range(0..8)); + let enterprise_sector = quadrants[enterprise_quadrant.as_index()].find_empty_sector(); + Galaxy { - quadrants: Vec::new(), - enterprise: Enterprise { quadrant: Pos(0,0), sector: Pos(0,0) }, + quadrants: quadrants, + enterprise: Enterprise { quadrant: enterprise_quadrant, sector: enterprise_sector }, game_status: GameStatus::ShortRangeScan } } + + fn generate_quadrants() -> Vec { + let mut rng = rand::thread_rng(); + let mut result = Vec::new(); + for _ in 0..64 { + + let mut quadrant = Quadrant { stars: Vec::new(), star_base: None, klingons: Vec::new() }; + let star_count = rng.gen_range(0..=7); + for _ in 0..star_count { + quadrant.stars.push(quadrant.find_empty_sector()); + } + + if rng.gen::() > 0.96 { + quadrant.star_base = Some(quadrant.find_empty_sector()); + } + + let klingon_count = + match rng.gen::() { + n if n > 0.98 => 3, + n if n > 0.95 => 2, + n if n > 0.8 => 1, + _ => 0 + }; + for _ in 0..klingon_count { + quadrant.klingons.push(Klingon { sector: quadrant.find_empty_sector() }); + } + + result.push(quadrant); + } + result + } +} + +impl Quadrant { + pub fn sector_status(&self, sector: &Pos) -> SectorStatus { + if self.stars.contains(§or) { + SectorStatus::Star + } else if self.is_starbase(§or) { + SectorStatus::StarBase + } else if self.has_klingon(§or) { + SectorStatus::Klingon + } else { + SectorStatus::Empty + } + } + + fn is_starbase(&self, sector: &Pos) -> bool { + match &self.star_base { + None => false, + Some(p) => p == sector + } + } + + fn has_klingon(&self, sector: &Pos) -> bool { + let klingons = &self.klingons; + klingons.into_iter().find(|k| &k.sector == sector).is_some() + } + + fn find_empty_sector(&self) -> Pos { + let mut rng = rand::thread_rng(); + loop { + let pos = Pos(rng.gen_range(0..8), rng.gen_range(0..8)); + if self.sector_status(&pos) == SectorStatus::Empty { + return pos + } + } + } } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 2f6bdf223..4f0975cf4 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -1,4 +1,4 @@ -use crate::model::{Galaxy, GameStatus, Quadrant, Pos, Klingon}; +use crate::model::{Galaxy, GameStatus, Quadrant, Pos, SectorStatus}; pub fn view(model: &Galaxy) { @@ -17,19 +17,16 @@ fn render_quadrant(enterprise_sector: &Pos, quadrant: &Quadrant) { let pos = Pos(x, y); if &pos == enterprise_sector { print!("<*> ") - } else if quadrant.stars.contains(&pos) { - print!(" * ") - } else if quadrant.star_bases.contains(&pos) { - print!(">!< ") - } else if let Some(_) = find_klingon(&pos, &quadrant.klingons) { - print!("+K+ ") - } + } else { + match quadrant.sector_status(&pos) { + SectorStatus::Star => print!(" * "), + SectorStatus::StarBase => print!(">!< "), + SectorStatus::Klingon => print!("+K+ "), + _ => print!(" "), + } + } } print!("\n") } println!("{:-^33}", ""); } - -fn find_klingon<'a>(sector: &Pos, klingons: &'a Vec) -> Option<&'a Klingon> { - klingons.into_iter().find(|k| &k.sector == sector) -} \ No newline at end of file From 31b9834a7c1967d56f5634329742c7bc9885a44f Mon Sep 17 00:00:00 2001 From: Christopher Date: Tue, 28 Feb 2023 13:53:38 +1300 Subject: [PATCH 022/377] work on nav command this involves architectural shifts --- 84_Super_Star_Trek/rust/src/main.rs | 60 ++++++++++++++++++++------- 84_Super_Star_Trek/rust/src/model.rs | 4 +- 84_Super_Star_Trek/rust/src/update.rs | 23 +++++++++- 84_Super_Star_Trek/rust/src/view.rs | 5 ++- 4 files changed, 72 insertions(+), 20 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 20cd7ea36..43e3045cb 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -17,35 +17,63 @@ fn main() { } fn wait_for_command(game_status: &GameStatus) -> Message { - let stdin = stdin(); - let mut stdout = stdout(); loop { match game_status { + GameStatus::NeedDirectionForNav => { + let text = prompt("Course (1-9)?"); + if let Some(msg) = as_message(&text, game_status) { + return msg + } + }, + GameStatus::NeedSpeedForNav(_) => { + let text = prompt("Warp Factor (0-8)?"); + if let Some(msg) = as_message(&text, game_status) { + return msg + } + }, _ => { - print!("Command? "); - let _ = stdout.flush(); - - let mut buffer = String::new(); - if let Ok(_) = stdin.read_line(&mut buffer) { - let text = buffer.trim_end(); - if let Some(msg) = as_message(text, game_status) { - return msg - } - print_command_help(); + let text = prompt("Command?"); + if let Some(msg) = as_message(&text, game_status) { + return msg } + print_command_help(); } } } } -fn as_message(text: &str, game_status: &GameStatus) -> Option { - if text == "" { - return None +fn prompt(prompt: &str) -> String { + let stdin = stdin(); + let mut stdout = stdout(); + + print!("{prompt} "); + let _ = stdout.flush(); + + let mut buffer = String::new(); + if let Ok(_) = stdin.read_line(&mut buffer) { + return buffer.trim_end().into(); } + "".into() +} + +fn as_message(text: &str, game_status: &GameStatus) -> Option { match game_status { + GameStatus::NeedDirectionForNav => { + match text.parse::() { + Ok(n) if (n >= 1 && n <= 8) => Some(Message::DirectionForNav(n)), + _ => None + } + }, + GameStatus::NeedSpeedForNav(dir) => { + match text.parse::() { + Ok(n) if (n >= 1 && n <= 8) => Some(Message::DirectionAndSpeedForNav(*dir, n)), + _ => None + } + } _ => { match text { "SRS" => Some(Message::RequestShortRangeScan), + "NAV" => Some(Message::RequestNavigation), _ => None } } @@ -53,5 +81,5 @@ fn as_message(text: &str, game_status: &GameStatus) -> Option { } fn print_command_help() { - println!("valid commands are just SRS at the mo") + println!("valid commands are just SRS and NAV at the mo") } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 4468e6f9f..a05d85661 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -36,7 +36,9 @@ pub struct Enterprise { } pub enum GameStatus { - ShortRangeScan + ShortRangeScan, + NeedDirectionForNav, + NeedSpeedForNav(u8), } impl Galaxy { diff --git a/84_Super_Star_Trek/rust/src/update.rs b/84_Super_Star_Trek/rust/src/update.rs index cf30c83ed..5788c7784 100644 --- a/84_Super_Star_Trek/rust/src/update.rs +++ b/84_Super_Star_Trek/rust/src/update.rs @@ -1,15 +1,36 @@ use crate::model::{Galaxy, GameStatus}; pub enum Message { - RequestShortRangeScan + RequestShortRangeScan, + RequestNavigation, + DirectionForNav (u8), + DirectionAndSpeedForNav (u8, u8), } pub fn update(message: Message, model: Galaxy) -> Galaxy { match message { Message::RequestShortRangeScan => + Galaxy { + game_status: GameStatus::ShortRangeScan, + ..model + }, + Message::RequestNavigation => { + Galaxy { + game_status: GameStatus::NeedDirectionForNav, + ..model + } + }, + Message::DirectionForNav(dir) => { + Galaxy { + game_status: GameStatus::NeedSpeedForNav(dir), + ..model + } + }, + Message::DirectionAndSpeedForNav(dir, speed) => { Galaxy { game_status: GameStatus::ShortRangeScan, ..model } + } } } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 4f0975cf4..9527289d2 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -5,8 +5,9 @@ pub fn view(model: &Galaxy) { match model.game_status { GameStatus::ShortRangeScan => { let quadrant = &model.quadrants[model.enterprise.sector.as_index()]; - render_quadrant(&model.enterprise.sector, quadrant) - } + render_quadrant(&model.enterprise.sector, quadrant); + }, + _ => () } } From 8903e77d838e21c221a482a450a7a16ced314fca Mon Sep 17 00:00:00 2001 From: Christopher Date: Tue, 28 Feb 2023 19:45:54 +1300 Subject: [PATCH 023/377] reduced down to command and response (collapsed MVU) --- 84_Super_Star_Trek/rust/Cargo.toml | 1 + .../rust/src/{view.rs => commands.rs} | 17 +--- 84_Super_Star_Trek/rust/src/main.rs | 80 +++++-------------- 84_Super_Star_Trek/rust/src/model.rs | 12 +-- 84_Super_Star_Trek/rust/src/update.rs | 36 --------- 5 files changed, 29 insertions(+), 117 deletions(-) rename 84_Super_Star_Trek/rust/src/{view.rs => commands.rs} (54%) delete mode 100644 84_Super_Star_Trek/rust/src/update.rs diff --git a/84_Super_Star_Trek/rust/Cargo.toml b/84_Super_Star_Trek/rust/Cargo.toml index 3b1d02f52..01457249b 100644 --- a/84_Super_Star_Trek/rust/Cargo.toml +++ b/84_Super_Star_Trek/rust/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +ctrlc = "3.2.5" rand = "0.8.5" diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/commands.rs similarity index 54% rename from 84_Super_Star_Trek/rust/src/view.rs rename to 84_Super_Star_Trek/rust/src/commands.rs index 9527289d2..264f79092 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,22 +1,13 @@ -use crate::model::{Galaxy, GameStatus, Quadrant, Pos, SectorStatus}; +use crate::model::{Galaxy, Pos, SectorStatus}; +pub fn short_range_scan(model: &Galaxy) { + let quadrant = &model.quadrants[model.enterprise.sector.as_index()]; -pub fn view(model: &Galaxy) { - match model.game_status { - GameStatus::ShortRangeScan => { - let quadrant = &model.quadrants[model.enterprise.sector.as_index()]; - render_quadrant(&model.enterprise.sector, quadrant); - }, - _ => () - } -} - -fn render_quadrant(enterprise_sector: &Pos, quadrant: &Quadrant) { println!("{:-^33}", ""); for y in 0..=7 { for x in 0..=7 { let pos = Pos(x, y); - if &pos == enterprise_sector { + if &pos == &model.enterprise.sector { print!("<*> ") } else { match quadrant.sector_status(&pos) { diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 43e3045cb..cc6948aca 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,44 +1,27 @@ -use std::io::{stdin, stdout, Write}; +use std::{io::{stdin, stdout, Write}, process::exit}; -use model::{Galaxy, GameStatus}; -use update::Message; +use model::Galaxy; mod model; -mod view; -mod update; +mod commands; fn main() { - let mut galaxy = Galaxy::generate_new(); - loop { - view::view(&galaxy); - let command = wait_for_command(&galaxy.game_status); - galaxy = update::update(command, galaxy) - } -} + ctrlc::set_handler(move || { exit(0) }) + .expect("Error setting Ctrl-C handler"); + + let galaxy = Galaxy::generate_new(); + // init ops, starting state and notes + commands::short_range_scan(&galaxy); -fn wait_for_command(game_status: &GameStatus) -> Message { loop { - match game_status { - GameStatus::NeedDirectionForNav => { - let text = prompt("Course (1-9)?"); - if let Some(msg) = as_message(&text, game_status) { - return msg - } - }, - GameStatus::NeedSpeedForNav(_) => { - let text = prompt("Warp Factor (0-8)?"); - if let Some(msg) = as_message(&text, game_status) { - return msg - } - }, - _ => { - let text = prompt("Command?"); - if let Some(msg) = as_message(&text, game_status) { - return msg - } - print_command_help(); - } + match prompt("Command?").as_str() { + "SRS" => commands::short_range_scan(&galaxy), + _ => print_command_help() } + + // process the next command, based on it render something or update the galaxy or whatever + // this would be: read command, and based on it run dedicated function + // the function might get passed a mutable reference to the galaxy } } @@ -56,30 +39,11 @@ fn prompt(prompt: &str) -> String { "".into() } -fn as_message(text: &str, game_status: &GameStatus) -> Option { - match game_status { - GameStatus::NeedDirectionForNav => { - match text.parse::() { - Ok(n) if (n >= 1 && n <= 8) => Some(Message::DirectionForNav(n)), - _ => None - } - }, - GameStatus::NeedSpeedForNav(dir) => { - match text.parse::() { - Ok(n) if (n >= 1 && n <= 8) => Some(Message::DirectionAndSpeedForNav(*dir, n)), - _ => None - } - } - _ => { - match text { - "SRS" => Some(Message::RequestShortRangeScan), - "NAV" => Some(Message::RequestNavigation), - _ => None - } - } - } -} - fn print_command_help() { println!("valid commands are just SRS and NAV at the mo") -} \ No newline at end of file +} + +// match text.parse::() { +// Ok(n) if (n >= 1 && n <= 8) => Some(Message::DirectionForNav(n)), +// _ => None +// } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index a05d85661..a0f807513 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -2,8 +2,7 @@ use rand::Rng; pub struct Galaxy { pub quadrants: Vec, - pub enterprise: Enterprise, - pub game_status: GameStatus + pub enterprise: Enterprise } #[derive(PartialEq)] @@ -35,12 +34,6 @@ pub struct Enterprise { pub sector: Pos, } -pub enum GameStatus { - ShortRangeScan, - NeedDirectionForNav, - NeedSpeedForNav(u8), -} - impl Galaxy { pub fn generate_new() -> Self { let quadrants = Self::generate_quadrants(); @@ -51,8 +44,7 @@ impl Galaxy { Galaxy { quadrants: quadrants, - enterprise: Enterprise { quadrant: enterprise_quadrant, sector: enterprise_sector }, - game_status: GameStatus::ShortRangeScan + enterprise: Enterprise { quadrant: enterprise_quadrant, sector: enterprise_sector } } } diff --git a/84_Super_Star_Trek/rust/src/update.rs b/84_Super_Star_Trek/rust/src/update.rs deleted file mode 100644 index 5788c7784..000000000 --- a/84_Super_Star_Trek/rust/src/update.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::model::{Galaxy, GameStatus}; - -pub enum Message { - RequestShortRangeScan, - RequestNavigation, - DirectionForNav (u8), - DirectionAndSpeedForNav (u8, u8), -} - -pub fn update(message: Message, model: Galaxy) -> Galaxy { - match message { - Message::RequestShortRangeScan => - Galaxy { - game_status: GameStatus::ShortRangeScan, - ..model - }, - Message::RequestNavigation => { - Galaxy { - game_status: GameStatus::NeedDirectionForNav, - ..model - } - }, - Message::DirectionForNav(dir) => { - Galaxy { - game_status: GameStatus::NeedSpeedForNav(dir), - ..model - } - }, - Message::DirectionAndSpeedForNav(dir, speed) => { - Galaxy { - game_status: GameStatus::ShortRangeScan, - ..model - } - } - } -} \ No newline at end of file From 7c8c420d4435f8afcc52c5aba0ddcfd1c84f8ee6 Mon Sep 17 00:00:00 2001 From: Christopher Date: Tue, 28 Feb 2023 20:15:46 +1300 Subject: [PATCH 024/377] work on nav command under new model --- 84_Super_Star_Trek/rust/src/main.rs | 44 +++++++++++++++---- 84_Super_Star_Trek/rust/src/text_constants.rs | 2 + 2 files changed, 38 insertions(+), 8 deletions(-) create mode 100644 84_Super_Star_Trek/rust/src/text_constants.rs diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index cc6948aca..3fcf96324 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,21 +1,25 @@ -use std::{io::{stdin, stdout, Write}, process::exit}; +use std::{io::{stdin, stdout, Write}, process::exit, str::FromStr}; use model::Galaxy; +use crate::text_constants::BAD_NAV; + mod model; mod commands; +mod text_constants; fn main() { ctrlc::set_handler(move || { exit(0) }) .expect("Error setting Ctrl-C handler"); - let galaxy = Galaxy::generate_new(); + let mut galaxy = Galaxy::generate_new(); // init ops, starting state and notes commands::short_range_scan(&galaxy); loop { match prompt("Command?").as_str() { "SRS" => commands::short_range_scan(&galaxy), + "NAV" => gather_dir_and_speed_then_move(&mut galaxy), _ => print_command_help() } @@ -25,11 +29,31 @@ fn main() { } } -fn prompt(prompt: &str) -> String { +fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { + let dir = prompt_value::("Course (1-9)?", 1, 9); + if dir.is_none() { + println!("{}", BAD_NAV); + return; + } + + let speed = prompt_value::("Course (1-9)?", 0.0, 8.0); + if speed.is_none() { + println!("{}", BAD_NAV); + return; + } + + let distance = (speed.unwrap() * 8.0) as i32; + // could be done with a step function - while distance > 0, move by digit. + // if passing a boundary, test for the next quadrant in that direction + // if present, change quadrant and move to border + // else stop. +} + +fn prompt(prompt_text: &str) -> String { let stdin = stdin(); let mut stdout = stdout(); - print!("{prompt} "); + print!("{prompt_text} "); let _ = stdout.flush(); let mut buffer = String::new(); @@ -39,11 +63,15 @@ fn prompt(prompt: &str) -> String { "".into() } +fn prompt_value(prompt_text: &str, min: T, max: T) -> Option { + let passed = prompt(prompt_text); + match passed.parse::() { + Ok(n) if (n >= min && n <= max) => Some(n), + _ => None + } +} + fn print_command_help() { println!("valid commands are just SRS and NAV at the mo") } -// match text.parse::() { -// Ok(n) if (n >= 1 && n <= 8) => Some(Message::DirectionForNav(n)), -// _ => None -// } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/text_constants.rs b/84_Super_Star_Trek/rust/src/text_constants.rs new file mode 100644 index 000000000..36339abea --- /dev/null +++ b/84_Super_Star_Trek/rust/src/text_constants.rs @@ -0,0 +1,2 @@ + +pub const BAD_NAV: &str = " Lt. Sulu reports, 'Incorrect course data, sir!'"; \ No newline at end of file From 183ec6fde3df1475622d32570491c710fdf4b4e0 Mon Sep 17 00:00:00 2001 From: Christopher Date: Tue, 28 Feb 2023 20:19:54 +1300 Subject: [PATCH 025/377] added a note on how to calculate --- 84_Super_Star_Trek/rust/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 3fcf96324..46e932c3c 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -47,6 +47,8 @@ fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { // if passing a boundary, test for the next quadrant in that direction // if present, change quadrant and move to border // else stop. + // one way to sort this would be to convert current pos to a galaxy pos (e.g. sector.x, y * 8), + // add dist, then mod/divide to get quadrant and new sector } fn prompt(prompt_text: &str) -> String { From 615438a2676cf3e4dadf74e2a948d9f4b425b851 Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 08:29:47 +1300 Subject: [PATCH 026/377] more work on nav, almost done basics! --- 84_Super_Star_Trek/rust/src/main.rs | 44 ++++++++++++++++--- 84_Super_Star_Trek/rust/src/model.rs | 44 ++++++++++++++++++- 84_Super_Star_Trek/rust/src/text_constants.rs | 2 - 3 files changed, 82 insertions(+), 8 deletions(-) delete mode 100644 84_Super_Star_Trek/rust/src/text_constants.rs diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 46e932c3c..481d23781 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,12 +1,9 @@ use std::{io::{stdin, stdout, Write}, process::exit, str::FromStr}; -use model::Galaxy; - -use crate::text_constants::BAD_NAV; +use model::{Galaxy, Pos}; mod model; mod commands; -mod text_constants; fn main() { ctrlc::set_handler(move || { exit(0) }) @@ -30,6 +27,8 @@ fn main() { } fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { + const BAD_NAV: &str = " Lt. Sulu reports, 'Incorrect course data, sir!'"; + let dir = prompt_value::("Course (1-9)?", 1, 9); if dir.is_none() { println!("{}", BAD_NAV); @@ -42,7 +41,42 @@ fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { return; } - let distance = (speed.unwrap() * 8.0) as i32; + let distance = (speed.unwrap() * 8.0) as u8; + let galaxy_pos = galaxy.enterprise.quadrant * 8u8 + galaxy.enterprise.sector; + let (mut nx, mut ny) = galaxy_pos.translate(dir.unwrap(), distance); + + let mut hit_edge = false; + if nx < 0 { + nx = 0; + hit_edge = true; + } + if ny < 0 { + ny = 0; + hit_edge = true; + } + if nx >= 64 { + ny = 63; + hit_edge = true; + } + if nx >= 64 { + ny = 63; + hit_edge = true; + } + + let new_quadrant = Pos((nx / 8) as u8, (ny / 8) as u8); + let new_sector = Pos((nx % 8) as u8, (ny % 8) as u8); + + if hit_edge { + println!("Lt. Uhura report message from Starfleet Command: + 'Permission to attempt crossing of galactic perimeter + is hereby *Denied*. Shut down your engines.' + Chief Engineer Scott reports, 'Warp engines shut down + at sector {} of quadrant {}.'", new_quadrant, new_sector); + } + + galaxy.enterprise.quadrant = new_quadrant; + galaxy.enterprise.sector = new_sector; + // could be done with a step function - while distance > 0, move by digit. // if passing a boundary, test for the next quadrant in that direction // if present, change quadrant and move to border diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index a0f807513..36ec96284 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -1,3 +1,5 @@ +use std::{ops::{Mul, Add}, fmt::Display}; + use rand::Rng; pub struct Galaxy { @@ -5,13 +7,53 @@ pub struct Galaxy { pub enterprise: Enterprise } -#[derive(PartialEq)] +#[derive(PartialEq, Clone, Copy)] pub struct Pos(pub u8, pub u8); impl Pos { + const DIRECTIONS : [(i8, i8); 8] = [ + (1, 0), + (1, -1), + (0, -1), + (-1, -1), + (-1, 0), + (-1, 1), + (0, 1), + (1, 1), + ]; + pub fn as_index(&self) -> usize { (self.0 * 8 + self.1).into() } + + pub fn translate(&self, dir: u8, dist: u8) -> (i8, i8) { + let (dx, dy): (i8, i8) = Self::DIRECTIONS[dir as usize]; + let x = (self.0 as i8) + dx * dist as i8; + let y = (self.1 as i8) + dy * dist as i8; + (x, y) + } +} + +impl Mul for Pos { + type Output = Self; + + fn mul(self, rhs: u8) -> Self::Output { + Pos(self.0 * rhs, self.1 * rhs) + } +} + +impl Add for Pos { + type Output = Self; + + fn add(self, rhs: Pos) -> Self::Output { + Pos(self.0 + rhs.0, self.1 + rhs.1) + } +} + +impl Display for Pos { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } } #[derive(PartialEq)] diff --git a/84_Super_Star_Trek/rust/src/text_constants.rs b/84_Super_Star_Trek/rust/src/text_constants.rs deleted file mode 100644 index 36339abea..000000000 --- a/84_Super_Star_Trek/rust/src/text_constants.rs +++ /dev/null @@ -1,2 +0,0 @@ - -pub const BAD_NAV: &str = " Lt. Sulu reports, 'Incorrect course data, sir!'"; \ No newline at end of file From 80ac05e0053f9a38eba2b8e0177afe81077cc9fb Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 08:54:39 +1300 Subject: [PATCH 027/377] semi working nav (going weird directions) --- 84_Super_Star_Trek/rust/src/main.rs | 24 +++++++++++---------- 84_Super_Star_Trek/rust/src/model.rs | 31 +++++++++++----------------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 481d23781..a7265116a 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -2,6 +2,8 @@ use std::{io::{stdin, stdout, Write}, process::exit, str::FromStr}; use model::{Galaxy, Pos}; +use crate::model::DIRECTIONS; + mod model; mod commands; @@ -14,7 +16,7 @@ fn main() { commands::short_range_scan(&galaxy); loop { - match prompt("Command?").as_str() { + match prompt("Command?").to_uppercase().as_str() { "SRS" => commands::short_range_scan(&galaxy), "NAV" => gather_dir_and_speed_then_move(&mut galaxy), _ => print_command_help() @@ -28,22 +30,25 @@ fn main() { fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { const BAD_NAV: &str = " Lt. Sulu reports, 'Incorrect course data, sir!'"; - + let dir = prompt_value::("Course (1-9)?", 1, 9); if dir.is_none() { println!("{}", BAD_NAV); return; } - let speed = prompt_value::("Course (1-9)?", 0.0, 8.0); + let speed = prompt_value::("Warp Factor (0-8)?", 0.0, 8.0); if speed.is_none() { println!("{}", BAD_NAV); return; } - let distance = (speed.unwrap() * 8.0) as u8; + let distance = (speed.unwrap() * 8.0) as i8; let galaxy_pos = galaxy.enterprise.quadrant * 8u8 + galaxy.enterprise.sector; - let (mut nx, mut ny) = galaxy_pos.translate(dir.unwrap(), distance); + + let (dx, dy): (i8, i8) = DIRECTIONS[(dir.unwrap() - 1) as usize]; + let mut nx = (galaxy_pos.0 as i8) + dx * distance; + let mut ny = (galaxy_pos.1 as i8) + dy * distance; let mut hit_edge = false; if nx < 0 { @@ -77,12 +82,9 @@ fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { galaxy.enterprise.quadrant = new_quadrant; galaxy.enterprise.sector = new_sector; - // could be done with a step function - while distance > 0, move by digit. - // if passing a boundary, test for the next quadrant in that direction - // if present, change quadrant and move to border - // else stop. - // one way to sort this would be to convert current pos to a galaxy pos (e.g. sector.x, y * 8), - // add dist, then mod/divide to get quadrant and new sector + // if new_quadrant isnt old quadrant print intro + + commands::short_range_scan(&galaxy) } fn prompt(prompt_text: &str) -> String { diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 36ec96284..2e097b9c5 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -11,27 +11,9 @@ pub struct Galaxy { pub struct Pos(pub u8, pub u8); impl Pos { - const DIRECTIONS : [(i8, i8); 8] = [ - (1, 0), - (1, -1), - (0, -1), - (-1, -1), - (-1, 0), - (-1, 1), - (0, 1), - (1, 1), - ]; - pub fn as_index(&self) -> usize { (self.0 * 8 + self.1).into() } - - pub fn translate(&self, dir: u8, dist: u8) -> (i8, i8) { - let (dx, dy): (i8, i8) = Self::DIRECTIONS[dir as usize]; - let x = (self.0 as i8) + dx * dist as i8; - let y = (self.1 as i8) + dy * dist as i8; - (x, y) - } } impl Mul for Pos { @@ -52,10 +34,21 @@ impl Add for Pos { impl Display for Pos { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() + write!(f, "{} , {}", self.0, self.1) } } +pub const DIRECTIONS : [(i8, i8); 8] = [ + (1, 0), + (1, -1), + (0, -1), + (-1, -1), + (-1, 0), + (-1, 1), + (0, 1), + (1, 1), +]; + #[derive(PartialEq)] pub enum SectorStatus { Empty, Star, StarBase, Klingon From ab26776d61e60d20bf8fed252e60dc8f7453561d Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 09:16:00 +1300 Subject: [PATCH 028/377] moved nav function bulk to commands module --- 84_Super_Star_Trek/rust/src/commands.rs | 48 ++++++++++++++++++++- 84_Super_Star_Trek/rust/src/main.rs | 57 +++---------------------- 84_Super_Star_Trek/rust/src/model.rs | 2 +- 3 files changed, 53 insertions(+), 54 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 264f79092..e87dd9c09 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,4 +1,4 @@ -use crate::model::{Galaxy, Pos, SectorStatus}; +use crate::model::{Galaxy, Pos, SectorStatus, COURSES}; pub fn short_range_scan(model: &Galaxy) { let quadrant = &model.quadrants[model.enterprise.sector.as_index()]; @@ -22,3 +22,49 @@ pub fn short_range_scan(model: &Galaxy) { } println!("{:-^33}", ""); } + +pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { + let distance = (warp_speed * 8.0) as i8; + let galaxy_pos = galaxy.enterprise.quadrant * 8u8 + galaxy.enterprise.sector; + + let (dx, dy): (i8, i8) = COURSES[(course - 1) as usize]; + + let mut nx = (galaxy_pos.0 as i8) + dx * distance; + let mut ny = (galaxy_pos.1 as i8) + dy * distance; + + let mut hit_edge = false; + if nx < 0 { + nx = 0; + hit_edge = true; + } + if ny < 0 { + ny = 0; + hit_edge = true; + } + if nx >= 64 { + ny = 63; + hit_edge = true; + } + if nx >= 64 { + ny = 63; + hit_edge = true; + } + + let new_quadrant = Pos((nx / 8) as u8, (ny / 8) as u8); + let new_sector = Pos((nx % 8) as u8, (ny % 8) as u8); + + if hit_edge { + println!("Lt. Uhura report message from Starfleet Command: + 'Permission to attempt crossing of galactic perimeter + is hereby *Denied*. Shut down your engines.' + Chief Engineer Scott reports, 'Warp engines shut down + at sector {} of quadrant {}.'", new_quadrant, new_sector); + } + + galaxy.enterprise.quadrant = new_quadrant; + galaxy.enterprise.sector = new_sector; + + // if new_quadrant isnt old quadrant print intro + + short_range_scan(&galaxy) +} diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index a7265116a..a9b5f4cef 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,8 +1,6 @@ use std::{io::{stdin, stdout, Write}, process::exit, str::FromStr}; -use model::{Galaxy, Pos}; - -use crate::model::DIRECTIONS; +use model::Galaxy; mod model; mod commands; @@ -12,7 +10,7 @@ fn main() { .expect("Error setting Ctrl-C handler"); let mut galaxy = Galaxy::generate_new(); - // init ops, starting state and notes + // init options, starting state and notes commands::short_range_scan(&galaxy); loop { @@ -21,18 +19,14 @@ fn main() { "NAV" => gather_dir_and_speed_then_move(&mut galaxy), _ => print_command_help() } - - // process the next command, based on it render something or update the galaxy or whatever - // this would be: read command, and based on it run dedicated function - // the function might get passed a mutable reference to the galaxy } } fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { const BAD_NAV: &str = " Lt. Sulu reports, 'Incorrect course data, sir!'"; - let dir = prompt_value::("Course (1-9)?", 1, 9); - if dir.is_none() { + let course = prompt_value::("Course (1-9)?", 1, 9); + if course.is_none() { println!("{}", BAD_NAV); return; } @@ -43,48 +37,7 @@ fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { return; } - let distance = (speed.unwrap() * 8.0) as i8; - let galaxy_pos = galaxy.enterprise.quadrant * 8u8 + galaxy.enterprise.sector; - - let (dx, dy): (i8, i8) = DIRECTIONS[(dir.unwrap() - 1) as usize]; - let mut nx = (galaxy_pos.0 as i8) + dx * distance; - let mut ny = (galaxy_pos.1 as i8) + dy * distance; - - let mut hit_edge = false; - if nx < 0 { - nx = 0; - hit_edge = true; - } - if ny < 0 { - ny = 0; - hit_edge = true; - } - if nx >= 64 { - ny = 63; - hit_edge = true; - } - if nx >= 64 { - ny = 63; - hit_edge = true; - } - - let new_quadrant = Pos((nx / 8) as u8, (ny / 8) as u8); - let new_sector = Pos((nx % 8) as u8, (ny % 8) as u8); - - if hit_edge { - println!("Lt. Uhura report message from Starfleet Command: - 'Permission to attempt crossing of galactic perimeter - is hereby *Denied*. Shut down your engines.' - Chief Engineer Scott reports, 'Warp engines shut down - at sector {} of quadrant {}.'", new_quadrant, new_sector); - } - - galaxy.enterprise.quadrant = new_quadrant; - galaxy.enterprise.sector = new_sector; - - // if new_quadrant isnt old quadrant print intro - - commands::short_range_scan(&galaxy) + commands::move_enterprise(course.unwrap(), speed.unwrap(), galaxy); } fn prompt(prompt_text: &str) -> String { diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 2e097b9c5..2ea855480 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -38,7 +38,7 @@ impl Display for Pos { } } -pub const DIRECTIONS : [(i8, i8); 8] = [ +pub const COURSES : [(i8, i8); 8] = [ (1, 0), (1, -1), (0, -1), From 09cb10eeb718528480f065744bf0bfc414007c28 Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 09:39:08 +1300 Subject: [PATCH 029/377] added some unit tests for movement --- 84_Super_Star_Trek/rust/src/commands.rs | 128 ++++++++++++++++++++---- 84_Super_Star_Trek/rust/src/model.rs | 2 +- 2 files changed, 111 insertions(+), 19 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index e87dd9c09..485f57afa 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -24,11 +24,41 @@ pub fn short_range_scan(model: &Galaxy) { } pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { - let distance = (warp_speed * 8.0) as i8; - let galaxy_pos = galaxy.enterprise.quadrant * 8u8 + galaxy.enterprise.sector; + + let end = find_end_quadrant_sector(galaxy.enterprise.quadrant, galaxy.enterprise.sector, course, warp_speed); + if end.hit_edge { + println!("Lt. Uhura report message from Starfleet Command: + 'Permission to attempt crossing of galactic perimeter + is hereby *Denied*. Shut down your engines.' + Chief Engineer Scott reports, 'Warp engines shut down + at sector {} of quadrant {}.'", end.quadrant, end.sector); + } + + galaxy.enterprise.quadrant = end.quadrant; + galaxy.enterprise.sector = end.sector; + + // if new_quadrant isnt old quadrant print intro + + short_range_scan(&galaxy) +} + +struct EndPosition { + quadrant: Pos, + sector: Pos, + hit_edge: bool +} + +fn find_end_quadrant_sector(start_quadrant: Pos, start_sector: Pos, course: u8, warp_speed: f32) -> EndPosition { let (dx, dy): (i8, i8) = COURSES[(course - 1) as usize]; + let mut distance = (warp_speed * 8.0) as i8; + if distance == 0 { + distance = 1; + } + + let galaxy_pos = start_quadrant * 8u8 + start_sector; + let mut nx = (galaxy_pos.0 as i8) + dx * distance; let mut ny = (galaxy_pos.1 as i8) + dy * distance; @@ -42,29 +72,91 @@ pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { hit_edge = true; } if nx >= 64 { - ny = 63; + nx = 63; hit_edge = true; } - if nx >= 64 { + if ny >= 64 { ny = 63; hit_edge = true; } - let new_quadrant = Pos((nx / 8) as u8, (ny / 8) as u8); - let new_sector = Pos((nx % 8) as u8, (ny % 8) as u8); + let quadrant = Pos((nx / 8) as u8, (ny / 8) as u8); + let sector = Pos((nx % 8) as u8, (ny % 8) as u8); - if hit_edge { - println!("Lt. Uhura report message from Starfleet Command: - 'Permission to attempt crossing of galactic perimeter - is hereby *Denied*. Shut down your engines.' - Chief Engineer Scott reports, 'Warp engines shut down - at sector {} of quadrant {}.'", new_quadrant, new_sector); + EndPosition { quadrant, sector, hit_edge } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_course_east() { + let start_quadrant = Pos(0,0); + let start_sector = Pos(0,0); + let end = find_end_quadrant_sector(start_quadrant, start_sector, 1, 0.1); + assert_eq!(end.quadrant, start_quadrant, "right quadrant"); + assert_eq!(end.sector, Pos(1,0), "right sector"); + assert!(!end.hit_edge) } - galaxy.enterprise.quadrant = new_quadrant; - galaxy.enterprise.sector = new_sector; - - // if new_quadrant isnt old quadrant print intro + #[test] + fn test_course_far_east() { + let start_quadrant = Pos(0,0); + let start_sector = Pos(0,0); + let end = find_end_quadrant_sector(start_quadrant, start_sector, 1, 1.0); + assert_eq!(end.quadrant, Pos(1,0), "right quadrant"); + assert_eq!(end.sector, start_sector, "right sector"); + assert!(!end.hit_edge) + } - short_range_scan(&galaxy) -} + #[test] + fn test_course_too_far_east() { + let start_quadrant = Pos(0,0); + let start_sector = Pos(0,0); + let end = find_end_quadrant_sector(start_quadrant, start_sector, 1, 8.0); + assert_eq!(end.quadrant, Pos(7,0), "right quadrant"); + assert_eq!(end.sector, Pos(7,0), "right sector"); + assert!(end.hit_edge) + } + + #[test] + fn test_course_south() { + let start_quadrant = Pos(0,0); + let start_sector = Pos(0,0); + let end = find_end_quadrant_sector(start_quadrant, start_sector, 7, 0.1); + assert_eq!(end.quadrant, start_quadrant, "right quadrant"); + assert_eq!(end.sector, Pos(0,1), "right sector"); + assert!(!end.hit_edge) + } + + #[test] + fn test_course_far_south() { + let start_quadrant = Pos(0,0); + let start_sector = Pos(0,0); + let end = find_end_quadrant_sector(start_quadrant, start_sector, 7, 1.0); + assert_eq!(end.quadrant, Pos(0,1), "right quadrant"); + assert_eq!(end.sector, start_sector, "right sector"); + assert!(!end.hit_edge) + } + + #[test] + fn test_course_too_far_south() { + let start_quadrant = Pos(0,0); + let start_sector = Pos(0,0); + let end = find_end_quadrant_sector(start_quadrant, start_sector, 7, 8.0); + assert_eq!(end.quadrant, Pos(0,7), "right quadrant"); + assert_eq!(end.sector, Pos(0,7), "right sector"); + assert!(end.hit_edge) + } + + #[test] + fn test_course_north_east() { + let start_quadrant = Pos(0,0); + let start_sector = Pos(0,1); + let end = find_end_quadrant_sector(start_quadrant, start_sector, 2, 0.1); + assert_eq!(end.quadrant, start_quadrant, "right quadrant"); + assert_eq!(end.sector, Pos(1,0), "right sector"); + assert!(!end.hit_edge) + } +} \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 2ea855480..fa0ca4c2e 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -7,7 +7,7 @@ pub struct Galaxy { pub enterprise: Enterprise } -#[derive(PartialEq, Clone, Copy)] +#[derive(PartialEq, Clone, Copy, Debug)] pub struct Pos(pub u8, pub u8); impl Pos { From bc4470999c7f9499a43c50b90e1cc9e2ea2ed331 Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 09:42:44 +1300 Subject: [PATCH 030/377] bug fix - used sector instead of quadrant as index in srs --- 84_Super_Star_Trek/rust/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 485f57afa..34c301361 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,7 +1,7 @@ use crate::model::{Galaxy, Pos, SectorStatus, COURSES}; pub fn short_range_scan(model: &Galaxy) { - let quadrant = &model.quadrants[model.enterprise.sector.as_index()]; + let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()]; println!("{:-^33}", ""); for y in 0..=7 { From c23449fac320c6ccf3b4d3b44615ab62c12a7645 Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 09:44:14 +1300 Subject: [PATCH 031/377] just reorged some code --- 84_Super_Star_Trek/rust/src/model.rs | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index fa0ca4c2e..d1c937abc 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -7,6 +7,21 @@ pub struct Galaxy { pub enterprise: Enterprise } +pub struct Quadrant { + pub stars: Vec, + pub star_base: Option, + pub klingons: Vec +} + +pub struct Klingon { + pub sector: Pos +} + +pub struct Enterprise { + pub quadrant: Pos, + pub sector: Pos, +} + #[derive(PartialEq, Clone, Copy, Debug)] pub struct Pos(pub u8, pub u8); @@ -54,21 +69,6 @@ pub enum SectorStatus { Empty, Star, StarBase, Klingon } -pub struct Quadrant { - pub stars: Vec, - pub star_base: Option, - pub klingons: Vec -} - -pub struct Klingon { - pub sector: Pos -} - -pub struct Enterprise { - pub quadrant: Pos, - pub sector: Pos, -} - impl Galaxy { pub fn generate_new() -> Self { let quadrants = Self::generate_quadrants(); From 60f0492c2814deaf619f1123e06c8f30417503c6 Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 11:43:58 +1300 Subject: [PATCH 032/377] displaying stats properly aligned next to scan --- 84_Super_Star_Trek/rust/src/commands.rs | 15 +++++++++++++-- 84_Super_Star_Trek/rust/src/model.rs | 24 +++++++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 34c301361..100803a32 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -3,6 +3,17 @@ use crate::model::{Galaxy, Pos, SectorStatus, COURSES}; pub fn short_range_scan(model: &Galaxy) { let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()]; + let data : [String; 8] = [ + format!("Stardate {}", model.stardate), + format!("Condition {:?}", model.enterprise.condition), + format!("Quadrant {}", model.enterprise.quadrant), + format!("Sector {}", model.enterprise.sector), + format!("Photon torpedoes {}", model.enterprise.photon_torpedoes), + format!("Total energy {}", model.enterprise.total_energy), + format!("Shields {}", model.enterprise.shields), + format!("Klingons remaining {}", model.remaining_klingons()), + ]; + println!("{:-^33}", ""); for y in 0..=7 { for x in 0..=7 { @@ -14,11 +25,11 @@ pub fn short_range_scan(model: &Galaxy) { SectorStatus::Star => print!(" * "), SectorStatus::StarBase => print!(">!< "), SectorStatus::Klingon => print!("+K+ "), - _ => print!(" "), + _ => print!(" "), } } } - print!("\n") + println!("{:>9}{}", "", data[y as usize]) } println!("{:-^33}", ""); } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index d1c937abc..7fffd81fc 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -3,6 +3,7 @@ use std::{ops::{Mul, Add}, fmt::Display}; use rand::Rng; pub struct Galaxy { + pub stardate: f32, pub quadrants: Vec, pub enterprise: Enterprise } @@ -18,8 +19,17 @@ pub struct Klingon { } pub struct Enterprise { + pub condition: Condition, pub quadrant: Pos, pub sector: Pos, + pub photon_torpedoes: u8, + pub total_energy: u16, + pub shields: u16, +} + +#[derive(Debug)] +pub enum Condition { + Green, Yellow, Red } #[derive(PartialEq, Clone, Copy, Debug)] @@ -70,6 +80,11 @@ pub enum SectorStatus { } impl Galaxy { + pub fn remaining_klingons(&self) -> u8 { + let quadrants = &self.quadrants; + quadrants.into_iter().map(|q| { q.klingons.len() as u8 }).sum::() + } + pub fn generate_new() -> Self { let quadrants = Self::generate_quadrants(); @@ -78,8 +93,15 @@ impl Galaxy { let enterprise_sector = quadrants[enterprise_quadrant.as_index()].find_empty_sector(); Galaxy { + stardate: 3800.0, quadrants: quadrants, - enterprise: Enterprise { quadrant: enterprise_quadrant, sector: enterprise_sector } + enterprise: Enterprise { + condition: Condition::Green, + quadrant: enterprise_quadrant, + sector: enterprise_sector, + photon_torpedoes: 28, + total_energy: 3000, + shields: 0 } } } From 4b326547e4d4441bd3c1099d29ae0683e6c5527b Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 11:53:19 +1300 Subject: [PATCH 033/377] added a tasks tracking doc --- 84_Super_Star_Trek/rust/tasks.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 84_Super_Star_Trek/rust/tasks.md diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md new file mode 100644 index 000000000..3fcb826ad --- /dev/null +++ b/84_Super_Star_Trek/rust/tasks.md @@ -0,0 +1,7 @@ +# Tasks + +Started after movement and display of stats was finished (no energy management or collision detection or anything). + +- [ ] stop before hitting an object +- [ ] remove energy on move +- [ ] klingon movement \ No newline at end of file From b56819aadffe74fb53d3dd8ab7de51a1cb161045 Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 15:36:42 +1300 Subject: [PATCH 034/377] implemented taking damage and dying --- 84_Super_Star_Trek/rust/src/commands.rs | 4 +- 84_Super_Star_Trek/rust/src/main.rs | 27 ++++++++++++- 84_Super_Star_Trek/rust/src/model.rs | 50 ++++++++++++++++++++++--- 84_Super_Star_Trek/rust/tasks.md | 9 ++++- 4 files changed, 79 insertions(+), 11 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 100803a32..ffbdad61b 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,4 +1,4 @@ -use crate::model::{Galaxy, Pos, SectorStatus, COURSES}; +use crate::model::{Galaxy, Pos, SectorStatus, COURSES, Quadrant}; pub fn short_range_scan(model: &Galaxy) { let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()]; @@ -35,7 +35,7 @@ pub fn short_range_scan(model: &Galaxy) { } pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { - + let end = find_end_quadrant_sector(galaxy.enterprise.quadrant, galaxy.enterprise.sector, course, warp_speed); if end.hit_edge { diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index a9b5f4cef..9c2ea6066 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -2,6 +2,8 @@ use std::{io::{stdin, stdout, Write}, process::exit, str::FromStr}; use model::Galaxy; +use crate::model::Condition; + mod model; mod commands; @@ -10,7 +12,7 @@ fn main() { .expect("Error setting Ctrl-C handler"); let mut galaxy = Galaxy::generate_new(); - // init options, starting state and notes + // todo: init options, starting state and notes commands::short_range_scan(&galaxy); loop { @@ -19,6 +21,14 @@ fn main() { "NAV" => gather_dir_and_speed_then_move(&mut galaxy), _ => print_command_help() } + + if galaxy.enterprise.condition == Condition::Destroyed { // todo: also check if stranded + println!("Is is stardate {}. + There were {} Klingon battle cruisers left at + the end of your mission. + ", galaxy.stardate, galaxy.remaining_klingons()); + break; + } } } @@ -37,6 +47,21 @@ fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { return; } + let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; + for k in 0..quadrant.klingons.len() { + let new_sector = quadrant.find_empty_sector(); + quadrant.klingons[k].sector = new_sector; + } + + // todo: check if enterprise is protected by a starbase + + for k in 0..quadrant.klingons.len() { + quadrant.klingons[k].fire_on(&mut galaxy.enterprise); + } + + if galaxy.enterprise.condition == Condition::Destroyed { + return; + } commands::move_enterprise(course.unwrap(), speed.unwrap(), galaxy); } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 7fffd81fc..94e9128f1 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -15,7 +15,21 @@ pub struct Quadrant { } pub struct Klingon { - pub sector: Pos + pub sector: Pos, + energy: f32 +} + +impl Klingon { + pub fn fire_on(&mut self, enterprise: &mut Enterprise) { + let mut rng = rand::thread_rng(); + let attack_strength = rng.gen::(); + let dist_to_enterprise = self.sector.abs_diff(enterprise.sector) as f32; + let hit_strength = self.energy * (2.0 + attack_strength) / dist_to_enterprise; + + self.energy /= 3.0 + attack_strength; + + enterprise.take_hit(self.sector, hit_strength as u16); + } } pub struct Enterprise { @@ -26,10 +40,30 @@ pub struct Enterprise { pub total_energy: u16, pub shields: u16, } +impl Enterprise { + fn take_hit(&mut self, sector: Pos, hit_strength: u16) { + if self.condition == Condition::Destroyed { + return; + } + + println!("{hit_strength} unit hit on Enterprise from sector {sector}"); + + // absorb into shields + + if self.shields <= 0 { + println!("The Enterprise has been destroyed. The Federation will be conquered."); + self.condition = Condition::Destroyed; + } + + // report shields + // take damage if strength is greater than 20 + } +} -#[derive(Debug)] +#[derive(PartialEq, Debug)] pub enum Condition { - Green, Yellow, Red + Green, Yellow, Red, + Destroyed, } #[derive(PartialEq, Clone, Copy, Debug)] @@ -39,6 +73,10 @@ impl Pos { pub fn as_index(&self) -> usize { (self.0 * 8 + self.1).into() } + + fn abs_diff(&self, other: Pos) -> u8 { + self.0.abs_diff(other.0) + self.1.abs_diff(other.1) + } } impl Mul for Pos { @@ -128,7 +166,7 @@ impl Galaxy { _ => 0 }; for _ in 0..klingon_count { - quadrant.klingons.push(Klingon { sector: quadrant.find_empty_sector() }); + quadrant.klingons.push(Klingon { sector: quadrant.find_empty_sector(), energy: rng.gen_range(100..=300) as f32 }); } result.push(quadrant); @@ -162,7 +200,7 @@ impl Quadrant { klingons.into_iter().find(|k| &k.sector == sector).is_some() } - fn find_empty_sector(&self) -> Pos { + pub fn find_empty_sector(&self) -> Pos { let mut rng = rand::thread_rng(); loop { let pos = Pos(rng.gen_range(0..8), rng.gen_range(0..8)); @@ -171,4 +209,4 @@ impl Quadrant { } } } -} \ No newline at end of file +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 3fcb826ad..8a9951b5b 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -2,6 +2,11 @@ Started after movement and display of stats was finished (no energy management or collision detection or anything). -- [ ] stop before hitting an object +- [x] klingon movement +- [x] klingon firing, game over etc - [ ] remove energy on move -- [ ] klingon movement \ No newline at end of file +- [ ] shields +- [ ] stranded... +- [ ] stop before hitting an object + - when moving across a sector, the enterprise should stop before it runs into something + - the current move is a jump, which makes this problematic. would need to rewrite it From 1732d950328b0f2ec723c554db5b0753d6ce06fe Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 15:41:00 +1300 Subject: [PATCH 035/377] added proper help --- 84_Super_Star_Trek/rust/src/commands.rs | 16 +++++++++++++++- 84_Super_Star_Trek/rust/src/main.rs | 25 ++++++++++++------------- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index ffbdad61b..5cd901501 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -97,6 +97,20 @@ fn find_end_quadrant_sector(start_quadrant: Pos, start_sector: Pos, course: u8, EndPosition { quadrant, sector, hit_edge } } +pub fn move_klingons_and_fire(galaxy: &mut Galaxy) { + let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; + for k in 0..quadrant.klingons.len() { + let new_sector = quadrant.find_empty_sector(); + quadrant.klingons[k].sector = new_sector; + } + + // todo: check if enterprise is protected by a starbase + + for k in 0..quadrant.klingons.len() { + quadrant.klingons[k].fire_on(&mut galaxy.enterprise); + } +} + #[cfg(test)] mod tests { use super::*; @@ -170,4 +184,4 @@ mod tests { assert_eq!(end.sector, Pos(1,0), "right sector"); assert!(!end.hit_edge) } -} \ No newline at end of file +} diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 9c2ea6066..c91ca8bc2 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -47,18 +47,7 @@ fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { return; } - let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; - for k in 0..quadrant.klingons.len() { - let new_sector = quadrant.find_empty_sector(); - quadrant.klingons[k].sector = new_sector; - } - - // todo: check if enterprise is protected by a starbase - - for k in 0..quadrant.klingons.len() { - quadrant.klingons[k].fire_on(&mut galaxy.enterprise); - } - + commands::move_klingons_and_fire(galaxy); if galaxy.enterprise.condition == Condition::Destroyed { return; } @@ -88,6 +77,16 @@ fn prompt_value(prompt_text: &str, min: T, max: T) -> O } fn print_command_help() { - println!("valid commands are just SRS and NAV at the mo") + println!("Enter one of the following: + NAV (To set course) + SRS (For short range sensor scan) + LRS (For long range sensor scan) + PHA (To fire phasers) + TOR (To fire photon torpedoes) + SHE (To raise or lower shields) + DAM (For damage control reports) + COM (To call on library-computer) + XXX (To resign your command) + ") } From ec3b0697bb91927d8e94d1aee3f558d1cefa275f Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 19:05:38 +1300 Subject: [PATCH 036/377] moved blobs of text into text_display mod --- 84_Super_Star_Trek/rust/src/commands.rs | 14 +------ 84_Super_Star_Trek/rust/src/main.rs | 28 +++----------- 84_Super_Star_Trek/rust/src/model.rs | 12 +++++- 84_Super_Star_Trek/rust/src/text_display.rs | 42 +++++++++++++++++++++ 4 files changed, 59 insertions(+), 37 deletions(-) create mode 100644 84_Super_Star_Trek/rust/src/text_display.rs diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 5cd901501..5251109e0 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,4 +1,4 @@ -use crate::model::{Galaxy, Pos, SectorStatus, COURSES, Quadrant}; +use crate::{model::{Galaxy, Pos, SectorStatus, COURSES, Quadrant, EndPosition}, text_display}; pub fn short_range_scan(model: &Galaxy) { let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()]; @@ -39,11 +39,7 @@ pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { let end = find_end_quadrant_sector(galaxy.enterprise.quadrant, galaxy.enterprise.sector, course, warp_speed); if end.hit_edge { - println!("Lt. Uhura report message from Starfleet Command: - 'Permission to attempt crossing of galactic perimeter - is hereby *Denied*. Shut down your engines.' - Chief Engineer Scott reports, 'Warp engines shut down - at sector {} of quadrant {}.'", end.quadrant, end.sector); + text_display::hit_edge(&end); } galaxy.enterprise.quadrant = end.quadrant; @@ -54,12 +50,6 @@ pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { short_range_scan(&galaxy) } -struct EndPosition { - quadrant: Pos, - sector: Pos, - hit_edge: bool -} - fn find_end_quadrant_sector(start_quadrant: Pos, start_sector: Pos, course: u8, warp_speed: f32) -> EndPosition { let (dx, dy): (i8, i8) = COURSES[(course - 1) as usize]; diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index c91ca8bc2..bf6f5b966 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -6,6 +6,7 @@ use crate::model::Condition; mod model; mod commands; +mod text_display; fn main() { ctrlc::set_handler(move || { exit(0) }) @@ -19,31 +20,27 @@ fn main() { match prompt("Command?").to_uppercase().as_str() { "SRS" => commands::short_range_scan(&galaxy), "NAV" => gather_dir_and_speed_then_move(&mut galaxy), - _ => print_command_help() + _ => text_display::print_command_help() } if galaxy.enterprise.condition == Condition::Destroyed { // todo: also check if stranded - println!("Is is stardate {}. - There were {} Klingon battle cruisers left at - the end of your mission. - ", galaxy.stardate, galaxy.remaining_klingons()); + text_display::end_game_failure(&galaxy); break; } } } fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { - const BAD_NAV: &str = " Lt. Sulu reports, 'Incorrect course data, sir!'"; let course = prompt_value::("Course (1-9)?", 1, 9); if course.is_none() { - println!("{}", BAD_NAV); + text_display::bad_nav(); return; } let speed = prompt_value::("Warp Factor (0-8)?", 0.0, 8.0); if speed.is_none() { - println!("{}", BAD_NAV); + text_display::bad_nav(); return; } @@ -75,18 +72,3 @@ fn prompt_value(prompt_text: &str, min: T, max: T) -> O _ => None } } - -fn print_command_help() { - println!("Enter one of the following: - NAV (To set course) - SRS (For short range sensor scan) - LRS (For long range sensor scan) - PHA (To fire phasers) - TOR (To fire photon torpedoes) - SHE (To raise or lower shields) - DAM (For damage control reports) - COM (To call on library-computer) - XXX (To resign your command) - ") -} - diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 94e9128f1..5026bdd92 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -2,6 +2,8 @@ use std::{ops::{Mul, Add}, fmt::Display}; use rand::Rng; +use crate::text_display; + pub struct Galaxy { pub stardate: f32, pub quadrants: Vec, @@ -46,12 +48,12 @@ impl Enterprise { return; } - println!("{hit_strength} unit hit on Enterprise from sector {sector}"); + text_display::enterprise_hit(&hit_strength, §or); // absorb into shields if self.shields <= 0 { - println!("The Enterprise has been destroyed. The Federation will be conquered."); + text_display::enterprise_destroyed(); self.condition = Condition::Destroyed; } @@ -66,6 +68,12 @@ pub enum Condition { Destroyed, } +pub struct EndPosition { + pub quadrant: Pos, + pub sector: Pos, + pub hit_edge: bool +} + #[derive(PartialEq, Clone, Copy, Debug)] pub struct Pos(pub u8, pub u8); diff --git a/84_Super_Star_Trek/rust/src/text_display.rs b/84_Super_Star_Trek/rust/src/text_display.rs new file mode 100644 index 000000000..17ffcab1c --- /dev/null +++ b/84_Super_Star_Trek/rust/src/text_display.rs @@ -0,0 +1,42 @@ +use crate::model::{Galaxy, Pos, EndPosition}; + +pub fn print_command_help() { + println!("Enter one of the following: + NAV (To set course) + SRS (For short range sensor scan) + LRS (For long range sensor scan) + PHA (To fire phasers) + TOR (To fire photon torpedoes) + SHE (To raise or lower shields) + DAM (For damage control reports) + COM (To call on library-computer) + XXX (To resign your command) + ") +} + +pub fn end_game_failure(galaxy: &Galaxy) { + println!("Is is stardate {}. +There were {} Klingon battle cruisers left at +the end of your mission. +", galaxy.stardate, galaxy.remaining_klingons()); +} + +pub fn enterprise_destroyed() { + println!("The Enterprise has been destroyed. The Federation will be conquered."); +} + +pub fn bad_nav() { + println!(" Lt. Sulu reports, 'Incorrect course data, sir!'") +} + +pub fn enterprise_hit(hit_strength: &u16, from_sector: &Pos) { + println!("{hit_strength} unit hit on Enterprise from sector {from_sector}"); +} + +pub fn hit_edge(end: &EndPosition) { + println!("Lt. Uhura report message from Starfleet Command: + 'Permission to attempt crossing of galactic perimeter + is hereby *Denied*. Shut down your engines.' + Chief Engineer Scott reports, 'Warp engines shut down + at sector {} of quadrant {}.'", end.quadrant, end.sector); +} \ No newline at end of file From efba9423969af07b3a2eac360c028f1e90fc2379 Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 19:07:46 +1300 Subject: [PATCH 037/377] renamed text_display to view, and moved srs into it --- 84_Super_Star_Trek/rust/src/commands.rs | 40 +---------- 84_Super_Star_Trek/rust/src/main.rs | 14 ++-- 84_Super_Star_Trek/rust/src/model.rs | 6 +- 84_Super_Star_Trek/rust/src/text_display.rs | 42 ------------ 84_Super_Star_Trek/rust/src/view.rs | 76 +++++++++++++++++++++ 5 files changed, 89 insertions(+), 89 deletions(-) delete mode 100644 84_Super_Star_Trek/rust/src/text_display.rs create mode 100644 84_Super_Star_Trek/rust/src/view.rs diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 5251109e0..c27c65058 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,45 +1,11 @@ -use crate::{model::{Galaxy, Pos, SectorStatus, COURSES, Quadrant, EndPosition}, text_display}; - -pub fn short_range_scan(model: &Galaxy) { - let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()]; - - let data : [String; 8] = [ - format!("Stardate {}", model.stardate), - format!("Condition {:?}", model.enterprise.condition), - format!("Quadrant {}", model.enterprise.quadrant), - format!("Sector {}", model.enterprise.sector), - format!("Photon torpedoes {}", model.enterprise.photon_torpedoes), - format!("Total energy {}", model.enterprise.total_energy), - format!("Shields {}", model.enterprise.shields), - format!("Klingons remaining {}", model.remaining_klingons()), - ]; - - println!("{:-^33}", ""); - for y in 0..=7 { - for x in 0..=7 { - let pos = Pos(x, y); - if &pos == &model.enterprise.sector { - print!("<*> ") - } else { - match quadrant.sector_status(&pos) { - SectorStatus::Star => print!(" * "), - SectorStatus::StarBase => print!(">!< "), - SectorStatus::Klingon => print!("+K+ "), - _ => print!(" "), - } - } - } - println!("{:>9}{}", "", data[y as usize]) - } - println!("{:-^33}", ""); -} +use crate::{model::{Galaxy, Pos, COURSES, EndPosition}, view}; pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { let end = find_end_quadrant_sector(galaxy.enterprise.quadrant, galaxy.enterprise.sector, course, warp_speed); if end.hit_edge { - text_display::hit_edge(&end); + view::hit_edge(&end); } galaxy.enterprise.quadrant = end.quadrant; @@ -47,7 +13,7 @@ pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { // if new_quadrant isnt old quadrant print intro - short_range_scan(&galaxy) + view::short_range_scan(&galaxy) } fn find_end_quadrant_sector(start_quadrant: Pos, start_sector: Pos, course: u8, warp_speed: f32) -> EndPosition { diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index bf6f5b966..ec923c8cd 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -6,7 +6,7 @@ use crate::model::Condition; mod model; mod commands; -mod text_display; +mod view; fn main() { ctrlc::set_handler(move || { exit(0) }) @@ -14,17 +14,17 @@ fn main() { let mut galaxy = Galaxy::generate_new(); // todo: init options, starting state and notes - commands::short_range_scan(&galaxy); + view::short_range_scan(&galaxy); loop { match prompt("Command?").to_uppercase().as_str() { - "SRS" => commands::short_range_scan(&galaxy), + "SRS" => view::short_range_scan(&galaxy), "NAV" => gather_dir_and_speed_then_move(&mut galaxy), - _ => text_display::print_command_help() + _ => view::print_command_help() } if galaxy.enterprise.condition == Condition::Destroyed { // todo: also check if stranded - text_display::end_game_failure(&galaxy); + view::end_game_failure(&galaxy); break; } } @@ -34,13 +34,13 @@ fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { let course = prompt_value::("Course (1-9)?", 1, 9); if course.is_none() { - text_display::bad_nav(); + view::bad_nav(); return; } let speed = prompt_value::("Warp Factor (0-8)?", 0.0, 8.0); if speed.is_none() { - text_display::bad_nav(); + view::bad_nav(); return; } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 5026bdd92..2e54555c5 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -2,7 +2,7 @@ use std::{ops::{Mul, Add}, fmt::Display}; use rand::Rng; -use crate::text_display; +use crate::view; pub struct Galaxy { pub stardate: f32, @@ -48,12 +48,12 @@ impl Enterprise { return; } - text_display::enterprise_hit(&hit_strength, §or); + view::enterprise_hit(&hit_strength, §or); // absorb into shields if self.shields <= 0 { - text_display::enterprise_destroyed(); + view::enterprise_destroyed(); self.condition = Condition::Destroyed; } diff --git a/84_Super_Star_Trek/rust/src/text_display.rs b/84_Super_Star_Trek/rust/src/text_display.rs deleted file mode 100644 index 17ffcab1c..000000000 --- a/84_Super_Star_Trek/rust/src/text_display.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::model::{Galaxy, Pos, EndPosition}; - -pub fn print_command_help() { - println!("Enter one of the following: - NAV (To set course) - SRS (For short range sensor scan) - LRS (For long range sensor scan) - PHA (To fire phasers) - TOR (To fire photon torpedoes) - SHE (To raise or lower shields) - DAM (For damage control reports) - COM (To call on library-computer) - XXX (To resign your command) - ") -} - -pub fn end_game_failure(galaxy: &Galaxy) { - println!("Is is stardate {}. -There were {} Klingon battle cruisers left at -the end of your mission. -", galaxy.stardate, galaxy.remaining_klingons()); -} - -pub fn enterprise_destroyed() { - println!("The Enterprise has been destroyed. The Federation will be conquered."); -} - -pub fn bad_nav() { - println!(" Lt. Sulu reports, 'Incorrect course data, sir!'") -} - -pub fn enterprise_hit(hit_strength: &u16, from_sector: &Pos) { - println!("{hit_strength} unit hit on Enterprise from sector {from_sector}"); -} - -pub fn hit_edge(end: &EndPosition) { - println!("Lt. Uhura report message from Starfleet Command: - 'Permission to attempt crossing of galactic perimeter - is hereby *Denied*. Shut down your engines.' - Chief Engineer Scott reports, 'Warp engines shut down - at sector {} of quadrant {}.'", end.quadrant, end.sector); -} \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs new file mode 100644 index 000000000..5d8c1fd69 --- /dev/null +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -0,0 +1,76 @@ +use crate::model::{Galaxy, Pos, EndPosition, SectorStatus}; + +pub fn short_range_scan(model: &Galaxy) { + let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()]; + + let data : [String; 8] = [ + format!("Stardate {}", model.stardate), + format!("Condition {:?}", model.enterprise.condition), + format!("Quadrant {}", model.enterprise.quadrant), + format!("Sector {}", model.enterprise.sector), + format!("Photon torpedoes {}", model.enterprise.photon_torpedoes), + format!("Total energy {}", model.enterprise.total_energy), + format!("Shields {}", model.enterprise.shields), + format!("Klingons remaining {}", model.remaining_klingons()), + ]; + + println!("{:-^33}", ""); + for y in 0..=7 { + for x in 0..=7 { + let pos = Pos(x, y); + if &pos == &model.enterprise.sector { + print!("<*> ") + } else { + match quadrant.sector_status(&pos) { + SectorStatus::Star => print!(" * "), + SectorStatus::StarBase => print!(">!< "), + SectorStatus::Klingon => print!("+K+ "), + _ => print!(" "), + } + } + } + println!("{:>9}{}", "", data[y as usize]) + } + println!("{:-^33}", ""); +} + +pub fn print_command_help() { + println!("Enter one of the following: + NAV (To set course) + SRS (For short range sensor scan) + LRS (For long range sensor scan) + PHA (To fire phasers) + TOR (To fire photon torpedoes) + SHE (To raise or lower shields) + DAM (For damage control reports) + COM (To call on library-computer) + XXX (To resign your command) + ") +} + +pub fn end_game_failure(galaxy: &Galaxy) { + println!("Is is stardate {}. +There were {} Klingon battle cruisers left at +the end of your mission. +", galaxy.stardate, galaxy.remaining_klingons()); +} + +pub fn enterprise_destroyed() { + println!("The Enterprise has been destroyed. The Federation will be conquered."); +} + +pub fn bad_nav() { + println!(" Lt. Sulu reports, 'Incorrect course data, sir!'") +} + +pub fn enterprise_hit(hit_strength: &u16, from_sector: &Pos) { + println!("{hit_strength} unit hit on Enterprise from sector {from_sector}"); +} + +pub fn hit_edge(end: &EndPosition) { + println!("Lt. Uhura report message from Starfleet Command: + 'Permission to attempt crossing of galactic perimeter + is hereby *Denied*. Shut down your engines.' + Chief Engineer Scott reports, 'Warp engines shut down + at sector {} of quadrant {}.'", end.quadrant, end.sector); +} From a18112767dfd0e587958623e5d0abe224ac439ac Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 19:51:50 +1300 Subject: [PATCH 038/377] added intro section with quadrant name --- 84_Super_Star_Trek/rust/src/main.rs | 8 +++-- 84_Super_Star_Trek/rust/src/model.rs | 10 ++++++- 84_Super_Star_Trek/rust/src/view.rs | 45 ++++++++++++++++++++++++++++ 84_Super_Star_Trek/rust/tasks.md | 2 ++ 4 files changed, 62 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index ec923c8cd..8af85b777 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,4 +1,4 @@ -use std::{io::{stdin, stdout, Write}, process::exit, str::FromStr}; +use std::{io::{stdin, stdout, Write, Read}, process::exit, str::FromStr}; use model::Galaxy; @@ -13,7 +13,11 @@ fn main() { .expect("Error setting Ctrl-C handler"); let mut galaxy = Galaxy::generate_new(); - // todo: init options, starting state and notes + + view::intro(&galaxy); + let _ = prompt("Press Enter when ready to accept command"); + + view::starting_quadrant(&galaxy.enterprise.quadrant); view::short_range_scan(&galaxy); loop { diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 2e54555c5..dd959220e 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -6,6 +6,7 @@ use crate::view; pub struct Galaxy { pub stardate: f32, + pub final_stardate: f32, pub quadrants: Vec, pub enterprise: Enterprise } @@ -131,15 +132,22 @@ impl Galaxy { quadrants.into_iter().map(|q| { q.klingons.len() as u8 }).sum::() } + pub fn remaining_starbases(&self) -> u8 { + let quadrants = &self.quadrants; + quadrants.into_iter().filter(|q| q.star_base.is_some()).count() as u8 + } + pub fn generate_new() -> Self { let quadrants = Self::generate_quadrants(); let mut rng = rand::thread_rng(); let enterprise_quadrant = Pos(rng.gen_range(0..8), rng.gen_range(0..8)); let enterprise_sector = quadrants[enterprise_quadrant.as_index()].find_empty_sector(); + let stardate = rng.gen_range(20..=40) as f32 * 100.0; Galaxy { - stardate: 3800.0, + stardate, + final_stardate: stardate + rng.gen_range(25..=35) as f32, quadrants: quadrants, enterprise: Enterprise { condition: Condition::Green, diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 5d8c1fd69..62d22eea8 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -1,5 +1,50 @@ use crate::model::{Galaxy, Pos, EndPosition, SectorStatus}; +pub fn intro(model: &Galaxy) { + let star_bases = model.remaining_starbases(); + let mut star_base_message: String = "There is 1 starbase".into(); + if star_bases > 1 { + star_base_message = format!("There are {} starbases", star_bases); + } + println!("Your orders are as follows: + Destroy the {} Klingon warships which have invaded + the galaxy before they can attack federation headquarters + on stardate {}. This gives you {} days. {} in the galaxy for resupplying your ship.", + model.remaining_klingons(), model.final_stardate, model.final_stardate - model.stardate, star_base_message) +} + +const REGION_NAMES: [&str; 16] = [ + "Antares", + "Sirius", + "Rigel", + "Deneb", + "Procyon", + "Capella", + "Vega", + "Betelgeuse", + "Canopus", + "Aldebaran", + "Altair", + "Regulus", + "Sagittarius", + "Arcturus", + "Pollux", + "Spica" +]; + +const SUB_REGION_NAMES: [&str; 4] = ["I", "II", "III", "IV"]; + +fn quadrant_name(quadrant: &Pos) -> String { + format!("{} {}", + REGION_NAMES[(quadrant.0 << 1 + quadrant.1 >> 1) as usize], + SUB_REGION_NAMES[(quadrant.1 % 4) as usize]) +} + +pub fn starting_quadrant(quadrant: &Pos) { + println!("Your mission begins with your starship located +in the galactic quadrant, '{}'.", quadrant_name(quadrant)) +} + pub fn short_range_scan(model: &Galaxy) { let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()]; diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 8a9951b5b..3da9cf93a 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -4,6 +4,8 @@ Started after movement and display of stats was finished (no energy management o - [x] klingon movement - [x] klingon firing, game over etc +- [ ] add intro +- [ ] add entering (and starting in) sector headers - [ ] remove energy on move - [ ] shields - [ ] stranded... From 41ca9c3c709425809668f7ff9fbedd4dafdf06a2 Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 20:36:01 +1300 Subject: [PATCH 039/377] added enterprise to intro, entering quadrant names, and fixed bug in name indexing --- 84_Super_Star_Trek/rust/src/commands.rs | 6 ++-- 84_Super_Star_Trek/rust/src/main.rs | 1 + 84_Super_Star_Trek/rust/src/model.rs | 2 +- 84_Super_Star_Trek/rust/src/view.rs | 40 ++++++++++++++++++++++--- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index c27c65058..00ab13770 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -8,10 +8,12 @@ pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { view::hit_edge(&end); } + if galaxy.enterprise.quadrant != end.quadrant { + view::enter_quadrant(&end.quadrant); + } + galaxy.enterprise.quadrant = end.quadrant; galaxy.enterprise.sector = end.sector; - - // if new_quadrant isnt old quadrant print intro view::short_range_scan(&galaxy) } diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 8af85b777..2c1c06be0 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -14,6 +14,7 @@ fn main() { let mut galaxy = Galaxy::generate_new(); + view::enterprise(); view::intro(&galaxy); let _ = prompt("Press Enter when ready to accept command"); diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index dd959220e..d79089dd4 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -106,7 +106,7 @@ impl Add for Pos { impl Display for Pos { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{} , {}", self.0, self.1) + write!(f, "{} , {}", self.0 + 1, self.1 + 1) } } diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 62d22eea8..774505f5a 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -1,5 +1,33 @@ use crate::model::{Galaxy, Pos, EndPosition, SectorStatus}; +pub fn enterprise() { + println!(" + + + + + + + + + + + ,------*------, + ,------------- '--- ------' + '-------- --' / / + ,---' '-------/ /--, + '----------------' + + THE USS ENTERPRISE --- NCC-1701 + + + + + + +") +} + pub fn intro(model: &Galaxy) { let star_bases = model.remaining_starbases(); let mut star_base_message: String = "There is 1 starbase".into(); @@ -9,7 +37,7 @@ pub fn intro(model: &Galaxy) { println!("Your orders are as follows: Destroy the {} Klingon warships which have invaded the galaxy before they can attack federation headquarters - on stardate {}. This gives you {} days. {} in the galaxy for resupplying your ship.", + on stardate {}. This gives you {} days. {} in the galaxy for resupplying your ship.\n", model.remaining_klingons(), model.final_stardate, model.final_stardate - model.stardate, star_base_message) } @@ -36,13 +64,17 @@ const SUB_REGION_NAMES: [&str; 4] = ["I", "II", "III", "IV"]; fn quadrant_name(quadrant: &Pos) -> String { format!("{} {}", - REGION_NAMES[(quadrant.0 << 1 + quadrant.1 >> 1) as usize], + REGION_NAMES[((quadrant.0 << 1) + (quadrant.1 >> 2)) as usize], SUB_REGION_NAMES[(quadrant.1 % 4) as usize]) } pub fn starting_quadrant(quadrant: &Pos) { - println!("Your mission begins with your starship located -in the galactic quadrant, '{}'.", quadrant_name(quadrant)) + println!("\nYour mission begins with your starship located +in the galactic quadrant, '{}'.\n", quadrant_name(quadrant)) +} + +pub fn enter_quadrant(quadrant: &Pos) { + println!("\nNow entering {} quadrant . . .\n", quadrant_name(quadrant)) } pub fn short_range_scan(model: &Galaxy) { From dee8a96f3cd46f88b8f6da461c30c5c2e1307759 Mon Sep 17 00:00:00 2001 From: Christopher Date: Wed, 1 Mar 2023 20:42:51 +1300 Subject: [PATCH 040/377] working on tasks --- 84_Super_Star_Trek/rust/tasks.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 3da9cf93a..2b532d482 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -4,8 +4,9 @@ Started after movement and display of stats was finished (no energy management o - [x] klingon movement - [x] klingon firing, game over etc -- [ ] add intro -- [ ] add entering (and starting in) sector headers +- [x] add intro +- [x] add entering (and starting in) sector headers +- [ ] conditions and danger messages - [ ] remove energy on move - [ ] shields - [ ] stranded... From 4cda6be184beea9568bebd542aec192574886b2d Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 10:02:56 +1300 Subject: [PATCH 041/377] added warning messages when entering a sector --- 84_Super_Star_Trek/rust/src/commands.rs | 7 +++++++ 84_Super_Star_Trek/rust/src/main.rs | 6 ++---- 84_Super_Star_Trek/rust/src/model.rs | 16 ++++++---------- 84_Super_Star_Trek/rust/src/view.rs | 16 +++++++++++++++- 84_Super_Star_Trek/rust/tasks.md | 8 +++++++- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 00ab13770..d55b08ff9 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -10,6 +10,13 @@ pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { if galaxy.enterprise.quadrant != end.quadrant { view::enter_quadrant(&end.quadrant); + + if galaxy.quadrants[end.quadrant.as_index()].klingons.len() > 0 { + view::condition_red(); + if galaxy.enterprise.shields <= 200 { + view::danger_shields(); + } + } } galaxy.enterprise.quadrant = end.quadrant; diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 2c1c06be0..498c5bd2b 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -2,8 +2,6 @@ use std::{io::{stdin, stdout, Write, Read}, process::exit, str::FromStr}; use model::Galaxy; -use crate::model::Condition; - mod model; mod commands; mod view; @@ -28,7 +26,7 @@ fn main() { _ => view::print_command_help() } - if galaxy.enterprise.condition == Condition::Destroyed { // todo: also check if stranded + if galaxy.enterprise.destroyed { // todo: also check if stranded view::end_game_failure(&galaxy); break; } @@ -50,7 +48,7 @@ fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { } commands::move_klingons_and_fire(galaxy); - if galaxy.enterprise.condition == Condition::Destroyed { + if galaxy.enterprise.destroyed { return; } commands::move_enterprise(course.unwrap(), speed.unwrap(), galaxy); diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index d79089dd4..9caa100ac 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -36,7 +36,8 @@ impl Klingon { } pub struct Enterprise { - pub condition: Condition, + pub destroyed: bool, + pub damaged: bool, // later this could be by subsystem pub quadrant: Pos, pub sector: Pos, pub photon_torpedoes: u8, @@ -45,7 +46,7 @@ pub struct Enterprise { } impl Enterprise { fn take_hit(&mut self, sector: Pos, hit_strength: u16) { - if self.condition == Condition::Destroyed { + if self.destroyed { return; } @@ -55,7 +56,7 @@ impl Enterprise { if self.shields <= 0 { view::enterprise_destroyed(); - self.condition = Condition::Destroyed; + self.destroyed = true } // report shields @@ -63,12 +64,6 @@ impl Enterprise { } } -#[derive(PartialEq, Debug)] -pub enum Condition { - Green, Yellow, Red, - Destroyed, -} - pub struct EndPosition { pub quadrant: Pos, pub sector: Pos, @@ -150,7 +145,8 @@ impl Galaxy { final_stardate: stardate + rng.gen_range(25..=35) as f32, quadrants: quadrants, enterprise: Enterprise { - condition: Condition::Green, + destroyed: false, + damaged: false, quadrant: enterprise_quadrant, sector: enterprise_sector, photon_torpedoes: 28, diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 774505f5a..320cb4eb7 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -79,10 +79,16 @@ pub fn enter_quadrant(quadrant: &Pos) { pub fn short_range_scan(model: &Galaxy) { let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()]; + let mut condition = "GREEN"; + if quadrant.klingons.len() > 0 { + condition = "*RED*"; + } else if model.enterprise.damaged { + condition = "YELLOW"; + } let data : [String; 8] = [ format!("Stardate {}", model.stardate), - format!("Condition {:?}", model.enterprise.condition), + format!("Condition {}", condition), format!("Quadrant {}", model.enterprise.quadrant), format!("Sector {}", model.enterprise.sector), format!("Photon torpedoes {}", model.enterprise.photon_torpedoes), @@ -151,3 +157,11 @@ pub fn hit_edge(end: &EndPosition) { Chief Engineer Scott reports, 'Warp engines shut down at sector {} of quadrant {}.'", end.quadrant, end.sector); } + +pub fn condition_red() { + println!("COMBAT AREA CONDITION RED") +} + +pub fn danger_shields() { + println!(" SHIELDS DANGEROUSLY LOW ") +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 2b532d482..374c1a297 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -6,10 +6,16 @@ Started after movement and display of stats was finished (no energy management o - [x] klingon firing, game over etc - [x] add intro - [x] add entering (and starting in) sector headers -- [ ] conditions and danger messages +- [x] conditions and danger messages - [ ] remove energy on move - [ ] shields + - [ ] shield control + - [ ] shield hit absorption +- [ ] subsystem damage + - and support for reports +- [ ] lrs? - [ ] stranded... - [ ] stop before hitting an object - when moving across a sector, the enterprise should stop before it runs into something - the current move is a jump, which makes this problematic. would need to rewrite it +- [ ] better command reading - support entering multiple values on a line (e.g. nav 3 0.1) From 7aec8284c03a866adff95e7040ee7e987d89d795 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 10:24:13 +1300 Subject: [PATCH 042/377] can now specify positional params on the nav command --- 84_Super_Star_Trek/rust/src/main.rs | 36 +++++++++++++++++++++-------- 84_Super_Star_Trek/rust/tasks.md | 2 +- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 498c5bd2b..4212c6a74 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -20,9 +20,13 @@ fn main() { view::short_range_scan(&galaxy); loop { - match prompt("Command?").to_uppercase().as_str() { + let command = prompt("Command?"); + if command.len() == 0 { + continue; + } + match command[0].to_uppercase().as_str() { "SRS" => view::short_range_scan(&galaxy), - "NAV" => gather_dir_and_speed_then_move(&mut galaxy), + "NAV" => gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), _ => view::print_command_help() } @@ -33,15 +37,15 @@ fn main() { } } -fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { +fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec) { - let course = prompt_value::("Course (1-9)?", 1, 9); + let course = param_or_prompt_value(&provided, 0, "Course (1-9)?", 1, 9); if course.is_none() { view::bad_nav(); return; } - let speed = prompt_value::("Warp Factor (0-8)?", 0.0, 8.0); + let speed = param_or_prompt_value(&provided, 1, "Warp Factor (0-8)?", 0.0, 8.0); if speed.is_none() { view::bad_nav(); return; @@ -54,7 +58,7 @@ fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy) { commands::move_enterprise(course.unwrap(), speed.unwrap(), galaxy); } -fn prompt(prompt_text: &str) -> String { +fn prompt(prompt_text: &str) -> Vec { let stdin = stdin(); let mut stdout = stdout(); @@ -63,15 +67,29 @@ fn prompt(prompt_text: &str) -> String { let mut buffer = String::new(); if let Ok(_) = stdin.read_line(&mut buffer) { - return buffer.trim_end().into(); + return buffer.trim_end().split(" ").map(|s| s.to_string()).collect(); } - "".into() + Vec::new() } fn prompt_value(prompt_text: &str, min: T, max: T) -> Option { let passed = prompt(prompt_text); - match passed.parse::() { + if passed.len() != 1 { + return None + } + match passed[0].parse::() { Ok(n) if (n >= min && n <= max) => Some(n), _ => None } } + +fn param_or_prompt_value(params: &Vec, param_pos: usize, prompt_text: &str, min: T, max: T) -> Option { + if params.len() > param_pos { + match params[param_pos].parse::() { + Ok(n) => Some(n), + _ => None + } + } else { + return prompt_value::(prompt_text, min, max); + } +} \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 374c1a297..da2b9c1bd 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -18,4 +18,4 @@ Started after movement and display of stats was finished (no energy management o - [ ] stop before hitting an object - when moving across a sector, the enterprise should stop before it runs into something - the current move is a jump, which makes this problematic. would need to rewrite it -- [ ] better command reading - support entering multiple values on a line (e.g. nav 3 0.1) +- [x] better command reading - support entering multiple values on a line (e.g. nav 3 0.1) From ca89609c3e91470a959ac9a25533db80e8e4ce32 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 11:26:43 +1300 Subject: [PATCH 043/377] energy is now removed with travel --- 84_Super_Star_Trek/rust/src/commands.rs | 31 ++++++++++++++++++++----- 84_Super_Star_Trek/rust/src/model.rs | 3 ++- 84_Super_Star_Trek/rust/src/view.rs | 9 +++++++ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index d55b08ff9..3cc4aff56 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -2,25 +2,43 @@ use crate::{model::{Galaxy, Pos, COURSES, EndPosition}, view}; pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { - let end = find_end_quadrant_sector(galaxy.enterprise.quadrant, galaxy.enterprise.sector, course, warp_speed); + let ship = &mut galaxy.enterprise; + + // todo account for being blocked + + let end = find_end_quadrant_sector(ship.quadrant, ship.sector, course, warp_speed); + + // todo account for engine damage + + if end.energy_cost > ship.total_energy { + view::insuffient_warp_energy(warp_speed); + return + } if end.hit_edge { view::hit_edge(&end); } + - if galaxy.enterprise.quadrant != end.quadrant { + if ship.quadrant != end.quadrant { view::enter_quadrant(&end.quadrant); if galaxy.quadrants[end.quadrant.as_index()].klingons.len() > 0 { view::condition_red(); - if galaxy.enterprise.shields <= 200 { + if ship.shields <= 200 { view::danger_shields(); } } } - galaxy.enterprise.quadrant = end.quadrant; - galaxy.enterprise.sector = end.sector; + ship.quadrant = end.quadrant; + ship.sector = end.sector; + + ship.total_energy = (ship.total_energy - end.energy_cost).max(0); + if ship.shields > ship.total_energy { + view::divert_energy_from_shields(); + ship.shields = ship.total_energy; + } view::short_range_scan(&galaxy) } @@ -58,8 +76,9 @@ fn find_end_quadrant_sector(start_quadrant: Pos, start_sector: Pos, course: u8, let quadrant = Pos((nx / 8) as u8, (ny / 8) as u8); let sector = Pos((nx % 8) as u8, (ny % 8) as u8); + let energy_cost = distance as u16 + 10; - EndPosition { quadrant, sector, hit_edge } + EndPosition { quadrant, sector, hit_edge, energy_cost } } pub fn move_klingons_and_fire(galaxy: &mut Galaxy) { diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 9caa100ac..103887f5b 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -67,7 +67,8 @@ impl Enterprise { pub struct EndPosition { pub quadrant: Pos, pub sector: Pos, - pub hit_edge: bool + pub hit_edge: bool, + pub energy_cost: u16, } #[derive(PartialEq, Clone, Copy, Debug)] diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 320cb4eb7..f460eaa7b 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -165,3 +165,12 @@ pub fn condition_red() { pub fn danger_shields() { println!(" SHIELDS DANGEROUSLY LOW ") } + +pub fn insuffient_warp_energy(warp_speed: f32) { + println!("Engineering reports, 'Insufficient energy available + for maneuvering at warp {warp_speed} !'") +} + +pub fn divert_energy_from_shields() { + println!("Shield Control supplies energy to complete the maneuver.") +} From 2feb1a9c6532cd4c3dcbb93aa45aefc513989fad Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 11:37:58 +1300 Subject: [PATCH 044/377] implemented setting shields --- 84_Super_Star_Trek/rust/src/main.rs | 22 ++++++++++++++++++++++ 84_Super_Star_Trek/rust/src/view.rs | 17 +++++++++++++++++ 84_Super_Star_Trek/rust/tasks.md | 6 +++--- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 4212c6a74..477a0594e 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -27,6 +27,7 @@ fn main() { match command[0].to_uppercase().as_str() { "SRS" => view::short_range_scan(&galaxy), "NAV" => gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), + "SHE" => get_amount_and_set_shields(&mut galaxy, command[1..].into()), _ => view::print_command_help() } @@ -37,6 +38,27 @@ fn main() { } } +fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { + + // todo check for damaged module + + view::energy_available(galaxy.enterprise.total_energy); + let value = param_or_prompt_value(&provided, 0, "Number of units to shields", 0, i32::MAX); + if value.is_none() { + view::shields_unchanged(); + return; + } + let value = value.unwrap() as u16; + if value > galaxy.enterprise.total_energy { + view::ridiculous(); + view::shields_unchanged(); + return; + } + + galaxy.enterprise.shields = value; + view::shields_set(value); +} + fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec) { let course = param_or_prompt_value(&provided, 0, "Course (1-9)?", 1, 9); diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index f460eaa7b..95cad41d9 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -174,3 +174,20 @@ pub fn insuffient_warp_energy(warp_speed: f32) { pub fn divert_energy_from_shields() { println!("Shield Control supplies energy to complete the maneuver.") } + +pub fn energy_available(total_energy: u16) { + println!("Energy available = {{{total_energy}}}") +} + +pub fn shields_unchanged() { + println!("") +} + +pub fn ridiculous() { + println!("Shield Control reports, 'This is not the Federation Treasury.'") +} + +pub fn shields_set(value: u16) { + println!("Deflector control room report: + 'Shields now at {value} units per your command.'") +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index da2b9c1bd..7c7e1df8d 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -7,9 +7,9 @@ Started after movement and display of stats was finished (no energy management o - [x] add intro - [x] add entering (and starting in) sector headers - [x] conditions and danger messages -- [ ] remove energy on move -- [ ] shields - - [ ] shield control +- [x] remove energy on move +- [x] shields + - [x] shield control - [ ] shield hit absorption - [ ] subsystem damage - and support for reports From 2898e701c3504192816172192e16c5c868e0cbd5 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 11:41:43 +1300 Subject: [PATCH 045/377] shield hit absorbtion --- 84_Super_Star_Trek/rust/src/model.rs | 4 ++-- 84_Super_Star_Trek/rust/src/view.rs | 4 ++++ 84_Super_Star_Trek/rust/tasks.md | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 103887f5b..4f5a65acb 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -52,14 +52,14 @@ impl Enterprise { view::enterprise_hit(&hit_strength, §or); - // absorb into shields + self.shields = (self.shields - hit_strength).max(0); if self.shields <= 0 { view::enterprise_destroyed(); self.destroyed = true } - // report shields + view::shields_hit(self.shields); // take damage if strength is greater than 20 } } diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 95cad41d9..02c728159 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -191,3 +191,7 @@ pub fn shields_set(value: u16) { println!("Deflector control room report: 'Shields now at {value} units per your command.'") } + +pub fn shields_hit(shields: u16) { + println!(" ") +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 7c7e1df8d..918a03950 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -10,7 +10,7 @@ Started after movement and display of stats was finished (no energy management o - [x] remove energy on move - [x] shields - [x] shield control - - [ ] shield hit absorption + - [x] shield hit absorption - [ ] subsystem damage - and support for reports - [ ] lrs? From 5b560f929ce66cb0884f9df2b5eb2cb1864fa3e6 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 11:48:24 +1300 Subject: [PATCH 046/377] trimmed edge tests in nav, and removed no longer needed unit tests --- 84_Super_Star_Trek/rust/src/commands.rs | 95 +------------------------ 1 file changed, 3 insertions(+), 92 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 3cc4aff56..2f42edd5e 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -56,23 +56,9 @@ fn find_end_quadrant_sector(start_quadrant: Pos, start_sector: Pos, course: u8, let mut nx = (galaxy_pos.0 as i8) + dx * distance; let mut ny = (galaxy_pos.1 as i8) + dy * distance; - let mut hit_edge = false; - if nx < 0 { - nx = 0; - hit_edge = true; - } - if ny < 0 { - ny = 0; - hit_edge = true; - } - if nx >= 64 { - nx = 63; - hit_edge = true; - } - if ny >= 64 { - ny = 63; - hit_edge = true; - } + let hit_edge = nx < 0 || ny < 0 || nx >= 64 || ny >= 64; + nx = nx.min(63).max(0); + ny = ny.min(63).max(0); let quadrant = Pos((nx / 8) as u8, (ny / 8) as u8); let sector = Pos((nx % 8) as u8, (ny % 8) as u8); @@ -94,78 +80,3 @@ pub fn move_klingons_and_fire(galaxy: &mut Galaxy) { quadrant.klingons[k].fire_on(&mut galaxy.enterprise); } } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_course_east() { - let start_quadrant = Pos(0,0); - let start_sector = Pos(0,0); - let end = find_end_quadrant_sector(start_quadrant, start_sector, 1, 0.1); - assert_eq!(end.quadrant, start_quadrant, "right quadrant"); - assert_eq!(end.sector, Pos(1,0), "right sector"); - assert!(!end.hit_edge) - } - - #[test] - fn test_course_far_east() { - let start_quadrant = Pos(0,0); - let start_sector = Pos(0,0); - let end = find_end_quadrant_sector(start_quadrant, start_sector, 1, 1.0); - assert_eq!(end.quadrant, Pos(1,0), "right quadrant"); - assert_eq!(end.sector, start_sector, "right sector"); - assert!(!end.hit_edge) - } - - #[test] - fn test_course_too_far_east() { - let start_quadrant = Pos(0,0); - let start_sector = Pos(0,0); - let end = find_end_quadrant_sector(start_quadrant, start_sector, 1, 8.0); - assert_eq!(end.quadrant, Pos(7,0), "right quadrant"); - assert_eq!(end.sector, Pos(7,0), "right sector"); - assert!(end.hit_edge) - } - - #[test] - fn test_course_south() { - let start_quadrant = Pos(0,0); - let start_sector = Pos(0,0); - let end = find_end_quadrant_sector(start_quadrant, start_sector, 7, 0.1); - assert_eq!(end.quadrant, start_quadrant, "right quadrant"); - assert_eq!(end.sector, Pos(0,1), "right sector"); - assert!(!end.hit_edge) - } - - #[test] - fn test_course_far_south() { - let start_quadrant = Pos(0,0); - let start_sector = Pos(0,0); - let end = find_end_quadrant_sector(start_quadrant, start_sector, 7, 1.0); - assert_eq!(end.quadrant, Pos(0,1), "right quadrant"); - assert_eq!(end.sector, start_sector, "right sector"); - assert!(!end.hit_edge) - } - - #[test] - fn test_course_too_far_south() { - let start_quadrant = Pos(0,0); - let start_sector = Pos(0,0); - let end = find_end_quadrant_sector(start_quadrant, start_sector, 7, 8.0); - assert_eq!(end.quadrant, Pos(0,7), "right quadrant"); - assert_eq!(end.sector, Pos(0,7), "right sector"); - assert!(end.hit_edge) - } - - #[test] - fn test_course_north_east() { - let start_quadrant = Pos(0,0); - let start_sector = Pos(0,1); - let end = find_end_quadrant_sector(start_quadrant, start_sector, 2, 0.1); - assert_eq!(end.quadrant, start_quadrant, "right quadrant"); - assert_eq!(end.sector, Pos(1,0), "right sector"); - assert!(!end.hit_edge) - } -} From d7e3feff54689f5830a5c39d25ec263dde26f108 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 11:53:33 +1300 Subject: [PATCH 047/377] some reorganisation of code --- 84_Super_Star_Trek/rust/src/commands.rs | 48 ++++++++++++- 84_Super_Star_Trek/rust/src/input.rs | 37 ++++++++++ 84_Super_Star_Trek/rust/src/main.rs | 90 +++---------------------- 3 files changed, 90 insertions(+), 85 deletions(-) create mode 100644 84_Super_Star_Trek/rust/src/input.rs diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 2f42edd5e..3239b45ee 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,6 +1,48 @@ -use crate::{model::{Galaxy, Pos, COURSES, EndPosition}, view}; +use crate::{model::{Galaxy, Pos, COURSES, EndPosition}, view, input}; -pub fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { +pub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { + + // todo check for damaged module + + view::energy_available(galaxy.enterprise.total_energy); + let value = input::param_or_prompt_value(&provided, 0, "Number of units to shields", 0, i32::MAX); + if value.is_none() { + view::shields_unchanged(); + return; + } + let value = value.unwrap() as u16; + if value > galaxy.enterprise.total_energy { + view::ridiculous(); + view::shields_unchanged(); + return; + } + + galaxy.enterprise.shields = value; + view::shields_set(value); +} + +pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec) { + + let course = input::param_or_prompt_value(&provided, 0, "Course (1-9)?", 1, 9); + if course.is_none() { + view::bad_nav(); + return; + } + + let speed = input::param_or_prompt_value(&provided, 1, "Warp Factor (0-8)?", 0.0, 8.0); + if speed.is_none() { + view::bad_nav(); + return; + } + + move_klingons_and_fire(galaxy); + if galaxy.enterprise.destroyed { + return; + } + move_enterprise(course.unwrap(), speed.unwrap(), galaxy); +} + +fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { let ship = &mut galaxy.enterprise; @@ -67,7 +109,7 @@ fn find_end_quadrant_sector(start_quadrant: Pos, start_sector: Pos, course: u8, EndPosition { quadrant, sector, hit_edge, energy_cost } } -pub fn move_klingons_and_fire(galaxy: &mut Galaxy) { +fn move_klingons_and_fire(galaxy: &mut Galaxy) { let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; for k in 0..quadrant.klingons.len() { let new_sector = quadrant.find_empty_sector(); diff --git a/84_Super_Star_Trek/rust/src/input.rs b/84_Super_Star_Trek/rust/src/input.rs new file mode 100644 index 000000000..75f121023 --- /dev/null +++ b/84_Super_Star_Trek/rust/src/input.rs @@ -0,0 +1,37 @@ +use std::{io::{stdin, stdout, Write}, str::FromStr}; + +pub fn prompt(prompt_text: &str) -> Vec { + let stdin = stdin(); + let mut stdout = stdout(); + + print!("{prompt_text} "); + let _ = stdout.flush(); + + let mut buffer = String::new(); + if let Ok(_) = stdin.read_line(&mut buffer) { + return buffer.trim_end().split(" ").map(|s| s.to_string()).collect(); + } + Vec::new() +} + +pub fn prompt_value(prompt_text: &str, min: T, max: T) -> Option { + let passed = prompt(prompt_text); + if passed.len() != 1 { + return None + } + match passed[0].parse::() { + Ok(n) if (n >= min && n <= max) => Some(n), + _ => None + } +} + +pub fn param_or_prompt_value(params: &Vec, param_pos: usize, prompt_text: &str, min: T, max: T) -> Option { + if params.len() > param_pos { + match params[param_pos].parse::() { + Ok(n) => Some(n), + _ => None + } + } else { + return prompt_value::(prompt_text, min, max); + } +} \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 477a0594e..1b9a0522a 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,7 +1,8 @@ -use std::{io::{stdin, stdout, Write, Read}, process::exit, str::FromStr}; +use std::process::exit; use model::Galaxy; +mod input; mod model; mod commands; mod view; @@ -14,104 +15,29 @@ fn main() { view::enterprise(); view::intro(&galaxy); - let _ = prompt("Press Enter when ready to accept command"); + let _ = input::prompt("Press Enter when ready to accept command"); view::starting_quadrant(&galaxy.enterprise.quadrant); view::short_range_scan(&galaxy); loop { - let command = prompt("Command?"); + let command = input::prompt("Command?"); if command.len() == 0 { continue; } match command[0].to_uppercase().as_str() { "SRS" => view::short_range_scan(&galaxy), - "NAV" => gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), - "SHE" => get_amount_and_set_shields(&mut galaxy, command[1..].into()), + "NAV" => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), + "SHE" => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), _ => view::print_command_help() } if galaxy.enterprise.destroyed { // todo: also check if stranded view::end_game_failure(&galaxy); + // todo check if can restart break; } - } -} - -fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { - - // todo check for damaged module - - view::energy_available(galaxy.enterprise.total_energy); - let value = param_or_prompt_value(&provided, 0, "Number of units to shields", 0, i32::MAX); - if value.is_none() { - view::shields_unchanged(); - return; - } - let value = value.unwrap() as u16; - if value > galaxy.enterprise.total_energy { - view::ridiculous(); - view::shields_unchanged(); - return; - } - - galaxy.enterprise.shields = value; - view::shields_set(value); -} - -fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec) { - - let course = param_or_prompt_value(&provided, 0, "Course (1-9)?", 1, 9); - if course.is_none() { - view::bad_nav(); - return; - } - - let speed = param_or_prompt_value(&provided, 1, "Warp Factor (0-8)?", 0.0, 8.0); - if speed.is_none() { - view::bad_nav(); - return; - } - commands::move_klingons_and_fire(galaxy); - if galaxy.enterprise.destroyed { - return; + // todo check for victory } - commands::move_enterprise(course.unwrap(), speed.unwrap(), galaxy); } - -fn prompt(prompt_text: &str) -> Vec { - let stdin = stdin(); - let mut stdout = stdout(); - - print!("{prompt_text} "); - let _ = stdout.flush(); - - let mut buffer = String::new(); - if let Ok(_) = stdin.read_line(&mut buffer) { - return buffer.trim_end().split(" ").map(|s| s.to_string()).collect(); - } - Vec::new() -} - -fn prompt_value(prompt_text: &str, min: T, max: T) -> Option { - let passed = prompt(prompt_text); - if passed.len() != 1 { - return None - } - match passed[0].parse::() { - Ok(n) if (n >= min && n <= max) => Some(n), - _ => None - } -} - -fn param_or_prompt_value(params: &Vec, param_pos: usize, prompt_text: &str, min: T, max: T) -> Option { - if params.len() > param_pos { - match params[param_pos].parse::() { - Ok(n) => Some(n), - _ => None - } - } else { - return prompt_value::(prompt_text, min, max); - } -} \ No newline at end of file From bcb1c68cb54293090b77253071226c33a0745f53 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 11:55:55 +1300 Subject: [PATCH 048/377] added some tasks --- 84_Super_Star_Trek/rust/tasks.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 918a03950..29f47cd36 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -19,3 +19,9 @@ Started after movement and display of stats was finished (no energy management o - when moving across a sector, the enterprise should stop before it runs into something - the current move is a jump, which makes this problematic. would need to rewrite it - [x] better command reading - support entering multiple values on a line (e.g. nav 3 0.1) +- [ ] starbases + - [ ] repair +- [ ] weapons + - [ ] phasers + - [ ] torpedoes +- [ ] restarting the game From 0581fe38f81b42bc81f8dd8d1b80b7ba80781aa8 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 13:36:30 +1300 Subject: [PATCH 049/377] basic damage to systems and restricted warp speed --- 84_Super_Star_Trek/rust/src/commands.rs | 33 ++++++++++++++++++++++--- 84_Super_Star_Trek/rust/src/main.rs | 6 ++--- 84_Super_Star_Trek/rust/src/model.rs | 6 ++--- 84_Super_Star_Trek/rust/src/view.rs | 25 ++++++++++++++++++- 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 3239b45ee..0675ee4f9 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,8 +1,20 @@ use crate::{model::{Galaxy, Pos, COURSES, EndPosition}, view, input}; +pub fn perform_short_range_scan(galaxy: &Galaxy) { + if galaxy.enterprise.damaged.contains_key(view::keys::SHORT_RANGE_SCAN) { + view::scanners_out(); + return; + } + + view::short_range_scan(&galaxy) +} + pub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { - // todo check for damaged module + if galaxy.enterprise.damaged.contains_key(view::keys::SHIELD_CONTROL) { + view::inoperable("Shield Control"); + return; + } view::energy_available(galaxy.enterprise.total_energy); let value = input::param_or_prompt_value(&provided, 0, "Number of units to shields", 0, i32::MAX); @@ -10,6 +22,7 @@ pub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { view::shields_unchanged(); return; } + let value = value.unwrap() as u16; if value > galaxy.enterprise.total_energy { view::ridiculous(); @@ -29,17 +42,31 @@ pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec return; } - let speed = input::param_or_prompt_value(&provided, 1, "Warp Factor (0-8)?", 0.0, 8.0); + let course = course.unwrap(); + + let mut max_warp = 8.0; + if galaxy.enterprise.damaged.contains_key(view::keys::NAVIGATION) { + max_warp = 0.2; + } + + let speed = input::param_or_prompt_value(&provided, 1, format!("Warp Factor (0-{})?", max_warp).as_str(), 0.0, 8.0); if speed.is_none() { view::bad_nav(); return; } + + let speed = speed.unwrap(); + + if speed > max_warp { + view::damaged_engines(max_warp, speed); + return; + } move_klingons_and_fire(galaxy); if galaxy.enterprise.destroyed { return; } - move_enterprise(course.unwrap(), speed.unwrap(), galaxy); + move_enterprise(course, speed, galaxy); } fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 1b9a0522a..ecde04767 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -26,9 +26,9 @@ fn main() { continue; } match command[0].to_uppercase().as_str() { - "SRS" => view::short_range_scan(&galaxy), - "NAV" => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), - "SHE" => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), + view::keys::SHORT_RANGE_SCAN => commands::perform_short_range_scan(&galaxy), + view::keys::NAVIGATION => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), + view::keys::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), _ => view::print_command_help() } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 4f5a65acb..a078df05d 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -1,4 +1,4 @@ -use std::{ops::{Mul, Add}, fmt::Display}; +use std::{ops::{Mul, Add}, fmt::Display, collections::HashMap}; use rand::Rng; @@ -37,7 +37,7 @@ impl Klingon { pub struct Enterprise { pub destroyed: bool, - pub damaged: bool, // later this could be by subsystem + pub damaged: HashMap, pub quadrant: Pos, pub sector: Pos, pub photon_torpedoes: u8, @@ -147,7 +147,7 @@ impl Galaxy { quadrants: quadrants, enterprise: Enterprise { destroyed: false, - damaged: false, + damaged: HashMap::new(), quadrant: enterprise_quadrant, sector: enterprise_sector, photon_torpedoes: 28, diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 02c728159..689345499 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -1,5 +1,15 @@ use crate::model::{Galaxy, Pos, EndPosition, SectorStatus}; +pub mod keys { + pub const SHORT_RANGE_SCAN: &str = "SRS"; + pub const NAVIGATION: &str = "NAV"; + pub const SHIELD_CONTROL: &str = "SHE"; + + pub const ALL_SYSTEMS: [&str; 3] = [ + SHORT_RANGE_SCAN, NAVIGATION, SHIELD_CONTROL + ]; +} + pub fn enterprise() { println!(" @@ -82,7 +92,7 @@ pub fn short_range_scan(model: &Galaxy) { let mut condition = "GREEN"; if quadrant.klingons.len() > 0 { condition = "*RED*"; - } else if model.enterprise.damaged { + } else if model.enterprise.damaged.len() > 0 { condition = "YELLOW"; } @@ -195,3 +205,16 @@ pub fn shields_set(value: u16) { pub fn shields_hit(shields: u16) { println!(" ") } + +pub fn inoperable(arg: &str) { + println!("{} inoperable", arg) +} + +pub fn scanners_out() { + println!("*** Short Range Sensors are out ***") +} + +pub fn damaged_engines(max_warp: f32, warp_factor: f32) { + println!("Warp engines are damaged. Maximum speed = warp {max_warp} + Chief Engineer Scott reports, 'The engines won't take warp {warp_factor} !'") +} From f253ff7155a140c5903f1a1bd742ad46f175d585 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 13:39:12 +1300 Subject: [PATCH 050/377] moved where system keys are defined --- 84_Super_Star_Trek/rust/src/commands.rs | 10 ++++------ 84_Super_Star_Trek/rust/src/main.rs | 6 +++--- 84_Super_Star_Trek/rust/src/model.rs | 10 ++++++++++ 84_Super_Star_Trek/rust/src/view.rs | 10 ---------- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 0675ee4f9..86c72f98a 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,7 +1,7 @@ -use crate::{model::{Galaxy, Pos, COURSES, EndPosition}, view, input}; +use crate::{model::{Galaxy, Pos, COURSES, EndPosition, self}, view, input}; pub fn perform_short_range_scan(galaxy: &Galaxy) { - if galaxy.enterprise.damaged.contains_key(view::keys::SHORT_RANGE_SCAN) { + if galaxy.enterprise.damaged.contains_key(model::systems::SHORT_RANGE_SCAN) { view::scanners_out(); return; } @@ -11,7 +11,7 @@ pub fn perform_short_range_scan(galaxy: &Galaxy) { pub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { - if galaxy.enterprise.damaged.contains_key(view::keys::SHIELD_CONTROL) { + if galaxy.enterprise.damaged.contains_key(model::systems::SHIELD_CONTROL) { view::inoperable("Shield Control"); return; } @@ -45,7 +45,7 @@ pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec let course = course.unwrap(); let mut max_warp = 8.0; - if galaxy.enterprise.damaged.contains_key(view::keys::NAVIGATION) { + if galaxy.enterprise.damaged.contains_key(model::systems::WARP_ENGINES) { max_warp = 0.2; } @@ -77,8 +77,6 @@ fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { let end = find_end_quadrant_sector(ship.quadrant, ship.sector, course, warp_speed); - // todo account for engine damage - if end.energy_cost > ship.total_energy { view::insuffient_warp_energy(warp_speed); return diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index ecde04767..5db8350ca 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -26,9 +26,9 @@ fn main() { continue; } match command[0].to_uppercase().as_str() { - view::keys::SHORT_RANGE_SCAN => commands::perform_short_range_scan(&galaxy), - view::keys::NAVIGATION => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), - view::keys::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), + model::systems::SHORT_RANGE_SCAN => commands::perform_short_range_scan(&galaxy), + model::systems::WARP_ENGINES => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), + model::systems::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), _ => view::print_command_help() } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index a078df05d..f46cc548a 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -64,6 +64,16 @@ impl Enterprise { } } +pub mod systems { + pub const SHORT_RANGE_SCAN: &str = "SRS"; + pub const WARP_ENGINES: &str = "NAV"; + pub const SHIELD_CONTROL: &str = "SHE"; + + pub const ALL: [&str; 3] = [ + SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL + ]; +} + pub struct EndPosition { pub quadrant: Pos, pub sector: Pos, diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 689345499..e7bc55162 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -1,15 +1,5 @@ use crate::model::{Galaxy, Pos, EndPosition, SectorStatus}; -pub mod keys { - pub const SHORT_RANGE_SCAN: &str = "SRS"; - pub const NAVIGATION: &str = "NAV"; - pub const SHIELD_CONTROL: &str = "SHE"; - - pub const ALL_SYSTEMS: [&str; 3] = [ - SHORT_RANGE_SCAN, NAVIGATION, SHIELD_CONTROL - ]; -} - pub fn enterprise() { println!(" From cb685efe0cc32112242d4f657ee802505d2e6dc4 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 13:48:42 +1300 Subject: [PATCH 051/377] random system damage on hit --- 84_Super_Star_Trek/rust/src/commands.rs | 1 - 84_Super_Star_Trek/rust/src/model.rs | 17 +++++++++++++++++ 84_Super_Star_Trek/rust/tasks.md | 5 +++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 86c72f98a..c5e59c122 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -86,7 +86,6 @@ fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { view::hit_edge(&end); } - if ship.quadrant != end.quadrant { view::enter_quadrant(&end.quadrant); diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index f46cc548a..c968c08a2 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -60,7 +60,24 @@ impl Enterprise { } view::shields_hit(self.shields); + // take damage if strength is greater than 20 + if hit_strength >= 20 { + self.take_damage(hit_strength) + } + } + + fn take_damage(&mut self, hit_strength: u16) { + let mut rng = rand::thread_rng(); + + let hit_past_shield = hit_strength as f32 / self.shields as f32; + if rng.gen::() > 0.6 || hit_past_shield < 0.02 { + return + } + + let system = systems::ALL[rng.gen_range(0..systems::ALL.len())].to_string(); + let damage = hit_past_shield + rng.gen::() * 0.5; + self.damaged.entry(system).and_modify(|d| *d += damage).or_insert(damage); } } diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 29f47cd36..c55914df2 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -11,8 +11,9 @@ Started after movement and display of stats was finished (no energy management o - [x] shields - [x] shield control - [x] shield hit absorption -- [ ] subsystem damage - - and support for reports +- [x] subsystem damage + - [ ] and support for reports +- [ ] random system damage on move - [ ] lrs? - [ ] stranded... - [ ] stop before hitting an object From 33fc2b4c5a9a833fe73794e74a8c1c071c72afb5 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 14:11:49 +1300 Subject: [PATCH 052/377] implemented damage command --- 84_Super_Star_Trek/rust/src/commands.rs | 16 +++++++++++++++- 84_Super_Star_Trek/rust/src/main.rs | 1 + 84_Super_Star_Trek/rust/src/model.rs | 14 ++++++++++---- 84_Super_Star_Trek/rust/tasks.md | 2 +- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index c5e59c122..2bc5f4f63 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,4 +1,4 @@ -use crate::{model::{Galaxy, Pos, COURSES, EndPosition, self}, view, input}; +use crate::{model::{Galaxy, Pos, COURSES, EndPosition, self, Enterprise, systems}, view, input}; pub fn perform_short_range_scan(galaxy: &Galaxy) { if galaxy.enterprise.damaged.contains_key(model::systems::SHORT_RANGE_SCAN) { @@ -146,3 +146,17 @@ fn move_klingons_and_fire(galaxy: &mut Galaxy) { quadrant.klingons[k].fire_on(&mut galaxy.enterprise); } } + +pub fn display_damage_control(enterprise: &Enterprise) { + if enterprise.damaged.contains_key(model::systems::DAMAGE_CONTROL) { + view::inoperable("Damage Control"); + return; + } + + println!("Device State of Repair"); + for i in 0..systems::NAMES.len() { + let damage = enterprise.damaged.get(systems::ALL[i]).unwrap_or(&0.0); + println!("{:<25}{}", systems::NAMES[i], damage) + } + println!(); +} diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 5db8350ca..0809ec235 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -29,6 +29,7 @@ fn main() { model::systems::SHORT_RANGE_SCAN => commands::perform_short_range_scan(&galaxy), model::systems::WARP_ENGINES => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), model::systems::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), + model::systems::DAMAGE_CONTROL => commands::display_damage_control(&galaxy.enterprise), _ => view::print_command_help() } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index c968c08a2..675ac8ecb 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -61,7 +61,6 @@ impl Enterprise { view::shields_hit(self.shields); - // take damage if strength is greater than 20 if hit_strength >= 20 { self.take_damage(hit_strength) } @@ -77,17 +76,24 @@ impl Enterprise { let system = systems::ALL[rng.gen_range(0..systems::ALL.len())].to_string(); let damage = hit_past_shield + rng.gen::() * 0.5; - self.damaged.entry(system).and_modify(|d| *d += damage).or_insert(damage); + self.damaged.entry(system).and_modify(|d| *d -= damage).or_insert(-damage); } } pub mod systems { + use std::collections::HashMap; + pub const SHORT_RANGE_SCAN: &str = "SRS"; pub const WARP_ENGINES: &str = "NAV"; pub const SHIELD_CONTROL: &str = "SHE"; + pub const DAMAGE_CONTROL: &str = "DAM"; + + pub const ALL: [&str; 4] = [ + SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL + ]; - pub const ALL: [&str; 3] = [ - SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL + pub const NAMES: [&str; 4] = [ + "Short Range Scanners", "Warp Engines", "Shield Control", "Damage Control" ]; } diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index c55914df2..e6c68ce15 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -12,7 +12,7 @@ Started after movement and display of stats was finished (no energy management o - [x] shield control - [x] shield hit absorption - [x] subsystem damage - - [ ] and support for reports + - [x] and support for reports - [ ] random system damage on move - [ ] lrs? - [ ] stranded... From 51663ea0b168b2ee6915b9b198a6b74ec864c9fb Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 17:13:52 +1300 Subject: [PATCH 053/377] implemented random system movement changes damage and repair, with changes to how this is implemented / reported --- 84_Super_Star_Trek/rust/src/commands.rs | 52 +++++++++++++++++++++++-- 84_Super_Star_Trek/rust/src/model.rs | 34 ++++++++++++---- 84_Super_Star_Trek/rust/src/view.rs | 16 ++++++++ 84_Super_Star_Trek/rust/tasks.md | 2 +- 4 files changed, 93 insertions(+), 11 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 2bc5f4f63..3b14e4cf8 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,3 +1,5 @@ +use rand::Rng; + use crate::{model::{Galaxy, Pos, COURSES, EndPosition, self, Enterprise, systems}, view, input}; pub fn perform_short_range_scan(galaxy: &Galaxy) { @@ -66,9 +68,53 @@ pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec if galaxy.enterprise.destroyed { return; } + + repair_systems(&mut galaxy.enterprise, speed); + repair_or_damage_random_system(&mut galaxy.enterprise); + move_enterprise(course, speed, galaxy); } +fn repair_systems(enterprise: &mut Enterprise, amount: f32) { + + let keys: Vec = enterprise.damaged.keys().map(|k| k.to_string()).collect(); + let mut repaired = Vec::new(); + for key in keys { + let fully_fixed = enterprise.repair_system(&key, amount); + if fully_fixed { + repaired.push(systems::name_for(&key)); + } + } + + if repaired.len() <= 0 { + return; + } + + view::damage_control_report(); + for name in repaired { + view::system_repair_completed(name); + } +} + +fn repair_or_damage_random_system(enterprise: &mut Enterprise) { + let mut rng = rand::thread_rng(); + + if rng.gen::() > 0.2 { + return; + } + + let system = systems::KEYS[rng.gen_range(0..systems::KEYS.len())].to_string(); + let system_name = &systems::name_for(&system); + + if rng.gen::() >= 0.6 { + enterprise.repair_system(&system, rng.gen::() * 3.0 + 1.0); + view::random_repair_report_for(system_name, false); + } else { + enterprise.damage_system(&system, rng.gen::() * 5.0 + 1.0); + view::random_repair_report_for(system_name, true); + } +} + fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { let ship = &mut galaxy.enterprise; @@ -154,9 +200,9 @@ pub fn display_damage_control(enterprise: &Enterprise) { } println!("Device State of Repair"); - for i in 0..systems::NAMES.len() { - let damage = enterprise.damaged.get(systems::ALL[i]).unwrap_or(&0.0); - println!("{:<25}{}", systems::NAMES[i], damage) + for key in systems::KEYS { + let damage = enterprise.damaged.get(key).unwrap_or(&0.0); + println!("{:<25}{}", systems::name_for(key), damage) } println!(); } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 675ac8ecb..515b7fb2e 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -74,27 +74,47 @@ impl Enterprise { return } - let system = systems::ALL[rng.gen_range(0..systems::ALL.len())].to_string(); + let system = systems::KEYS[rng.gen_range(0..systems::KEYS.len())].to_string(); let damage = hit_past_shield + rng.gen::() * 0.5; - self.damaged.entry(system).and_modify(|d| *d -= damage).or_insert(-damage); + self.damage_system(&system, damage); + } + + pub fn damage_system(&mut self, system: &str, damage: f32) { + self.damaged.entry(system.to_string()).and_modify(|d| *d -= damage).or_insert(-damage); + } + + pub fn repair_system(&mut self, system: &str, amount: f32) -> bool { + let existing_damage = self.damaged[system]; + if existing_damage + amount >= 0.0 { + self.damaged.remove(system); + return true; + } + + self.damaged.entry(system.to_string()).and_modify(|d| *d += amount); + return false; } } pub mod systems { - use std::collections::HashMap; pub const SHORT_RANGE_SCAN: &str = "SRS"; pub const WARP_ENGINES: &str = "NAV"; pub const SHIELD_CONTROL: &str = "SHE"; pub const DAMAGE_CONTROL: &str = "DAM"; - pub const ALL: [&str; 4] = [ + pub const KEYS: [&str; 4] = [ SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL ]; - pub const NAMES: [&str; 4] = [ - "Short Range Scanners", "Warp Engines", "Shield Control", "Damage Control" - ]; + pub fn name_for(key: &str) -> String { + match key { + SHORT_RANGE_SCAN => "Short Range Scanners".into(), + WARP_ENGINES => "Warp Engines".into(), + SHIELD_CONTROL => "Shield Control".into(), + DAMAGE_CONTROL => "Damage Control".into(), + _ => "Unknown".into() + } + } } pub struct EndPosition { diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index e7bc55162..e34c44d4c 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -208,3 +208,19 @@ pub fn damaged_engines(max_warp: f32, warp_factor: f32) { println!("Warp engines are damaged. Maximum speed = warp {max_warp} Chief Engineer Scott reports, 'The engines won't take warp {warp_factor} !'") } + +pub fn damage_control_report() { + println!("Damage Control report:") +} + +pub fn random_repair_report_for(name: &str, damaged: bool) { + let mut message = "state of repair improved"; + if damaged { + message = "damaged"; + } + println!("Damage Control report: {name} {message}") +} + +pub fn system_repair_completed(name: String) { + println!(" {name} repair completed.") +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index e6c68ce15..0c81bce1b 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -13,7 +13,7 @@ Started after movement and display of stats was finished (no energy management o - [x] shield hit absorption - [x] subsystem damage - [x] and support for reports -- [ ] random system damage on move +- [x] random system damage or repairs on move - [ ] lrs? - [ ] stranded... - [ ] stop before hitting an object From 4644a91024b2e0d5dfd70d68bf8b3cca61e01b66 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 18:56:47 +1300 Subject: [PATCH 054/377] implemented long range scanners --- 84_Super_Star_Trek/rust/src/commands.rs | 9 +++++++++ 84_Super_Star_Trek/rust/src/main.rs | 3 ++- 84_Super_Star_Trek/rust/src/model.rs | 6 ++++-- 84_Super_Star_Trek/rust/src/view.rs | 27 +++++++++++++++++++++++++ 84_Super_Star_Trek/rust/tasks.md | 3 +++ 5 files changed, 45 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 3b14e4cf8..25c2954d9 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -206,3 +206,12 @@ pub fn display_damage_control(enterprise: &Enterprise) { } println!(); } + +pub fn perform_long_range_scan(galaxy: &Galaxy) { + if galaxy.enterprise.damaged.contains_key(model::systems::SHORT_RANGE_SCAN) { + view::inoperable("Long Range Scanners"); + return; + } + + view::long_range_scan(galaxy); +} \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 0809ec235..fd01b9b52 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -25,11 +25,12 @@ fn main() { if command.len() == 0 { continue; } - match command[0].to_uppercase().as_str() { + match command[0].to_uppercase().as_str() { // order is weird because i built it in this order :) model::systems::SHORT_RANGE_SCAN => commands::perform_short_range_scan(&galaxy), model::systems::WARP_ENGINES => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), model::systems::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), model::systems::DAMAGE_CONTROL => commands::display_damage_control(&galaxy.enterprise), + model::systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&galaxy), _ => view::print_command_help() } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 515b7fb2e..f502a13f9 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -101,9 +101,10 @@ pub mod systems { pub const WARP_ENGINES: &str = "NAV"; pub const SHIELD_CONTROL: &str = "SHE"; pub const DAMAGE_CONTROL: &str = "DAM"; + pub const LONG_RANGE_SCAN: &str = "LRS"; - pub const KEYS: [&str; 4] = [ - SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL + pub const KEYS: [&str; 5] = [ + SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL, LONG_RANGE_SCAN ]; pub fn name_for(key: &str) -> String { @@ -112,6 +113,7 @@ pub mod systems { WARP_ENGINES => "Warp Engines".into(), SHIELD_CONTROL => "Shield Control".into(), DAMAGE_CONTROL => "Damage Control".into(), + LONG_RANGE_SCAN => "Long Range Scanners".into(), _ => "Unknown".into() } } diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index e34c44d4c..26daf0703 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -224,3 +224,30 @@ pub fn random_repair_report_for(name: &str, damaged: bool) { pub fn system_repair_completed(name: String) { println!(" {name} repair completed.") } + +pub fn long_range_scan(galaxy: &Galaxy) { + + let cx = galaxy.enterprise.quadrant.0 as i8; + let cy = galaxy.enterprise.quadrant.1 as i8; + + println!("Long range scan for quadrant {}", galaxy.enterprise.quadrant); + println!("{:-^19}", ""); + for y in cy - 1..=cy + 1 { + for x in cx - 1..=cx + 1 { + let mut klingons = "*".into(); + let mut star_bases = "*".into(); + let mut stars = "*".into(); + + if y >= 0 && y < 8 && x >= 0 && x < 8 { + let quadrant = &galaxy.quadrants[Pos(x as u8, y as u8).as_index()]; + klingons = format!("{}", quadrant.klingons.len()); + star_bases = quadrant.star_base.map_or("0", |_| "1"); + stars = format!("{}", quadrant.stars.len()); + } + + print!(": {}{}{} ", klingons, stars, star_bases) + } + println!(":"); + println!("{:-^19}", ""); + } +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 0c81bce1b..8dd2d166e 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -19,6 +19,7 @@ Started after movement and display of stats was finished (no energy management o - [ ] stop before hitting an object - when moving across a sector, the enterprise should stop before it runs into something - the current move is a jump, which makes this problematic. would need to rewrite it + - also, movement courses could be floats, according to the instructions, allowing for more precise movement and aiming - [x] better command reading - support entering multiple values on a line (e.g. nav 3 0.1) - [ ] starbases - [ ] repair @@ -26,3 +27,5 @@ Started after movement and display of stats was finished (no energy management o - [ ] phasers - [ ] torpedoes - [ ] restarting the game +- [ ] time progression + - check all areas where time should move, and adjust accordingly From 460dcd7ab44ca6c3df435b33a43e698f17335c3b Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 18:57:53 +1300 Subject: [PATCH 055/377] slight tweak to allow close to fixed to be fixed --- 84_Super_Star_Trek/rust/src/model.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index f502a13f9..a55eb62f4 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -85,7 +85,7 @@ impl Enterprise { pub fn repair_system(&mut self, system: &str, amount: f32) -> bool { let existing_damage = self.damaged[system]; - if existing_damage + amount >= 0.0 { + if existing_damage + amount >= -0.1 { self.damaged.remove(system); return true; } From d76b0482369cff2c82a83ac9804d78f3aaad6835 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 19:01:48 +1300 Subject: [PATCH 056/377] revised random repair or damage to only repair damaged systems --- 84_Super_Star_Trek/rust/src/commands.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 25c2954d9..099b54961 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -103,16 +103,25 @@ fn repair_or_damage_random_system(enterprise: &mut Enterprise) { return; } - let system = systems::KEYS[rng.gen_range(0..systems::KEYS.len())].to_string(); - let system_name = &systems::name_for(&system); - if rng.gen::() >= 0.6 { + if enterprise.damaged.len() == 0 { + return; + } + + let damaged: Vec = enterprise.damaged.keys().map(|k| k.to_string()).collect(); + let system = damaged[rng.gen_range(0..damaged.len())].to_string(); + let system_name = &systems::name_for(&system); + enterprise.repair_system(&system, rng.gen::() * 3.0 + 1.0); view::random_repair_report_for(system_name, false); - } else { - enterprise.damage_system(&system, rng.gen::() * 5.0 + 1.0); - view::random_repair_report_for(system_name, true); + return; } + + let system = systems::KEYS[rng.gen_range(0..systems::KEYS.len())].to_string(); + let system_name = &systems::name_for(&system); + + enterprise.damage_system(&system, rng.gen::() * 5.0 + 1.0); + view::random_repair_report_for(system_name, true); } fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { From 2360bfd0c2dd869025a4ff46490852178f785ac7 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 19:08:21 +1300 Subject: [PATCH 057/377] implemented getting stranded --- 84_Super_Star_Trek/rust/src/main.rs | 2 +- 84_Super_Star_Trek/rust/src/model.rs | 8 ++++++++ 84_Super_Star_Trek/rust/src/view.rs | 6 ++++++ 84_Super_Star_Trek/rust/tasks.md | 5 +++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index fd01b9b52..385d122ce 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -34,7 +34,7 @@ fn main() { _ => view::print_command_help() } - if galaxy.enterprise.destroyed { // todo: also check if stranded + if galaxy.enterprise.destroyed || galaxy.enterprise.check_stranded() { view::end_game_failure(&galaxy); // todo check if can restart break; diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index a55eb62f4..f231124c5 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -93,6 +93,14 @@ impl Enterprise { self.damaged.entry(system.to_string()).and_modify(|d| *d += amount); return false; } + + pub fn check_stranded(&self) -> bool { + if self.total_energy < 10 || (self.total_energy - self.shields < 10 && self.damaged.contains_key(systems::SHIELD_CONTROL)) { + view::stranded(); + return true; + } + return false; + } } pub mod systems { diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 26daf0703..fc4a4735c 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -251,3 +251,9 @@ pub fn long_range_scan(galaxy: &Galaxy) { println!("{:-^19}", ""); } } + +pub fn stranded() { + println!("** FATAL ERROR ** You've just stranded your ship in space +You have insufficient maneuvering energy, and shield control +is presently incapable of cross-circuiting to engine room!!") +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 8dd2d166e..a2729d9b5 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -14,8 +14,8 @@ Started after movement and display of stats was finished (no energy management o - [x] subsystem damage - [x] and support for reports - [x] random system damage or repairs on move -- [ ] lrs? -- [ ] stranded... +- [x] lrs? +- [x] stranded... - [ ] stop before hitting an object - when moving across a sector, the enterprise should stop before it runs into something - the current move is a jump, which makes this problematic. would need to rewrite it @@ -29,3 +29,4 @@ Started after movement and display of stats was finished (no energy management o - [ ] restarting the game - [ ] time progression - check all areas where time should move, and adjust accordingly +- [ ] intro instructions From 134b17f77e1feb2bc5d1f56452605d69fc9b5490 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 19:59:57 +1300 Subject: [PATCH 058/377] implemented computer with region map --- 84_Super_Star_Trek/rust/src/commands.rs | 31 ++++- 84_Super_Star_Trek/rust/src/main.rs | 1 + 84_Super_Star_Trek/rust/src/model.rs | 6 +- 84_Super_Star_Trek/rust/src/view.rs | 166 ++++++++++++++++++++++-- 84_Super_Star_Trek/rust/tasks.md | 9 ++ 5 files changed, 194 insertions(+), 19 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 099b54961..db3d4a320 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -14,7 +14,7 @@ pub fn perform_short_range_scan(galaxy: &Galaxy) { pub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { if galaxy.enterprise.damaged.contains_key(model::systems::SHIELD_CONTROL) { - view::inoperable("Shield Control"); + view::inoperable(&systems::name_for(systems::SHIELD_CONTROL)); return; } @@ -204,7 +204,7 @@ fn move_klingons_and_fire(galaxy: &mut Galaxy) { pub fn display_damage_control(enterprise: &Enterprise) { if enterprise.damaged.contains_key(model::systems::DAMAGE_CONTROL) { - view::inoperable("Damage Control"); + view::inoperable(&systems::name_for(systems::DAMAGE_CONTROL)); return; } @@ -217,10 +217,33 @@ pub fn display_damage_control(enterprise: &Enterprise) { } pub fn perform_long_range_scan(galaxy: &Galaxy) { - if galaxy.enterprise.damaged.contains_key(model::systems::SHORT_RANGE_SCAN) { - view::inoperable("Long Range Scanners"); + if galaxy.enterprise.damaged.contains_key(model::systems::LONG_RANGE_SCAN) { + view::inoperable(&systems::name_for(systems::LONG_RANGE_SCAN)); return; } view::long_range_scan(galaxy); +} + +pub fn access_computer(galaxy: &Galaxy, provided: Vec) { + if galaxy.enterprise.damaged.contains_key(model::systems::COMPUTER) { + view::inoperable(&systems::name_for(systems::COMPUTER)); + return; + } + + let operation : i32; + loop { + let entered = input::param_or_prompt_value(&provided, 0, "Computer active and waiting command?", 0, 5); + if entered.is_none() { + view::computer_options(); + } else { + operation = entered.unwrap(); + break; + } + } + + match operation { + 5 => view::galaxy_region_map(), + _ => todo!() // todo implement others + } } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 385d122ce..f7db08453 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -31,6 +31,7 @@ fn main() { model::systems::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), model::systems::DAMAGE_CONTROL => commands::display_damage_control(&galaxy.enterprise), model::systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&galaxy), + model::systems::COMPUTER => commands::access_computer(&galaxy, command[1..].into()), _ => view::print_command_help() } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index f231124c5..549031db3 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -110,9 +110,10 @@ pub mod systems { pub const SHIELD_CONTROL: &str = "SHE"; pub const DAMAGE_CONTROL: &str = "DAM"; pub const LONG_RANGE_SCAN: &str = "LRS"; + pub const COMPUTER: &str = "COM"; - pub const KEYS: [&str; 5] = [ - SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL, LONG_RANGE_SCAN + pub const KEYS: [&str; 6] = [ + SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL, LONG_RANGE_SCAN, COMPUTER ]; pub fn name_for(key: &str) -> String { @@ -122,6 +123,7 @@ pub mod systems { SHIELD_CONTROL => "Shield Control".into(), DAMAGE_CONTROL => "Damage Control".into(), LONG_RANGE_SCAN => "Long Range Scanners".into(), + COMPUTER => "Library-Computer".into(), _ => "Unknown".into() } } diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index fc4a4735c..e4fbed20f 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -1,5 +1,114 @@ use crate::model::{Galaxy, Pos, EndPosition, SectorStatus}; +pub fn full_instructions() { + println!( +" INSTRUCTIONS FOR 'SUPER STAR TREK' + + 1. When you see \"Command ?\" printed, enter one of the legal + commands (NAV, SRS, LRS, PHA, TOR, SHE, DAM, COM, OR XXX). + 2. If you should type in an illegal command, you'll get a short + list of the legal commands printed out. + 3. Some commands require you to enter data (for example, the + 'NAV' command comes back with 'Course (1-9) ?'.) If you + type in illegal data (like negative numbers), then command + will be aborted. + + The galaxy is divided into an 8 X 8 quadrant grid, + and each quadrant is further divided into an 8 X 8 sector grid. + + You will be assigned a starting point somewhere in the + galaxy to begin a tour of duty as commander of the starship + Enterprise; your mission: to seek and destroy the fleet of + Klingon warships which are menacing the United Federation of + Planets. + + You have the following commands available to you as captain + of the starship Enterprise: + + NAV command = Warp Engine Control + Course is in a circular numerical 4 3 2 + vector arrangement as shown . . . + integer and real values may be ... + used. (Thus course 1.5 is half- 5 ---*--- 1 + way between 1 and 2. ... + . . . + Values may approach 9.0, which 6 7 8 + itself is equivalent to 1.0 + COURSE + One warp factor is the size of + one quadrant. Therefore, to get + from quadrant 6,5 to 5,5, you WOULD + use course 3, warp factor 1. + + SRS command = Short Range Sensor Scan + Shows you a scan of your present quadrant. + + Symbology on your sensor screen is as follows: + <*> = Your starship's position + +K+ = Klingon battle cruiser + >!< = Federation starbase (refuel/repair/re-arm here!) + * = Star + + A condensed 'status report' will also be presented. + + LRS command = Long Range Sensor Scan + Shows conditions in space for one quadrant on each side + of the Enterprise (which is in the middle of the scan). + The scan is coded in the form ###, where the units digit + is the number of stars, the tens digit is the number of + starbases, and the hundreds digit is the number of + Klingons. + + Example - 207 = 2 Klingons, No starbases, & 7 stars. + + PHA command = Phaser Control + Allows you to destroy the Klingon battle cruisers by + zapping them with suitably large units of energy to + deplete their shield power. (Remember, Klingons have + phasers, too!) + + TOR command = Photon Torpedo Control + Torpedo course is the same as used in warp engine control. + If you hit the Klingon vessel, he is destroyed and + cannot fire back at you. If you miss, you are subject to + his phaser fire. In either case, you are also subject to + the phaser fire of all other Klingons in the quadrant. + + The library-computer (COM command) has an option to + compute torpedo trajectory for you (Option 2). + + SHE command = Shield Control + Defines the number of energy units to be assigned to the + shields. Energy is taken from total ship's energy. Note + that the status display total energy includes shield energy. + + DAM command = Damage Control Report + Gives the state of repair of all devices. Where a negative + 'state of repair' shows that the device is temporarily + damaged. + + COM command = Library-Computer + The library-computer contains six options: + Option 0 = Cumulative Galactic Record + This option shows computer memory of the results of all + previous short and long range sensor scans. + Option 1 = Status Report + This option shows the number of Klingons, Stardates, + and starbases remaining in the game. + Option 2 = Photon Torpedo Data + Which gives directions and distance from the Enterprise + to all Klingons in your quadrant. + Option 3 = Starbase Nav Data + This option gives direction and distance to any + starbase within your quadrant. + Option 4 = Direction/Distance Calculator + This option allows you to enter coordinates for + direction/distance calculations. + Option 5 = Galactic Region Name Map + This option prints the names of the sixteen major + galactic regions referred to in the game.") +} + pub fn enterprise() { println!(" @@ -34,10 +143,11 @@ pub fn intro(model: &Galaxy) { if star_bases > 1 { star_base_message = format!("There are {} starbases", star_bases); } - println!("Your orders are as follows: + println!( +"Your orders are as follows: Destroy the {} Klingon warships which have invaded - the galaxy before they can attack federation headquarters - on stardate {}. This gives you {} days. {} in the galaxy for resupplying your ship.\n", + the galaxy before they can attack federation headquarters + on stardate {}. This gives you {} days. {} in the galaxy for resupplying your ship.\n", model.remaining_klingons(), model.final_stardate, model.final_stardate - model.stardate, star_base_message) } @@ -69,7 +179,8 @@ fn quadrant_name(quadrant: &Pos) -> String { } pub fn starting_quadrant(quadrant: &Pos) { - println!("\nYour mission begins with your starship located + println!( +"\nYour mission begins with your starship located in the galactic quadrant, '{}'.\n", quadrant_name(quadrant)) } @@ -118,7 +229,8 @@ pub fn short_range_scan(model: &Galaxy) { } pub fn print_command_help() { - println!("Enter one of the following: + println!( +"Enter one of the following: NAV (To set course) SRS (For short range sensor scan) LRS (For long range sensor scan) @@ -132,7 +244,8 @@ pub fn print_command_help() { } pub fn end_game_failure(galaxy: &Galaxy) { - println!("Is is stardate {}. + println!( +"Is is stardate {}. There were {} Klingon battle cruisers left at the end of your mission. ", galaxy.stardate, galaxy.remaining_klingons()); @@ -151,10 +264,11 @@ pub fn enterprise_hit(hit_strength: &u16, from_sector: &Pos) { } pub fn hit_edge(end: &EndPosition) { - println!("Lt. Uhura report message from Starfleet Command: - 'Permission to attempt crossing of galactic perimeter + println!( +"Lt. Uhura report message from Starfleet Command: + 'Permission to attempt crossing of galactic perimeter is hereby *Denied*. Shut down your engines.' - Chief Engineer Scott reports, 'Warp engines shut down + Chief Engineer Scott reports, 'Warp engines shut down at sector {} of quadrant {}.'", end.quadrant, end.sector); } @@ -167,7 +281,8 @@ pub fn danger_shields() { } pub fn insuffient_warp_energy(warp_speed: f32) { - println!("Engineering reports, 'Insufficient energy available + println!( +"Engineering reports, 'Insufficient energy available for maneuvering at warp {warp_speed} !'") } @@ -188,7 +303,8 @@ pub fn ridiculous() { } pub fn shields_set(value: u16) { - println!("Deflector control room report: + println!( +"Deflector control room report: 'Shields now at {value} units per your command.'") } @@ -205,7 +321,8 @@ pub fn scanners_out() { } pub fn damaged_engines(max_warp: f32, warp_factor: f32) { - println!("Warp engines are damaged. Maximum speed = warp {max_warp} + println!( +"Warp engines are damaged. Maximum speed = warp {max_warp} Chief Engineer Scott reports, 'The engines won't take warp {warp_factor} !'") } @@ -253,7 +370,30 @@ pub fn long_range_scan(galaxy: &Galaxy) { } pub fn stranded() { - println!("** FATAL ERROR ** You've just stranded your ship in space + println!( +"** FATAL ERROR ** You've just stranded your ship in space You have insufficient maneuvering energy, and shield control is presently incapable of cross-circuiting to engine room!!") } + +pub fn computer_options() { + println!( +" 0 = Cumulative galactic record + 1 = Status report + 2 = Photon torpedo data + 3 = Starbase nav data + 4 = Direction/distance calculator + 5 = Galaxy 'region name' map") +} + +pub fn galaxy_region_map() { + println!( +" The Galaxy + 1 2 3 4 5 6 7 8 + ----- ----- ----- ----- ----- ----- ----- -----"); + for i in (0..REGION_NAMES.len()-1).step_by(2) { + println!( +"{} {:^23} {:^23} + ----- ----- ----- ----- ----- ----- ----- -----", (i/2)+1, REGION_NAMES[i], REGION_NAMES[i+1]); + } +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index a2729d9b5..46ba7d6a5 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -26,7 +26,16 @@ Started after movement and display of stats was finished (no energy management o - [ ] weapons - [ ] phasers - [ ] torpedoes +- [ ] computer + - [ ] 0 - output of all short and long range scans (requires tracking if a system has been scanned) + - [ ] 1 - klingons, starbases, stardate and damage control + - [ ] 2 - photon torpedo data: direction and distance to all local klingons + - [ ] 3 - starbase distance and dir locally + - [ ] 4 - direction/distance calculator (useful for nav actions I guess) + - [x] 5 - galactic name map + - [ ] restarting the game - [ ] time progression - check all areas where time should move, and adjust accordingly - [ ] intro instructions +- [ ] victory From 765fa239018778d22995f185845dfe82100680c3 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 20:29:08 +1300 Subject: [PATCH 059/377] implemented scan history --- 84_Super_Star_Trek/rust/src/commands.rs | 9 +++++-- 84_Super_Star_Trek/rust/src/main.rs | 2 +- 84_Super_Star_Trek/rust/src/model.rs | 9 +++++-- 84_Super_Star_Trek/rust/src/view.rs | 34 ++++++++++++++++++++++--- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index db3d4a320..20e694e00 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -143,6 +143,7 @@ fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { if ship.quadrant != end.quadrant { view::enter_quadrant(&end.quadrant); + galaxy.scanned.insert(end.quadrant); if galaxy.quadrants[end.quadrant.as_index()].klingons.len() > 0 { view::condition_red(); @@ -216,13 +217,16 @@ pub fn display_damage_control(enterprise: &Enterprise) { println!(); } -pub fn perform_long_range_scan(galaxy: &Galaxy) { +pub fn perform_long_range_scan(galaxy: &mut Galaxy) { if galaxy.enterprise.damaged.contains_key(model::systems::LONG_RANGE_SCAN) { view::inoperable(&systems::name_for(systems::LONG_RANGE_SCAN)); return; } - view::long_range_scan(galaxy); + let seen = view::long_range_scan(galaxy); + for pos in seen { + galaxy.scanned.insert(pos); + } } pub fn access_computer(galaxy: &Galaxy, provided: Vec) { @@ -243,6 +247,7 @@ pub fn access_computer(galaxy: &Galaxy, provided: Vec) { } match operation { + 0 => view::galaxy_scanned_map(galaxy), 5 => view::galaxy_region_map(), _ => todo!() // todo implement others } diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index f7db08453..4b809b979 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -30,7 +30,7 @@ fn main() { model::systems::WARP_ENGINES => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), model::systems::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), model::systems::DAMAGE_CONTROL => commands::display_damage_control(&galaxy.enterprise), - model::systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&galaxy), + model::systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&mut galaxy), model::systems::COMPUTER => commands::access_computer(&galaxy, command[1..].into()), _ => view::print_command_help() } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 549031db3..9bb386f1a 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -1,4 +1,4 @@ -use std::{ops::{Mul, Add}, fmt::Display, collections::HashMap}; +use std::{ops::{Mul, Add}, fmt::Display, collections::{HashMap, HashSet}}; use rand::Rng; @@ -8,6 +8,7 @@ pub struct Galaxy { pub stardate: f32, pub final_stardate: f32, pub quadrants: Vec, + pub scanned: HashSet, pub enterprise: Enterprise } @@ -136,7 +137,7 @@ pub struct EndPosition { pub energy_cost: u16, } -#[derive(PartialEq, Clone, Copy, Debug)] +#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq)] pub struct Pos(pub u8, pub u8); impl Pos { @@ -206,10 +207,14 @@ impl Galaxy { let enterprise_sector = quadrants[enterprise_quadrant.as_index()].find_empty_sector(); let stardate = rng.gen_range(20..=40) as f32 * 100.0; + let mut scanned = HashSet::new(); + scanned.insert(enterprise_quadrant); + Galaxy { stardate, final_stardate: stardate + rng.gen_range(25..=35) as f32, quadrants: quadrants, + scanned: scanned, enterprise: Enterprise { destroyed: false, damaged: HashMap::new(), diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index e4fbed20f..fec5434cb 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -174,7 +174,7 @@ const SUB_REGION_NAMES: [&str; 4] = ["I", "II", "III", "IV"]; fn quadrant_name(quadrant: &Pos) -> String { format!("{} {}", - REGION_NAMES[((quadrant.0 << 1) + (quadrant.1 >> 2)) as usize], + REGION_NAMES[((quadrant.1 << 1) + (quadrant.0 >> 2)) as usize], SUB_REGION_NAMES[(quadrant.1 % 4) as usize]) } @@ -342,11 +342,13 @@ pub fn system_repair_completed(name: String) { println!(" {name} repair completed.") } -pub fn long_range_scan(galaxy: &Galaxy) { +pub fn long_range_scan(galaxy: &Galaxy) -> Vec { let cx = galaxy.enterprise.quadrant.0 as i8; let cy = galaxy.enterprise.quadrant.1 as i8; + let mut seen = Vec::new(); + println!("Long range scan for quadrant {}", galaxy.enterprise.quadrant); println!("{:-^19}", ""); for y in cy - 1..=cy + 1 { @@ -356,7 +358,10 @@ pub fn long_range_scan(galaxy: &Galaxy) { let mut stars = "*".into(); if y >= 0 && y < 8 && x >= 0 && x < 8 { - let quadrant = &galaxy.quadrants[Pos(x as u8, y as u8).as_index()]; + let pos = Pos(x as u8, y as u8); + seen.push(pos); + + let quadrant = &galaxy.quadrants[pos.as_index()]; klingons = format!("{}", quadrant.klingons.len()); star_bases = quadrant.star_base.map_or("0", |_| "1"); stars = format!("{}", quadrant.stars.len()); @@ -367,6 +372,8 @@ pub fn long_range_scan(galaxy: &Galaxy) { println!(":"); println!("{:-^19}", ""); } + + seen } pub fn stranded() { @@ -397,3 +404,24 @@ pub fn galaxy_region_map() { ----- ----- ----- ----- ----- ----- ----- -----", (i/2)+1, REGION_NAMES[i], REGION_NAMES[i+1]); } } + +pub(crate) fn galaxy_scanned_map(galaxy: &Galaxy) { + println!( +"Computer record of galaxy for quadrant {} + 1 2 3 4 5 6 7 8 + ----- ----- ----- ----- ----- ----- ----- -----", galaxy.enterprise.quadrant); + for y in 0..8 { + print!("{} ", y+1); + for x in 0..8 { + let pos = Pos(x, y); + if galaxy.scanned.contains(&pos) { + let quadrant = &galaxy.quadrants[pos.as_index()]; + print!(" {}{}{} ", quadrant.klingons.len(), quadrant.stars.len(), quadrant.star_base.map_or("0", |_| "1")) + } else { + print!(" *** "); + } + } + println!( +"\n ----- ----- ----- ----- ----- ----- ----- -----") + } +} From 873b974473d94dfdc7941f8e5baacbd95d189ddd Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 21:34:04 +1300 Subject: [PATCH 060/377] work on phaser control everything but destruction of klingons --- 84_Super_Star_Trek/rust/src/commands.rs | 62 ++++++++++++++++++++++--- 84_Super_Star_Trek/rust/src/main.rs | 15 +++--- 84_Super_Star_Trek/rust/src/model.rs | 8 +++- 84_Super_Star_Trek/rust/src/view.rs | 14 ++++++ 84_Super_Star_Trek/rust/tasks.md | 6 ++- 5 files changed, 87 insertions(+), 18 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 20e694e00..52ca5dafa 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,9 +1,9 @@ use rand::Rng; -use crate::{model::{Galaxy, Pos, COURSES, EndPosition, self, Enterprise, systems}, view, input}; +use crate::{model::{Galaxy, Pos, COURSES, EndPosition, self, Enterprise, systems}, view, input::{self, prompt_value, param_or_prompt_value}}; pub fn perform_short_range_scan(galaxy: &Galaxy) { - if galaxy.enterprise.damaged.contains_key(model::systems::SHORT_RANGE_SCAN) { + if galaxy.enterprise.damaged.contains_key(systems::SHORT_RANGE_SCAN) { view::scanners_out(); return; } @@ -13,7 +13,7 @@ pub fn perform_short_range_scan(galaxy: &Galaxy) { pub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { - if galaxy.enterprise.damaged.contains_key(model::systems::SHIELD_CONTROL) { + if galaxy.enterprise.damaged.contains_key(systems::SHIELD_CONTROL) { view::inoperable(&systems::name_for(systems::SHIELD_CONTROL)); return; } @@ -47,7 +47,7 @@ pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec let course = course.unwrap(); let mut max_warp = 8.0; - if galaxy.enterprise.damaged.contains_key(model::systems::WARP_ENGINES) { + if galaxy.enterprise.damaged.contains_key(systems::WARP_ENGINES) { max_warp = 0.2; } @@ -204,7 +204,7 @@ fn move_klingons_and_fire(galaxy: &mut Galaxy) { } pub fn display_damage_control(enterprise: &Enterprise) { - if enterprise.damaged.contains_key(model::systems::DAMAGE_CONTROL) { + if enterprise.damaged.contains_key(systems::DAMAGE_CONTROL) { view::inoperable(&systems::name_for(systems::DAMAGE_CONTROL)); return; } @@ -218,7 +218,7 @@ pub fn display_damage_control(enterprise: &Enterprise) { } pub fn perform_long_range_scan(galaxy: &mut Galaxy) { - if galaxy.enterprise.damaged.contains_key(model::systems::LONG_RANGE_SCAN) { + if galaxy.enterprise.damaged.contains_key(systems::LONG_RANGE_SCAN) { view::inoperable(&systems::name_for(systems::LONG_RANGE_SCAN)); return; } @@ -230,7 +230,7 @@ pub fn perform_long_range_scan(galaxy: &mut Galaxy) { } pub fn access_computer(galaxy: &Galaxy, provided: Vec) { - if galaxy.enterprise.damaged.contains_key(model::systems::COMPUTER) { + if galaxy.enterprise.damaged.contains_key(systems::COMPUTER) { view::inoperable(&systems::name_for(systems::COMPUTER)); return; } @@ -251,4 +251,52 @@ pub fn access_computer(galaxy: &Galaxy, provided: Vec) { 5 => view::galaxy_region_map(), _ => todo!() // todo implement others } +} + +pub fn get_power_and_fire_phasers(galaxy: &mut Galaxy, provided: Vec) { + if galaxy.enterprise.damaged.contains_key(systems::PHASERS) { + view::inoperable(&systems::name_for(systems::PHASERS)); + return; + } + + let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; + if quadrant.klingons.len() == 0 { + view::no_local_enemies(); + return; + } + + let computer_damaged = galaxy.enterprise.damaged.contains_key(systems::COMPUTER); + if computer_damaged { + view::computer_accuracy_issue(); + } + + let available_energy = galaxy.enterprise.total_energy - galaxy.enterprise.shields; + view::phasers_locked(available_energy); + let mut power: f32; + loop { + let setting = param_or_prompt_value(&provided, 0, "Number of units to fire", 0, available_energy); + if setting.is_some() { + power = setting.unwrap() as f32; + break; + } + } + + if power == 0.0 { + return; + } + + galaxy.enterprise.total_energy -= power as u16; + + let mut rng = rand::thread_rng(); + if computer_damaged { + power *= rng.gen::(); + } + + let per_enemy = power / quadrant.klingons.len() as f32; + + // fire on each klingon + + for klingon in &mut quadrant.klingons { + klingon.fire_on(&mut galaxy.enterprise) + } } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 4b809b979..1bd1d6529 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,6 +1,6 @@ use std::process::exit; -use model::Galaxy; +use model::{Galaxy, systems}; mod input; mod model; @@ -26,12 +26,13 @@ fn main() { continue; } match command[0].to_uppercase().as_str() { // order is weird because i built it in this order :) - model::systems::SHORT_RANGE_SCAN => commands::perform_short_range_scan(&galaxy), - model::systems::WARP_ENGINES => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), - model::systems::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), - model::systems::DAMAGE_CONTROL => commands::display_damage_control(&galaxy.enterprise), - model::systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&mut galaxy), - model::systems::COMPUTER => commands::access_computer(&galaxy, command[1..].into()), + systems::SHORT_RANGE_SCAN => commands::perform_short_range_scan(&galaxy), + systems::WARP_ENGINES => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), + systems::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), + systems::DAMAGE_CONTROL => commands::display_damage_control(&galaxy.enterprise), + systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&mut galaxy), + systems::COMPUTER => commands::access_computer(&galaxy, command[1..].into()), + systems::PHASERS => commands::get_power_and_fire_phasers(&mut galaxy, command[1..].into()), _ => view::print_command_help() } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 9bb386f1a..dbd235222 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -25,6 +25,8 @@ pub struct Klingon { impl Klingon { pub fn fire_on(&mut self, enterprise: &mut Enterprise) { + // todo check if enterprise is protected + let mut rng = rand::thread_rng(); let attack_strength = rng.gen::(); let dist_to_enterprise = self.sector.abs_diff(enterprise.sector) as f32; @@ -112,9 +114,10 @@ pub mod systems { pub const DAMAGE_CONTROL: &str = "DAM"; pub const LONG_RANGE_SCAN: &str = "LRS"; pub const COMPUTER: &str = "COM"; + pub const PHASERS: &str = "PHA"; - pub const KEYS: [&str; 6] = [ - SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL, LONG_RANGE_SCAN, COMPUTER + pub const KEYS: [&str; 7] = [ + SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL, LONG_RANGE_SCAN, COMPUTER, PHASERS ]; pub fn name_for(key: &str) -> String { @@ -125,6 +128,7 @@ pub mod systems { DAMAGE_CONTROL => "Damage Control".into(), LONG_RANGE_SCAN => "Long Range Scanners".into(), COMPUTER => "Library-Computer".into(), + PHASERS => "Phaser Control".into(), _ => "Unknown".into() } } diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index fec5434cb..1c904958e 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -425,3 +425,17 @@ pub(crate) fn galaxy_scanned_map(galaxy: &Galaxy) { "\n ----- ----- ----- ----- ----- ----- ----- -----") } } + +pub fn no_local_enemies() { + println!( +"Science Officer Spock reports, 'Sensors show no enemy ships + in this quadrant'") +} + +pub fn computer_accuracy_issue() { + println!("Computer failure hampers accuracy") +} + +pub fn phasers_locked(available_energy: u16) { + println!("Phasers locked on target; Energy available = {available_energy} units") +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 46ba7d6a5..8f5b3babb 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -22,12 +22,14 @@ Started after movement and display of stats was finished (no energy management o - also, movement courses could be floats, according to the instructions, allowing for more precise movement and aiming - [x] better command reading - support entering multiple values on a line (e.g. nav 3 0.1) - [ ] starbases - - [ ] repair + - [ ] proximity detection for docking + - [ ] repair on damage control + - [ ] protection from shots - [ ] weapons - [ ] phasers - [ ] torpedoes - [ ] computer - - [ ] 0 - output of all short and long range scans (requires tracking if a system has been scanned) + - [x] 0 - output of all short and long range scans (requires tracking if a system has been scanned) - [ ] 1 - klingons, starbases, stardate and damage control - [ ] 2 - photon torpedo data: direction and distance to all local klingons - [ ] 3 - starbase distance and dir locally From 5973d97a16ed00a94e786a8e79557ed6125c6065 Mon Sep 17 00:00:00 2001 From: Christopher Date: Thu, 2 Mar 2023 21:35:45 +1300 Subject: [PATCH 061/377] some more reorg --- 84_Super_Star_Trek/rust/src/commands.rs | 7 +------ 84_Super_Star_Trek/rust/src/view.rs | 11 ++++++++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 52ca5dafa..911f88f5d 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -209,12 +209,7 @@ pub fn display_damage_control(enterprise: &Enterprise) { return; } - println!("Device State of Repair"); - for key in systems::KEYS { - let damage = enterprise.damaged.get(key).unwrap_or(&0.0); - println!("{:<25}{}", systems::name_for(key), damage) - } - println!(); + view::damage_control(enterprise); } pub fn perform_long_range_scan(galaxy: &mut Galaxy) { diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 1c904958e..290fa37bb 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -1,4 +1,4 @@ -use crate::model::{Galaxy, Pos, EndPosition, SectorStatus}; +use crate::model::{Galaxy, Pos, EndPosition, SectorStatus, Enterprise, systems}; pub fn full_instructions() { println!( @@ -342,6 +342,15 @@ pub fn system_repair_completed(name: String) { println!(" {name} repair completed.") } +pub fn damage_control(enterprise: &Enterprise) { + println!("Device State of Repair"); + for key in systems::KEYS { + let damage = enterprise.damaged.get(key).unwrap_or(&0.0); + println!("{:<25}{}", systems::name_for(key), damage) + } + println!(); +} + pub fn long_range_scan(galaxy: &Galaxy) -> Vec { let cx = galaxy.enterprise.quadrant.0 as i8; From 21ccbc0f9b8a7510300c054c62bc819cfa25833b Mon Sep 17 00:00:00 2001 From: Christopher Date: Fri, 3 Mar 2023 07:14:25 +1300 Subject: [PATCH 062/377] work on starbases --- 84_Super_Star_Trek/rust/src/commands.rs | 54 ++++++++++++++++++------- 84_Super_Star_Trek/rust/src/main.rs | 2 +- 84_Super_Star_Trek/rust/src/model.rs | 15 ++++--- 84_Super_Star_Trek/rust/src/view.rs | 9 ++++- 4 files changed, 59 insertions(+), 21 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 911f88f5d..255ced431 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,6 +1,6 @@ use rand::Rng; -use crate::{model::{Galaxy, Pos, COURSES, EndPosition, self, Enterprise, systems}, view, input::{self, prompt_value, param_or_prompt_value}}; +use crate::{model::*, view, input::{self, param_or_prompt_value}}; pub fn perform_short_range_scan(galaxy: &Galaxy) { if galaxy.enterprise.damaged.contains_key(systems::SHORT_RANGE_SCAN) { @@ -64,7 +64,9 @@ pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec return; } - move_klingons_and_fire(galaxy); + klingons_move(galaxy); + klingons_fire(galaxy); + if galaxy.enterprise.destroyed { return; } @@ -156,10 +158,17 @@ fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { ship.quadrant = end.quadrant; ship.sector = end.sector; - ship.total_energy = (ship.total_energy - end.energy_cost).max(0); - if ship.shields > ship.total_energy { - view::divert_energy_from_shields(); - ship.shields = ship.total_energy; + let quadrant = &galaxy.quadrants[end.quadrant.as_index()]; + if quadrant.docked_at_starbase(ship.sector) { + ship.shields = 0; + ship.photon_torpedoes = MAX_PHOTON_TORPEDOES; + ship.total_energy = MAX_ENERGY; + } else { + ship.total_energy = (ship.total_energy - end.energy_cost).max(0); + if ship.shields > ship.total_energy { + view::divert_energy_from_shields(); + ship.shields = ship.total_energy; + } } view::short_range_scan(&galaxy) @@ -189,27 +198,46 @@ fn find_end_quadrant_sector(start_quadrant: Pos, start_sector: Pos, course: u8, EndPosition { quadrant, sector, hit_edge, energy_cost } } -fn move_klingons_and_fire(galaxy: &mut Galaxy) { +fn klingons_move(galaxy: &mut Galaxy) { let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; for k in 0..quadrant.klingons.len() { let new_sector = quadrant.find_empty_sector(); quadrant.klingons[k].sector = new_sector; } +} - // todo: check if enterprise is protected by a starbase +fn klingons_fire(galaxy: &mut Galaxy) { + let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; + if quadrant.docked_at_starbase(galaxy.enterprise.sector) { + view::starbase_shields(); + return; + } for k in 0..quadrant.klingons.len() { quadrant.klingons[k].fire_on(&mut galaxy.enterprise); } } -pub fn display_damage_control(enterprise: &Enterprise) { - if enterprise.damaged.contains_key(systems::DAMAGE_CONTROL) { +pub fn run_damage_control(galaxy: &mut Galaxy) { + + let ship = &mut galaxy.enterprise; + + if ship.damaged.contains_key(systems::DAMAGE_CONTROL) { view::inoperable(&systems::name_for(systems::DAMAGE_CONTROL)); return; } - view::damage_control(enterprise); + view::damage_control(&ship); + + if ship.damaged.len() == 0 || !galaxy.quadrants[ship.quadrant.as_index()].docked_at_starbase(ship.sector) { + return; + } + + // try repeair + // if so write dam report + // and increment elapsed time + + view::damage_control(&ship); } pub fn perform_long_range_scan(galaxy: &mut Galaxy) { @@ -291,7 +319,5 @@ pub fn get_power_and_fire_phasers(galaxy: &mut Galaxy, provided: Vec) { // fire on each klingon - for klingon in &mut quadrant.klingons { - klingon.fire_on(&mut galaxy.enterprise) - } + klingons_fire(galaxy); } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 1bd1d6529..589e43e0b 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -29,7 +29,7 @@ fn main() { systems::SHORT_RANGE_SCAN => commands::perform_short_range_scan(&galaxy), systems::WARP_ENGINES => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), systems::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), - systems::DAMAGE_CONTROL => commands::display_damage_control(&galaxy.enterprise), + systems::DAMAGE_CONTROL => commands::run_damage_control(&mut galaxy), systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&mut galaxy), systems::COMPUTER => commands::access_computer(&galaxy, command[1..].into()), systems::PHASERS => commands::get_power_and_fire_phasers(&mut galaxy, command[1..].into()), diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index dbd235222..31fb3191b 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -25,8 +25,6 @@ pub struct Klingon { impl Klingon { pub fn fire_on(&mut self, enterprise: &mut Enterprise) { - // todo check if enterprise is protected - let mut rng = rand::thread_rng(); let attack_strength = rng.gen::(); let dist_to_enterprise = self.sector.abs_diff(enterprise.sector) as f32; @@ -149,7 +147,7 @@ impl Pos { (self.0 * 8 + self.1).into() } - fn abs_diff(&self, other: Pos) -> u8 { + pub fn abs_diff(&self, other: Pos) -> u8 { self.0.abs_diff(other.0) + self.1.abs_diff(other.1) } } @@ -192,6 +190,9 @@ pub enum SectorStatus { Empty, Star, StarBase, Klingon } +pub const MAX_PHOTON_TORPEDOES: u8 = 28; +pub const MAX_ENERGY: u16 = 3000; + impl Galaxy { pub fn remaining_klingons(&self) -> u8 { let quadrants = &self.quadrants; @@ -224,8 +225,8 @@ impl Galaxy { damaged: HashMap::new(), quadrant: enterprise_quadrant, sector: enterprise_sector, - photon_torpedoes: 28, - total_energy: 3000, + photon_torpedoes: MAX_PHOTON_TORPEDOES, + total_energy: MAX_ENERGY, shields: 0 } } } @@ -296,4 +297,8 @@ impl Quadrant { } } } + + pub fn docked_at_starbase(&self, enterprise_sector: Pos) -> bool { + self.star_base.is_some() && self.star_base.unwrap().abs_diff(enterprise_sector) == 1 + } } diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 290fa37bb..c7cc836d7 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -191,7 +191,10 @@ pub fn enter_quadrant(quadrant: &Pos) { pub fn short_range_scan(model: &Galaxy) { let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()]; let mut condition = "GREEN"; - if quadrant.klingons.len() > 0 { + if quadrant.docked_at_starbase(model.enterprise.sector) { + println!("Shields dropped for docking purposes"); + condition = "DOCKED"; + } else if quadrant.klingons.len() > 0 { condition = "*RED*"; } else if model.enterprise.damaged.len() > 0 { condition = "YELLOW"; @@ -448,3 +451,7 @@ pub fn computer_accuracy_issue() { pub fn phasers_locked(available_energy: u16) { println!("Phasers locked on target; Energy available = {available_energy} units") } + +pub fn starbase_shields() { + println!("Starbase shields protect the Enterprise") +} From 5b58b37ad1f1caf95dfcfd6f236f945069a50244 Mon Sep 17 00:00:00 2001 From: Christopher Date: Fri, 3 Mar 2023 07:59:12 +1300 Subject: [PATCH 063/377] finished implementing starbases --- 84_Super_Star_Trek/rust/src/commands.rs | 15 +++++++++++---- 84_Super_Star_Trek/rust/src/input.rs | 16 ++++++++++++++++ 84_Super_Star_Trek/rust/src/model.rs | 21 +++++++++++++-------- 84_Super_Star_Trek/rust/src/view.rs | 12 +++++++++--- 84_Super_Star_Trek/rust/tasks.md | 8 ++++---- 5 files changed, 53 insertions(+), 19 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 255ced431..60dcb9b91 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -229,14 +229,21 @@ pub fn run_damage_control(galaxy: &mut Galaxy) { view::damage_control(&ship); - if ship.damaged.len() == 0 || !galaxy.quadrants[ship.quadrant.as_index()].docked_at_starbase(ship.sector) { + let quadrant = &galaxy.quadrants[ship.quadrant.as_index()]; + if ship.damaged.len() == 0 || !quadrant.docked_at_starbase(ship.sector) { return; } - // try repeair - // if so write dam report - // and increment elapsed time + let repair_delay = quadrant.star_base.as_ref().unwrap().repair_delay; + let repair_time = (ship.damaged.len() as f32 * 0.1 + repair_delay).max(0.9); + view::repair_estimate(repair_time); + if !input::prompt_yes_no("Will you authorize the repair order") { + return; + } + + ship.damaged.clear(); + galaxy.stardate += repair_time; view::damage_control(&ship); } diff --git a/84_Super_Star_Trek/rust/src/input.rs b/84_Super_Star_Trek/rust/src/input.rs index 75f121023..5bd35fb3d 100644 --- a/84_Super_Star_Trek/rust/src/input.rs +++ b/84_Super_Star_Trek/rust/src/input.rs @@ -14,6 +14,22 @@ pub fn prompt(prompt_text: &str) -> Vec { Vec::new() } +pub fn prompt_yes_no(prompt_text: &str) -> bool { + loop { + let response = prompt(&format!("{prompt_text} (Y/N)")); + if response.len() == 0 { + continue; + } + let first_word = response[0].to_uppercase(); + if first_word.starts_with("Y") { + return true; + } + if first_word.starts_with("N") { + return false; + } + } +} + pub fn prompt_value(prompt_text: &str, min: T, max: T) -> Option { let passed = prompt(prompt_text); if passed.len() != 1 { diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 31fb3191b..a12673afb 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -14,10 +14,15 @@ pub struct Galaxy { pub struct Quadrant { pub stars: Vec, - pub star_base: Option, + pub star_base: Option, pub klingons: Vec } +pub struct StarBase { + pub sector: Pos, + pub repair_delay: f32, +} + pub struct Klingon { pub sector: Pos, energy: f32 @@ -243,7 +248,7 @@ impl Galaxy { } if rng.gen::() > 0.96 { - quadrant.star_base = Some(quadrant.find_empty_sector()); + quadrant.star_base = Some(StarBase { sector: quadrant.find_empty_sector(), repair_delay: rng.gen::() * 0.5 }); } let klingon_count = @@ -264,10 +269,10 @@ impl Galaxy { } impl Quadrant { - pub fn sector_status(&self, sector: &Pos) -> SectorStatus { + pub fn sector_status(&self, sector: Pos) -> SectorStatus { if self.stars.contains(§or) { SectorStatus::Star - } else if self.is_starbase(§or) { + } else if self.is_starbase(sector) { SectorStatus::StarBase } else if self.has_klingon(§or) { SectorStatus::Klingon @@ -276,10 +281,10 @@ impl Quadrant { } } - fn is_starbase(&self, sector: &Pos) -> bool { + fn is_starbase(&self, sector: Pos) -> bool { match &self.star_base { None => false, - Some(p) => p == sector + Some(p) => p.sector == sector } } @@ -292,13 +297,13 @@ impl Quadrant { let mut rng = rand::thread_rng(); loop { let pos = Pos(rng.gen_range(0..8), rng.gen_range(0..8)); - if self.sector_status(&pos) == SectorStatus::Empty { + if self.sector_status(pos) == SectorStatus::Empty { return pos } } } pub fn docked_at_starbase(&self, enterprise_sector: Pos) -> bool { - self.star_base.is_some() && self.star_base.unwrap().abs_diff(enterprise_sector) == 1 + self.star_base.is_some() && self.star_base.as_ref().unwrap().sector.abs_diff(enterprise_sector) == 1 } } diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index c7cc836d7..77b700577 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -218,7 +218,7 @@ pub fn short_range_scan(model: &Galaxy) { if &pos == &model.enterprise.sector { print!("<*> ") } else { - match quadrant.sector_status(&pos) { + match quadrant.sector_status(pos) { SectorStatus::Star => print!(" * "), SectorStatus::StarBase => print!(">!< "), SectorStatus::Klingon => print!("+K+ "), @@ -375,7 +375,7 @@ pub fn long_range_scan(galaxy: &Galaxy) -> Vec { let quadrant = &galaxy.quadrants[pos.as_index()]; klingons = format!("{}", quadrant.klingons.len()); - star_bases = quadrant.star_base.map_or("0", |_| "1"); + star_bases = quadrant.star_base.as_ref().map_or("0", |_| "1"); stars = format!("{}", quadrant.stars.len()); } @@ -428,7 +428,7 @@ pub(crate) fn galaxy_scanned_map(galaxy: &Galaxy) { let pos = Pos(x, y); if galaxy.scanned.contains(&pos) { let quadrant = &galaxy.quadrants[pos.as_index()]; - print!(" {}{}{} ", quadrant.klingons.len(), quadrant.stars.len(), quadrant.star_base.map_or("0", |_| "1")) + print!(" {}{}{} ", quadrant.klingons.len(), quadrant.stars.len(), quadrant.star_base.as_ref().map_or("0", |_| "1")) } else { print!(" *** "); } @@ -455,3 +455,9 @@ pub fn phasers_locked(available_energy: u16) { pub fn starbase_shields() { println!("Starbase shields protect the Enterprise") } + +pub fn repair_estimate(repair_time: f32) { + println!( +"Technicians standing by to effect repairs to your ship; +Estimated time to repair: {repair_time} stardates.") +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 8f5b3babb..bdd444813 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -21,10 +21,10 @@ Started after movement and display of stats was finished (no energy management o - the current move is a jump, which makes this problematic. would need to rewrite it - also, movement courses could be floats, according to the instructions, allowing for more precise movement and aiming - [x] better command reading - support entering multiple values on a line (e.g. nav 3 0.1) -- [ ] starbases - - [ ] proximity detection for docking - - [ ] repair on damage control - - [ ] protection from shots +- [x] starbases + - [x] proximity detection for docking + - [x] repair on damage control + - [x] protection from shots - [ ] weapons - [ ] phasers - [ ] torpedoes From 188b17d1523db62761716dd8cddbd97bd62ca0d2 Mon Sep 17 00:00:00 2001 From: Christopher Date: Fri, 3 Mar 2023 08:04:32 +1300 Subject: [PATCH 064/377] small fix so klingons can't move on top of enterprise --- 84_Super_Star_Trek/rust/src/commands.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 60dcb9b91..3cc68cbc7 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -201,7 +201,14 @@ fn find_end_quadrant_sector(start_quadrant: Pos, start_sector: Pos, course: u8, fn klingons_move(galaxy: &mut Galaxy) { let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; for k in 0..quadrant.klingons.len() { - let new_sector = quadrant.find_empty_sector(); + let new_sector: Pos; + loop { + let candidate = quadrant.find_empty_sector(); + if candidate != galaxy.enterprise.sector { + new_sector = candidate; + break; + } + } quadrant.klingons[k].sector = new_sector; } } From a8c55988ade850b8294782d0603007f58752d016 Mon Sep 17 00:00:00 2001 From: Christopher Date: Fri, 3 Mar 2023 14:49:06 +1300 Subject: [PATCH 065/377] phasers! completed this --- 84_Super_Star_Trek/rust/src/commands.rs | 18 +++++++++++++++++- 84_Super_Star_Trek/rust/src/model.rs | 2 +- 84_Super_Star_Trek/rust/src/view.rs | 16 ++++++++++++++++ 84_Super_Star_Trek/rust/tasks.md | 2 +- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 3cc68cbc7..6b2d4b086 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -331,7 +331,23 @@ pub fn get_power_and_fire_phasers(galaxy: &mut Galaxy, provided: Vec) { let per_enemy = power / quadrant.klingons.len() as f32; - // fire on each klingon + for k in &mut quadrant.klingons { + let dist = k.sector.abs_diff(galaxy.enterprise.sector) as f32; + let hit_strength = per_enemy / dist * (2.0 + rng.gen::()); + if hit_strength < 0.15 * k.energy { + view::no_damage(k.sector); + } else { + k.energy -= hit_strength; + view::hit_on_klingon(hit_strength, k.sector); + if k.energy > 0.0 { + view::klingon_remaining_energy(k.energy); + } else { + view::klingon_destroyed(); + } + } + } + + quadrant.klingons.retain(|k| k.energy > 0.0); klingons_fire(galaxy); } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index a12673afb..151b85d3a 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -25,7 +25,7 @@ pub struct StarBase { pub struct Klingon { pub sector: Pos, - energy: f32 + pub energy: f32 } impl Klingon { diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 77b700577..5372cc6bb 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -461,3 +461,19 @@ pub fn repair_estimate(repair_time: f32) { "Technicians standing by to effect repairs to your ship; Estimated time to repair: {repair_time} stardates.") } + +pub fn no_damage(sector: Pos) { + println!("Sensors show no damage to enemy at {sector}") +} + +pub fn hit_on_klingon(hit_strength: f32, sector: Pos) { + println!("{hit_strength} unit hit on Klingon at sector {sector}") +} + +pub fn klingon_remaining_energy(energy: f32) { + println!(" (sensors show {energy} units remaining)") +} + +pub fn klingon_destroyed() { + println!(" Target Destroyed!") // not standard for game but feedback is good. Sorry Mr. Roddenberry +} diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index bdd444813..06bcf57ae 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -26,7 +26,7 @@ Started after movement and display of stats was finished (no energy management o - [x] repair on damage control - [x] protection from shots - [ ] weapons - - [ ] phasers + - [x] phasers - [ ] torpedoes - [ ] computer - [x] 0 - output of all short and long range scans (requires tracking if a system has been scanned) From f7afb36cc7f67b651b34ba7f05b3f4dfdb399884 Mon Sep 17 00:00:00 2001 From: Christopher Date: Fri, 3 Mar 2023 16:16:01 +1300 Subject: [PATCH 066/377] work on victory and retry conditions --- 84_Super_Star_Trek/rust/src/main.rs | 20 +++++++++++++---- 84_Super_Star_Trek/rust/src/model.rs | 33 +++++++++++++++++----------- 84_Super_Star_Trek/rust/src/view.rs | 19 +++++++++++++++- 84_Super_Star_Trek/rust/tasks.md | 3 +++ 4 files changed, 57 insertions(+), 18 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 589e43e0b..2afded1c6 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,5 +1,6 @@ use std::process::exit; +use input::prompt; use model::{Galaxy, systems}; mod input; @@ -12,6 +13,8 @@ fn main() { .expect("Error setting Ctrl-C handler"); let mut galaxy = Galaxy::generate_new(); + let initial_klingons = galaxy.remaining_klingons(); + let initial_stardate = galaxy.stardate; view::enterprise(); view::intro(&galaxy); @@ -36,12 +39,21 @@ fn main() { _ => view::print_command_help() } - if galaxy.enterprise.destroyed || galaxy.enterprise.check_stranded() { + if galaxy.enterprise.destroyed || galaxy.enterprise.check_stranded() || galaxy.stardate >= galaxy.final_stardate { view::end_game_failure(&galaxy); - // todo check if can restart + if galaxy.remaining_klingons() > 0 && galaxy.remaining_starbases() > 0 && galaxy.stardate < galaxy.final_stardate { + view::replay(); + let result = prompt(""); + if result.len() > 0 && result[0].to_uppercase() == "AYE" { + galaxy.enterprise = Galaxy::new_captain(&galaxy.quadrants); + continue; + } + } + break; + } else if galaxy.remaining_klingons() == 0 { + let efficiency = 1000.0 * f32::powi(initial_klingons as f32 / (galaxy.stardate - initial_stardate), 2); + view::congratulations(efficiency); break; } - - // todo check for victory } } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 151b85d3a..2985f28a0 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -101,7 +101,7 @@ impl Enterprise { } pub fn check_stranded(&self) -> bool { - if self.total_energy < 10 || (self.total_energy - self.shields < 10 && self.damaged.contains_key(systems::SHIELD_CONTROL)) { + if self.total_energy < 10 || (self.shields + 10 > self.total_energy && self.damaged.contains_key(systems::SHIELD_CONTROL)) { view::stranded(); return true; } @@ -213,28 +213,35 @@ impl Galaxy { let quadrants = Self::generate_quadrants(); let mut rng = rand::thread_rng(); - let enterprise_quadrant = Pos(rng.gen_range(0..8), rng.gen_range(0..8)); - let enterprise_sector = quadrants[enterprise_quadrant.as_index()].find_empty_sector(); let stardate = rng.gen_range(20..=40) as f32 * 100.0; + let enterprise = Self::new_captain(&quadrants); + let mut scanned = HashSet::new(); - scanned.insert(enterprise_quadrant); + scanned.insert(enterprise.quadrant); Galaxy { stardate, final_stardate: stardate + rng.gen_range(25..=35) as f32, quadrants: quadrants, scanned: scanned, - enterprise: Enterprise { - destroyed: false, - damaged: HashMap::new(), - quadrant: enterprise_quadrant, - sector: enterprise_sector, - photon_torpedoes: MAX_PHOTON_TORPEDOES, - total_energy: MAX_ENERGY, - shields: 0 } + enterprise: enterprise } - } + } + + pub fn new_captain(quadrants: &Vec) -> Enterprise { + let mut rng = rand::thread_rng(); + let enterprise_quadrant = Pos(rng.gen_range(0..8), rng.gen_range(0..8)); + let enterprise_sector = quadrants[enterprise_quadrant.as_index()].find_empty_sector(); + Enterprise { + destroyed: false, + damaged: HashMap::new(), + quadrant: enterprise_quadrant, + sector: enterprise_sector, + photon_torpedoes: MAX_PHOTON_TORPEDOES, + total_energy: MAX_ENERGY, + shields: 0 } + } fn generate_quadrants() -> Vec { let mut rng = rand::thread_rng(); diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 5372cc6bb..f54bd4cca 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -417,7 +417,7 @@ pub fn galaxy_region_map() { } } -pub(crate) fn galaxy_scanned_map(galaxy: &Galaxy) { +pub fn galaxy_scanned_map(galaxy: &Galaxy) { println!( "Computer record of galaxy for quadrant {} 1 2 3 4 5 6 7 8 @@ -477,3 +477,20 @@ pub fn klingon_remaining_energy(energy: f32) { pub fn klingon_destroyed() { println!(" Target Destroyed!") // not standard for game but feedback is good. Sorry Mr. Roddenberry } + +pub fn congratulations(efficiency: f32) { + println!(" +Congratulations, Captain! The last Klingon battle cruiser +menacing the Federation has been destroyed. + +Your efficiency rating is {efficiency}. + ") +} + +pub fn replay() { + println!(" + +The Federation is in need of a new starship commander +for a similar mission -- if there is a volunteer +let him step forward and enter 'Aye'") +} \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 06bcf57ae..5dc79803e 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -37,7 +37,10 @@ Started after movement and display of stats was finished (no energy management o - [x] 5 - galactic name map - [ ] restarting the game + - after defeat + - and by resigning - [ ] time progression - check all areas where time should move, and adjust accordingly + - [ ] defeat due to time expired - [ ] intro instructions - [ ] victory From 7008127806f5ae4d52290ecc0a044fa57445c5fb Mon Sep 17 00:00:00 2001 From: Christopher Date: Fri, 3 Mar 2023 16:17:09 +1300 Subject: [PATCH 067/377] made it so you can still repair at starbases with a broken damage control --- 84_Super_Star_Trek/rust/src/commands.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 6b2d4b086..c878ae26c 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -231,11 +231,10 @@ pub fn run_damage_control(galaxy: &mut Galaxy) { if ship.damaged.contains_key(systems::DAMAGE_CONTROL) { view::inoperable(&systems::name_for(systems::DAMAGE_CONTROL)); - return; + } else { + view::damage_control(&ship); } - view::damage_control(&ship); - let quadrant = &galaxy.quadrants[ship.quadrant.as_index()]; if ship.damaged.len() == 0 || !quadrant.docked_at_starbase(ship.sector) { return; From 51cfce4fb8dfc965eb52058bd05b3e92cfdbdf2c Mon Sep 17 00:00:00 2001 From: Christopher Date: Sat, 4 Mar 2023 09:07:51 +1300 Subject: [PATCH 068/377] minor tweak to fix another underflow issue --- 84_Super_Star_Trek/rust/src/main.rs | 2 +- 84_Super_Star_Trek/rust/src/model.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 2afded1c6..5c9e10586 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -39,7 +39,7 @@ fn main() { _ => view::print_command_help() } - if galaxy.enterprise.destroyed || galaxy.enterprise.check_stranded() || galaxy.stardate >= galaxy.final_stardate { + if galaxy.enterprise.destroyed || galaxy.enterprise.is_stranded() || galaxy.stardate >= galaxy.final_stardate { view::end_game_failure(&galaxy); if galaxy.remaining_klingons() > 0 && galaxy.remaining_starbases() > 0 && galaxy.stardate < galaxy.final_stardate { view::replay(); diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 2985f28a0..144a7e938 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -58,13 +58,13 @@ impl Enterprise { view::enterprise_hit(&hit_strength, §or); - self.shields = (self.shields - hit_strength).max(0); - - if self.shields <= 0 { + if self.shields <= hit_strength { view::enterprise_destroyed(); self.destroyed = true } + self.shields -= hit_strength; + view::shields_hit(self.shields); if hit_strength >= 20 { @@ -100,7 +100,7 @@ impl Enterprise { return false; } - pub fn check_stranded(&self) -> bool { + pub fn is_stranded(&self) -> bool { if self.total_energy < 10 || (self.shields + 10 > self.total_energy && self.damaged.contains_key(systems::SHIELD_CONTROL)) { view::stranded(); return true; From 32c1508a5138dba883cb6b09cea42734abc02664 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sat, 4 Mar 2023 09:10:43 +1300 Subject: [PATCH 069/377] can now resign --- 84_Super_Star_Trek/rust/src/main.rs | 1 + 84_Super_Star_Trek/rust/src/view.rs | 1 - 84_Super_Star_Trek/rust/tasks.md | 10 +++++----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 5c9e10586..a7f11d2ae 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -36,6 +36,7 @@ fn main() { systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&mut galaxy), systems::COMPUTER => commands::access_computer(&galaxy, command[1..].into()), systems::PHASERS => commands::get_power_and_fire_phasers(&mut galaxy, command[1..].into()), + "XXX" => galaxy.enterprise.destroyed = true, _ => view::print_command_help() } diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index f54bd4cca..73ec39d73 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -489,7 +489,6 @@ Your efficiency rating is {efficiency}. pub fn replay() { println!(" - The Federation is in need of a new starship commander for a similar mission -- if there is a volunteer let him step forward and enter 'Aye'") diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 5dc79803e..7a663304b 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -36,11 +36,11 @@ Started after movement and display of stats was finished (no energy management o - [ ] 4 - direction/distance calculator (useful for nav actions I guess) - [x] 5 - galactic name map -- [ ] restarting the game - - after defeat - - and by resigning +- [x] restarting the game + - [x] after defeat + - [x] and by resigning - [ ] time progression - check all areas where time should move, and adjust accordingly - - [ ] defeat due to time expired + - [x] defeat due to time expired - [ ] intro instructions -- [ ] victory +- [x] victory From 7fb940f18ec7d97f394f2d22668c1e41f7537cbd Mon Sep 17 00:00:00 2001 From: Christopher Date: Sat, 4 Mar 2023 09:26:24 +1300 Subject: [PATCH 070/377] started work on photon torpedoes (final system) also moved all prompt text into views submodule --- 84_Super_Star_Trek/rust/src/commands.rs | 24 ++++++++++++++++++------ 84_Super_Star_Trek/rust/src/main.rs | 7 ++++--- 84_Super_Star_Trek/rust/src/model.rs | 8 ++++++-- 84_Super_Star_Trek/rust/src/view.rs | 18 ++++++++++++++++++ 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index c878ae26c..98b9e0d82 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -19,7 +19,7 @@ pub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { } view::energy_available(galaxy.enterprise.total_energy); - let value = input::param_or_prompt_value(&provided, 0, "Number of units to shields", 0, i32::MAX); + let value = input::param_or_prompt_value(&provided, 0, view::prompts::SHIELDS, 0, i32::MAX); if value.is_none() { view::shields_unchanged(); return; @@ -38,7 +38,7 @@ pub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec) { - let course = input::param_or_prompt_value(&provided, 0, "Course (1-9)?", 1, 9); + let course = input::param_or_prompt_value(&provided, 0, view::prompts::COURSE, 1, 9); if course.is_none() { view::bad_nav(); return; @@ -51,7 +51,7 @@ pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec max_warp = 0.2; } - let speed = input::param_or_prompt_value(&provided, 1, format!("Warp Factor (0-{})?", max_warp).as_str(), 0.0, 8.0); + let speed = input::param_or_prompt_value(&provided, 1, &view::prompts::warp_factor(max_warp), 0.0, 8.0); if speed.is_none() { view::bad_nav(); return; @@ -244,7 +244,7 @@ pub fn run_damage_control(galaxy: &mut Galaxy) { let repair_time = (ship.damaged.len() as f32 * 0.1 + repair_delay).max(0.9); view::repair_estimate(repair_time); - if !input::prompt_yes_no("Will you authorize the repair order") { + if !input::prompt_yes_no(view::prompts::REPAIR) { return; } @@ -273,7 +273,7 @@ pub fn access_computer(galaxy: &Galaxy, provided: Vec) { let operation : i32; loop { - let entered = input::param_or_prompt_value(&provided, 0, "Computer active and waiting command?", 0, 5); + let entered = input::param_or_prompt_value(&provided, 0, view::prompts::COMPUTER, 0, 5); if entered.is_none() { view::computer_options(); } else { @@ -310,7 +310,7 @@ pub fn get_power_and_fire_phasers(galaxy: &mut Galaxy, provided: Vec) { view::phasers_locked(available_energy); let mut power: f32; loop { - let setting = param_or_prompt_value(&provided, 0, "Number of units to fire", 0, available_energy); + let setting = param_or_prompt_value(&provided, 0, view::prompts::PHASERS, 0, available_energy); if setting.is_some() { power = setting.unwrap() as f32; break; @@ -349,4 +349,16 @@ pub fn get_power_and_fire_phasers(galaxy: &mut Galaxy, provided: Vec) { quadrant.klingons.retain(|k| k.energy > 0.0); klingons_fire(galaxy); +} + +pub fn gather_dir_and_launch_torpedo(galaxy: &mut Galaxy, provided: Vec) { + if galaxy.enterprise.damaged.contains_key(systems::TORPEDOES) { + view::inoperable(&systems::name_for(systems::TORPEDOES)); + return; + } + + if galaxy.enterprise.photon_torpedoes == 0 { + view::no_torpedoes_remaining(); + return; + } } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index a7f11d2ae..58be1f184 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -18,13 +18,13 @@ fn main() { view::enterprise(); view::intro(&galaxy); - let _ = input::prompt("Press Enter when ready to accept command"); + let _ = input::prompt(view::prompts::WHEN_READY); view::starting_quadrant(&galaxy.enterprise.quadrant); view::short_range_scan(&galaxy); loop { - let command = input::prompt("Command?"); + let command = input::prompt(view::prompts::COMMAND); if command.len() == 0 { continue; } @@ -36,7 +36,8 @@ fn main() { systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&mut galaxy), systems::COMPUTER => commands::access_computer(&galaxy, command[1..].into()), systems::PHASERS => commands::get_power_and_fire_phasers(&mut galaxy, command[1..].into()), - "XXX" => galaxy.enterprise.destroyed = true, + systems::TORPEDOES => commands::gather_dir_and_launch_torpedo(&mut galaxy, command[1..].into()), + systems::RESIGN => galaxy.enterprise.destroyed = true, _ => view::print_command_help() } diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 144a7e938..58251919e 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -118,9 +118,12 @@ pub mod systems { pub const LONG_RANGE_SCAN: &str = "LRS"; pub const COMPUTER: &str = "COM"; pub const PHASERS: &str = "PHA"; + pub const TORPEDOES: &str = "TOR"; - pub const KEYS: [&str; 7] = [ - SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL, LONG_RANGE_SCAN, COMPUTER, PHASERS + pub const RESIGN: &str = "XXX"; + + pub const KEYS: [&str; 8] = [ + SHORT_RANGE_SCAN, WARP_ENGINES, SHIELD_CONTROL, DAMAGE_CONTROL, LONG_RANGE_SCAN, COMPUTER, PHASERS, TORPEDOES ]; pub fn name_for(key: &str) -> String { @@ -132,6 +135,7 @@ pub mod systems { LONG_RANGE_SCAN => "Long Range Scanners".into(), COMPUTER => "Library-Computer".into(), PHASERS => "Phaser Control".into(), + TORPEDOES => "Photon Tubes".into(), _ => "Unknown".into() } } diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 73ec39d73..b087a949b 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -1,5 +1,19 @@ use crate::model::{Galaxy, Pos, EndPosition, SectorStatus, Enterprise, systems}; +pub mod prompts { + pub const COURSE: &str = "Course (1-9)?"; + pub const SHIELDS: &str = "Number of units to shields"; + pub const REPAIR: &str = "Will you authorize the repair order"; + pub const COMPUTER: &str = "Computer active and waiting command?"; + pub const PHASERS: &str = "Number of units to fire"; + pub const WHEN_READY: &str = "Press Enter when ready to accept command"; + pub const COMMAND: &str = "Command?"; + + pub fn warp_factor(max_warp: f32) -> String { + format!("Warp Factor (0-{})?", max_warp) + } +} + pub fn full_instructions() { println!( " INSTRUCTIONS FOR 'SUPER STAR TREK' @@ -492,4 +506,8 @@ pub fn replay() { The Federation is in need of a new starship commander for a similar mission -- if there is a volunteer let him step forward and enter 'Aye'") +} + +pub fn no_torpedoes_remaining() { + println!("All photon torpedoes expended") } \ No newline at end of file From 3344649ed4a35f579529f12271a29ee6b05c619d Mon Sep 17 00:00:00 2001 From: Christopher Date: Sat, 4 Mar 2023 11:36:42 +1300 Subject: [PATCH 071/377] changed nav function to calculate a path --- 84_Super_Star_Trek/rust/src/commands.rs | 86 +++++++++++++++++-------- 84_Super_Star_Trek/rust/src/model.rs | 19 +++--- 84_Super_Star_Trek/rust/src/view.rs | 9 +++ 3 files changed, 79 insertions(+), 35 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 98b9e0d82..b3ca531e8 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -38,7 +38,7 @@ pub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) { pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec) { - let course = input::param_or_prompt_value(&provided, 0, view::prompts::COURSE, 1, 9); + let course = input::param_or_prompt_value(&provided, 0, view::prompts::COURSE, 1.0, 9.0); if course.is_none() { view::bad_nav(); return; @@ -126,28 +126,28 @@ fn repair_or_damage_random_system(enterprise: &mut Enterprise) { view::random_repair_report_for(system_name, true); } -fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { +fn move_enterprise(course: f32, warp_speed: f32, galaxy: &mut Galaxy) { let ship = &mut galaxy.enterprise; // todo account for being blocked - let end = find_end_quadrant_sector(ship.quadrant, ship.sector, course, warp_speed); + let path = find_path(ship.quadrant, ship.sector, course, warp_speed); - if end.energy_cost > ship.total_energy { + if path.energy_cost > ship.total_energy { view::insuffient_warp_energy(warp_speed); return } - if end.hit_edge { - view::hit_edge(&end); + if path.hit_edge { + view::hit_edge(&path); } - if ship.quadrant != end.quadrant { - view::enter_quadrant(&end.quadrant); - galaxy.scanned.insert(end.quadrant); + if ship.quadrant != path.quadrant { + view::enter_quadrant(&path.quadrant); + galaxy.scanned.insert(path.quadrant); - if galaxy.quadrants[end.quadrant.as_index()].klingons.len() > 0 { + if galaxy.quadrants[path.quadrant.as_index()].klingons.len() > 0 { view::condition_red(); if ship.shields <= 200 { view::danger_shields(); @@ -155,16 +155,16 @@ fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { } } - ship.quadrant = end.quadrant; - ship.sector = end.sector; + ship.quadrant = path.quadrant; + ship.sector = path.sector; - let quadrant = &galaxy.quadrants[end.quadrant.as_index()]; + let quadrant = &galaxy.quadrants[path.quadrant.as_index()]; if quadrant.docked_at_starbase(ship.sector) { ship.shields = 0; ship.photon_torpedoes = MAX_PHOTON_TORPEDOES; ship.total_energy = MAX_ENERGY; } else { - ship.total_energy = (ship.total_energy - end.energy_cost).max(0); + ship.total_energy = (ship.total_energy - path.energy_cost).max(0); if ship.shields > ship.total_energy { view::divert_energy_from_shields(); ship.shields = ship.total_energy; @@ -174,26 +174,45 @@ fn move_enterprise(course: u8, warp_speed: f32, galaxy: &mut Galaxy) { view::short_range_scan(&galaxy) } -fn find_end_quadrant_sector(start_quadrant: Pos, start_sector: Pos, course: u8, warp_speed: f32) -> EndPosition { - let (dx, dy): (i8, i8) = COURSES[(course - 1) as usize]; +fn find_path(start_quadrant: Pos, start_sector: Pos, course: f32, warp_speed: f32) -> EndPosition { + + // this course delta stuff is a translation (of a translation, of a translation...) of the original basic calcs + let dir = (course - 1.0) % 8.0; + let (dx1, dy1) = COURSES[dir as usize]; + let (dx2, dy2) = COURSES[(dir + 1.0) as usize]; + let frac = dir - (dir as i32) as f32; + + let dx = dx1 + (dx2 - dx1) * frac; + let dy = dy1 + (dy2 - dy1) * frac; let mut distance = (warp_speed * 8.0) as i8; if distance == 0 { distance = 1; } - let galaxy_pos = start_quadrant * 8u8 + start_sector; + let mut last_sector = start_quadrant * 8 + start_sector; + let mut path = Vec::new(); + let mut hit_edge; - let mut nx = (galaxy_pos.0 as i8) + dx * distance; - let mut ny = (galaxy_pos.1 as i8) + dy * distance; + loop { + let nx = (last_sector.0 as f32 + dx) as i8; + let ny = (last_sector.1 as f32 + dy) as i8; + hit_edge = nx < 0 || ny < 0 || nx >= 64 || ny >= 64; + if hit_edge { + break; + } + last_sector = Pos(nx as u8, ny as u8); + path.push(last_sector); - let hit_edge = nx < 0 || ny < 0 || nx >= 64 || ny >= 64; - nx = nx.min(63).max(0); - ny = ny.min(63).max(0); - - let quadrant = Pos((nx / 8) as u8, (ny / 8) as u8); - let sector = Pos((nx % 8) as u8, (ny % 8) as u8); - let energy_cost = distance as u16 + 10; + distance -= 1; + if distance == 0 { + break; + } + } + + let quadrant = Pos((last_sector.0 / 8) as u8, (last_sector.1 / 8) as u8); + let sector = Pos((last_sector.0 % 8) as u8, (last_sector.1 % 8) as u8); + let energy_cost = path.len() as u16 + 10; EndPosition { quadrant, sector, hit_edge, energy_cost } } @@ -361,4 +380,19 @@ pub fn gather_dir_and_launch_torpedo(galaxy: &mut Galaxy, provided: Vec) view::no_torpedoes_remaining(); return; } + + let course = input::param_or_prompt_value(&provided, 0, view::prompts::TORPEDO_COURSE, 1.0, 9.0); + if course.is_none() { + view::bad_torpedo_course(); + return; + } + + galaxy.enterprise.photon_torpedoes -= 1; + view::torpedo_track(); + + // calculate direction + // step through sectors + // test for hits or final miss + + klingons_fire(galaxy); } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 58251919e..a8919b5eb 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -183,15 +183,16 @@ impl Display for Pos { } } -pub const COURSES : [(i8, i8); 8] = [ - (1, 0), - (1, -1), - (0, -1), - (-1, -1), - (-1, 0), - (-1, 1), - (0, 1), - (1, 1), +pub const COURSES : [(f32, f32); 9] = [ + (1., 0.), + (1., -1.), + (0., -1.), + (-1., -1.), + (-1., 0.), + (-1., 1.), + (0., 1.), + (1., 1.), + (1., 0.), // course 9 is equal to course 1 ]; #[derive(PartialEq)] diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index b087a949b..38e307df5 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -2,6 +2,7 @@ use crate::model::{Galaxy, Pos, EndPosition, SectorStatus, Enterprise, systems}; pub mod prompts { pub const COURSE: &str = "Course (1-9)?"; + pub const TORPEDO_COURSE: &str = "Photon torpedo course (1-9)?"; pub const SHIELDS: &str = "Number of units to shields"; pub const REPAIR: &str = "Will you authorize the repair order"; pub const COMPUTER: &str = "Computer active and waiting command?"; @@ -276,6 +277,10 @@ pub fn bad_nav() { println!(" Lt. Sulu reports, 'Incorrect course data, sir!'") } +pub fn bad_torpedo_course() { + println!(" Ensign Chekov reports, 'Incorrect course data, sir!'") +} + pub fn enterprise_hit(hit_strength: &u16, from_sector: &Pos) { println!("{hit_strength} unit hit on Enterprise from sector {from_sector}"); } @@ -510,4 +515,8 @@ let him step forward and enter 'Aye'") pub fn no_torpedoes_remaining() { println!("All photon torpedoes expended") +} + +pub fn torpedo_track() { + println!("Torpedo track:") } \ No newline at end of file From 5c25a83eafe9a8c062c0aed79e30262206cad81a Mon Sep 17 00:00:00 2001 From: Christopher Date: Sat, 4 Mar 2023 11:37:32 +1300 Subject: [PATCH 072/377] bug fix --- 84_Super_Star_Trek/rust/src/view.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 38e307df5..267fc91b7 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -291,7 +291,7 @@ pub fn hit_edge(end: &EndPosition) { 'Permission to attempt crossing of galactic perimeter is hereby *Denied*. Shut down your engines.' Chief Engineer Scott reports, 'Warp engines shut down - at sector {} of quadrant {}.'", end.quadrant, end.sector); + at sector {} of quadrant {}.'", end.sector, end.quadrant); } pub fn condition_red() { From 781d0566f8d351e38ba273854ba0fb1c624df180 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sat, 4 Mar 2023 15:24:05 +1300 Subject: [PATCH 073/377] implemented torpedoes! --- 84_Super_Star_Trek/rust/src/commands.rs | 127 ++++++++++++++++++------ 84_Super_Star_Trek/rust/src/main.rs | 2 +- 84_Super_Star_Trek/rust/src/model.rs | 29 ++++-- 84_Super_Star_Trek/rust/src/view.rs | 39 ++++++-- 84_Super_Star_Trek/rust/tasks.md | 4 +- 5 files changed, 148 insertions(+), 53 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index b3ca531e8..cc79dffbc 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -132,22 +132,24 @@ fn move_enterprise(course: f32, warp_speed: f32, galaxy: &mut Galaxy) { // todo account for being blocked - let path = find_path(ship.quadrant, ship.sector, course, warp_speed); + let (path, hit_edge) = find_nav_path(ship.quadrant, ship.sector, course, warp_speed); + let energy_cost = path.len() as u16 + 10; - if path.energy_cost > ship.total_energy { + if energy_cost > ship.total_energy { view::insuffient_warp_energy(warp_speed); return } - if path.hit_edge { - view::hit_edge(&path); + let (end_quadrant, end_sector) = path[path.len() - 1].to_local_quadrant_sector(); + if hit_edge { + view::hit_edge(end_quadrant, end_sector); } - if ship.quadrant != path.quadrant { - view::enter_quadrant(&path.quadrant); - galaxy.scanned.insert(path.quadrant); + if ship.quadrant != end_quadrant { + view::enter_quadrant(end_quadrant); + galaxy.scanned.insert(end_quadrant); - if galaxy.quadrants[path.quadrant.as_index()].klingons.len() > 0 { + if galaxy.quadrants[end_quadrant.as_index()].klingons.len() > 0 { view::condition_red(); if ship.shields <= 200 { view::danger_shields(); @@ -155,16 +157,16 @@ fn move_enterprise(course: f32, warp_speed: f32, galaxy: &mut Galaxy) { } } - ship.quadrant = path.quadrant; - ship.sector = path.sector; + ship.quadrant = end_quadrant; + ship.sector = end_sector; - let quadrant = &galaxy.quadrants[path.quadrant.as_index()]; + let quadrant = &galaxy.quadrants[end_quadrant.as_index()]; if quadrant.docked_at_starbase(ship.sector) { ship.shields = 0; ship.photon_torpedoes = MAX_PHOTON_TORPEDOES; ship.total_energy = MAX_ENERGY; } else { - ship.total_energy = (ship.total_energy - path.energy_cost).max(0); + ship.total_energy = ship.total_energy - energy_cost; if ship.shields > ship.total_energy { view::divert_energy_from_shields(); ship.shields = ship.total_energy; @@ -174,23 +176,16 @@ fn move_enterprise(course: f32, warp_speed: f32, galaxy: &mut Galaxy) { view::short_range_scan(&galaxy) } -fn find_path(start_quadrant: Pos, start_sector: Pos, course: f32, warp_speed: f32) -> EndPosition { +fn find_nav_path(start_quadrant: Pos, start_sector: Pos, course: f32, warp_speed: f32) -> (Vec, bool) { - // this course delta stuff is a translation (of a translation, of a translation...) of the original basic calcs - let dir = (course - 1.0) % 8.0; - let (dx1, dy1) = COURSES[dir as usize]; - let (dx2, dy2) = COURSES[(dir + 1.0) as usize]; - let frac = dir - (dir as i32) as f32; - - let dx = dx1 + (dx2 - dx1) * frac; - let dy = dy1 + (dy2 - dy1) * frac; + let (dx, dy) = calculate_delta(course); let mut distance = (warp_speed * 8.0) as i8; if distance == 0 { distance = 1; } - let mut last_sector = start_quadrant * 8 + start_sector; + let mut last_sector = start_sector.as_galactic_sector(start_quadrant); let mut path = Vec::new(); let mut hit_edge; @@ -210,11 +205,20 @@ fn find_path(start_quadrant: Pos, start_sector: Pos, course: f32, warp_speed: f3 } } - let quadrant = Pos((last_sector.0 / 8) as u8, (last_sector.1 / 8) as u8); - let sector = Pos((last_sector.0 % 8) as u8, (last_sector.1 % 8) as u8); - let energy_cost = path.len() as u16 + 10; + (path, hit_edge) +} - EndPosition { quadrant, sector, hit_edge, energy_cost } +fn calculate_delta(course: f32) -> (f32, f32) { + // this course delta stuff is a translation (of a translation, of a translation...) of the original basic calcs + let dir = (course - 1.0) % 8.0; + let (dx1, dy1) = COURSES[dir as usize]; + let (dx2, dy2) = COURSES[(dir + 1.0) as usize]; + let frac = dir - (dir as i32) as f32; + + let dx = dx1 + (dx2 - dx1) * frac; + let dy = dy1 + (dy2 - dy1) * frac; + + (dx, dy) } fn klingons_move(galaxy: &mut Galaxy) { @@ -371,12 +375,15 @@ pub fn get_power_and_fire_phasers(galaxy: &mut Galaxy, provided: Vec) { } pub fn gather_dir_and_launch_torpedo(galaxy: &mut Galaxy, provided: Vec) { - if galaxy.enterprise.damaged.contains_key(systems::TORPEDOES) { + let star_bases = galaxy.remaining_starbases(); + let ship = &mut galaxy.enterprise; + + if ship.damaged.contains_key(systems::TORPEDOES) { view::inoperable(&systems::name_for(systems::TORPEDOES)); return; } - if galaxy.enterprise.photon_torpedoes == 0 { + if ship.photon_torpedoes == 0 { view::no_torpedoes_remaining(); return; } @@ -387,12 +394,68 @@ pub fn gather_dir_and_launch_torpedo(galaxy: &mut Galaxy, provided: Vec) return; } - galaxy.enterprise.photon_torpedoes -= 1; + ship.photon_torpedoes -= 1; view::torpedo_track(); - // calculate direction - // step through sectors - // test for hits or final miss + let path = find_torpedo_path(ship.sector, course.unwrap()); + let quadrant = &mut galaxy.quadrants[ship.quadrant.as_index()]; + let mut hit = false; + for p in path { + view::torpedo_path(p); + match quadrant.sector_status(p) { + SectorStatus::Empty => continue, + SectorStatus::Star => { + hit = true; + view::star_absorbed_torpedo(p); + break; + }, + SectorStatus::Klingon => { + hit = true; + quadrant.get_klingon(p).unwrap().energy = 0.0; + quadrant.klingons.retain(|k| k.energy > 0.0); + view::klingon_destroyed(); + break; + }, + SectorStatus::StarBase => { + hit = true; + quadrant.star_base = None; + let remaining = star_bases - 1; + view::destroyed_starbase(remaining > 0); + if remaining == 0 { + ship.destroyed = true; + } + break; + } + } + } + + if ship.destroyed { // if you wiped out the last starbase, trigger game over + return; + } + + if !hit { + view::torpedo_missed(); + } klingons_fire(galaxy); +} + +fn find_torpedo_path(start_sector: Pos, course: f32) -> Vec { + + let (dx, dy) = calculate_delta(course); + + let mut last_sector = start_sector; + let mut path = Vec::new(); + + loop { + let nx = (last_sector.0 as f32 + dx) as i8; + let ny = (last_sector.1 as f32 + dy) as i8; + if nx < 0 || ny < 0 || nx >= 8 || ny >= 8 { + break; + } + last_sector = Pos(nx as u8, ny as u8); + path.push(last_sector); + } + + path } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 58be1f184..78e59531d 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -20,7 +20,7 @@ fn main() { view::intro(&galaxy); let _ = input::prompt(view::prompts::WHEN_READY); - view::starting_quadrant(&galaxy.enterprise.quadrant); + view::starting_quadrant(galaxy.enterprise.quadrant); view::short_range_scan(&galaxy); loop { diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index a8919b5eb..9b2f1118d 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -60,7 +60,8 @@ impl Enterprise { if self.shields <= hit_strength { view::enterprise_destroyed(); - self.destroyed = true + self.destroyed = true; + return; } self.shields -= hit_strength; @@ -141,13 +142,6 @@ pub mod systems { } } -pub struct EndPosition { - pub quadrant: Pos, - pub sector: Pos, - pub hit_edge: bool, - pub energy_cost: u16, -} - #[derive(PartialEq, Clone, Copy, Debug, Hash, Eq)] pub struct Pos(pub u8, pub u8); @@ -159,6 +153,14 @@ impl Pos { pub fn abs_diff(&self, other: Pos) -> u8 { self.0.abs_diff(other.0) + self.1.abs_diff(other.1) } + + pub fn as_galactic_sector(&self, containing_quadrant: Pos) -> Self { + Pos(containing_quadrant.0 * 8 + self.0, containing_quadrant.1 * 8 + self.1) + } + + pub fn to_local_quadrant_sector(&self) -> (Self, Self) { + (Pos(self.0 / 8, self.1 / 8), Pos(self.0 % 8, self.1 % 8)) + } } impl Mul for Pos { @@ -286,7 +288,7 @@ impl Quadrant { SectorStatus::Star } else if self.is_starbase(sector) { SectorStatus::StarBase - } else if self.has_klingon(§or) { + } else if self.has_klingon(sector) { SectorStatus::Klingon } else { SectorStatus::Empty @@ -300,9 +302,14 @@ impl Quadrant { } } - fn has_klingon(&self, sector: &Pos) -> bool { + fn has_klingon(&self, sector: Pos) -> bool { let klingons = &self.klingons; - klingons.into_iter().find(|k| &k.sector == sector).is_some() + klingons.into_iter().find(|k| k.sector == sector).is_some() + } + + pub fn get_klingon(&mut self, sector: Pos) -> Option<&mut Klingon> { + let klingons = &mut self.klingons; + klingons.into_iter().find(|k| k.sector == sector) } pub fn find_empty_sector(&self) -> Pos { diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 267fc91b7..f7bac4dbe 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -1,4 +1,4 @@ -use crate::model::{Galaxy, Pos, EndPosition, SectorStatus, Enterprise, systems}; +use crate::model::{Galaxy, Pos, SectorStatus, Enterprise, systems}; pub mod prompts { pub const COURSE: &str = "Course (1-9)?"; @@ -187,19 +187,19 @@ const REGION_NAMES: [&str; 16] = [ const SUB_REGION_NAMES: [&str; 4] = ["I", "II", "III", "IV"]; -fn quadrant_name(quadrant: &Pos) -> String { +fn quadrant_name(quadrant: Pos) -> String { format!("{} {}", REGION_NAMES[((quadrant.1 << 1) + (quadrant.0 >> 2)) as usize], SUB_REGION_NAMES[(quadrant.1 % 4) as usize]) } -pub fn starting_quadrant(quadrant: &Pos) { +pub fn starting_quadrant(quadrant: Pos) { println!( "\nYour mission begins with your starship located in the galactic quadrant, '{}'.\n", quadrant_name(quadrant)) } -pub fn enter_quadrant(quadrant: &Pos) { +pub fn enter_quadrant(quadrant: Pos) { println!("\nNow entering {} quadrant . . .\n", quadrant_name(quadrant)) } @@ -285,13 +285,13 @@ pub fn enterprise_hit(hit_strength: &u16, from_sector: &Pos) { println!("{hit_strength} unit hit on Enterprise from sector {from_sector}"); } -pub fn hit_edge(end: &EndPosition) { +pub fn hit_edge(quadrant: Pos, sector: Pos) { println!( "Lt. Uhura report message from Starfleet Command: 'Permission to attempt crossing of galactic perimeter is hereby *Denied*. Shut down your engines.' Chief Engineer Scott reports, 'Warp engines shut down - at sector {} of quadrant {}.'", end.sector, end.quadrant); + at sector {} of quadrant {}.'", sector, quadrant); } pub fn condition_red() { @@ -494,7 +494,7 @@ pub fn klingon_remaining_energy(energy: f32) { } pub fn klingon_destroyed() { - println!(" Target Destroyed!") // not standard for game but feedback is good. Sorry Mr. Roddenberry + println!("*** Klingon destroyed ***") } pub fn congratulations(efficiency: f32) { @@ -519,4 +519,29 @@ pub fn no_torpedoes_remaining() { pub fn torpedo_track() { println!("Torpedo track:") +} + +pub fn torpedo_path(sector: Pos) { + println!("{:<16}{}", "", sector) +} + +pub fn torpedo_missed() { + println!("Torpedo missed!") +} + +pub fn star_absorbed_torpedo(sector: Pos) { + println!("Star at {sector} absorbed torpedo energy.") +} + +pub fn destroyed_starbase(not_the_last_starbase: bool) { + println!("*** Starbase destroyed ***"); + if not_the_last_starbase { + println!(" +Starfleet Command reviewing your record to consider +court martial!") + } else { + println!(" +That does it, Captain!! You are hereby relieved of command +and sentenced to 99 stardates at hard labor on Cygnus 12!!") + } } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 7a663304b..2ddea3dfe 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -25,9 +25,9 @@ Started after movement and display of stats was finished (no energy management o - [x] proximity detection for docking - [x] repair on damage control - [x] protection from shots -- [ ] weapons +- [x] weapons - [x] phasers - - [ ] torpedoes + - [x] torpedoes - [ ] computer - [x] 0 - output of all short and long range scans (requires tracking if a system has been scanned) - [ ] 1 - klingons, starbases, stardate and damage control From ca4b4a9373be89ad84546997f66ff225f087e865 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Sat, 4 Mar 2023 18:54:49 +1100 Subject: [PATCH 074/377] Rename variables --- 77_Salvo/csharp/Game.cs | 449 +++++++++++++++++++++------------------- 77_Salvo/salvo.bas | 2 + 2 files changed, 233 insertions(+), 218 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index e7a7f818b..02cab91ed 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -17,410 +17,423 @@ internal void Play() { _io.Write(Streams.Title); -L1040: var AA = new float[11,11]; - var BA = new float[11,11]; - var CA = new int[8]; - var DA = new int[8]; - var EA = new int[13]; - var FA = new int[13]; - var GA = new int[13]; - var HA = new float[13]; - var KA = new int[11,11]; -L1050: var Z8 = 0; +L1040: var computerGrid = new float[11,11]; + var humanGrid = new float[11,11]; + var shotsX = new int[8]; + var shotsY = new int[8]; + var hitTurnRecord = new int[13]; + var tempX = new int[13]; + var tempY = new int[13]; + var hitShipValue = new float[13]; + var temp = new int[11,11]; L1060: for (var W = 1; W <= 12; W++) { -L1070: EA[W] = -1; -L1080: HA[W] = -1; +L1070: hitTurnRecord[W] = -1; +L1080: hitShipValue[W] = -1; } L1100: for (var X = 1; X <= 10; X++) { L1110: for (var Y = 1; Y <= 10; Y++) { -L1120: BA[X,Y] = 0; +L1120: humanGrid[X,Y] = 0; } } L1150: for (var X = 1; X <= 12; X++) { -L1160: FA[X]=0; -L1170: GA[X]=0; +L1160: tempX[X]=0; +L1170: tempY[X]=0; } L1190: for (var X = 1; X <= 10; X++) { L1200: for (var Y = 1; Y <= 10; Y++) { -L1210: AA[X,Y]=0; +L1210: computerGrid[X,Y]=0; } } L1240: for (var K = 4; K >= 1; K--) { -L1250: var U6=0; -L1260: var (X, Y, V, V2) = L2910(); -L1270: int FNA(int K) => (5-K)*3-2*K/4+Math.Sign(K-1)-1; -L1280: int FNB(int K) => K+K/4-Math.Sign(K-1); -L1290: if (V+V2+V*V2 == 0) { goto L1260; } -L1300: if (Y+V*FNB(K)>10) { goto L1260; } -L1310: if (Y+V*FNB(K)<1) { goto L1260; } -L1320: if (X+V2*FNB(K)>10) { goto L1260; } -L1330: if (X+V2*FNB(K)<1) { goto L1260; } -L1340: U6=U6+1; -L1350: if (U6>25) { goto L1190; } -L1360: for (var Z = 0; Z <= FNB(K); Z++) +L1250: var shipGenerationAttempts=0; +L1260: var (startX, startY, deltaY, deltaX) = L2910(); +L1270: int GetFirstIndex(int shipNumber) => (5-shipNumber)*3-2*(shipNumber/4)+Math.Sign(shipNumber-1)-1; +L1280: int GetShipSizeLessOne(int shipNumber) => shipNumber + shipNumber/4 - Math.Sign(shipNumber-1); +L1290: if (deltaY+deltaX+deltaY*deltaX == 0) { goto L1260; } +L1300: if (startY+deltaY*GetShipSizeLessOne(K)>10) { goto L1260; } +L1310: if (startY+deltaY*GetShipSizeLessOne(K)<1) { goto L1260; } +L1320: if (startX+deltaX*GetShipSizeLessOne(K)>10) { goto L1260; } +L1330: if (startX+deltaX*GetShipSizeLessOne(K)<1) { goto L1260; } +L1340: shipGenerationAttempts=shipGenerationAttempts+1; +L1350: if (shipGenerationAttempts>25) { goto L1190; } + // determine ship coordinates +L1360: for (var i = 0; i <= GetShipSizeLessOne(K); i++) { -L1370: FA[Z+FNA(K)]=X+V2*Z; -L1380: GA[Z+FNA(K)]=Y+V*Z; + tempX[i+GetFirstIndex(K)]=startX+deltaX*i; +L1380: tempY[i+GetFirstIndex(K)]=startY+deltaY*i; } -L1400: var U8=FNA(K); -L1405: if (U8>U8+FNB(K)) { goto L1460; } -L1410: for (var Z2 = U8; Z2 <= U8+FNB(K); Z2++) +L1400: var firstIndex=GetFirstIndex(K); +L1405: if (firstIndex>firstIndex+GetShipSizeLessOne(K)) { goto L1460; } // Can't be true + // detect proximity to previous ships + for (var i = firstIndex; i <= firstIndex+GetShipSizeLessOne(K); i++) { -L1415: if (U8<2) { continue; } -L1420: for (var Z3 = 1; Z3 <= U8-1; Z3++) +L1415: if (firstIndex<2) { continue; } // Only true for the Battleship +L1420: for (var j = 1; j <= firstIndex-1; j++) { -L1430: if (Math.Sqrt((FA[Z3]-FA[Z2])*(FA[Z3]-FA[Z2]) + (GA[Z3]-GA[Z2])*(GA[Z3]-GA[Z2])) < 3.59) { goto L1260; } +L1430: if (Math.Sqrt((tempX[j]-tempX[i])*(tempX[j]-tempX[i]) + (tempY[j]-tempY[i])*(tempY[j]-tempY[i])) < 3.59) { goto L1260; } } } -L1460: for (var Z = 0; Z <= FNB(K); Z++) + // put ship on board +L1460: for (var i = 0; i <= GetShipSizeLessOne(K); i++) { -L1470: AA[FA[Z+U8],GA[Z+U8]]=.5F+Math.Sign(K-1)*(K-1.5F); +L1470: computerGrid[tempX[i+firstIndex],tempY[i+firstIndex]]=.5F+Math.Sign(K-1)*(K-1.5F); } } L1500: _io.WriteLine("ENTER COORDINATES FOR..."); L1510: _io.WriteLine("BATTLESHIP"); -L1520: for (var X = 1; X <= 5; X++) +L1520: for (var i = 1; i <= 5; i++) { - var (Y, Z) = _io.Read2Numbers(""); - BA[(int)Y, (int)Z] = 3; -L1540: BA[(int)Y, (int)Z] = 3; + var (x, y) = _io.Read2Numbers(""); +L1540: humanGrid[(int)x, (int)y] = 3; } L1560: _io.WriteLine("CRUISER"); -L1570: for (var X = 1; X <= 3; X++) +L1570: for (var i = 1; i <= 3; i++) { - var (Y, Z) = _io.Read2Numbers(""); -L1590: BA[(int)Y, (int)Z]=2; + var (x, y) = _io.Read2Numbers(""); +L1590: humanGrid[(int)x, (int)y]=2; } L1610: _io.WriteLine("DESTROYER"); -L1620: for (var X = 1; X <= 2; X++) +L1620: for (var i = 1; i <= 2; i++) { - var (Y, Z) = _io.Read2Numbers(""); -L1640: BA[(int)Y, (int)Z]=1; + var (x, y) = _io.Read2Numbers(""); +L1640: humanGrid[(int)x, (int)y]=1; } L1660: _io.WriteLine("DESTROYER"); -L1670: for (var X = 1; X <= 2; X++) +L1670: for (var i = 1; i <= 2; i++) { - var (Y, Z) = _io.Read2Numbers(""); -L1690: BA[(int)Y, (int)Z]=.5F; + var (x, y) = _io.Read2Numbers(""); +L1690: humanGrid[(int)x, (int)y]=.5F; } -L1710: var JS = _io.ReadString("DO YOU WANT TO START"); -L1730: if (JS != "WHERE ARE YOUR SHIPS?") { goto L1890; } +L1710: var startResponse = _io.ReadString("DO YOU WANT TO START"); +L1730: if (startResponse != "WHERE ARE YOUR SHIPS?") { goto L1890; } L1740: _io.WriteLine("BATTLESHIP"); -L1750: for (var Z = 1; Z <= 5; Z++) +L1750: for (var i = 1; i <= 5; i++) { -L1760: _io.WriteLine($" {FA[Z]} {GA[Z]} "); +L1760: _io.WriteLine($" {tempX[i]} {tempY[i]} "); } L1780: _io.WriteLine("CRUISER"); -L1790: _io.WriteLine($" {FA[6]} {GA[6]} "); -L1800: _io.WriteLine($" {FA[7]} {GA[7]} "); -L1810: _io.WriteLine($" {FA[8]} {GA[8]} "); +L1790: _io.WriteLine($" {tempX[6]} {tempY[6]} "); +L1800: _io.WriteLine($" {tempX[7]} {tempY[7]} "); +L1810: _io.WriteLine($" {tempX[8]} {tempY[8]} "); L1820: _io.WriteLine("DESTROYER"); -L1830: _io.WriteLine($" {FA[9]} {GA[9]} "); -L1840: _io.WriteLine($" {FA[10]} {GA[10]} "); +L1830: _io.WriteLine($" {tempX[9]} {tempY[9]} "); +L1840: _io.WriteLine($" {tempX[10]} {tempY[10]} "); L1850: _io.WriteLine("DESTROYER"); -L1860: _io.WriteLine($" {FA[11]} {GA[11]} "); -L1870: _io.WriteLine($" {FA[12]} {GA[12]} "); +L1860: _io.WriteLine($" {tempX[11]} {tempY[11]} "); +L1870: _io.WriteLine($" {tempX[12]} {tempY[12]} "); L1880: goto L1710; -L1890: var C=0; -L1900: var KS = _io.ReadString("DO YOU WANT TO SEE MY SHOTS"); +L1890: var turnNumber=0; +L1900: var seeShotsResponse = _io.ReadString("DO YOU WANT TO SEE MY SHOTS"); L1920: _io.WriteLine(); -L1930: if (JS != "YES") { goto L2620; } -L1950: if (JS != "YES") { goto L1990; } -L1960: C=C+1; +L1930: if (startResponse != "YES") { goto L2620; } +L1950: if (startResponse != "YES") { goto L1990; } +L1960: turnNumber=turnNumber+1; L1970: _io.WriteLine(); -L1980: _io.WriteLine($"TURN {C}"); -L1990: var A=0; -L2000: for (var W = .5F; W <= 3; W += .5F) +L1980: _io.WriteLine($"TURN {turnNumber}"); +L1990: var maxShotCount=0; +L2000: for (var shipValue = .5F; shipValue <= 3; shipValue += .5F) { -L2010: for (var X = 1; X <= 10; X++) +L2010: for (var x = 1; x <= 10; x++) { -L2020: for (var Y = 1; Y <= 10; Y++) +L2020: for (var y = 1; y <= 10; y++) { -L2030: if (BA[X,Y] == W) { goto L2070; } +L2030: if (humanGrid[x,y] == shipValue) { goto L2070; } } } L2060: continue; -L2070: A=A+(int)(W+.5F); +L2070: maxShotCount=maxShotCount+(int)(shipValue+.5F); } -L2090: for (var W = 1; W <= 7; W++) +L2090: for (var i = 1; i <= 7; i++) { -L2100: CA[W] = 0; -L2110: DA[W] = 0; -L2120: FA[W] = 0; -L2130: GA[W] = 0; +L2100: shotsX[i] = 0; +L2110: shotsY[i] = 0; +L2120: tempX[i] = 0; +L2130: tempY[i] = 0; } -L2150: var P3=0; -L2160: for (var X = 1; X <= 10; X++) +L2150: var untriedSquareCount=0; +L2160: for (var x = 1; x <= 10; x++) { -L2170: for (var Y = 1; Y <= 10; Y++) +L2170: for (var y = 1; y <= 10; y++) { -L2180: if (AA[X,Y]>10) { continue; } -L2190: P3=P3+1; +L2180: if (computerGrid[x,y]>10) { continue; } +L2190: untriedSquareCount=untriedSquareCount+1; } } -L2220: _io.WriteLine($"YOU HAVE {A} SHOTS."); -L2230: if (P3 >= A) { goto L2260; } +L2220: _io.WriteLine($"YOU HAVE {maxShotCount} SHOTS."); +L2230: if (untriedSquareCount >= maxShotCount) { goto L2260; } L2240: _io.WriteLine("YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES."); L2250: goto L2890; -L2260: if (A != 0) { goto L2290; } +L2260: if (maxShotCount != 0) { goto L2290; } L2270: _io.WriteLine("I HAVE WON."); L2280: return; -L2290: for (var W = 1; W <= A; W++) +L2290: for (var i = 1; i <= maxShotCount; i++) { -L2300: var (X, Y) = _io.Read2Numbers(""); -L2310: if (X != (int)X) { goto L2370; } -L2320: if (X > 10) { goto L2370; } -L2330: if (X < 1) { goto L2370; } -L2340: if (Y != (int)Y) { goto L2370; } -L2350: if (Y > 10) { goto L2370; } -L2360: if (Y >= 1) { goto L2390; } +L2300: var (x, y) = _io.Read2Numbers(""); +L2310: if (x != (int)x) { goto L2370; } +L2320: if (x > 10) { goto L2370; } +L2330: if (x < 1) { goto L2370; } +L2340: if (y != (int)y) { goto L2370; } +L2350: if (y > 10) { goto L2370; } +L2360: if (y >= 1) { goto L2390; } L2370: _io.WriteLine("ILLEGAL, ENTER AGAIN."); L2380: goto L2300; -L2390: if (AA[(int)X,(int)Y]>10) +L2390: if (computerGrid[(int)x,(int)y]>10) { - _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {AA[(int)X,(int)Y]-10}"); + _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {computerGrid[(int)x,(int)y]-10}"); goto L2300; } -L2400: CA[W]=(int)X; -L2410: DA[W]=(int)Y; +L2400: shotsX[i]=(int)x; +L2410: shotsY[i]=(int)y; } -L2460: for (var W = 1; W <= A; W++) +L2460: for (var W = 1; W <= maxShotCount; W++) { -L2470: if (AA[CA[W],DA[W]] == 3) +L2470: if (computerGrid[shotsX[W],shotsY[W]] == 3) { _io.WriteLine("YOU HIT MY BATTLESHIP."); goto L2510; } -L2480: if (AA[CA[W],DA[W]] == 2) +L2480: if (computerGrid[shotsX[W],shotsY[W]] == 2) { _io.WriteLine("YOU HIT MY CRUISER."); goto L2510; } -L2490: if (AA[CA[W],DA[W]] == 1) +L2490: if (computerGrid[shotsX[W],shotsY[W]] == 1) { _io.WriteLine("YOU HIT MY DESTROYER."); goto L2510; } -L2500: if (AA[CA[W],DA[W]] == .5F) +L2500: if (computerGrid[shotsX[W],shotsY[W]] == .5F) { _io.WriteLine("YOU HIT MY DESTROYER."); goto L2510; } -L2510: AA[CA[W],DA[W]] = 10+C; +L2510: computerGrid[shotsX[W],shotsY[W]] = 10+turnNumber; } -L2620: A = 0; -L2630: if (JS == "YES") { goto L2670; } -L2640: C = C + 1; +L2620: maxShotCount = 0; +L2630: if (startResponse == "YES") { goto L2670; } +L2640: turnNumber = turnNumber + 1; L2650: _io.WriteLine(); -L2660: _io.WriteLine($"TURN {C}"); -L2670: A = 0; -L2680: for (var W = .5F; W <= 3; W += .5F) +L2660: _io.WriteLine($"TURN {turnNumber}"); +L2670: maxShotCount = 0; +L2680: for (var shipValue = .5F; shipValue <= 3; shipValue += .5F) { -L2690: for (var X = 1; X <= 10; X++) +L2690: for (var x = 1; x <= 10; x++) { -L2700: for (var Y = 1; Y <= 10; Y++) +L2700: for (var y = 1; y <= 10; y++) { -L2710: if (AA[X,Y] == W) { goto L2750; } +L2710: if (computerGrid[x,y] == shipValue) { goto L2750; } } } L2740: continue; -L2750: A = A + (int)(W+.5F); +L2750: maxShotCount = maxShotCount + (int)(shipValue+.5F); } -L2770: P3=0; -L2780: for (var X = 1; X <= 10; X++) +L2770: untriedSquareCount=0; +L2780: for (var x = 1; x <= 10; x++) { -L2790: for (var Y = 1; Y <= 10; Y++) +L2790: for (var y = 1; y <= 10; y++) { -L2800: if (AA[X,Y]>10) { continue; } -L2810: P3=P3+1; +L2800: if (computerGrid[x,y]>10) { continue; } +L2810: untriedSquareCount=untriedSquareCount+1; } } -L2840: _io.WriteLine($"I HAVE {A} SHOTS."); -L2850: if (P3>A) { goto L2880; } +L2840: _io.WriteLine($"I HAVE {maxShotCount} SHOTS."); +L2850: if (untriedSquareCount>maxShotCount) { goto L2880; } L2860: _io.WriteLine("I HAVE MORE SHOTS THAN BLANK SQUARES."); L2870: goto L2270; -L2880: if (A != 0) { goto L2960; } +L2880: if (maxShotCount != 0) { goto L2960; } L2890: _io.WriteLine("YOU HAVE WON."); L2900: return; (int, int, int, int) L2910() { - var X = _random.Next(1, 11); - var Y = _random.Next(1, 11); - var V = _random.Next(-1, 2); - var V2 = _random.Next(-1, 2); + var startX = _random.Next(1, 11); + var startY = _random.Next(1, 11); + var deltaY = _random.Next(-1, 2); + var deltaX = _random.Next(-1, 2); - return (X, Y, V, V2); + return (startX, startY, deltaY, deltaX); } -L2960: for (var W = 1; W <= 12; W++) +L2960: for (var i = 1; i <= 12; i++) { -L2970: if (HA[W]>0) { goto L3800; } + // if damaged ships +L2970: if (hitShipValue[i]>0) { goto L3800; } } -L3000: var w=0; -L3010: var R3=0; -L3020: var (x, y, v, v2) = L2910(); +L3000: var shotCount=0; +L3010: var shotAttempts=0; +L3020: var (shotX, shotY, _, _) = L2910(); L3030: //RESTORE var index = 0; -L3040: var R2=0; -L3050: R3=R3+1; -L3060: if (R3>100) { goto L3010; } -L3070: if (x>10) { goto L3110; } -L3080: if (x>0) { goto L3120; } -L3090: x = 1 + (int)(_random.NextFloat() * 2.5F); +L3040: var strategyNumber=0; +L3050: shotAttempts=shotAttempts+1; +L3060: if (shotAttempts>100) { goto L3010; } + // ensure shot is in range +L3070: if (shotX>10) { goto L3110; } +L3080: if (shotX>0) { goto L3120; } +L3090: shotX = 1 + (int)_random.NextFloat(2.5F); L3100: goto L3120; -L3110: x = 10 - (int)(_random.NextFloat() * 2.5F); -L3120: if (y>10) { goto L3160; } -L3130: if (y>0) { goto L3270; } -L3140: y=1+(int)(_random.NextFloat() * 2.5F); +L3110: shotX = 10 - (int)_random.NextFloat(2.5F); +L3120: if (shotY>10) { goto L3160; } +L3130: if (shotY>0) { goto L3270; } +L3140: shotY=1+(int)_random.NextFloat(2.5F); L3150: goto L3270; -L3160: y=10-(int)(_random.NextFloat() * 2.5F); +L3160: shotY=10-(int)_random.NextFloat(2.5F); L3170: goto L3270; -L3180: FA[w]=x; -L3190: GA[w]=y; -L3200: if (w==A) { goto L3380; } -L3210: if (R2==6) { goto L3030; } + // record shot +L3180: tempX[shotCount]=shotX; +L3190: tempY[shotCount]=shotY; +L3200: if (shotCount==maxShotCount) { goto L3380; } +L3210: if (strategyNumber==6) { goto L3030; } L3240: //DATA 1,1,-1,1,1,-3,1,1,0,2,-1,1 var data = new[] { 1,1,-1,1,1,-3,1,1,0,2,-1,1 }; L3220: //READ X1,Y1 - var (X1, Y1) = (data[index++], data[index++]); -L3230: R2=R2+1; -L3250: x=x+X1; -L3260: y=y+Y1; -L3270: if (x>10) { goto L3210; } -L3280: if (x<1) { goto L3210; } -L3290: if (y>10) { goto L3210; } -L3300: if (y<1) { goto L3210; } -L3310: if (BA[x,y]>10) { goto L3210; } -L3320: for (var Q9 = 1; Q9 <= w; Q9++) + var (xOffset, yOffset) = (data[index++], data[index++]); +L3230: strategyNumber=strategyNumber+1; +L3250: shotX=shotX+xOffset; +L3260: shotY=shotY+yOffset; + // is the shot in range? +L3270: if (shotX>10) { goto L3210; } +L3280: if (shotX<1) { goto L3210; } +L3290: if (shotY>10) { goto L3210; } +L3300: if (shotY<1) { goto L3210; } + // have we fired here before +L3310: if (humanGrid[shotX,shotY]>10) { goto L3210; } + // have we already selected this shot? +L3320: for (var i = 1; i <= shotCount; i++) { -L3330: if (FA[Q9] != x) { continue; } -L3340: if (GA[Q9] == y) { goto L3210; } +L3330: if (tempX[i] != shotX) { continue; } +L3340: if (tempY[i] == shotY) { goto L3210; } } -L3360: w=w+1; +L3360: shotCount=shotCount+1; L3370: goto L3180; -L3380: if (KS != "YES") { goto L3420; } -L3390: for (var Z5 = 1; Z5 <= A; Z5++) + // display shots +L3380: if (seeShotsResponse != "YES") { goto L3420; } +L3390: for (var i = 1; i <= maxShotCount; i++) { -L3400: _io.WriteLine($" {FA[Z5]} {GA[Z5]}"); +L3400: _io.WriteLine($" {tempX[i]} {tempY[i]}"); } -L3420: for (var W = 1; W <= A; W++) +L3420: for (var i = 1; i <= maxShotCount; i++) { -L3430: if (BA[FA[W],GA[W]] == 3) +L3430: if (humanGrid[tempX[i],tempY[i]] == 3) { _io.WriteLine("I HIT YOUR BATTLESHIP"); } - else if (BA[FA[W],GA[W]] == 2) + else if (humanGrid[tempX[i],tempY[i]] == 2) { _io.WriteLine("I HIT YOUR CRUISER"); } - else if (BA[FA[W],GA[W]] == 1) + else if (humanGrid[tempX[i],tempY[i]] == 1) { _io.WriteLine("I HIT YOUR DESTROYER"); } - else if (BA[FA[W],GA[W]] == .5F) + else if (humanGrid[tempX[i],tempY[i]] == .5F) { _io.WriteLine("I HIT YOUR DESTROYER"); } else { - BA[FA[W],GA[W]]=10+C; + humanGrid[tempX[i],tempY[i]]=10+turnNumber; continue; } -L3570: for (var Q = 1; Q <= 12; Q++) +L3570: for (var j = 1; j <= 12; j++) { -L3580: if (EA[Q] != -1) { continue; } -L3590: EA[Q]=10+C; -L3600: HA[Q]=BA[FA[W],GA[W]]; -L3610: var M3=0; -L3620: for (var M2 = 1; M2 <= 12; M2++) + // record hit +L3580: if (hitTurnRecord[j] != -1) { continue; } +L3590: hitTurnRecord[j]=10+turnNumber; +L3600: hitShipValue[j]=humanGrid[tempX[i],tempY[i]]; + // look for past hits on same ship +L3610: var shipHits=0; +L3620: for (var k = 1; k <= 12; k++) { -L3630: if (HA[M2] != HA[Q]) { continue; } -L3640: M3=M3+1; +L3630: if (hitShipValue[k] != hitShipValue[j]) { continue; } +L3640: shipHits=shipHits+1; } -L3660: if (M3 != (int)(HA[Q]+.5F)+1+(int)(HA[Q]+.5F)/3) { goto L3470; } -L3670: for (var M2 = 1; M2 <= 12; M2++) + // if ship is not sunk +L3660: if (shipHits != (int)(hitShipValue[j]+.5F)+1+(int)(hitShipValue[j]+.5F)/3) { goto L3470; } + // otherwise, remove ship hit records +L3670: for (var k = 1; k <= 12; k++) { -L3680: if (HA[M2] != HA[Q]) { continue; } -L3690: EA[M2] = -1; -L3700: HA[M2] = -1; +L3680: if (hitShipValue[k] != hitShipValue[j]) { continue; } +L3690: hitTurnRecord[k] = -1; +L3700: hitShipValue[k] = -1; } L3720: goto L3470; } + // we shouldn't get here L3740: _io.WriteLine("PROGRAM ABORT:"); -L3750: for (var Q = 1; Q <= 12; Q++) +L3750: for (var j = 1; j <= 12; j++) { -L3760: _io.WriteLine($"EA[{Q}] = {EA[Q]}"); -L3770: _io.WriteLine($"HA[{Q}] = {HA[Q]}"); +L3760: _io.WriteLine($"{nameof(hitTurnRecord)}( {j} ) = {hitTurnRecord[j]}"); +L3770: _io.WriteLine($"{nameof(hitShipValue)}( {j} ) = {hitShipValue[j]}"); } return; -L3470: BA[FA[W],GA[W]]=10+C; +L3470: humanGrid[tempX[i],tempY[i]]=10+turnNumber; } L3490: goto L1950; L3800: //REM************************USINGEARRAY -L3810: for (var R = 1; R <= 10; R++) +L3810: for (var x = 1; x <= 10; x++) { -L3820: for (var S = 1; S <= 10; S++) +L3820: for (var y = 1; y <= 10; y++) { - KA[R,S]=0; + temp[x,y]=0; } } -L3860: for (var U = 1; U <= 12; U++) +L3860: for (var i = 1; i <= 12; i++) { -L3870: if (EA[U]<10) { continue; } -L3880: for (var R = 1; R <= 10; R++) +L3870: if (hitTurnRecord[i]<10) { continue; } +L3880: for (var x = 1; x <= 10; x++) { -L3890: for (var S = 1; S <= 10; S++) +L3890: for (var y = 1; y <= 10; y++) { -L3900: if (BA[R,S]<10) { goto L3930; } -L3910: KA[R,S]=-10000000; +L3900: if (humanGrid[x,y]<10) { goto L3930; } +L3910: temp[x,y]=-10000000; L3920: continue; -L3930: for (var M = Math.Sign(1-R); M <= Math.Sign(10-R); M++) +L3930: for (var dX = Math.Sign(1-x); dX <= Math.Sign(10-x); dX++) { -L3940: for (var N = Math.Sign(1-S); N <= Math.Sign(10-S); N++) +L3940: for (var dY = Math.Sign(1-y); dY <= Math.Sign(10-y); dY++) { -L3950: if (N+M+N*M==0) { continue; } -L3960: if (BA[R+M,S+N] != EA[U]) { continue; } -L3970: KA[R,S]=KA[R,S]+EA[U]-S*(int)(HA[U]+.5F); +L3950: if (dY+dX+dY*dX==0) { continue; } +L3960: if (humanGrid[x+dX,y+dY] != hitTurnRecord[i]) { continue; } +L3970: temp[x,y]=temp[x,y]+hitTurnRecord[i]-y*(int)(hitShipValue[i]+.5F); } } } } } -L4030: for (var R = 1; R <= A; R++) +L4030: for (var i = 1; i <= maxShotCount; i++) { -L4040: FA[R]=R; -L4050: GA[R]=R; +L4040: tempX[i]=i; +L4050: tempY[i]=i; } -L4070: for (var R = 1; R <= 10; R++) +L4070: for (var x = 1; x <= 10; x++) { -L4080: for (var S = 1; S <= 10; S++) +L4080: for (var y = 1; y <= 10; y++) { L4090: var Q9=1; -L4100: for (var M = 1; M <= A; M++) +L4100: for (var i = 1; i <= maxShotCount; i++) { -L4110: if (KA[FA[M],GA[M]]>=KA[FA[Q9],GA[Q9]]) { continue; } -L4120: Q9=M; +L4110: if (temp[tempX[i],tempY[i]]>=temp[tempX[Q9],tempY[Q9]]) { continue; } +L4120: Q9=i; } -L4131: if (R>A) { goto L4140; } -L4132: if (R==S) { goto L4210; } -L4140: if (KA[R,S]maxShotCount) { goto L4140; } +L4132: if (x==y) { goto L4210; } +L4140: if (temp[x,y] Date: Sat, 4 Mar 2023 21:35:00 +1300 Subject: [PATCH 075/377] update to tasks --- 84_Super_Star_Trek/rust/tasks.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 2ddea3dfe..7d31efd73 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -39,8 +39,9 @@ Started after movement and display of stats was finished (no energy management o - [x] restarting the game - [x] after defeat - [x] and by resigning -- [ ] time progression - - check all areas where time should move, and adjust accordingly +- [x] time progression + - [x] check all areas where time should move, and adjust accordingly + - looks to only be on nav and repair - [x] defeat due to time expired - [ ] intro instructions - [x] victory From 217e76071b11717ac0ad6a8b01c9659678480339 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sat, 4 Mar 2023 21:36:29 +1300 Subject: [PATCH 076/377] added pre-game text blobs --- 84_Super_Star_Trek/rust/src/view.rs | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index f7bac4dbe..a838922b3 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -1,6 +1,7 @@ use crate::model::{Galaxy, Pos, SectorStatus, Enterprise, systems}; pub mod prompts { + pub const INSTRUCTIONS: &str = "Do you need instructions"; pub const COURSE: &str = "Course (1-9)?"; pub const TORPEDO_COURSE: &str = "Photon torpedo course (1-9)?"; pub const SHIELDS: &str = "Number of units to shields"; @@ -15,6 +16,38 @@ pub mod prompts { } } +pub fn title() { + println!(" + + + + + + + + + + + + ************************************* + * * + * * + * * * SUPER STAR TREK * * * + * * + * * + ************************************* + + + + + + + + + + "); +} + pub fn full_instructions() { println!( " INSTRUCTIONS FOR 'SUPER STAR TREK' From 15cf7b31ff26d7dc32da696d85efb5d41fc39678 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 06:33:59 +1300 Subject: [PATCH 077/377] implemented input instructions --- 84_Super_Star_Trek/rust/src/main.rs | 8 +++++++- 84_Super_Star_Trek/rust/src/view.rs | 4 +++- 84_Super_Star_Trek/rust/tasks.md | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index 78e59531d..e51b179e0 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -1,6 +1,6 @@ use std::process::exit; -use input::prompt; +use input::{prompt, prompt_yes_no}; use model::{Galaxy, systems}; mod input; @@ -12,6 +12,12 @@ fn main() { ctrlc::set_handler(move || { exit(0) }) .expect("Error setting Ctrl-C handler"); + view::title(); + if prompt_yes_no(view::prompts::INSTRUCTIONS) { + view::full_instructions(); + let _ = input::prompt(view::prompts::WHEN_READY); + } + let mut galaxy = Galaxy::generate_new(); let initial_klingons = galaxy.remaining_klingons(); let initial_stardate = galaxy.stardate; diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index a838922b3..22f397eff 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -154,7 +154,9 @@ pub fn full_instructions() { direction/distance calculations. Option 5 = Galactic Region Name Map This option prints the names of the sixteen major - galactic regions referred to in the game.") + galactic regions referred to in the game. + +") } pub fn enterprise() { diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 7d31efd73..20f9a5c1b 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -43,5 +43,5 @@ Started after movement and display of stats was finished (no energy management o - [x] check all areas where time should move, and adjust accordingly - looks to only be on nav and repair - [x] defeat due to time expired -- [ ] intro instructions +- [x] intro instructions - [x] victory From c4d4f820ac72a42d903d90bc33f3e29b16befd08 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 07:49:25 +1300 Subject: [PATCH 078/377] work on some computer functions --- 84_Super_Star_Trek/rust/src/commands.rs | 16 ++++++++++++++++ 84_Super_Star_Trek/rust/src/view.rs | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index cc79dffbc..cf4273109 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -307,11 +307,27 @@ pub fn access_computer(galaxy: &Galaxy, provided: Vec) { match operation { 0 => view::galaxy_scanned_map(galaxy), + 3 => show_starbase_data(galaxy), 5 => view::galaxy_region_map(), _ => todo!() // todo implement others } } +fn show_starbase_data(galaxy: &Galaxy) { + let quadrant = &galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; + match &quadrant.star_base { + None => { + view::no_local_starbase(); + return; + }, + Some(s) => { + view::starbase_report(); + let pos = s.sector; + // calulcate direction and distance then print + } + } +} + pub fn get_power_and_fire_phasers(galaxy: &mut Galaxy, provided: Vec) { if galaxy.enterprise.damaged.contains_key(systems::PHASERS) { view::inoperable(&systems::name_for(systems::PHASERS)); diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 22f397eff..75ad19242 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -579,4 +579,12 @@ court martial!") That does it, Captain!! You are hereby relieved of command and sentenced to 99 stardates at hard labor on Cygnus 12!!") } +} + +pub fn no_local_starbase() { + println!("Mr. Spock reports, 'Sensors show no starbases in this quadrant.'") +} + +pub fn starbase_report() { + println!("From Enterprise to Starbase:'") } \ No newline at end of file From 5542e2fe59c7fa4837d65c31c54dd8988acb279b Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 08:11:24 +1300 Subject: [PATCH 079/377] first cut of dir / dist to local objects also bug fix for param reading, where the param wasnt bound by min max --- 84_Super_Star_Trek/rust/src/commands.rs | 5 +++-- 84_Super_Star_Trek/rust/src/input.rs | 11 ++++++---- 84_Super_Star_Trek/rust/src/model.rs | 27 +++++++++++++++++++++++++ 84_Super_Star_Trek/rust/src/view.rs | 7 +++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index cf4273109..60ffcb212 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -322,8 +322,9 @@ fn show_starbase_data(galaxy: &Galaxy) { }, Some(s) => { view::starbase_report(); - let pos = s.sector; - // calulcate direction and distance then print + let origin = galaxy.enterprise.sector; + let target = s.sector; + view::direction_distance(origin.direction(target), origin.dist(target)) } } } diff --git a/84_Super_Star_Trek/rust/src/input.rs b/84_Super_Star_Trek/rust/src/input.rs index 5bd35fb3d..68ab7006e 100644 --- a/84_Super_Star_Trek/rust/src/input.rs +++ b/84_Super_Star_Trek/rust/src/input.rs @@ -42,12 +42,15 @@ pub fn prompt_value(prompt_text: &str, min: T, max: T) } pub fn param_or_prompt_value(params: &Vec, param_pos: usize, prompt_text: &str, min: T, max: T) -> Option { + let mut res: Option = None; if params.len() > param_pos { match params[param_pos].parse::() { - Ok(n) => Some(n), - _ => None + Ok(n) if (n >= min && n <= max) => res = Some(n), + _ => () } - } else { - return prompt_value::(prompt_text, min, max); } + if res.is_some() { + return res; + } + return prompt_value::(prompt_text, min, max); } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 9b2f1118d..dd2b8dd8b 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -154,6 +154,33 @@ impl Pos { self.0.abs_diff(other.0) + self.1.abs_diff(other.1) } + pub fn dist(&self, other: Pos) -> f32 { + let dx = other.0 as f32 - self.0 as f32; + let dy = other.1 as f32 - self.1 as f32; + (f32::powi(dx, 2) + f32::powi(dy, 2)).sqrt() + } + + pub fn direction(&self, other: Pos) -> f32 { + // this is a replication of the original BASIC code + let dx = other.0 as f32 - self.0 as f32; + let dy = other.1 as f32 - self.1 as f32; + let dx_dominant = dx.abs() > dy.abs(); + + let frac = if dx_dominant { dy / dx } else { -dx / dy }; + let nearest_cardinal = + if dx_dominant { + if dx > 0. { 7. } else { 3. } + } else { + if dy > 0. { 1. } else { 5. } + }; + + let mut dir = nearest_cardinal + frac; + if dir < 1. { + dir += 8. + } + dir + } + pub fn as_galactic_sector(&self, containing_quadrant: Pos) -> Self { Pos(containing_quadrant.0 * 8 + self.0, containing_quadrant.1 * 8 + self.1) } diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 75ad19242..19cc7a574 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -587,4 +587,11 @@ pub fn no_local_starbase() { pub fn starbase_report() { println!("From Enterprise to Starbase:'") +} + +pub fn direction_distance(dir: f32, dist: f32) { + println!( +"Direction = {dir} +Distance = {dist}" + ) } \ No newline at end of file From 2dba25c4eef4d4ad1563b8aa1192221e53b5a500 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 11:05:43 +1300 Subject: [PATCH 080/377] fixed calculation for direction --- 84_Super_Star_Trek/rust/src/model.rs | 9 +++++---- 84_Super_Star_Trek/rust/src/view.rs | 6 +++--- 84_Super_Star_Trek/rust/tasks.md | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index dd2b8dd8b..1bb5ef8e7 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -154,16 +154,17 @@ impl Pos { self.0.abs_diff(other.0) + self.1.abs_diff(other.1) } - pub fn dist(&self, other: Pos) -> f32 { + pub fn dist(&self, other: Pos) -> u8 { let dx = other.0 as f32 - self.0 as f32; let dy = other.1 as f32 - self.1 as f32; - (f32::powi(dx, 2) + f32::powi(dy, 2)).sqrt() + (f32::powi(dx, 2) + f32::powi(dy, 2)).sqrt() as u8 } pub fn direction(&self, other: Pos) -> f32 { // this is a replication of the original BASIC code - let dx = other.0 as f32 - self.0 as f32; - let dy = other.1 as f32 - self.1 as f32; + let dy = other.0 as f32 - self.0 as f32; + let dx = other.1 as f32 - self.1 as f32; + // note i actually use x,y, but the calculation assumes y,x so they're flipped above let dx_dominant = dx.abs() > dy.abs(); let frac = if dx_dominant { dy / dx } else { -dx / dy }; diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 19cc7a574..00598b58d 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -433,7 +433,7 @@ pub fn long_range_scan(galaxy: &Galaxy) -> Vec { stars = format!("{}", quadrant.stars.len()); } - print!(": {}{}{} ", klingons, stars, star_bases) + print!(": {}{}{} ", klingons, star_bases, stars) } println!(":"); println!("{:-^19}", ""); @@ -482,7 +482,7 @@ pub fn galaxy_scanned_map(galaxy: &Galaxy) { let pos = Pos(x, y); if galaxy.scanned.contains(&pos) { let quadrant = &galaxy.quadrants[pos.as_index()]; - print!(" {}{}{} ", quadrant.klingons.len(), quadrant.stars.len(), quadrant.star_base.as_ref().map_or("0", |_| "1")) + print!(" {}{}{} ", quadrant.klingons.len(), quadrant.star_base.as_ref().map_or("0", |_| "1"), quadrant.stars.len()) } else { print!(" *** "); } @@ -589,7 +589,7 @@ pub fn starbase_report() { println!("From Enterprise to Starbase:'") } -pub fn direction_distance(dir: f32, dist: f32) { +pub fn direction_distance(dir: f32, dist: u8) { println!( "Direction = {dir} Distance = {dist}" diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 20f9a5c1b..f3350bd68 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -45,3 +45,4 @@ Started after movement and display of stats was finished (no energy management o - [x] defeat due to time expired - [x] intro instructions - [x] victory +- [ ] switch from x,y to y,x \ No newline at end of file From e593bfd39aa817a921480aa32d9ec35f0c8041a1 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 11:59:16 +1300 Subject: [PATCH 081/377] general status from computer --- 84_Super_Star_Trek/rust/src/commands.rs | 19 ++++++++++++------- 84_Super_Star_Trek/rust/src/main.rs | 5 ++++- 84_Super_Star_Trek/rust/src/view.rs | 16 ++++++++++++++++ 84_Super_Star_Trek/rust/tasks.md | 4 ++-- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 60ffcb212..cfbc77e1c 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -248,16 +248,17 @@ fn klingons_fire(galaxy: &mut Galaxy) { } } -pub fn run_damage_control(galaxy: &mut Galaxy) { - - let ship = &mut galaxy.enterprise; - - if ship.damaged.contains_key(systems::DAMAGE_CONTROL) { +pub fn run_damage_control(galaxy: &Galaxy) { + if galaxy.enterprise.damaged.contains_key(systems::DAMAGE_CONTROL) { view::inoperable(&systems::name_for(systems::DAMAGE_CONTROL)); - } else { - view::damage_control(&ship); + return; } + + view::damage_control(&galaxy.enterprise); +} +pub fn try_starbase_ship_repair(galaxy: &mut Galaxy) { + let ship = &mut galaxy.enterprise; let quadrant = &galaxy.quadrants[ship.quadrant.as_index()]; if ship.damaged.len() == 0 || !quadrant.docked_at_starbase(ship.sector) { return; @@ -307,6 +308,10 @@ pub fn access_computer(galaxy: &Galaxy, provided: Vec) { match operation { 0 => view::galaxy_scanned_map(galaxy), + 1 => { + view::status_report(galaxy); + run_damage_control(galaxy); + }, 3 => show_starbase_data(galaxy), 5 => view::galaxy_region_map(), _ => todo!() // todo implement others diff --git a/84_Super_Star_Trek/rust/src/main.rs b/84_Super_Star_Trek/rust/src/main.rs index e51b179e0..4c1a277ef 100644 --- a/84_Super_Star_Trek/rust/src/main.rs +++ b/84_Super_Star_Trek/rust/src/main.rs @@ -38,7 +38,10 @@ fn main() { systems::SHORT_RANGE_SCAN => commands::perform_short_range_scan(&galaxy), systems::WARP_ENGINES => commands::gather_dir_and_speed_then_move(&mut galaxy, command[1..].into()), systems::SHIELD_CONTROL => commands::get_amount_and_set_shields(&mut galaxy, command[1..].into()), - systems::DAMAGE_CONTROL => commands::run_damage_control(&mut galaxy), + systems::DAMAGE_CONTROL => { + commands::run_damage_control(&galaxy); + commands::try_starbase_ship_repair(&mut galaxy); + } systems::LONG_RANGE_SCAN => commands::perform_long_range_scan(&mut galaxy), systems::COMPUTER => commands::access_computer(&galaxy, command[1..].into()), systems::PHASERS => commands::get_power_and_fire_phasers(&mut galaxy, command[1..].into()), diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 00598b58d..34568bf31 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -594,4 +594,20 @@ pub fn direction_distance(dir: f32, dist: u8) { "Direction = {dir} Distance = {dist}" ) +} + +pub fn status_report(galaxy: &Galaxy) { + let klingon_count = galaxy.remaining_klingons(); + let star_bases = galaxy.remaining_starbases(); + let time_remaining = galaxy.final_stardate - galaxy.stardate; + let mut plural_starbase = ""; + if star_bases > 1 { + plural_starbase = "s"; + } + + println!(" Status report: +Klingons left: {klingon_count} +Mission must be completed in {time_remaining} stardates. +The Federation is maintaining {star_bases} starbase{plural_starbase} in the galaxy. +") } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index f3350bd68..9fcd937d3 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -30,9 +30,9 @@ Started after movement and display of stats was finished (no energy management o - [x] torpedoes - [ ] computer - [x] 0 - output of all short and long range scans (requires tracking if a system has been scanned) - - [ ] 1 - klingons, starbases, stardate and damage control + - [x] 1 - klingons, starbases, stardate and damage control - [ ] 2 - photon torpedo data: direction and distance to all local klingons - - [ ] 3 - starbase distance and dir locally + - [x] 3 - starbase distance and dir locally - [ ] 4 - direction/distance calculator (useful for nav actions I guess) - [x] 5 - galactic name map From 50a4ddbcdc382c4c694b52e26128dfc7d2ccd737 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 14:02:39 +1300 Subject: [PATCH 082/377] direction distance calculator --- 84_Super_Star_Trek/rust/src/commands.rs | 21 ++++++++++++++++++++- 84_Super_Star_Trek/rust/src/input.rs | 19 ++++++++++++++++++- 84_Super_Star_Trek/rust/src/view.rs | 10 ++++++++++ 84_Super_Star_Trek/rust/tasks.md | 2 +- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index cfbc77e1c..2848b039b 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -1,6 +1,6 @@ use rand::Rng; -use crate::{model::*, view, input::{self, param_or_prompt_value}}; +use crate::{model::*, view, input::{self, param_or_prompt_value, prompt_two_values}}; pub fn perform_short_range_scan(galaxy: &Galaxy) { if galaxy.enterprise.damaged.contains_key(systems::SHORT_RANGE_SCAN) { @@ -313,6 +313,7 @@ pub fn access_computer(galaxy: &Galaxy, provided: Vec) { run_damage_control(galaxy); }, 3 => show_starbase_data(galaxy), + 4 => direction_dist_calculator(galaxy), 5 => view::galaxy_region_map(), _ => todo!() // todo implement others } @@ -334,6 +335,24 @@ fn show_starbase_data(galaxy: &Galaxy) { } } +fn direction_dist_calculator(galaxy: &Galaxy) { + view::direction_dist_intro(&galaxy.enterprise); + loop { + let coords1 = prompt_two_values(view::prompts::INITIAL_COORDS, 1, 8).map(|(x, y)| Pos(x, y)); + if coords1.is_none() { + continue; + } + let coords2 = prompt_two_values(view::prompts::TARGET_COORDS, 1, 8).map(|(x, y)| Pos(x, y)); + if coords2.is_none() { + continue; + } + let dir = coords1.unwrap().direction(coords2.unwrap()); + let dist = coords1.unwrap().dist(coords2.unwrap()); + view::direction_distance(dir, dist); + break; + } +} + pub fn get_power_and_fire_phasers(galaxy: &mut Galaxy, provided: Vec) { if galaxy.enterprise.damaged.contains_key(systems::PHASERS) { view::inoperable(&systems::name_for(systems::PHASERS)); diff --git a/84_Super_Star_Trek/rust/src/input.rs b/84_Super_Star_Trek/rust/src/input.rs index 68ab7006e..62d4daee9 100644 --- a/84_Super_Star_Trek/rust/src/input.rs +++ b/84_Super_Star_Trek/rust/src/input.rs @@ -9,7 +9,7 @@ pub fn prompt(prompt_text: &str) -> Vec { let mut buffer = String::new(); if let Ok(_) = stdin.read_line(&mut buffer) { - return buffer.trim_end().split(" ").map(|s| s.to_string()).collect(); + return buffer.trim_end().split([' ', ',']).map(|s| s.to_string()).collect(); } Vec::new() } @@ -53,4 +53,21 @@ pub fn param_or_prompt_value(params: &Vec, para return res; } return prompt_value::(prompt_text, min, max); +} + +pub fn prompt_two_values(prompt_text: &str, min: T, max: T) -> Option<(T, T)> { + let passed = prompt(prompt_text); + if passed.len() != 2 { + return None + } + match passed[0].parse::() { + Ok(n1) if (n1 >= min && n1 <= max) => { + match passed[1].parse::() { + Ok(n2) if (n2 >= min && n2 <= max) => + Some((n1, n2)), + _ => None + } + } + _ => None + } } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 34568bf31..282e6dc4f 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -10,6 +10,8 @@ pub mod prompts { pub const PHASERS: &str = "Number of units to fire"; pub const WHEN_READY: &str = "Press Enter when ready to accept command"; pub const COMMAND: &str = "Command?"; + pub const INITIAL_COORDS: &str = " Initial coordinates (X/Y)"; + pub const TARGET_COORDS: &str = " Final coordinates (X/Y)"; pub fn warp_factor(max_warp: f32) -> String { format!("Warp Factor (0-{})?", max_warp) @@ -610,4 +612,12 @@ Klingons left: {klingon_count} Mission must be completed in {time_remaining} stardates. The Federation is maintaining {star_bases} starbase{plural_starbase} in the galaxy. ") +} + +pub fn direction_dist_intro(enterprise: &Enterprise) { + let quadrant = enterprise.quadrant; + let sector = enterprise.sector; + println!("Direction/distance calculator: +You are at quadrant {quadrant} sector {sector} +Please enter") } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 9fcd937d3..1871b3174 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -33,7 +33,7 @@ Started after movement and display of stats was finished (no energy management o - [x] 1 - klingons, starbases, stardate and damage control - [ ] 2 - photon torpedo data: direction and distance to all local klingons - [x] 3 - starbase distance and dir locally - - [ ] 4 - direction/distance calculator (useful for nav actions I guess) + - [x] 4 - direction/distance calculator (useful for nav actions I guess) - [x] 5 - galactic name map - [x] restarting the game From d973dec62d26e0688dd548ad32d0feb7c0f57440 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 14:09:28 +1300 Subject: [PATCH 083/377] implemented klongon data, final computer program --- 84_Super_Star_Trek/rust/src/commands.rs | 20 ++++++++++++++++++-- 84_Super_Star_Trek/rust/src/view.rs | 8 ++++++++ 84_Super_Star_Trek/rust/tasks.md | 4 ++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 2848b039b..2bc28da85 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -312,14 +312,30 @@ pub fn access_computer(galaxy: &Galaxy, provided: Vec) { view::status_report(galaxy); run_damage_control(galaxy); }, - 3 => show_starbase_data(galaxy), + 2 => show_klingon_direction_data(galaxy), + 3 => show_starbase_direction_data(galaxy), 4 => direction_dist_calculator(galaxy), 5 => view::galaxy_region_map(), _ => todo!() // todo implement others } } -fn show_starbase_data(galaxy: &Galaxy) { +fn show_klingon_direction_data(galaxy: &Galaxy) { + let quadrant = &galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; + if quadrant.klingons.len() == 0 { + view::no_local_enemies(); + return; + } + + view::klingon_report(quadrant.klingons.len() > 1); + let origin = galaxy.enterprise.sector; + for k in &quadrant.klingons { + let target = k.sector; + view::direction_distance(origin.direction(target), origin.dist(target)) + } +} + +fn show_starbase_direction_data(galaxy: &Galaxy) { let quadrant = &galaxy.quadrants[galaxy.enterprise.quadrant.as_index()]; match &quadrant.star_base { None => { diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 282e6dc4f..7e8aa3995 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -620,4 +620,12 @@ pub fn direction_dist_intro(enterprise: &Enterprise) { println!("Direction/distance calculator: You are at quadrant {quadrant} sector {sector} Please enter") +} + +pub fn klingon_report(more_than_one: bool) { + let mut plural = ""; + if more_than_one { + plural = "s"; + } + println!("From Enterprise to Klingon battle cruiser{}", plural) } \ No newline at end of file diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index 1871b3174..c4406208b 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -28,10 +28,10 @@ Started after movement and display of stats was finished (no energy management o - [x] weapons - [x] phasers - [x] torpedoes -- [ ] computer +- [x] computer - [x] 0 - output of all short and long range scans (requires tracking if a system has been scanned) - [x] 1 - klingons, starbases, stardate and damage control - - [ ] 2 - photon torpedo data: direction and distance to all local klingons + - [x] 2 - photon torpedo data: direction and distance to all local klingons - [x] 3 - starbase distance and dir locally - [x] 4 - direction/distance calculator (useful for nav actions I guess) - [x] 5 - galactic name map From b9947f69b515d675f7c0f4be65a1f264adeb0688 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 15:05:25 +1300 Subject: [PATCH 084/377] switched from x/y system to y/x (y is horizontal, x is vertical --- 84_Super_Star_Trek/rust/src/model.rs | 19 +++++++++---------- 84_Super_Star_Trek/rust/src/view.rs | 18 +++++++++--------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 1bb5ef8e7..1e4359ede 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -162,9 +162,8 @@ impl Pos { pub fn direction(&self, other: Pos) -> f32 { // this is a replication of the original BASIC code - let dy = other.0 as f32 - self.0 as f32; - let dx = other.1 as f32 - self.1 as f32; - // note i actually use x,y, but the calculation assumes y,x so they're flipped above + let dx = other.0 as f32 - self.0 as f32; + let dy = other.1 as f32 - self.1 as f32; let dx_dominant = dx.abs() > dy.abs(); let frac = if dx_dominant { dy / dx } else { -dx / dy }; @@ -214,15 +213,15 @@ impl Display for Pos { } pub const COURSES : [(f32, f32); 9] = [ - (1., 0.), - (1., -1.), - (0., -1.), - (-1., -1.), - (-1., 0.), - (-1., 1.), (0., 1.), + (-1., 1.), + (-1., 0.), + (-1., -1.), + (0., -1.), + (1., -1.), + (1., 0.), (1., 1.), - (1., 0.), // course 9 is equal to course 1 + (0., 1.), // course 9 is equal to course 1 ]; #[derive(PartialEq)] diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 7e8aa3995..1cc2d2021 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -226,7 +226,7 @@ const SUB_REGION_NAMES: [&str; 4] = ["I", "II", "III", "IV"]; fn quadrant_name(quadrant: Pos) -> String { format!("{} {}", - REGION_NAMES[((quadrant.1 << 1) + (quadrant.0 >> 2)) as usize], + REGION_NAMES[((quadrant.0 << 1) + (quadrant.1 >> 2)) as usize], SUB_REGION_NAMES[(quadrant.1 % 4) as usize]) } @@ -264,8 +264,8 @@ pub fn short_range_scan(model: &Galaxy) { ]; println!("{:-^33}", ""); - for y in 0..=7 { - for x in 0..=7 { + for x in 0..=7 { + for y in 0..=7 { let pos = Pos(x, y); if &pos == &model.enterprise.sector { print!("<*> ") @@ -278,7 +278,7 @@ pub fn short_range_scan(model: &Galaxy) { } } } - println!("{:>9}{}", "", data[y as usize]) + println!("{:>9}{}", "", data[x as usize]) } println!("{:-^33}", ""); } @@ -419,8 +419,8 @@ pub fn long_range_scan(galaxy: &Galaxy) -> Vec { println!("Long range scan for quadrant {}", galaxy.enterprise.quadrant); println!("{:-^19}", ""); - for y in cy - 1..=cy + 1 { - for x in cx - 1..=cx + 1 { + for x in cx - 1..=cx + 1 { + for y in cy - 1..=cy + 1 { let mut klingons = "*".into(); let mut star_bases = "*".into(); let mut stars = "*".into(); @@ -478,9 +478,9 @@ pub fn galaxy_scanned_map(galaxy: &Galaxy) { "Computer record of galaxy for quadrant {} 1 2 3 4 5 6 7 8 ----- ----- ----- ----- ----- ----- ----- -----", galaxy.enterprise.quadrant); - for y in 0..8 { - print!("{} ", y+1); - for x in 0..8 { + for x in 0..8 { + print!("{} ", x+1); + for y in 0..8 { let pos = Pos(x, y); if galaxy.scanned.contains(&pos) { let quadrant = &galaxy.quadrants[pos.as_index()]; From 8c1e7257163ecdcee5512c141bf707be0d6f79c4 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 15:05:49 +1300 Subject: [PATCH 085/377] updated tasks --- 84_Super_Star_Trek/rust/tasks.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md index c4406208b..da9e49c90 100644 --- a/84_Super_Star_Trek/rust/tasks.md +++ b/84_Super_Star_Trek/rust/tasks.md @@ -45,4 +45,5 @@ Started after movement and display of stats was finished (no energy management o - [x] defeat due to time expired - [x] intro instructions - [x] victory -- [ ] switch from x,y to y,x \ No newline at end of file +- [x] switch from x,y to y,x +- [ ] uppercase prompts? \ No newline at end of file From 9f4f04582610c50340c35304554ff16c8349b7b9 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 15:30:17 +1300 Subject: [PATCH 086/377] implemented collision detection --- 84_Super_Star_Trek/rust/src/commands.rs | 26 +++++++++++-- 84_Super_Star_Trek/rust/src/model.rs | 2 +- 84_Super_Star_Trek/rust/src/view.rs | 8 +++- 84_Super_Star_Trek/rust/tasks.md | 49 ------------------------- 4 files changed, 29 insertions(+), 56 deletions(-) delete mode 100644 84_Super_Star_Trek/rust/tasks.md diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 2bc28da85..38bc35084 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -40,7 +40,7 @@ pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec let course = input::param_or_prompt_value(&provided, 0, view::prompts::COURSE, 1.0, 9.0); if course.is_none() { - view::bad_nav(); + view::bad_course_data(); return; } @@ -53,7 +53,7 @@ pub fn gather_dir_and_speed_then_move(galaxy: &mut Galaxy, provided: Vec let speed = input::param_or_prompt_value(&provided, 1, &view::prompts::warp_factor(max_warp), 0.0, 8.0); if speed.is_none() { - view::bad_nav(); + view::bad_course_data(); return; } @@ -130,9 +130,27 @@ fn move_enterprise(course: f32, warp_speed: f32, galaxy: &mut Galaxy) { let ship = &mut galaxy.enterprise; - // todo account for being blocked + let (mut path, mut hit_edge) = find_nav_path(ship.quadrant, ship.sector, course, warp_speed); + for i in 0..path.len() { + let (quadrant, sector) = path[i].to_local_quadrant_sector(); + if quadrant != ship.quadrant { + break; // have left current quadrant, so collision checks removed. if there is a collision at the dest... /shrug? + } + let quadrant = &galaxy.quadrants[quadrant.as_index()]; + if quadrant.sector_status(sector) != SectorStatus::Empty { + path = path[..i].into(); + hit_edge = false; + if i > 0 { + let (_, last_sector) = path[path.len() - 1].to_local_quadrant_sector(); + view::bad_nav(last_sector); + } else { + view::bad_nav(ship.sector); + return; + } + break; + } + } - let (path, hit_edge) = find_nav_path(ship.quadrant, ship.sector, course, warp_speed); let energy_cost = path.len() as u16 + 10; if energy_cost > ship.total_energy { diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 1e4359ede..10b97a4d4 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -56,7 +56,7 @@ impl Enterprise { return; } - view::enterprise_hit(&hit_strength, §or); + view::enterprise_hit(&hit_strength, sector); if self.shields <= hit_strength { view::enterprise_destroyed(); diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index 1cc2d2021..c276dee20 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -310,15 +310,19 @@ pub fn enterprise_destroyed() { println!("The Enterprise has been destroyed. The Federation will be conquered."); } -pub fn bad_nav() { +pub fn bad_course_data() { println!(" Lt. Sulu reports, 'Incorrect course data, sir!'") } +pub fn bad_nav(current_sector: Pos) { + println!("Warp engines shut down at sector {current_sector} dues to bad navigation") +} + pub fn bad_torpedo_course() { println!(" Ensign Chekov reports, 'Incorrect course data, sir!'") } -pub fn enterprise_hit(hit_strength: &u16, from_sector: &Pos) { +pub fn enterprise_hit(hit_strength: &u16, from_sector: Pos) { println!("{hit_strength} unit hit on Enterprise from sector {from_sector}"); } diff --git a/84_Super_Star_Trek/rust/tasks.md b/84_Super_Star_Trek/rust/tasks.md deleted file mode 100644 index da9e49c90..000000000 --- a/84_Super_Star_Trek/rust/tasks.md +++ /dev/null @@ -1,49 +0,0 @@ -# Tasks - -Started after movement and display of stats was finished (no energy management or collision detection or anything). - -- [x] klingon movement -- [x] klingon firing, game over etc -- [x] add intro -- [x] add entering (and starting in) sector headers -- [x] conditions and danger messages -- [x] remove energy on move -- [x] shields - - [x] shield control - - [x] shield hit absorption -- [x] subsystem damage - - [x] and support for reports -- [x] random system damage or repairs on move -- [x] lrs? -- [x] stranded... -- [ ] stop before hitting an object - - when moving across a sector, the enterprise should stop before it runs into something - - the current move is a jump, which makes this problematic. would need to rewrite it - - also, movement courses could be floats, according to the instructions, allowing for more precise movement and aiming -- [x] better command reading - support entering multiple values on a line (e.g. nav 3 0.1) -- [x] starbases - - [x] proximity detection for docking - - [x] repair on damage control - - [x] protection from shots -- [x] weapons - - [x] phasers - - [x] torpedoes -- [x] computer - - [x] 0 - output of all short and long range scans (requires tracking if a system has been scanned) - - [x] 1 - klingons, starbases, stardate and damage control - - [x] 2 - photon torpedo data: direction and distance to all local klingons - - [x] 3 - starbase distance and dir locally - - [x] 4 - direction/distance calculator (useful for nav actions I guess) - - [x] 5 - galactic name map - -- [x] restarting the game - - [x] after defeat - - [x] and by resigning -- [x] time progression - - [x] check all areas where time should move, and adjust accordingly - - looks to only be on nav and repair - - [x] defeat due to time expired -- [x] intro instructions -- [x] victory -- [x] switch from x,y to y,x -- [ ] uppercase prompts? \ No newline at end of file From c59dea8e21c9719bf5dd673765961df22b77bc81 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 15:48:53 +1300 Subject: [PATCH 087/377] removed final todo --- 84_Super_Star_Trek/rust/src/commands.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 38bc35084..d2eefc61c 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -334,7 +334,7 @@ pub fn access_computer(galaxy: &Galaxy, provided: Vec) { 3 => show_starbase_direction_data(galaxy), 4 => direction_dist_calculator(galaxy), 5 => view::galaxy_region_map(), - _ => todo!() // todo implement others + _ => () // unreachable } } From e6118b4622ad91ad0594403bbd59cdb55d437764 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 15:55:54 +1300 Subject: [PATCH 088/377] added a readme --- 84_Super_Star_Trek/rust/readme.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 84_Super_Star_Trek/rust/readme.md diff --git a/84_Super_Star_Trek/rust/readme.md b/84_Super_Star_Trek/rust/readme.md new file mode 100644 index 000000000..7889ddf3d --- /dev/null +++ b/84_Super_Star_Trek/rust/readme.md @@ -0,0 +1,10 @@ +# Super Star Trek - Rust version + +Explanation of modules: + +- main.rs - creates the galaxy (generation functions are in model.rs as impl methods) then loops listening for commands. after each command checks for victory or defeat condtions. +- model.rs - all the structs and enums that represent the galaxy. key methods in here (as impl methods) are generation functions on galaxy and quadrant, and various comparison methods on the 'Pos' tuple type. +- commands.rs - most of the code that implements instructions given by the player (some code logic is in the model impls, and some in view.rs if its view only). +- view.rs - all text printed to the output, mostly called by command.rs (like view::bad_nav for example). also contains the prompts printed to the user (e.g. view::prompts::COMMAND). +- input.rs - utility methods for getting input from the user, including logic for parsing numbers, repeating prompts until a correct value is provided etc. + From 790e36611fe90e66f7bd6ef949d909a60cbd5015 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 16:02:59 +1300 Subject: [PATCH 089/377] more detail in the readme --- 84_Super_Star_Trek/rust/readme.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/84_Super_Star_Trek/rust/readme.md b/84_Super_Star_Trek/rust/readme.md index 7889ddf3d..ae2f58dc3 100644 --- a/84_Super_Star_Trek/rust/readme.md +++ b/84_Super_Star_Trek/rust/readme.md @@ -2,9 +2,18 @@ Explanation of modules: -- main.rs - creates the galaxy (generation functions are in model.rs as impl methods) then loops listening for commands. after each command checks for victory or defeat condtions. -- model.rs - all the structs and enums that represent the galaxy. key methods in here (as impl methods) are generation functions on galaxy and quadrant, and various comparison methods on the 'Pos' tuple type. -- commands.rs - most of the code that implements instructions given by the player (some code logic is in the model impls, and some in view.rs if its view only). -- view.rs - all text printed to the output, mostly called by command.rs (like view::bad_nav for example). also contains the prompts printed to the user (e.g. view::prompts::COMMAND). -- input.rs - utility methods for getting input from the user, including logic for parsing numbers, repeating prompts until a correct value is provided etc. +- [main.rs](./src/main.rs) - creates the galaxy (generation functions are in model.rs as impl methods) then loops listening for commands. after each command checks for victory or defeat condtions. +- [model.rs](./src/model.rs) - all the structs and enums that represent the galaxy. key methods in here (as impl methods) are generation functions on galaxy and quadrant, and various comparison methods on the 'Pos' tuple type. +- [commands.rs](./src/commands.rs) - most of the code that implements instructions given by the player (some code logic is in the model impls, and some in view.rs if its view only). +- [view.rs](./src/view.rs) - all text printed to the output, mostly called by command.rs (like view::bad_nav for example). also contains the prompts printed to the user (e.g. view::prompts::COMMAND). +- [input.rs](./src/input.rs) - utility methods for getting input from the user, including logic for parsing numbers, repeating prompts until a correct value is provided etc. +Basically the user is asked for the next command, this runs a function that usually checks if the command system is working, and if so will gather additional input (see next note for a slight change here), then either the model is read and info printed, or its mutated in some way (e.g. firing a torpedo, which reduces the torpedo count on the enterprise and can destroy klingons and star bases; finally the klingons fire back and can destroy the enterprise). Finally the win/lose conditions are checked before the loop repeats. + +## Changes from the original + +I have tried to keep it as close as possible. Notable changes are: + +- commands can be given with parameters in line. e.g. while 'nav' will ask for course and then warp speed in the original, here you can *optionally* also do this as one line, e.g. `nav 1 0.1` to move one sector east. I'm sorry - it was driving me insane in its original form (which is still sorted, as is partial application e.g. nav 1 to preset direction and then provide speed). +- text is mostly not uppercase, as text was in the basic version. this would be easy to change however as all text is in view.rs, but I chose not to. +- the navigation system (plotting direction, paths and collision detection) is as close as I could make it to the basic version (by using other language conversions as specification sources) but I suspect is not perfect. seems to work well enough however. \ No newline at end of file From 371b72fc36733a6881782cf7670788ec3262b4f6 Mon Sep 17 00:00:00 2001 From: Christopher Date: Sun, 5 Mar 2023 16:04:42 +1300 Subject: [PATCH 090/377] small cleanup --- 84_Super_Star_Trek/rust/src/model.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs index 10b97a4d4..aa08d7345 100644 --- a/84_Super_Star_Trek/rust/src/model.rs +++ b/84_Super_Star_Trek/rust/src/model.rs @@ -257,9 +257,9 @@ impl Galaxy { Galaxy { stardate, final_stardate: stardate + rng.gen_range(25..=35) as f32, - quadrants: quadrants, - scanned: scanned, - enterprise: enterprise + quadrants, + scanned, + enterprise } } From cfc7def425fefb1b6b41d3f2754e799dd53ba3e5 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Sun, 5 Mar 2023 21:03:40 +1100 Subject: [PATCH 091/377] Simplify some logic --- 77_Salvo/csharp/Game.cs | 320 ++++++++++++++++++++-------------------- 1 file changed, 159 insertions(+), 161 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 02cab91ed..3c3825218 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -4,6 +4,10 @@ namespace Salvo; internal class Game { + private static readonly float[] _shipValue = new[] { 0.5F, 1, 2, 3 }; + private static readonly int[] _shipFirstIndex = new[] { 11, 9, 6, 1 }; + private static readonly int[] _shipSize = new[] { 2, 2, 3, 5 }; + private readonly IReadWrite _io; private readonly IRandom _random; @@ -17,7 +21,8 @@ internal void Play() { _io.Write(Streams.Title); -L1040: var computerGrid = new float[11,11]; + +L1040: var humanGrid = new float[11,11]; var shotsX = new int[8]; var shotsY = new int[8]; @@ -25,54 +30,27 @@ internal void Play() var tempX = new int[13]; var tempY = new int[13]; var hitShipValue = new float[13]; - var temp = new int[11,11]; -L1060: for (var W = 1; W <= 12; W++) - { -L1070: hitTurnRecord[W] = -1; -L1080: hitShipValue[W] = -1; - } -L1100: for (var X = 1; X <= 10; X++) - { -L1110: for (var Y = 1; Y <= 10; Y++) - { -L1120: humanGrid[X,Y] = 0; - } - } -L1150: for (var X = 1; X <= 12; X++) +L1060: for (var i = 1; i <= 12; i++) { -L1160: tempX[X]=0; -L1170: tempY[X]=0; +L1070: hitTurnRecord[i] = -1; +L1080: hitShipValue[i] = -1; } -L1190: for (var X = 1; X <= 10; X++) - { -L1200: for (var Y = 1; Y <= 10; Y++) - { -L1210: computerGrid[X,Y]=0; - } - } -L1240: for (var K = 4; K >= 1; K--) +L1190: var computerGrid = new float[11,11]; +L1240: for (var K = 3; K >= 0; K--) { L1250: var shipGenerationAttempts=0; -L1260: var (startX, startY, deltaY, deltaX) = L2910(); -L1270: int GetFirstIndex(int shipNumber) => (5-shipNumber)*3-2*(shipNumber/4)+Math.Sign(shipNumber-1)-1; -L1280: int GetShipSizeLessOne(int shipNumber) => shipNumber + shipNumber/4 - Math.Sign(shipNumber-1); -L1290: if (deltaY+deltaX+deltaY*deltaX == 0) { goto L1260; } -L1300: if (startY+deltaY*GetShipSizeLessOne(K)>10) { goto L1260; } -L1310: if (startY+deltaY*GetShipSizeLessOne(K)<1) { goto L1260; } -L1320: if (startX+deltaX*GetShipSizeLessOne(K)>10) { goto L1260; } -L1330: if (startX+deltaX*GetShipSizeLessOne(K)<1) { goto L1260; } -L1340: shipGenerationAttempts=shipGenerationAttempts+1; +L1260: var (startX, startY, deltaY, deltaX) = GetRandomShipCoordinatesInRange(K); +L1340: shipGenerationAttempts++; L1350: if (shipGenerationAttempts>25) { goto L1190; } // determine ship coordinates -L1360: for (var i = 0; i <= GetShipSizeLessOne(K); i++) +L1360: for (var i = 0; i <= _shipSize[K] - 1; i++) { - tempX[i+GetFirstIndex(K)]=startX+deltaX*i; -L1380: tempY[i+GetFirstIndex(K)]=startY+deltaY*i; + tempX[i+_shipFirstIndex[K]]=startX+deltaX*i; +L1380: tempY[i+_shipFirstIndex[K]]=startY+deltaY*i; } -L1400: var firstIndex=GetFirstIndex(K); -L1405: if (firstIndex>firstIndex+GetShipSizeLessOne(K)) { goto L1460; } // Can't be true +L1400: var firstIndex=_shipFirstIndex[K]; // detect proximity to previous ships - for (var i = firstIndex; i <= firstIndex+GetShipSizeLessOne(K); i++) + for (var i = firstIndex; i <= firstIndex+_shipSize[K] - 1; i++) { L1415: if (firstIndex<2) { continue; } // Only true for the Battleship L1420: for (var j = 1; j <= firstIndex-1; j++) @@ -81,60 +59,63 @@ internal void Play() } } // put ship on board -L1460: for (var i = 0; i <= GetShipSizeLessOne(K); i++) +L1460: for (var i = firstIndex; i <= firstIndex + _shipSize[K] - 1; i++) { -L1470: computerGrid[tempX[i+firstIndex],tempY[i+firstIndex]]=.5F+Math.Sign(K-1)*(K-1.5F); + computerGrid[tempX[i], tempY[i]] = _shipValue[K]; } } L1500: _io.WriteLine("ENTER COORDINATES FOR..."); L1510: _io.WriteLine("BATTLESHIP"); L1520: for (var i = 1; i <= 5; i++) { - var (x, y) = _io.Read2Numbers(""); -L1540: humanGrid[(int)x, (int)y] = 3; + var (x, y) = _io.ReadCoordinates(); +L1540: humanGrid[x, y] = 3; } L1560: _io.WriteLine("CRUISER"); L1570: for (var i = 1; i <= 3; i++) { - var (x, y) = _io.Read2Numbers(""); -L1590: humanGrid[(int)x, (int)y]=2; + var (x, y) = _io.ReadCoordinates(); +L1590: humanGrid[x, y] = 2; } L1610: _io.WriteLine("DESTROYER"); L1620: for (var i = 1; i <= 2; i++) { - var (x, y) = _io.Read2Numbers(""); -L1640: humanGrid[(int)x, (int)y]=1; + var (x, y) = _io.ReadCoordinates(); +L1640: humanGrid[x, y] = 1; } L1660: _io.WriteLine("DESTROYER"); L1670: for (var i = 1; i <= 2; i++) { - var (x, y) = _io.Read2Numbers(""); -L1690: humanGrid[(int)x, (int)y]=.5F; + var (x, y) = _io.ReadCoordinates(); +L1690: humanGrid[x, y] = 0.5F; } L1710: var startResponse = _io.ReadString("DO YOU WANT TO START"); -L1730: if (startResponse != "WHERE ARE YOUR SHIPS?") { goto L1890; } -L1740: _io.WriteLine("BATTLESHIP"); -L1750: for (var i = 1; i <= 5; i++) +L1730: while (startResponse == "WHERE ARE YOUR SHIPS?") { -L1760: _io.WriteLine($" {tempX[i]} {tempY[i]} "); + _io.WriteLine("BATTLESHIP"); + for (var i = 1; i <= 5; i++) + { + _io.WriteLine($" {tempX[i]} {tempY[i]} "); + } + _io.WriteLine("CRUISER"); + _io.WriteLine($" {tempX[6]} {tempY[6]} "); + _io.WriteLine($" {tempX[7]} {tempY[7]} "); + _io.WriteLine($" {tempX[8]} {tempY[8]} "); + _io.WriteLine("DESTROYER"); + _io.WriteLine($" {tempX[9]} {tempY[9]} "); + _io.WriteLine($" {tempX[10]} {tempY[10]} "); + _io.WriteLine("DESTROYER"); + _io.WriteLine($" {tempX[11]} {tempY[11]} "); + _io.WriteLine($" {tempX[12]} {tempY[12]} "); + + startResponse = _io.ReadString("DO YOU WANT TO START"); } -L1780: _io.WriteLine("CRUISER"); -L1790: _io.WriteLine($" {tempX[6]} {tempY[6]} "); -L1800: _io.WriteLine($" {tempX[7]} {tempY[7]} "); -L1810: _io.WriteLine($" {tempX[8]} {tempY[8]} "); -L1820: _io.WriteLine("DESTROYER"); -L1830: _io.WriteLine($" {tempX[9]} {tempY[9]} "); -L1840: _io.WriteLine($" {tempX[10]} {tempY[10]} "); -L1850: _io.WriteLine("DESTROYER"); -L1860: _io.WriteLine($" {tempX[11]} {tempY[11]} "); -L1870: _io.WriteLine($" {tempX[12]} {tempY[12]} "); -L1880: goto L1710; L1890: var turnNumber=0; L1900: var seeShotsResponse = _io.ReadString("DO YOU WANT TO SEE MY SHOTS"); L1920: _io.WriteLine(); L1930: if (startResponse != "YES") { goto L2620; } L1950: if (startResponse != "YES") { goto L1990; } -L1960: turnNumber=turnNumber+1; +L1960: turnNumber++; L1970: _io.WriteLine(); L1980: _io.WriteLine($"TURN {turnNumber}"); L1990: var maxShotCount=0; @@ -148,78 +129,56 @@ internal void Play() } } L2060: continue; -L2070: maxShotCount=maxShotCount+(int)(shipValue+.5F); +L2070: maxShotCount+=(int)(shipValue+.5F); } L2090: for (var i = 1; i <= 7; i++) { -L2100: shotsX[i] = 0; -L2110: shotsY[i] = 0; -L2120: tempX[i] = 0; -L2130: tempY[i] = 0; +L2100: shotsX[i] = shotsY[i] = tempX[i] = tempY[i] = 0; } L2150: var untriedSquareCount=0; L2160: for (var x = 1; x <= 10; x++) { L2170: for (var y = 1; y <= 10; y++) { -L2180: if (computerGrid[x,y]>10) { continue; } -L2190: untriedSquareCount=untriedSquareCount+1; +L2180: if (computerGrid[x,y] <= 10) { untriedSquareCount++; } } } L2220: _io.WriteLine($"YOU HAVE {maxShotCount} SHOTS."); -L2230: if (untriedSquareCount >= maxShotCount) { goto L2260; } -L2240: _io.WriteLine("YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES."); -L2250: goto L2890; -L2260: if (maxShotCount != 0) { goto L2290; } -L2270: _io.WriteLine("I HAVE WON."); -L2280: return; + if (maxShotCount == 0) { goto L2270; } +L2230: if (maxShotCount > untriedSquareCount) + { + _io.WriteLine("YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES."); +L2250: goto L2890; + } L2290: for (var i = 1; i <= maxShotCount; i++) { -L2300: var (x, y) = _io.Read2Numbers(""); -L2310: if (x != (int)x) { goto L2370; } -L2320: if (x > 10) { goto L2370; } -L2330: if (x < 1) { goto L2370; } -L2340: if (y != (int)y) { goto L2370; } -L2350: if (y > 10) { goto L2370; } -L2360: if (y >= 1) { goto L2390; } -L2370: _io.WriteLine("ILLEGAL, ENTER AGAIN."); -L2380: goto L2300; -L2390: if (computerGrid[(int)x,(int)y]>10) - { - _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {computerGrid[(int)x,(int)y]-10}"); - goto L2300; + while (true) + { + var (x, y) = _io.ReadValidCoordinates(); +L2390: if (computerGrid[x,y]>10) + { + _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {computerGrid[x,y]-10}"); + continue; + } + shotsX[i]=x; + shotsY[i]=y; + break; } -L2400: shotsX[i]=(int)x; -L2410: shotsY[i]=(int)y; } L2460: for (var W = 1; W <= maxShotCount; W++) { -L2470: if (computerGrid[shotsX[W],shotsY[W]] == 3) - { - _io.WriteLine("YOU HIT MY BATTLESHIP."); - goto L2510; - } -L2480: if (computerGrid[shotsX[W],shotsY[W]] == 2) - { - _io.WriteLine("YOU HIT MY CRUISER."); - goto L2510; - } -L2490: if (computerGrid[shotsX[W],shotsY[W]] == 1) - { - _io.WriteLine("YOU HIT MY DESTROYER."); - goto L2510; - } -L2500: if (computerGrid[shotsX[W],shotsY[W]] == .5F) - { - - _io.WriteLine("YOU HIT MY DESTROYER."); - goto L2510; - } + _io.WriteLine(computerGrid[shotsX[W],shotsY[W]] switch + { + 3 => "YOU HIT MY BATTLESHIP.", + 2 => "YOU HIT MY CRUISER.", + 1 => "YOU HIT MY DESTROYER.", + .5F => "YOU HIT MY DESTROYER.", + _ => throw new InvalidOperationException($"Unexpected value {computerGrid[shotsX[W],shotsY[W]]}") + }); L2510: computerGrid[shotsX[W],shotsY[W]] = 10+turnNumber; } -L2620: maxShotCount = 0; -L2630: if (startResponse == "YES") { goto L2670; } -L2640: turnNumber = turnNumber + 1; +L2620: if (startResponse == "YES") { goto L2670; } +L2640: turnNumber++; L2650: _io.WriteLine(); L2660: _io.WriteLine($"TURN {turnNumber}"); L2670: maxShotCount = 0; @@ -233,7 +192,7 @@ internal void Play() } } L2740: continue; -L2750: maxShotCount = maxShotCount + (int)(shipValue+.5F); +L2750: maxShotCount += (int)(shipValue+.5F); } L2770: untriedSquareCount=0; L2780: for (var x = 1; x <= 10; x++) @@ -241,7 +200,7 @@ internal void Play() L2790: for (var y = 1; y <= 10; y++) { L2800: if (computerGrid[x,y]>10) { continue; } -L2810: untriedSquareCount=untriedSquareCount+1; +L2810: untriedSquareCount++; } } L2840: _io.WriteLine($"I HAVE {maxShotCount} SHOTS."); @@ -251,16 +210,9 @@ internal void Play() L2880: if (maxShotCount != 0) { goto L2960; } L2890: _io.WriteLine("YOU HAVE WON."); L2900: return; +L2270: _io.WriteLine("I HAVE WON."); + return; - (int, int, int, int) L2910() - { - var startX = _random.Next(1, 11); - var startY = _random.Next(1, 11); - var deltaY = _random.Next(-1, 2); - var deltaX = _random.Next(-1, 2); - - return (startX, startY, deltaY, deltaX); - } L2960: for (var i = 1; i <= 12; i++) { @@ -269,11 +221,11 @@ internal void Play() } L3000: var shotCount=0; L3010: var shotAttempts=0; -L3020: var (shotX, shotY, _, _) = L2910(); +L3020: var (shotX, shotY, _, _) = GetRandomShipCoordinates(); L3030: //RESTORE var index = 0; L3040: var strategyNumber=0; -L3050: shotAttempts=shotAttempts+1; +L3050: shotAttempts++; L3060: if (shotAttempts>100) { goto L3010; } // ensure shot is in range L3070: if (shotX>10) { goto L3110; } @@ -296,9 +248,9 @@ internal void Play() var data = new[] { 1,1,-1,1,1,-3,1,1,0,2,-1,1 }; L3220: //READ X1,Y1 var (xOffset, yOffset) = (data[index++], data[index++]); -L3230: strategyNumber=strategyNumber+1; -L3250: shotX=shotX+xOffset; -L3260: shotY=shotY+yOffset; +L3230: strategyNumber++; +L3250: shotX+=xOffset; +L3260: shotY+=yOffset; // is the shot in range? L3270: if (shotX>10) { goto L3210; } L3280: if (shotX<1) { goto L3210; } @@ -309,10 +261,9 @@ internal void Play() // have we already selected this shot? L3320: for (var i = 1; i <= shotCount; i++) { -L3330: if (tempX[i] != shotX) { continue; } -L3340: if (tempY[i] == shotY) { goto L3210; } +L3330: if (tempX[i] == shotX && tempY[i] == shotY) { goto L3210; } } -L3360: shotCount=shotCount+1; +L3360: shotCount++; L3370: goto L3180; // display shots L3380: if (seeShotsResponse != "YES") { goto L3420; } @@ -354,16 +305,17 @@ internal void Play() L3620: for (var k = 1; k <= 12; k++) { L3630: if (hitShipValue[k] != hitShipValue[j]) { continue; } -L3640: shipHits=shipHits+1; +L3640: shipHits++; } // if ship is not sunk L3660: if (shipHits != (int)(hitShipValue[j]+.5F)+1+(int)(hitShipValue[j]+.5F)/3) { goto L3470; } // otherwise, remove ship hit records L3670: for (var k = 1; k <= 12; k++) { -L3680: if (hitShipValue[k] != hitShipValue[j]) { continue; } -L3690: hitTurnRecord[k] = -1; -L3700: hitShipValue[k] = -1; +L3680: if (hitShipValue[k] == hitShipValue[j]) + { +L3700: hitShipValue[k] = hitTurnRecord[k] = -1; + } } L3720: goto L3470; } @@ -379,13 +331,7 @@ internal void Play() } L3490: goto L1950; L3800: //REM************************USINGEARRAY -L3810: for (var x = 1; x <= 10; x++) - { -L3820: for (var y = 1; y <= 10; y++) - { - temp[x,y]=0; - } - } + var temp = new int[11,11]; L3860: for (var i = 1; i <= 12; i++) { L3870: if (hitTurnRecord[i]<10) { continue; } @@ -393,18 +339,24 @@ internal void Play() { L3890: for (var y = 1; y <= 10; y++) { -L3900: if (humanGrid[x,y]<10) { goto L3930; } -L3910: temp[x,y]=-10000000; -L3920: continue; -L3930: for (var dX = Math.Sign(1-x); dX <= Math.Sign(10-x); dX++) - { -L3940: for (var dY = Math.Sign(1-y); dY <= Math.Sign(10-y); dY++) +L3900: if (humanGrid[x,y]>=10) + { +L3930: for (var dX = Math.Sign(1-x); dX <= Math.Sign(10-x); dX++) { -L3950: if (dY+dX+dY*dX==0) { continue; } -L3960: if (humanGrid[x+dX,y+dY] != hitTurnRecord[i]) { continue; } -L3970: temp[x,y]=temp[x,y]+hitTurnRecord[i]-y*(int)(hitShipValue[i]+.5F); +L3940: for (var dY = Math.Sign(1-y); dY <= Math.Sign(10-y); dY++) + { +L3950: if (dX == 0 && dY ==0) { continue; } +L3960: if (humanGrid[x+dX,y+dY] == hitTurnRecord[i]) + { +L3970: temp[x,y]=temp[x,y]+hitTurnRecord[i]-y*(int)(hitShipValue[i]+.5F); + } + } } } + else + { +L3910: temp[x,y]=-10000000; + } } } } @@ -426,10 +378,10 @@ internal void Play() L4131: if (x>maxShotCount) { goto L4140; } L4132: if (x==y) { goto L4210; } L4140: if (temp[x,y]=1 && endX<=10 && endY>=1 && endY<=10) + { + return (startX, startY, deltaX, deltaY); + } + } + } +} + +internal static class IOExtensions +{ + internal static (int X, int Y) ReadCoordinates(this IReadWrite io) + { + var (x, y) = io.Read2Numbers(""); + return ((int)x, (int)y); + } + + internal static (int X, int Y) ReadValidCoordinates(this IReadWrite io) + { + while (true) + { + var (x, y) = io.Read2Numbers(""); + if (x == (int)x && x is >= 1 and <= 10 && y == (int)y && y is >= 1 and <= 10) + { + return ((int)x, (int)y); + } + io.WriteLine("ILLEGAL, ENTER AGAIN."); + } + } +} From 050765e89f084d2f0e6fb470ebe31a92772403b8 Mon Sep 17 00:00:00 2001 From: Christopher Date: Mon, 6 Mar 2023 09:37:45 +1300 Subject: [PATCH 092/377] minor bug fix for 0 path trying to exit the perimeter --- 84_Super_Star_Trek/rust/src/commands.rs | 7 +++++++ 84_Super_Star_Trek/rust/src/view.rs | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index d2eefc61c..c1c4bc8d4 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -151,6 +151,13 @@ fn move_enterprise(course: f32, warp_speed: f32, galaxy: &mut Galaxy) { } } + if path.len() == 0 { + if hit_edge { + view::hit_edge(ship.quadrant, ship.sector); + } + return; + } + let energy_cost = path.len() as u16 + 10; if energy_cost > ship.total_energy { diff --git a/84_Super_Star_Trek/rust/src/view.rs b/84_Super_Star_Trek/rust/src/view.rs index c276dee20..caf6b74d2 100644 --- a/84_Super_Star_Trek/rust/src/view.rs +++ b/84_Super_Star_Trek/rust/src/view.rs @@ -199,7 +199,7 @@ pub fn intro(model: &Galaxy) { "Your orders are as follows: Destroy the {} Klingon warships which have invaded the galaxy before they can attack federation headquarters - on stardate {}. This gives you {} days. {} in the galaxy for resupplying your ship.\n", + on stardate {:.1}. This gives you {} days. {} in the galaxy for resupplying your ship.\n", model.remaining_klingons(), model.final_stardate, model.final_stardate - model.stardate, star_base_message) } @@ -253,7 +253,7 @@ pub fn short_range_scan(model: &Galaxy) { } let data : [String; 8] = [ - format!("Stardate {}", model.stardate), + format!("Stardate {:.1}", model.stardate), format!("Condition {}", condition), format!("Quadrant {}", model.enterprise.quadrant), format!("Sector {}", model.enterprise.sector), @@ -300,7 +300,7 @@ pub fn print_command_help() { pub fn end_game_failure(galaxy: &Galaxy) { println!( -"Is is stardate {}. +"Is is stardate {:.1}. There were {} Klingon battle cruisers left at the end of your mission. ", galaxy.stardate, galaxy.remaining_klingons()); @@ -519,7 +519,7 @@ pub fn starbase_shields() { pub fn repair_estimate(repair_time: f32) { println!( "Technicians standing by to effect repairs to your ship; -Estimated time to repair: {repair_time} stardates.") +Estimated time to repair: {repair_time:.1} stardates.") } pub fn no_damage(sector: Pos) { @@ -613,7 +613,7 @@ pub fn status_report(galaxy: &Galaxy) { println!(" Status report: Klingons left: {klingon_count} -Mission must be completed in {time_remaining} stardates. +Mission must be completed in {time_remaining:.1} stardates. The Federation is maintaining {star_bases} starbase{plural_starbase} in the galaxy. ") } From a6d191261dc8c245f433b73e0a509ac72a2f94d6 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Mon, 6 Mar 2023 08:50:21 +1100 Subject: [PATCH 093/377] Introduce Coordinate and Offset --- 77_Salvo/csharp/Game.cs | 175 +++++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 81 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 3c3825218..4d4551d1c 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -21,14 +21,10 @@ internal void Play() { _io.Write(Streams.Title); - -L1040: - var humanGrid = new float[11,11]; - var shotsX = new int[8]; - var shotsY = new int[8]; +L1040: var humanGrid = new float[11,11]; var hitTurnRecord = new int[13]; - var tempX = new int[13]; - var tempY = new int[13]; + var shots = new Coordinates[8]; + var temp = new Coordinates[13]; var hitShipValue = new float[13]; L1060: for (var i = 1; i <= 12; i++) { @@ -39,14 +35,13 @@ internal void Play() L1240: for (var K = 3; K >= 0; K--) { L1250: var shipGenerationAttempts=0; -L1260: var (startX, startY, deltaY, deltaX) = GetRandomShipCoordinatesInRange(K); +L1260: var (start, delta) = GetRandomShipCoordinatesInRange(K); L1340: shipGenerationAttempts++; L1350: if (shipGenerationAttempts>25) { goto L1190; } // determine ship coordinates -L1360: for (var i = 0; i <= _shipSize[K] - 1; i++) +L1360: for (var i = _shipFirstIndex[K]; i <= _shipFirstIndex[K] + _shipSize[K] - 1; i++) { - tempX[i+_shipFirstIndex[K]]=startX+deltaX*i; -L1380: tempY[i+_shipFirstIndex[K]]=startY+deltaY*i; + temp[i] = start + delta * i; } L1400: var firstIndex=_shipFirstIndex[K]; // detect proximity to previous ships @@ -55,13 +50,13 @@ internal void Play() L1415: if (firstIndex<2) { continue; } // Only true for the Battleship L1420: for (var j = 1; j <= firstIndex-1; j++) { -L1430: if (Math.Sqrt((tempX[j]-tempX[i])*(tempX[j]-tempX[i]) + (tempY[j]-tempY[i])*(tempY[j]-tempY[i])) < 3.59) { goto L1260; } +L1430: if (temp[j].DistanceTo(temp[i]) < 3.59) { goto L1260; } } } // put ship on board L1460: for (var i = firstIndex; i <= firstIndex + _shipSize[K] - 1; i++) { - computerGrid[tempX[i], tempY[i]] = _shipValue[K]; + computerGrid[temp[i].X, temp[i].Y] = _shipValue[K]; } } L1500: _io.WriteLine("ENTER COORDINATES FOR..."); @@ -95,18 +90,18 @@ internal void Play() _io.WriteLine("BATTLESHIP"); for (var i = 1; i <= 5; i++) { - _io.WriteLine($" {tempX[i]} {tempY[i]} "); + _io.WriteLine(temp[i]); } _io.WriteLine("CRUISER"); - _io.WriteLine($" {tempX[6]} {tempY[6]} "); - _io.WriteLine($" {tempX[7]} {tempY[7]} "); - _io.WriteLine($" {tempX[8]} {tempY[8]} "); + _io.WriteLine(temp[6]); + _io.WriteLine(temp[7]); + _io.WriteLine(temp[8]); _io.WriteLine("DESTROYER"); - _io.WriteLine($" {tempX[9]} {tempY[9]} "); - _io.WriteLine($" {tempX[10]} {tempY[10]} "); + _io.WriteLine(temp[9]); + _io.WriteLine(temp[10]); _io.WriteLine("DESTROYER"); - _io.WriteLine($" {tempX[11]} {tempY[11]} "); - _io.WriteLine($" {tempX[12]} {tempY[12]} "); + _io.WriteLine(temp[11]); + _io.WriteLine(temp[12]); startResponse = _io.ReadString("DO YOU WANT TO START"); } @@ -133,7 +128,7 @@ internal void Play() } L2090: for (var i = 1; i <= 7; i++) { -L2100: shotsX[i] = shotsY[i] = tempX[i] = tempY[i] = 0; + shots[i] = temp[i] = 0; } L2150: var untriedSquareCount=0; L2160: for (var x = 1; x <= 10; x++) @@ -160,22 +155,21 @@ internal void Play() _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {computerGrid[x,y]-10}"); continue; } - shotsX[i]=x; - shotsY[i]=y; + shots[i]= new(x, y); break; } } L2460: for (var W = 1; W <= maxShotCount; W++) { - _io.WriteLine(computerGrid[shotsX[W],shotsY[W]] switch + _io.WriteLine(computerGrid[shots[W].X,shots[W].Y] switch { 3 => "YOU HIT MY BATTLESHIP.", 2 => "YOU HIT MY CRUISER.", 1 => "YOU HIT MY DESTROYER.", .5F => "YOU HIT MY DESTROYER.", - _ => throw new InvalidOperationException($"Unexpected value {computerGrid[shotsX[W],shotsY[W]]}") + _ => throw new InvalidOperationException($"Unexpected value {computerGrid[shots[W].X,shots[W].Y]}") }); -L2510: computerGrid[shotsX[W],shotsY[W]] = 10+turnNumber; +L2510: computerGrid[shots[W].X,shots[W].Y] = 10+turnNumber; } L2620: if (startResponse == "YES") { goto L2670; } L2640: turnNumber++; @@ -221,47 +215,30 @@ internal void Play() } L3000: var shotCount=0; L3010: var shotAttempts=0; -L3020: var (shotX, shotY, _, _) = GetRandomShipCoordinates(); -L3030: //RESTORE - var index = 0; -L3040: var strategyNumber=0; +L3020: var (shot, _) = GetRandomShipCoordinates(); +L3030: var strategyNumber=0; //RESTORE L3050: shotAttempts++; L3060: if (shotAttempts>100) { goto L3010; } // ensure shot is in range -L3070: if (shotX>10) { goto L3110; } -L3080: if (shotX>0) { goto L3120; } -L3090: shotX = 1 + (int)_random.NextFloat(2.5F); -L3100: goto L3120; -L3110: shotX = 10 - (int)_random.NextFloat(2.5F); -L3120: if (shotY>10) { goto L3160; } -L3130: if (shotY>0) { goto L3270; } -L3140: shotY=1+(int)_random.NextFloat(2.5F); -L3150: goto L3270; -L3160: shotY=10-(int)_random.NextFloat(2.5F); +L3070: shot = shot.BringIntoRange(_random); L3170: goto L3270; // record shot -L3180: tempX[shotCount]=shotX; -L3190: tempY[shotCount]=shotY; +L3180: temp[shotCount]=shot; L3200: if (shotCount==maxShotCount) { goto L3380; } L3210: if (strategyNumber==6) { goto L3030; } L3240: //DATA 1,1,-1,1,1,-3,1,1,0,2,-1,1 - var data = new[] { 1,1,-1,1,1,-3,1,1,0,2,-1,1 }; + var data = new Offset[] { new(1,1),new(-1,1),new(1,-3),new(1,1),new(0,2),new(-1,1) }; L3220: //READ X1,Y1 - var (xOffset, yOffset) = (data[index++], data[index++]); -L3230: strategyNumber++; -L3250: shotX+=xOffset; -L3260: shotY+=yOffset; + var offset = data[strategyNumber++]; +L3250: shot+=offset; // is the shot in range? -L3270: if (shotX>10) { goto L3210; } -L3280: if (shotX<1) { goto L3210; } -L3290: if (shotY>10) { goto L3210; } -L3300: if (shotY<1) { goto L3210; } +L3270: if (!shot.IsInRange) { goto L3210; } // have we fired here before -L3310: if (humanGrid[shotX,shotY]>10) { goto L3210; } +L3310: if (humanGrid[shot.X,shot.Y]>10) { goto L3210; } // have we already selected this shot? L3320: for (var i = 1; i <= shotCount; i++) { -L3330: if (tempX[i] == shotX && tempY[i] == shotY) { goto L3210; } +L3330: if (temp[i] == shot) { goto L3210; } } L3360: shotCount++; L3370: goto L3180; @@ -269,29 +246,29 @@ internal void Play() L3380: if (seeShotsResponse != "YES") { goto L3420; } L3390: for (var i = 1; i <= maxShotCount; i++) { -L3400: _io.WriteLine($" {tempX[i]} {tempY[i]}"); +L3400: _io.WriteLine(temp[i]); } L3420: for (var i = 1; i <= maxShotCount; i++) { -L3430: if (humanGrid[tempX[i],tempY[i]] == 3) +L3430: if (humanGrid[temp[i].X,temp[i].Y] == 3) { _io.WriteLine("I HIT YOUR BATTLESHIP"); } - else if (humanGrid[tempX[i],tempY[i]] == 2) + else if (humanGrid[temp[i].X,temp[i].Y] == 2) { _io.WriteLine("I HIT YOUR CRUISER"); } - else if (humanGrid[tempX[i],tempY[i]] == 1) + else if (humanGrid[temp[i].X,temp[i].Y] == 1) { _io.WriteLine("I HIT YOUR DESTROYER"); } - else if (humanGrid[tempX[i],tempY[i]] == .5F) + else if (humanGrid[temp[i].X,temp[i].Y] == .5F) { _io.WriteLine("I HIT YOUR DESTROYER"); } else { - humanGrid[tempX[i],tempY[i]]=10+turnNumber; + humanGrid[temp[i].X,temp[i].Y]=10+turnNumber; continue; } L3570: for (var j = 1; j <= 12; j++) @@ -299,7 +276,7 @@ internal void Play() // record hit L3580: if (hitTurnRecord[j] != -1) { continue; } L3590: hitTurnRecord[j]=10+turnNumber; -L3600: hitShipValue[j]=humanGrid[tempX[i],tempY[i]]; +L3600: hitShipValue[j]=humanGrid[temp[i].X,temp[i].Y]; // look for past hits on same ship L3610: var shipHits=0; L3620: for (var k = 1; k <= 12; k++) @@ -327,11 +304,11 @@ internal void Play() L3770: _io.WriteLine($"{nameof(hitShipValue)}( {j} ) = {hitShipValue[j]}"); } return; -L3470: humanGrid[tempX[i],tempY[i]]=10+turnNumber; +L3470: humanGrid[temp[i].X,temp[i].Y]=10+turnNumber; } L3490: goto L1950; L3800: //REM************************USINGEARRAY - var temp = new int[11,11]; + var tempGrid = new int[11,11]; L3860: for (var i = 1; i <= 12; i++) { L3870: if (hitTurnRecord[i]<10) { continue; } @@ -348,22 +325,21 @@ internal void Play() L3950: if (dX == 0 && dY ==0) { continue; } L3960: if (humanGrid[x+dX,y+dY] == hitTurnRecord[i]) { -L3970: temp[x,y]=temp[x,y]+hitTurnRecord[i]-y*(int)(hitShipValue[i]+.5F); +L3970: tempGrid[x,y] += hitTurnRecord[i]-y*(int)(hitShipValue[i]+.5F); } } } } else { -L3910: temp[x,y]=-10000000; +L3910: tempGrid[x,y]=-10000000; } } } } L4030: for (var i = 1; i <= maxShotCount; i++) { -L4040: tempX[i]=i; -L4050: tempY[i]=i; +L4040: temp[i]=i; } L4070: for (var x = 1; x <= 10; x++) { @@ -372,19 +348,18 @@ internal void Play() L4090: var Q9=1; L4100: for (var i = 1; i <= maxShotCount; i++) { -L4110: if (temp[tempX[i],tempY[i]]>=temp[tempX[Q9],tempY[Q9]]) { continue; } +L4110: if (tempGrid[temp[i].X,temp[i].Y]>=tempGrid[temp[Q9].X,temp[Q9].Y]) { continue; } L4120: Q9=i; } L4131: if (x>maxShotCount) { goto L4140; } L4132: if (x==y) { goto L4210; } -L4140: if (temp[x,y]=1 && endX<=10 && endY>=1 && endY<=10) + var end = start + delta * shipSizeLessOne; + if (delta != 0 && end.IsInRange) { - return (startX, startY, deltaX, deltaY); + return (start, delta); } } } @@ -438,3 +412,42 @@ internal static (int X, int Y) ReadValidCoordinates(this IReadWrite io) } } } + +internal record struct Coordinates(int X, int Y) +{ + internal Coordinates(float x, float y) + : this((int)x, (int)y) + { + } + + public bool IsInRange => X is >= 1 and <= 10 && Y is >= 1 and <= 10; + + internal double DistanceTo(Coordinates other) + => Math.Sqrt((X - other.X) * (X - other.Y) + (Y - other.Y) * (Y - other.Y)); + + internal Coordinates BringIntoRange(IRandom random) + => IsInRange ? this : new(BringIntoRange(X, random), BringIntoRange(Y, random)); + + private int BringIntoRange(int value, IRandom random) + => value switch + { + < 1 => 1 + (int)random.NextFloat(2.5F), + > 10 => 10 - (int)random.NextFloat(2.5F), + _ => value + }; + + public static Coordinates operator +(Coordinates coordinates, Offset offset) + => new(coordinates.X + offset.X, coordinates.Y + offset.Y); + + public static implicit operator Coordinates(int value) => new(value, value); + + public override string ToString() => $" {X} {Y} "; +} + +internal record struct Offset(int X, int Y) +{ + public static Offset operator *(Offset offset, int scale) + => new(offset.X * scale, offset.Y * scale); + + public static implicit operator Offset(int value) => new(value, value); +} From 0089593453f5a025318d049cdce27b8a3d06c663 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Tue, 7 Mar 2023 08:34:55 +1100 Subject: [PATCH 094/377] Add coordinate loops --- 77_Salvo/csharp/Game.cs | 107 ++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 37 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 4d4551d1c..1bdeed5f7 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -311,29 +311,22 @@ internal void Play() var tempGrid = new int[11,11]; L3860: for (var i = 1; i <= 12; i++) { -L3870: if (hitTurnRecord[i]<10) { continue; } -L3880: for (var x = 1; x <= 10; x++) + if (hitTurnRecord[i]<10) { continue; } + foreach (var position in Coordinates.All) { -L3890: for (var y = 1; y <= 10; y++) - { -L3900: if (humanGrid[x,y]>=10) - { -L3930: for (var dX = Math.Sign(1-x); dX <= Math.Sign(10-x); dX++) + if (humanGrid[position.X,position.Y]>=10) + { + foreach (var neighbour in position.Neighbours) + { + if (humanGrid[neighbour.X,neighbour.Y] == hitTurnRecord[i]) { -L3940: for (var dY = Math.Sign(1-y); dY <= Math.Sign(10-y); dY++) - { -L3950: if (dX == 0 && dY ==0) { continue; } -L3960: if (humanGrid[x+dX,y+dY] == hitTurnRecord[i]) - { -L3970: tempGrid[x,y] += hitTurnRecord[i]-y*(int)(hitShipValue[i]+.5F); - } - } + tempGrid[position.X,position.Y] += hitTurnRecord[i]-position.Y*(int)(hitShipValue[i]+.5F); } } - else - { -L3910: tempGrid[x,y]=-10000000; - } + } + else + { + tempGrid[position.X,position.Y]=-10000000; } } } @@ -341,27 +334,24 @@ internal void Play() { L4040: temp[i]=i; } -L4070: for (var x = 1; x <= 10; x++) + foreach (var position in Coordinates.All) { -L4080: for (var y = 1; y <= 10; y++) +L4090: var Q9=1; +L4100: for (var i = 1; i <= maxShotCount; i++) { -L4090: var Q9=1; -L4100: for (var i = 1; i <= maxShotCount; i++) - { -L4110: if (tempGrid[temp[i].X,temp[i].Y]>=tempGrid[temp[Q9].X,temp[Q9].Y]) { continue; } -L4120: Q9=i; - } -L4131: if (x>maxShotCount) { goto L4140; } -L4132: if (x==y) { goto L4210; } -L4140: if (tempGrid[x,y]=tempGrid[temp[Q9].X,temp[Q9].Y]) { continue; } +L4120: Q9=i; } +L4131: if (x>maxShotCount) { goto L4140; } +L4132: if (x==y) { goto L4210; } +L4140: if (tempGrid[x,y] X is >= 1 and <= 10 && Y is >= 1 and <= 10; + public static IEnumerable All + { + get + { + for (int x = 1; x <= 10; x++) + { + for (int y = 1; y <= 10; y++) + { + yield return new(x, y); + } + } + } + } + + public IEnumerable Neighbours + { + get + { + foreach (var offset in Offset.Units) + { + var neighbour = this + offset; + if (neighbour.IsInRange) { yield return neighbour; } + } + } + } + internal double DistanceTo(Coordinates other) => Math.Sqrt((X - other.X) * (X - other.Y) + (Y - other.Y) * (Y - other.Y)); @@ -446,8 +462,25 @@ private int BringIntoRange(int value, IRandom random) internal record struct Offset(int X, int Y) { + public static readonly Offset Zero = 0; + public static Offset operator *(Offset offset, int scale) => new(offset.X * scale, offset.Y * scale); public static implicit operator Offset(int value) => new(value, value); + + public static IEnumerable Units + { + get + { + for (int x = -1; x <= 1; x++) + { + for (int y = -1; y <= 1; y++) + { + var offset = new Offset(x, y); + if (offset != Zero) { yield return offset; } + } + } + } + } } From ee9bfec90ee335549257618a933ea29a84271fbf Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Wed, 8 Mar 2023 08:13:00 +1100 Subject: [PATCH 095/377] Introduce Grid --- 77_Salvo/csharp/Game.cs | 170 ++++++++++++++++++++++------------------ 1 file changed, 92 insertions(+), 78 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 1bdeed5f7..03a111970 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -21,7 +21,7 @@ internal void Play() { _io.Write(Streams.Title); -L1040: var humanGrid = new float[11,11]; +L1040: var humanGrid = new Grid(); var hitTurnRecord = new int[13]; var shots = new Coordinates[8]; var temp = new Coordinates[13]; @@ -31,7 +31,7 @@ internal void Play() L1070: hitTurnRecord[i] = -1; L1080: hitShipValue[i] = -1; } -L1190: var computerGrid = new float[11,11]; +L1190: var computerGrid = new Grid(); L1240: for (var K = 3; K >= 0; K--) { L1250: var shipGenerationAttempts=0; @@ -56,36 +56,32 @@ internal void Play() // put ship on board L1460: for (var i = firstIndex; i <= firstIndex + _shipSize[K] - 1; i++) { - computerGrid[temp[i].X, temp[i].Y] = _shipValue[K]; + computerGrid[temp[i]] = _shipValue[K]; } } -L1500: _io.WriteLine("ENTER COORDINATES FOR..."); -L1510: _io.WriteLine("BATTLESHIP"); -L1520: for (var i = 1; i <= 5; i++) + _io.WriteLine("ENTER COORDINATES FOR..."); + _io.WriteLine("BATTLESHIP"); + for (var i = 1; i <= 5; i++) { - var (x, y) = _io.ReadCoordinates(); -L1540: humanGrid[x, y] = 3; + humanGrid[_io.ReadCoordinates()] = 3; } -L1560: _io.WriteLine("CRUISER"); -L1570: for (var i = 1; i <= 3; i++) + _io.WriteLine("CRUISER"); + for (var i = 1; i <= 3; i++) { - var (x, y) = _io.ReadCoordinates(); -L1590: humanGrid[x, y] = 2; + humanGrid[_io.ReadCoordinates()] = 2; } -L1610: _io.WriteLine("DESTROYER"); -L1620: for (var i = 1; i <= 2; i++) + _io.WriteLine("DESTROYER"); + for (var i = 1; i <= 2; i++) { - var (x, y) = _io.ReadCoordinates(); -L1640: humanGrid[x, y] = 1; + humanGrid[_io.ReadCoordinates()] = 1; } -L1660: _io.WriteLine("DESTROYER"); -L1670: for (var i = 1; i <= 2; i++) + _io.WriteLine("DESTROYER"); + for (var i = 1; i <= 2; i++) { - var (x, y) = _io.ReadCoordinates(); -L1690: humanGrid[x, y] = 0.5F; + humanGrid[_io.ReadCoordinates()] = 0.5F; } -L1710: var startResponse = _io.ReadString("DO YOU WANT TO START"); -L1730: while (startResponse == "WHERE ARE YOUR SHIPS?") + var startResponse = _io.ReadString("DO YOU WANT TO START"); + while (startResponse == "WHERE ARE YOUR SHIPS?") { _io.WriteLine("BATTLESHIP"); for (var i = 1; i <= 5; i++) @@ -116,27 +112,23 @@ internal void Play() L1990: var maxShotCount=0; L2000: for (var shipValue = .5F; shipValue <= 3; shipValue += .5F) { -L2010: for (var x = 1; x <= 10; x++) + foreach (var position in Coordinates.All) { -L2020: for (var y = 1; y <= 10; y++) - { -L2030: if (humanGrid[x,y] == shipValue) { goto L2070; } + if (humanGrid[position] == shipValue) + { + maxShotCount+=(int)(shipValue+.5F); + break; } } -L2060: continue; -L2070: maxShotCount+=(int)(shipValue+.5F); } L2090: for (var i = 1; i <= 7; i++) { shots[i] = temp[i] = 0; } L2150: var untriedSquareCount=0; -L2160: for (var x = 1; x <= 10; x++) + foreach (var position in Coordinates.All) { -L2170: for (var y = 1; y <= 10; y++) - { -L2180: if (computerGrid[x,y] <= 10) { untriedSquareCount++; } - } + if (computerGrid[position.X] <= 10) { untriedSquareCount++; } } L2220: _io.WriteLine($"YOU HAVE {maxShotCount} SHOTS."); if (maxShotCount == 0) { goto L2270; } @@ -149,27 +141,27 @@ internal void Play() { while (true) { - var (x, y) = _io.ReadValidCoordinates(); -L2390: if (computerGrid[x,y]>10) + var position = _io.ReadValidCoordinates(); +L2390: if (computerGrid[position]>10) { - _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {computerGrid[x,y]-10}"); + _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {computerGrid[position]-10}"); continue; } - shots[i]= new(x, y); + shots[i]= position; break; } } L2460: for (var W = 1; W <= maxShotCount; W++) { - _io.WriteLine(computerGrid[shots[W].X,shots[W].Y] switch + _io.WriteLine(computerGrid[shots[W]] switch { 3 => "YOU HIT MY BATTLESHIP.", 2 => "YOU HIT MY CRUISER.", 1 => "YOU HIT MY DESTROYER.", .5F => "YOU HIT MY DESTROYER.", - _ => throw new InvalidOperationException($"Unexpected value {computerGrid[shots[W].X,shots[W].Y]}") + _ => throw new InvalidOperationException($"Unexpected value {computerGrid[shots[W]]}") }); -L2510: computerGrid[shots[W].X,shots[W].Y] = 10+turnNumber; +L2510: computerGrid[shots[W]] = 10+turnNumber; } L2620: if (startResponse == "YES") { goto L2670; } L2640: turnNumber++; @@ -178,24 +170,19 @@ internal void Play() L2670: maxShotCount = 0; L2680: for (var shipValue = .5F; shipValue <= 3; shipValue += .5F) { -L2690: for (var x = 1; x <= 10; x++) + foreach (var position in Coordinates.All) { -L2700: for (var y = 1; y <= 10; y++) - { -L2710: if (computerGrid[x,y] == shipValue) { goto L2750; } + if (computerGrid[position] == shipValue) + { + maxShotCount += (int)(shipValue+.5F); + break; } } -L2740: continue; -L2750: maxShotCount += (int)(shipValue+.5F); } L2770: untriedSquareCount=0; -L2780: for (var x = 1; x <= 10; x++) + foreach (var position in Coordinates.All) { -L2790: for (var y = 1; y <= 10; y++) - { -L2800: if (computerGrid[x,y]>10) { continue; } -L2810: untriedSquareCount++; - } + if (computerGrid[position]<=10) { untriedSquareCount++; } } L2840: _io.WriteLine($"I HAVE {maxShotCount} SHOTS."); L2850: if (untriedSquareCount>maxShotCount) { goto L2880; } @@ -234,7 +221,7 @@ internal void Play() // is the shot in range? L3270: if (!shot.IsInRange) { goto L3210; } // have we fired here before -L3310: if (humanGrid[shot.X,shot.Y]>10) { goto L3210; } +L3310: if (humanGrid[shot]>10) { goto L3210; } // have we already selected this shot? L3320: for (var i = 1; i <= shotCount; i++) { @@ -250,25 +237,25 @@ internal void Play() } L3420: for (var i = 1; i <= maxShotCount; i++) { -L3430: if (humanGrid[temp[i].X,temp[i].Y] == 3) +L3430: if (humanGrid[temp[i]] == 3) { _io.WriteLine("I HIT YOUR BATTLESHIP"); } - else if (humanGrid[temp[i].X,temp[i].Y] == 2) + else if (humanGrid[temp[i]] == 2) { _io.WriteLine("I HIT YOUR CRUISER"); } - else if (humanGrid[temp[i].X,temp[i].Y] == 1) + else if (humanGrid[temp[i]] == 1) { _io.WriteLine("I HIT YOUR DESTROYER"); } - else if (humanGrid[temp[i].X,temp[i].Y] == .5F) + else if (humanGrid[temp[i]] == .5F) { _io.WriteLine("I HIT YOUR DESTROYER"); } else { - humanGrid[temp[i].X,temp[i].Y]=10+turnNumber; + humanGrid[temp[i]]=10+turnNumber; continue; } L3570: for (var j = 1; j <= 12; j++) @@ -276,7 +263,7 @@ internal void Play() // record hit L3580: if (hitTurnRecord[j] != -1) { continue; } L3590: hitTurnRecord[j]=10+turnNumber; -L3600: hitShipValue[j]=humanGrid[temp[i].X,temp[i].Y]; +L3600: hitShipValue[j]=humanGrid[temp[i]]; // look for past hits on same ship L3610: var shipHits=0; L3620: for (var k = 1; k <= 12; k++) @@ -304,29 +291,29 @@ internal void Play() L3770: _io.WriteLine($"{nameof(hitShipValue)}( {j} ) = {hitShipValue[j]}"); } return; -L3470: humanGrid[temp[i].X,temp[i].Y]=10+turnNumber; +L3470: humanGrid[temp[i]]=10+turnNumber; } L3490: goto L1950; L3800: //REM************************USINGEARRAY - var tempGrid = new int[11,11]; + var tempGrid = new Grid(); L3860: for (var i = 1; i <= 12; i++) { if (hitTurnRecord[i]<10) { continue; } foreach (var position in Coordinates.All) { - if (humanGrid[position.X,position.Y]>=10) + if (humanGrid[position]>=10) { foreach (var neighbour in position.Neighbours) { - if (humanGrid[neighbour.X,neighbour.Y] == hitTurnRecord[i]) + if (humanGrid[neighbour] == hitTurnRecord[i]) { - tempGrid[position.X,position.Y] += hitTurnRecord[i]-position.Y*(int)(hitShipValue[i]+.5F); + tempGrid[position] += hitTurnRecord[i]-position.Y*(int)(hitShipValue[i]+.5F); } } } else { - tempGrid[position.X,position.Y]=-10000000; + tempGrid[position]=-10000000; } } } @@ -339,22 +326,21 @@ internal void Play() L4090: var Q9=1; L4100: for (var i = 1; i <= maxShotCount; i++) { -L4110: if (tempGrid[temp[i].X,temp[i].Y]>=tempGrid[temp[Q9].X,temp[Q9].Y]) { continue; } +L4110: if (tempGrid[temp[i]]>=tempGrid[temp[Q9]]) { continue; } L4120: Q9=i; } -L4131: if (x>maxShotCount) { goto L4140; } -L4132: if (x==y) { goto L4210; } -L4140: if (tempGrid[x,y]maxShotCount) { goto L4140; } +L4132: if (position.IsOnDiagonal) { goto L4210; } +L4140: if (tempGrid[position] _positions[position.X - 1, position.Y - 1]; + set => _positions[position.X - 1, position.Y - 1] = value; + } +} + internal static class IOExtensions { - internal static (int X, int Y) ReadCoordinates(this IReadWrite io) + internal static Coordinates ReadCoordinates(this IReadWrite io) { var (x, y) = io.Read2Numbers(""); - return ((int)x, (int)y); + return new(x, y); } - internal static (int X, int Y) ReadValidCoordinates(this IReadWrite io) + internal static Coordinates ReadValidCoordinates(this IReadWrite io) { while (true) { var (x, y) = io.Read2Numbers(""); - if (x == (int)x && x is >= 1 and <= 10 && y == (int)y && y is >= 1 and <= 10) + if (Coordinates.TryCreateValid(x, y, out var position)) { - return ((int)x, (int)y); + return position; } io.WriteLine("ILLEGAL, ENTER AGAIN."); } @@ -411,6 +408,23 @@ internal Coordinates(float x, float y) } public bool IsInRange => X is >= 1 and <= 10 && Y is >= 1 and <= 10; + public bool IsOnDiagonal => X == Y; + + public static bool TryCreateValid(float x, float y, out Coordinates coordinates) + { + coordinates = default; + if (x != (int)x || y != (int)y) { return false; } + + var result = new Coordinates(x, y); + + if (result.IsInRange) + { + coordinates = result; + return true; + } + + return false; + } public static IEnumerable All { From a0683190347402c98ed3f910f1cf7223fafd1dd7 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Wed, 8 Mar 2023 08:17:56 +1100 Subject: [PATCH 096/377] Rename Coordinates to Position --- 77_Salvo/csharp/Game.cs | 79 ++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 03a111970..bd33c3d22 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -23,8 +23,8 @@ internal void Play() L1040: var humanGrid = new Grid(); var hitTurnRecord = new int[13]; - var shots = new Coordinates[8]; - var temp = new Coordinates[13]; + var shots = new Position[8]; + var temp = new Position[13]; var hitShipValue = new float[13]; L1060: for (var i = 1; i <= 12; i++) { @@ -35,10 +35,10 @@ internal void Play() L1240: for (var K = 3; K >= 0; K--) { L1250: var shipGenerationAttempts=0; -L1260: var (start, delta) = GetRandomShipCoordinatesInRange(K); +L1260: var (start, delta) = GetRandomShipPositionInRange(K); L1340: shipGenerationAttempts++; L1350: if (shipGenerationAttempts>25) { goto L1190; } - // determine ship coordinates + // determine ship position L1360: for (var i = _shipFirstIndex[K]; i <= _shipFirstIndex[K] + _shipSize[K] - 1; i++) { temp[i] = start + delta * i; @@ -59,26 +59,26 @@ internal void Play() computerGrid[temp[i]] = _shipValue[K]; } } - _io.WriteLine("ENTER COORDINATES FOR..."); + _io.WriteLine("ENTER POSITION FOR..."); _io.WriteLine("BATTLESHIP"); for (var i = 1; i <= 5; i++) { - humanGrid[_io.ReadCoordinates()] = 3; + humanGrid[_io.ReadPosition()] = 3; } _io.WriteLine("CRUISER"); for (var i = 1; i <= 3; i++) { - humanGrid[_io.ReadCoordinates()] = 2; + humanGrid[_io.ReadPosition()] = 2; } _io.WriteLine("DESTROYER"); for (var i = 1; i <= 2; i++) { - humanGrid[_io.ReadCoordinates()] = 1; + humanGrid[_io.ReadPosition()] = 1; } _io.WriteLine("DESTROYER"); for (var i = 1; i <= 2; i++) { - humanGrid[_io.ReadCoordinates()] = 0.5F; + humanGrid[_io.ReadPosition()] = 0.5F; } var startResponse = _io.ReadString("DO YOU WANT TO START"); while (startResponse == "WHERE ARE YOUR SHIPS?") @@ -112,7 +112,7 @@ internal void Play() L1990: var maxShotCount=0; L2000: for (var shipValue = .5F; shipValue <= 3; shipValue += .5F) { - foreach (var position in Coordinates.All) + foreach (var position in Position.All) { if (humanGrid[position] == shipValue) { @@ -126,7 +126,7 @@ internal void Play() shots[i] = temp[i] = 0; } L2150: var untriedSquareCount=0; - foreach (var position in Coordinates.All) + foreach (var position in Position.All) { if (computerGrid[position.X] <= 10) { untriedSquareCount++; } } @@ -141,7 +141,7 @@ internal void Play() { while (true) { - var position = _io.ReadValidCoordinates(); + var position = _io.ReadValidPosition(); L2390: if (computerGrid[position]>10) { _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {computerGrid[position]-10}"); @@ -170,7 +170,7 @@ internal void Play() L2670: maxShotCount = 0; L2680: for (var shipValue = .5F; shipValue <= 3; shipValue += .5F) { - foreach (var position in Coordinates.All) + foreach (var position in Position.All) { if (computerGrid[position] == shipValue) { @@ -180,7 +180,7 @@ internal void Play() } } L2770: untriedSquareCount=0; - foreach (var position in Coordinates.All) + foreach (var position in Position.All) { if (computerGrid[position]<=10) { untriedSquareCount++; } } @@ -202,7 +202,7 @@ internal void Play() } L3000: var shotCount=0; L3010: var shotAttempts=0; -L3020: var (shot, _) = GetRandomShipCoordinates(); +L3020: var (shot, _) = GetRandomShipPosition(); L3030: var strategyNumber=0; //RESTORE L3050: shotAttempts++; L3060: if (shotAttempts>100) { goto L3010; } @@ -299,7 +299,7 @@ internal void Play() L3860: for (var i = 1; i <= 12; i++) { if (hitTurnRecord[i]<10) { continue; } - foreach (var position in Coordinates.All) + foreach (var position in Position.All) { if (humanGrid[position]>=10) { @@ -321,7 +321,7 @@ internal void Play() { L4040: temp[i]=i; } - foreach (var position in Coordinates.All) + foreach (var position in Position.All) { L4090: var Q9=1; L4100: for (var i = 1; i <= maxShotCount; i++) @@ -343,7 +343,7 @@ internal void Play() L4230: goto L3380; } - private (Coordinates, Offset) GetRandomShipCoordinates() + private (Position, Offset) GetRandomShipPosition() { var startX = _random.Next(1, 11); var startY = _random.Next(1, 11); @@ -352,11 +352,11 @@ internal void Play() return (new(startX, startY), new(deltaX, deltaY)); } - private (Coordinates, Offset) GetRandomShipCoordinatesInRange(int shipNumber) + private (Position, Offset) GetRandomShipPositionInRange(int shipNumber) { while (true) { - var (start, delta) = GetRandomShipCoordinates(); + var (start, delta) = GetRandomShipPosition(); var shipSizeLessOne = _shipSize[shipNumber] - 1; var end = start + delta * shipSizeLessOne; if (delta != 0 && end.IsInRange) @@ -371,7 +371,7 @@ internal class Grid { private readonly float[,] _positions = new float[10, 10]; - public float this[Coordinates position] + public float this[Position position] { get => _positions[position.X - 1, position.Y - 1]; set => _positions[position.X - 1, position.Y - 1] = value; @@ -380,18 +380,18 @@ public float this[Coordinates position] internal static class IOExtensions { - internal static Coordinates ReadCoordinates(this IReadWrite io) + internal static Position ReadPosition(this IReadWrite io) { var (x, y) = io.Read2Numbers(""); return new(x, y); } - internal static Coordinates ReadValidCoordinates(this IReadWrite io) + internal static Position ReadValidPosition(this IReadWrite io) { while (true) { var (x, y) = io.Read2Numbers(""); - if (Coordinates.TryCreateValid(x, y, out var position)) + if (Position.TryCreateValid(x, y, out var position)) { return position; } @@ -400,9 +400,9 @@ internal static Coordinates ReadValidCoordinates(this IReadWrite io) } } -internal record struct Coordinates(int X, int Y) +internal record struct Position(int X, int Y) { - internal Coordinates(float x, float y) + internal Position(float x, float y) : this((int)x, (int)y) { } @@ -410,23 +410,23 @@ internal Coordinates(float x, float y) public bool IsInRange => X is >= 1 and <= 10 && Y is >= 1 and <= 10; public bool IsOnDiagonal => X == Y; - public static bool TryCreateValid(float x, float y, out Coordinates coordinates) + public static bool TryCreateValid(float x, float y, out Position position) { - coordinates = default; + position = default; if (x != (int)x || y != (int)y) { return false; } - var result = new Coordinates(x, y); + var result = new Position(x, y); if (result.IsInRange) { - coordinates = result; + position = result; return true; } return false; } - public static IEnumerable All + public static IEnumerable All { get { @@ -440,7 +440,7 @@ public static IEnumerable All } } - public IEnumerable Neighbours + public IEnumerable Neighbours { get { @@ -452,13 +452,13 @@ public IEnumerable Neighbours } } - internal double DistanceTo(Coordinates other) + internal double DistanceTo(Position other) => Math.Sqrt((X - other.X) * (X - other.Y) + (Y - other.Y) * (Y - other.Y)); - internal Coordinates BringIntoRange(IRandom random) + internal Position BringIntoRange(IRandom random) => IsInRange ? this : new(BringIntoRange(X, random), BringIntoRange(Y, random)); - private int BringIntoRange(int value, IRandom random) + private static int BringIntoRange(int value, IRandom random) => value switch { < 1 => 1 + (int)random.NextFloat(2.5F), @@ -466,10 +466,10 @@ private int BringIntoRange(int value, IRandom random) _ => value }; - public static Coordinates operator +(Coordinates coordinates, Offset offset) - => new(coordinates.X + offset.X, coordinates.Y + offset.Y); + public static Position operator +(Position position, Offset offset) + => new(position.X + offset.X, position.Y + offset.Y); - public static implicit operator Coordinates(int value) => new(value, value); + public static implicit operator Position(int value) => new(value, value); public override string ToString() => $" {X} {Y} "; } @@ -478,8 +478,7 @@ internal record struct Offset(int X, int Y) { public static readonly Offset Zero = 0; - public static Offset operator *(Offset offset, int scale) - => new(offset.X * scale, offset.Y * scale); + public static Offset operator *(Offset offset, int scale) => new(offset.X * scale, offset.Y * scale); public static implicit operator Offset(int value) => new(value, value); From a936de69d1da40bc3c05b149db02f3a2342a3ed3 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Thu, 9 Mar 2023 08:17:39 +1100 Subject: [PATCH 097/377] Introduce Coordinate --- 77_Salvo/csharp/Game.cs | 104 ++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 47 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index bd33c3d22..233487d3d 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -128,7 +128,7 @@ internal void Play() L2150: var untriedSquareCount=0; foreach (var position in Position.All) { - if (computerGrid[position.X] <= 10) { untriedSquareCount++; } + if (computerGrid[position] <= 10) { untriedSquareCount++; } } L2220: _io.WriteLine($"YOU HAVE {maxShotCount} SHOTS."); if (maxShotCount == 0) { goto L2270; } @@ -373,25 +373,20 @@ internal class Grid public float this[Position position] { - get => _positions[position.X - 1, position.Y - 1]; - set => _positions[position.X - 1, position.Y - 1] = value; + get => _positions[position.X, position.Y]; + set => _positions[position.X, position.Y] = value; } } internal static class IOExtensions { - internal static Position ReadPosition(this IReadWrite io) - { - var (x, y) = io.Read2Numbers(""); - return new(x, y); - } + internal static Position ReadPosition(this IReadWrite io) => Position.Create(io.Read2Numbers("")); internal static Position ReadValidPosition(this IReadWrite io) { while (true) { - var (x, y) = io.Read2Numbers(""); - if (Position.TryCreateValid(x, y, out var position)) + if (Position.TryCreateValid(io.Read2Numbers(""), out var position)) { return position; } @@ -400,45 +395,27 @@ internal static Position ReadValidPosition(this IReadWrite io) } } -internal record struct Position(int X, int Y) +internal record struct Position(Coordinate X, Coordinate Y) { - internal Position(float x, float y) - : this((int)x, (int)y) - { - } - - public bool IsInRange => X is >= 1 and <= 10 && Y is >= 1 and <= 10; + public bool IsInRange => X.IsInRange && Y.IsInRange; public bool IsOnDiagonal => X == Y; - public static bool TryCreateValid(float x, float y, out Position position) - { - position = default; - if (x != (int)x || y != (int)y) { return false; } + public static Position Create((float X, float Y) coordinates) => new(coordinates.X, coordinates.Y); - var result = new Position(x, y); - - if (result.IsInRange) + public static bool TryCreateValid((float X, float Y) coordinates, out Position position) + { + if (Coordinate.TryCreateValid(coordinates.X, out var x) && Coordinate.TryCreateValid(coordinates.Y, out var y)) { - position = result; + position = new(x, y); return true; } + position = default; return false; } public static IEnumerable All - { - get - { - for (int x = 1; x <= 10; x++) - { - for (int y = 1; y <= 10; y++) - { - yield return new(x, y); - } - } - } - } + => Coordinate.Range.SelectMany(x => Coordinate.Range.Select(y => new Position(x, y))); public IEnumerable Neighbours { @@ -456,22 +433,55 @@ internal double DistanceTo(Position other) => Math.Sqrt((X - other.X) * (X - other.Y) + (Y - other.Y) * (Y - other.Y)); internal Position BringIntoRange(IRandom random) - => IsInRange ? this : new(BringIntoRange(X, random), BringIntoRange(Y, random)); - - private static int BringIntoRange(int value, IRandom random) - => value switch - { - < 1 => 1 + (int)random.NextFloat(2.5F), - > 10 => 10 - (int)random.NextFloat(2.5F), - _ => value - }; + => IsInRange ? this : new(X.BringIntoRange(random), Y.BringIntoRange(random)); public static Position operator +(Position position, Offset offset) => new(position.X + offset.X, position.Y + offset.Y); public static implicit operator Position(int value) => new(value, value); - public override string ToString() => $" {X} {Y} "; + public override string ToString() => $"{X}{Y}"; +} + +internal record struct Coordinate(int Value) +{ + public static IEnumerable Range => Enumerable.Range(0, 10).Select(v => new Coordinate(v)); + + public bool IsInRange => Value is >= 0 and <= 9; + + public static Coordinate Create(float value) => new((int)value - 1); + + public static bool TryCreateValid(float value, out Coordinate coordinate) + { + coordinate = default; + if (value != (int)value) { return false; } + + var result = Create(value); + + if (result.IsInRange) + { + coordinate = result; + return true; + } + + return false; + } + + public Coordinate BringIntoRange(IRandom random) + => Value switch + { + < 0 => new(0 + (int)random.NextFloat(2.5F)), + > 9 => new(9 - (int)random.NextFloat(2.5F)), + _ => this + }; + + public static implicit operator Coordinate(float value) => new((int)value); + public static implicit operator int(Coordinate coordinate) => coordinate.Value; + + public static Coordinate operator +(Coordinate coordinate, int offset) => new(coordinate.Value + offset); + public static int operator -(Coordinate a, Coordinate b) => a.Value - b.Value; + + public override string ToString() => $" {Value + 1} "; } internal record struct Offset(int X, int Y) From 579e18d8c63e1d45c8a8749c7b0ab7a9b648892f Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Mon, 13 Mar 2023 08:33:48 +1100 Subject: [PATCH 098/377] Fix some bugs --- 77_Salvo/csharp/Game.cs | 48 +++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 233487d3d..bcc16477e 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -35,13 +35,13 @@ internal void Play() L1240: for (var K = 3; K >= 0; K--) { L1250: var shipGenerationAttempts=0; -L1260: var (start, delta) = GetRandomShipPositionInRange(K); +L1260: var (start, delta) = _random.GetRandomShipPositionInRange(_shipSize[K]); L1340: shipGenerationAttempts++; L1350: if (shipGenerationAttempts>25) { goto L1190; } // determine ship position -L1360: for (var i = _shipFirstIndex[K]; i <= _shipFirstIndex[K] + _shipSize[K] - 1; i++) +L1360: for (var i = 0; i < _shipSize[K]; i++) { - temp[i] = start + delta * i; + temp[_shipFirstIndex[K] + i] = start + delta * i; } L1400: var firstIndex=_shipFirstIndex[K]; // detect proximity to previous ships @@ -153,14 +153,15 @@ internal void Play() } L2460: for (var W = 1; W <= maxShotCount; W++) { - _io.WriteLine(computerGrid[shots[W]] switch + var hit = computerGrid[shots[W]] switch { 3 => "YOU HIT MY BATTLESHIP.", 2 => "YOU HIT MY CRUISER.", 1 => "YOU HIT MY DESTROYER.", .5F => "YOU HIT MY DESTROYER.", - _ => throw new InvalidOperationException($"Unexpected value {computerGrid[shots[W]]}") - }); + _ => null + }; + if (hit is not null) { _io.WriteLine(); } L2510: computerGrid[shots[W]] = 10+turnNumber; } L2620: if (startResponse == "YES") { goto L2670; } @@ -202,7 +203,7 @@ internal void Play() } L3000: var shotCount=0; L3010: var shotAttempts=0; -L3020: var (shot, _) = GetRandomShipPosition(); +L3020: var (shot, _) = _random.NextShipPosition(); L3030: var strategyNumber=0; //RESTORE L3050: shotAttempts++; L3060: if (shotAttempts>100) { goto L3010; } @@ -342,22 +343,30 @@ internal void Play() } L4230: goto L3380; } +} - private (Position, Offset) GetRandomShipPosition() +internal static class RandomExtensions +{ + internal static (Position, Offset) NextShipPosition(this IRandom random) { - var startX = _random.Next(1, 11); - var startY = _random.Next(1, 11); - var deltaY = _random.Next(-1, 2); - var deltaX = _random.Next(-1, 2); + var startX = random.NextCoordinate(); + var startY = random.NextCoordinate(); + var deltaY = random.NextOffset(); + var deltaX = random.NextOffset(); return (new(startX, startY), new(deltaX, deltaY)); } - private (Position, Offset) GetRandomShipPositionInRange(int shipNumber) + private static Coordinate NextCoordinate(this IRandom random) + => random.Next(Coordinate.MinValue, Coordinate.MaxValue + 1); + + private static int NextOffset(this IRandom random) => random.Next(-1, 2); + + internal static (Position, Offset) GetRandomShipPositionInRange(this IRandom random, int shipSize) { while (true) { - var (start, delta) = GetRandomShipPosition(); - var shipSizeLessOne = _shipSize[shipNumber] - 1; + var (start, delta) = random.NextShipPosition(); + var shipSizeLessOne = shipSize - 1; var end = start + delta * shipSizeLessOne; if (delta != 0 && end.IsInRange) { @@ -445,9 +454,12 @@ internal Position BringIntoRange(IRandom random) internal record struct Coordinate(int Value) { + public const int MinValue = 0; + public const int MaxValue = 9; + public static IEnumerable Range => Enumerable.Range(0, 10).Select(v => new Coordinate(v)); - public bool IsInRange => Value is >= 0 and <= 9; + public bool IsInRange => Value is >= MinValue and <= MaxValue; public static Coordinate Create(float value) => new((int)value - 1); @@ -470,8 +482,8 @@ public static bool TryCreateValid(float value, out Coordinate coordinate) public Coordinate BringIntoRange(IRandom random) => Value switch { - < 0 => new(0 + (int)random.NextFloat(2.5F)), - > 9 => new(9 - (int)random.NextFloat(2.5F)), + < MinValue => new(MinValue + (int)random.NextFloat(2.5F)), + > MaxValue => new(MaxValue - (int)random.NextFloat(2.5F)), _ => this }; From f5b2fe6e8a293ca066d65c6f4103ce0448c2faf1 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Mon, 27 Mar 2023 08:10:43 +1100 Subject: [PATCH 099/377] Add Ship type --- 77_Salvo/csharp/Game.cs | 211 +++++++++++++++++++++++++++------------- 1 file changed, 141 insertions(+), 70 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index bcc16477e..ddf9aa132 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -1,3 +1,4 @@ +using System.Collections.Immutable; using Games.Common.Randomness; namespace Salvo; @@ -21,84 +22,26 @@ internal void Play() { _io.Write(Streams.Title); -L1040: var humanGrid = new Grid(); var hitTurnRecord = new int[13]; var shots = new Position[8]; var temp = new Position[13]; var hitShipValue = new float[13]; -L1060: for (var i = 1; i <= 12; i++) + + for (var i = 1; i <= 12; i++) { -L1070: hitTurnRecord[i] = -1; -L1080: hitShipValue[i] = -1; - } -L1190: var computerGrid = new Grid(); -L1240: for (var K = 3; K >= 0; K--) - { -L1250: var shipGenerationAttempts=0; -L1260: var (start, delta) = _random.GetRandomShipPositionInRange(_shipSize[K]); -L1340: shipGenerationAttempts++; -L1350: if (shipGenerationAttempts>25) { goto L1190; } - // determine ship position -L1360: for (var i = 0; i < _shipSize[K]; i++) - { - temp[_shipFirstIndex[K] + i] = start + delta * i; - } -L1400: var firstIndex=_shipFirstIndex[K]; - // detect proximity to previous ships - for (var i = firstIndex; i <= firstIndex+_shipSize[K] - 1; i++) - { -L1415: if (firstIndex<2) { continue; } // Only true for the Battleship -L1420: for (var j = 1; j <= firstIndex-1; j++) - { -L1430: if (temp[j].DistanceTo(temp[i]) < 3.59) { goto L1260; } - } - } - // put ship on board -L1460: for (var i = firstIndex; i <= firstIndex + _shipSize[K] - 1; i++) - { - computerGrid[temp[i]] = _shipValue[K]; - } - } - _io.WriteLine("ENTER POSITION FOR..."); - _io.WriteLine("BATTLESHIP"); - for (var i = 1; i <= 5; i++) - { - humanGrid[_io.ReadPosition()] = 3; - } - _io.WriteLine("CRUISER"); - for (var i = 1; i <= 3; i++) - { - humanGrid[_io.ReadPosition()] = 2; - } - _io.WriteLine("DESTROYER"); - for (var i = 1; i <= 2; i++) - { - humanGrid[_io.ReadPosition()] = 1; - } - _io.WriteLine("DESTROYER"); - for (var i = 1; i <= 2; i++) - { - humanGrid[_io.ReadPosition()] = 0.5F; + hitTurnRecord[i] = -1; + hitShipValue[i] = -1; } + var computerGrid = new Grid().PositionShips(_random); + var humanGrid = new Grid().PositionShips(_io); + var startResponse = _io.ReadString("DO YOU WANT TO START"); while (startResponse == "WHERE ARE YOUR SHIPS?") { - _io.WriteLine("BATTLESHIP"); - for (var i = 1; i <= 5; i++) + foreach (var ship in computerGrid.Ships) { - _io.WriteLine(temp[i]); + _io.WriteLine(ship); } - _io.WriteLine("CRUISER"); - _io.WriteLine(temp[6]); - _io.WriteLine(temp[7]); - _io.WriteLine(temp[8]); - _io.WriteLine("DESTROYER"); - _io.WriteLine(temp[9]); - _io.WriteLine(temp[10]); - _io.WriteLine("DESTROYER"); - _io.WriteLine(temp[11]); - _io.WriteLine(temp[12]); - startResponse = _io.ReadString("DO YOU WANT TO START"); } L1890: var turnNumber=0; @@ -109,7 +52,7 @@ internal void Play() L1960: turnNumber++; L1970: _io.WriteLine(); L1980: _io.WriteLine($"TURN {turnNumber}"); -L1990: var maxShotCount=0; +L1990: var maxShotCount = 0; L2000: for (var shipValue = .5F; shipValue <= 3; shipValue += .5F) { foreach (var position in Position.All) @@ -345,6 +288,73 @@ internal void Play() } } +internal abstract class Ship +{ + private readonly List _positions = new(); + + internal virtual string Name => GetType().Name; + internal abstract int Shots { get; } + internal abstract int Size { get; } + internal abstract float Value { get; } + internal IEnumerable Positions => _positions; + internal bool IsAfloat => _positions.Count > 0; + + internal void SetPositionInRange(IRandom random) + { + var (start, delta) = random.GetRandomShipPositionInRange(Size); + for (var i = 0; i < Size; i++) + { + _positions[i] = start + delta * i; + } + } + + internal void GetPosition(IReadWrite io, Grid grid) + { + io.WriteLine(Name); + for (var i = 0; i < Size; i++) + { + var position = io.ReadPosition(); + _positions[i] = position; + grid[position] = Value; + } + } + + internal bool IsHit(Position position) => _positions.Remove(position); + + internal float DistanceTo(Ship other) + => _positions.SelectMany(a => other._positions.Select(b => a.DistanceTo(b))).Min(); + + public override string ToString() + => string.Join(Environment.NewLine, _positions.Select(p => p.ToString()).Prepend(Name)); +} + +internal sealed class Battleship : Ship +{ + internal override int Shots => 3; + internal override int Size => 5; + internal override float Value => 3; +} + +internal sealed class Cruiser : Ship +{ + internal override int Shots => 2; + internal override int Size => 3; + internal override float Value => 2; +} + +internal sealed class Destroyer : Ship +{ + internal Destroyer(string nameIndex) + { + Name = $"{base.Name}<{nameIndex}>"; + } + + internal override string Name { get; } + internal override int Shots => 1; + internal override int Size => 2; + internal override float Value => Name.EndsWith("") ? 1 : 0.5F; +} + internal static class RandomExtensions { internal static (Position, Offset) NextShipPosition(this IRandom random) @@ -378,6 +388,67 @@ internal static (Position, Offset) GetRandomShipPositionInRange(this IRandom ran internal class Grid { + private readonly List _ships = new() + { + new Battleship(), + new Cruiser(), + new Destroyer("A"), + new Destroyer("B") + }; + + internal IEnumerable Ships => _ships.AsEnumerable(); + + internal Grid PositionShips(IRandom random) + { + while (true) + { + var allPositioned = false; + for (var i = 0; i < _ships.Count; i++) + { + if (!TryPositionShip(i)) { break; } + if (i == _ships.Count - 1) { allPositioned = true; } + } + if (allPositioned) { break; } + } + + foreach (var ship in _ships) + { + foreach (var position in ship.Positions) + { + this[position] = ship.Value; + } + } + + return this; + + bool TryPositionShip(int i) + { + while (true) + { + var shipGenerationAttempts = 0; + _ships[i].SetPositionInRange(random); + if (i == 0) { return true; } + shipGenerationAttempts++; + if (shipGenerationAttempts > 25) { return false; } + for (var j = 0; j < i; j++) + { + if (_ships[i].DistanceTo(_ships[j]) >= 3.59) { return true; } + } + } + } + } + + internal Grid PositionShips(IReadWrite io) + { + io.WriteLine("ENTER POSITION FOR..."); + foreach (var ship in _ships) + { + ship.GetPosition(io, this); + } + + return this; + } + private readonly float[,] _positions = new float[10, 10]; public float this[Position position] @@ -438,8 +509,8 @@ public IEnumerable Neighbours } } - internal double DistanceTo(Position other) - => Math.Sqrt((X - other.X) * (X - other.Y) + (Y - other.Y) * (Y - other.Y)); + internal float DistanceTo(Position other) + => (float)Math.Sqrt((X - other.X) * (X - other.Y) + (Y - other.Y) * (Y - other.Y)); internal Position BringIntoRange(IRandom random) => IsInRange ? this : new(X.BringIntoRange(random), Y.BringIntoRange(random)); From 192a6e7e6263451c351b20cc01d5b1d16d56ac17 Mon Sep 17 00:00:00 2001 From: Jack Boyce Date: Sun, 2 Apr 2023 00:02:24 -0700 Subject: [PATCH 100/377] remove author name from header --- 84_Super_Star_Trek/python/superstartrek.py | 1 - 1 file changed, 1 deletion(-) diff --git a/84_Super_Star_Trek/python/superstartrek.py b/84_Super_Star_Trek/python/superstartrek.py index 21e03e455..2a86efba9 100644 --- a/84_Super_Star_Trek/python/superstartrek.py +++ b/84_Super_Star_Trek/python/superstartrek.py @@ -8,7 +8,6 @@ **** LEEDOM - APRIL & DECEMBER 1974, **** WITH A LITTLE HELP FROM HIS FRIENDS . . . -Python translation by Jack Boyce - February 2021 Output is identical to BASIC version except for a few fixes (as noted, search `bug`) and minor cleanup. """ From b5d573f075f280233c772ffefa3fb0bbbb033ec0 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Tue, 4 Apr 2023 17:29:50 +1000 Subject: [PATCH 101/377] More use of grid --- 77_Salvo/csharp/Game.cs | 116 ++++++++++++++++------------------------ 1 file changed, 46 insertions(+), 70 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index ddf9aa132..145043043 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -5,10 +5,6 @@ namespace Salvo; internal class Game { - private static readonly float[] _shipValue = new[] { 0.5F, 1, 2, 3 }; - private static readonly int[] _shipFirstIndex = new[] { 11, 9, 6, 1 }; - private static readonly int[] _shipSize = new[] { 2, 2, 3, 5 }; - private readonly IReadWrite _io; private readonly IRandom _random; @@ -34,7 +30,6 @@ internal void Play() } var computerGrid = new Grid().PositionShips(_random); var humanGrid = new Grid().PositionShips(_io); - var startResponse = _io.ReadString("DO YOU WANT TO START"); while (startResponse == "WHERE ARE YOUR SHIPS?") { @@ -52,30 +47,14 @@ internal void Play() L1960: turnNumber++; L1970: _io.WriteLine(); L1980: _io.WriteLine($"TURN {turnNumber}"); -L1990: var maxShotCount = 0; -L2000: for (var shipValue = .5F; shipValue <= 3; shipValue += .5F) - { - foreach (var position in Position.All) - { - if (humanGrid[position] == shipValue) - { - maxShotCount+=(int)(shipValue+.5F); - break; - } - } - } +L1990: var maxShotCount = humanGrid.Ships.Sum(s => s.Shots); L2090: for (var i = 1; i <= 7; i++) { shots[i] = temp[i] = 0; } -L2150: var untriedSquareCount=0; - foreach (var position in Position.All) - { - if (computerGrid[position] <= 10) { untriedSquareCount++; } - } L2220: _io.WriteLine($"YOU HAVE {maxShotCount} SHOTS."); if (maxShotCount == 0) { goto L2270; } -L2230: if (maxShotCount > untriedSquareCount) +L2230: if (maxShotCount > computerGrid.UntriedSquareCount) { _io.WriteLine("YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES."); L2250: goto L2890; @@ -111,32 +90,15 @@ internal void Play() L2640: turnNumber++; L2650: _io.WriteLine(); L2660: _io.WriteLine($"TURN {turnNumber}"); -L2670: maxShotCount = 0; -L2680: for (var shipValue = .5F; shipValue <= 3; shipValue += .5F) - { - foreach (var position in Position.All) - { - if (computerGrid[position] == shipValue) - { - maxShotCount += (int)(shipValue+.5F); - break; - } - } - } -L2770: untriedSquareCount=0; - foreach (var position in Position.All) - { - if (computerGrid[position]<=10) { untriedSquareCount++; } - } +L2670: maxShotCount = computerGrid.Ships.Sum(s => s.Shots); L2840: _io.WriteLine($"I HAVE {maxShotCount} SHOTS."); -L2850: if (untriedSquareCount>maxShotCount) { goto L2880; } +L2850: if (humanGrid.UntriedSquareCount > maxShotCount) { goto L2880; } L2860: _io.WriteLine("I HAVE MORE SHOTS THAN BLANK SQUARES."); -L2870: goto L2270; +L2270: _io.WriteLine("I HAVE WON."); + return; L2880: if (maxShotCount != 0) { goto L2960; } L2890: _io.WriteLine("YOU HAVE WON."); L2900: return; -L2270: _io.WriteLine("I HAVE WON."); - return; L2960: for (var i = 1; i <= 12; i++) @@ -304,20 +266,11 @@ internal void SetPositionInRange(IRandom random) var (start, delta) = random.GetRandomShipPositionInRange(Size); for (var i = 0; i < Size; i++) { - _positions[i] = start + delta * i; + _positions.Add(start + delta * i); } } - internal void GetPosition(IReadWrite io, Grid grid) - { - io.WriteLine(Name); - for (var i = 0; i < Size; i++) - { - var position = io.ReadPosition(); - _positions[i] = position; - grid[position] = Value; - } - } + internal void AddPosition(Position position) => _positions.Add(position); internal bool IsHit(Position position) => _positions.Remove(position); @@ -395,7 +348,21 @@ internal class Grid new Destroyer("A"), new Destroyer("B") }; + private readonly Dictionary _shots = new(); + public float this[Position position] + { + get => _shots.TryGetValue(position, out var value) + ? value + 10 + : _ships.FirstOrDefault(s => s.Positions.Contains(position))?.Value ?? 0; + set + { + _ = _ships.FirstOrDefault(s => s.IsHit(position)); + _shots[position] = (int)value - 10; + } + } + + internal int UntriedSquareCount => 100 - _shots.Count; internal IEnumerable Ships => _ships.AsEnumerable(); internal Grid PositionShips(IRandom random) @@ -439,23 +406,10 @@ bool TryPositionShip(int i) } internal Grid PositionShips(IReadWrite io) - { - io.WriteLine("ENTER POSITION FOR..."); - foreach (var ship in _ships) - { - ship.GetPosition(io, this); - } - + { + io.ReadShipPositions(this); return this; } - - private readonly float[,] _positions = new float[10, 10]; - - public float this[Position position] - { - get => _positions[position.X, position.Y]; - set => _positions[position.X, position.Y] = value; - } } internal static class IOExtensions @@ -473,6 +427,28 @@ internal static Position ReadValidPosition(this IReadWrite io) io.WriteLine("ILLEGAL, ENTER AGAIN."); } } + + + internal static void ReadShipPositions(this IReadWrite io, Grid grid) + { + io.WriteLine("ENTER POSITION FOR..."); + foreach (var ship in grid.Ships) + { + io.ReadPosition(ship, grid); + } + } + + internal static void ReadPosition(this IReadWrite io, Ship ship, Grid grid) + { + io.WriteLine(ship.Name); + for (var i = 0; i < ship.Size; i++) + { + var position = io.ReadPosition(); + ship.AddPosition(position); + grid[position] = ship.Value; + } + } + } internal record struct Position(Coordinate X, Coordinate Y) From 223422b94ac9e8ec73ad86ad2f8faf21172bf50c Mon Sep 17 00:00:00 2001 From: kbrannen Date: Fri, 7 Apr 2023 22:57:07 -0500 Subject: [PATCH 102/377] added 06_banner for perl --- 06_Banner/perl/banner.pl | 150 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 06_Banner/perl/banner.pl diff --git a/06_Banner/perl/banner.pl b/06_Banner/perl/banner.pl new file mode 100644 index 000000000..2524ef00c --- /dev/null +++ b/06_Banner/perl/banner.pl @@ -0,0 +1,150 @@ +#!/usr/bin/perl + +# Banner program in Perl +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +sub print_lines +{ + my $lines = shift; + print "\n" x $lines; +} + +# each letter is made of 7 slices (or rows); +# the initial & unused 0 is to allow for Perl arrays being 0-based +# but allow the algorithm to be 1-based (like Basic arrays); +# the numbers are essentially the dots/columns per slice in powers of 2. +my %data = ( + " " => [ 0, 0, 0, 0, 0, 0, 0, 0 ], + "." => [ 0, 1, 1, 129, 449, 129, 1, 1 ], + "!" => [ 0, 1, 1, 1, 384, 1, 1, 1 ], + "=" => [ 0, 41, 41, 41, 41, 41, 41, 41 ], + "?" => [ 0, 5, 3, 2, 354, 18, 11, 5 ], + "*" => [ 0, 69, 41, 17, 512, 17, 41, 69 ], + "0" => [ 0, 57, 69, 131, 258, 131, 69, 57 ], + "1" => [ 0, 0, 0, 261, 259, 512, 257, 257 ], + "2" => [ 0, 261, 387, 322, 290, 274, 267, 261 ], + "3" => [ 0, 66, 130, 258, 274, 266, 150, 100 ], + "4" => [ 0, 33, 49, 41, 37, 35, 512, 33 ], + "5" => [ 0, 160, 274, 274, 274, 274, 274, 226 ], + "6" => [ 0, 194, 291, 293, 297, 305, 289, 193 ], + "7" => [ 0, 258, 130, 66, 34, 18, 10, 8 ], + "8" => [ 0, 69, 171, 274, 274, 274, 171, 69 ], + "9" => [ 0, 263, 138, 74, 42, 26, 10, 7 ], + "A" => [ 0, 505, 37, 35, 34, 35, 37, 505 ], + "B" => [ 0, 512, 274, 274, 274, 274, 274, 239 ], + "C" => [ 0, 125, 131, 258, 258, 258, 131, 69 ], + "D" => [ 0, 512, 258, 258, 258, 258, 131, 125 ], + "E" => [ 0, 512, 274, 274, 274, 274, 258, 258 ], + "F" => [ 0, 512, 18, 18, 18, 18, 2, 2 ], + "G" => [ 0, 125, 131, 258, 258, 290, 163, 101 ], + "H" => [ 0, 512, 17, 17, 17, 17, 17, 512 ], + "I" => [ 0, 258, 258, 258, 512, 258, 258, 258 ], + "J" => [ 0, 65, 129, 257, 257, 257, 129, 128 ], + "K" => [ 0, 512, 17, 17, 41, 69, 131, 258 ], + "L" => [ 0, 512, 257, 257, 257, 257, 257, 257 ], + "M" => [ 0, 512, 7, 13, 25, 13, 7, 512 ], + "N" => [ 0, 512, 7, 9, 17, 33, 193, 512 ], + "O" => [ 0, 125, 131, 258, 258, 258, 131, 125 ], + "P" => [ 0, 512, 18, 18, 18, 18, 18, 15 ], + "Q" => [ 0, 125, 131, 258, 258, 322, 131, 381 ], + "R" => [ 0, 512, 18, 18, 50, 82, 146, 271 ], + "S" => [ 0, 69, 139, 274, 274, 274, 163, 69 ], + "T" => [ 0, 2, 2, 2, 512, 2, 2, 2 ], + "U" => [ 0, 128, 129, 257, 257, 257, 129, 128 ], + "V" => [ 0, 64, 65, 129, 257, 129, 65, 64 ], + "W" => [ 0, 256, 257, 129, 65, 129, 257, 256 ], + "X" => [ 0, 388, 69, 41, 17, 41, 69, 388 ], + "Y" => [ 0, 8, 9, 17, 481, 17, 9, 8 ], + "Z" => [ 0, 386, 322, 290, 274, 266, 262, 260 ], +); + +my ($horz, $vert, $center, $char, $msg) = (0, 0, '', '', ''); + +# get args to run with +while ($horz < 1) +{ + print "HORIZONTAL (1 or more): "; + chomp($horz = <>); + $horz = int($horz); +} + +while ($vert < 1) +{ + print "VERTICAL (1 or more): "; + chomp($vert = <>); + $vert = int($vert); +} + +print "CENTERED (Y/N): "; +chomp($center = <>); +$center = ($center =~ m/^Y/i) ? 1 : 0; + +# note you can enter multiple chars and the program will do the right thing +# thanks to the length() calls below, which was in the original Basic +print "CHARACTER TO PRINT (TYPE 'ALL' IF YOU WANT CHARACTER BEING PRINTED): "; +chomp($char = uc(<>)); + +while (!$msg) +{ + print "STATEMENT: "; + chomp($msg = uc(<>)); +} + +print "SET PAGE TO PRINT, HIT RETURN WHEN READY"; +$_ = <>; +print_lines(2 * $horz); + +# print the message +for my $letter ( split(//, $msg) ) +{ + if (!exists($data{$letter})) + { + die "Cannot use letter '$letter'!"; + } + my @s = @{$data{$letter}}; + #if ($letter eq " ") { print_lines(7 * $horz); next; } + + my $print_letter = ($char eq "ALL") ? $letter : $char; + for my $slice (1 .. 7) + { + my (@j, @f); + for (my $k = 8; $k >= 0; $k--) + { + if (2**$k < $s[$slice]) + { + $j[9 - $k] = 1; + $s[$slice] = $s[$slice] - 2**$k; + if ($s[$slice] == 1) + { + $f[$slice] = 9 - $k; + } + } + else + { + $j[9 - $k] = 0; + } + } + + for my $t1 (1 .. $horz) + { + print " " x int((63 - 4.5 * $vert) * $center / (length($print_letter)) + 1); + for my $b (1 .. (defined($f[$slice]) ? $f[$slice] : 0)) + { + my $str = $j[$b] ? $print_letter : (" " x length($print_letter)); + print $str for (1 .. $vert); + } + print "\n"; + } + } + + # space between letters + print_lines(2 * $horz); +} + +# while in the original code, this seems pretty excessive +#print_lines(75); + +exit(0); From 69240e50a0b175ad1d46b75f5f00fd226fa2c927 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Wed, 12 Apr 2023 07:49:10 +1000 Subject: [PATCH 103/377] More improvments to Ships and Grid --- 77_Salvo/csharp/Game.cs | 153 +++++++++++++++++++++++----------------- 1 file changed, 87 insertions(+), 66 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 145043043..312796db6 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -28,8 +28,8 @@ internal void Play() hitTurnRecord[i] = -1; hitShipValue[i] = -1; } - var computerGrid = new Grid().PositionShips(_random); - var humanGrid = new Grid().PositionShips(_io); + var computerGrid = new Grid(_random); + var humanGrid = new Grid(_io); var startResponse = _io.ReadString("DO YOU WANT TO START"); while (startResponse == "WHERE ARE YOUR SHIPS?") { @@ -254,15 +254,16 @@ internal abstract class Ship { private readonly List _positions = new(); - internal virtual string Name => GetType().Name; - internal abstract int Shots { get; } - internal abstract int Size { get; } - internal abstract float Value { get; } - internal IEnumerable Positions => _positions; - internal bool IsAfloat => _positions.Count > 0; + protected Ship(IReadWrite io, string? nameSuffix = null) + { + Name = GetType().Name + nameSuffix; + _positions = io.ReadPositions(Name, Size).ToList(); + } - internal void SetPositionInRange(IRandom random) + protected Ship(IRandom random, string? nameSuffix = null) { + Name = GetType().Name + nameSuffix; + var (start, delta) = random.GetRandomShipPositionInRange(Size); for (var i = 0; i < Size; i++) { @@ -270,7 +271,12 @@ internal void SetPositionInRange(IRandom random) } } - internal void AddPosition(Position position) => _positions.Add(position); + internal string Name { get; } + internal abstract int Shots { get; } + internal abstract int Size { get; } + internal abstract float Value { get; } + internal IEnumerable Positions => _positions; + internal bool IsAfloat => _positions.Count > 0; internal bool IsHit(Position position) => _positions.Remove(position); @@ -283,6 +289,16 @@ public override string ToString() internal sealed class Battleship : Ship { + internal Battleship(IReadWrite io) + : base(io) + { + } + + internal Battleship(IRandom random) + : base(random) + { + } + internal override int Shots => 3; internal override int Size => 5; internal override float Value => 3; @@ -290,6 +306,16 @@ internal sealed class Battleship : Ship internal sealed class Cruiser : Ship { + internal Cruiser(IReadWrite io) + : base(io) + { + } + + internal Cruiser(IRandom random) + : base(random) + { + } + internal override int Shots => 2; internal override int Size => 3; internal override float Value => 2; @@ -297,12 +323,16 @@ internal sealed class Cruiser : Ship internal sealed class Destroyer : Ship { - internal Destroyer(string nameIndex) + internal Destroyer(string nameIndex, IReadWrite io) + : base(io, $"<{nameIndex}>") + { + } + + internal Destroyer(string nameIndex, IRandom random) + : base(random, $"<{nameIndex}>") { - Name = $"{base.Name}<{nameIndex}>"; } - internal override string Name { get; } internal override int Shots => 1; internal override int Size => 2; internal override float Value => Name.EndsWith("") ? 1 : 0.5F; @@ -341,41 +371,39 @@ internal static (Position, Offset) GetRandomShipPositionInRange(this IRandom ran internal class Grid { - private readonly List _ships = new() - { - new Battleship(), - new Cruiser(), - new Destroyer("A"), - new Destroyer("B") - }; + private readonly List _ships; private readonly Dictionary _shots = new(); - public float this[Position position] + internal Grid() { - get => _shots.TryGetValue(position, out var value) - ? value + 10 - : _ships.FirstOrDefault(s => s.Positions.Contains(position))?.Value ?? 0; - set - { - _ = _ships.FirstOrDefault(s => s.IsHit(position)); - _shots[position] = (int)value - 10; - } + _ships = new(); } - internal int UntriedSquareCount => 100 - _shots.Count; - internal IEnumerable Ships => _ships.AsEnumerable(); + internal Grid(IReadWrite io) + { + io.WriteLine("ENTER POSITION FOR..."); + _ships = new() + { + new Battleship(io), + new Cruiser(io), + new Destroyer("A", io), + new Destroyer("B", io) + }; + } - internal Grid PositionShips(IRandom random) + internal Grid(IRandom random) { + _ships = new(); while (true) { - var allPositioned = false; - for (var i = 0; i < _ships.Count; i++) + _ships.Add(new Battleship(random)); + if (TryPositionShip(() => new Cruiser(random)) && + TryPositionShip(() => new Destroyer("A", random)) && + TryPositionShip(() => new Destroyer("B", random))) { - if (!TryPositionShip(i)) { break; } - if (i == _ships.Count - 1) { allPositioned = true; } - } - if (allPositioned) { break; } + break; + } + _ships.Clear(); } foreach (var ship in _ships) @@ -386,30 +414,36 @@ internal Grid PositionShips(IRandom random) } } - return this; - - bool TryPositionShip(int i) + bool TryPositionShip(Func shipFactory) { while (true) { var shipGenerationAttempts = 0; - _ships[i].SetPositionInRange(random); - if (i == 0) { return true; } + var ship = shipFactory.Invoke(); shipGenerationAttempts++; if (shipGenerationAttempts > 25) { return false; } - for (var j = 0; j < i; j++) + foreach (var previousShip in _ships) { - if (_ships[i].DistanceTo(_ships[j]) >= 3.59) { return true; } + if (ship.DistanceTo(previousShip) >= 3.59) { return true; } } } } } - internal Grid PositionShips(IReadWrite io) - { - io.ReadShipPositions(this); - return this; + public float this[Position position] + { + get => _shots.TryGetValue(position, out var value) + ? value + 10 + : _ships.FirstOrDefault(s => s.Positions.Contains(position))?.Value ?? 0; + set + { + _ = _ships.FirstOrDefault(s => s.IsHit(position)); + _shots[position] = (int)value - 10; + } } + + internal int UntriedSquareCount => 100 - _shots.Count; + internal IEnumerable Ships => _ships.AsEnumerable(); } internal static class IOExtensions @@ -428,27 +462,14 @@ internal static Position ReadValidPosition(this IReadWrite io) } } - - internal static void ReadShipPositions(this IReadWrite io, Grid grid) - { - io.WriteLine("ENTER POSITION FOR..."); - foreach (var ship in grid.Ships) - { - io.ReadPosition(ship, grid); - } - } - - internal static void ReadPosition(this IReadWrite io, Ship ship, Grid grid) + internal static IEnumerable ReadPositions(this IReadWrite io, string shipName, int shipSize) { - io.WriteLine(ship.Name); - for (var i = 0; i < ship.Size; i++) + io.WriteLine(shipName); + for (var i = 0; i < shipSize; i++) { - var position = io.ReadPosition(); - ship.AddPosition(position); - grid[position] = ship.Value; + yield return io.ReadPosition(); } } - } internal record struct Position(Coordinate X, Coordinate Y) From a5584b401481b26ceaf575a7aeff612209cf816a Mon Sep 17 00:00:00 2001 From: kbrannen Date: Thu, 20 Apr 2023 12:23:44 -0500 Subject: [PATCH 104/377] Added 2 versions of the perl 07-basketball game. Also updated the README. --- 07_Basketball/perl/README.md | 18 ++ 07_Basketball/perl/basketball-orig.pl | 415 ++++++++++++++++++++++++++ 07_Basketball/perl/basketball.pl | 394 ++++++++++++++++++++++++ 3 files changed, 827 insertions(+) create mode 100755 07_Basketball/perl/basketball-orig.pl create mode 100755 07_Basketball/perl/basketball.pl diff --git a/07_Basketball/perl/README.md b/07_Basketball/perl/README.md index e69c8b819..51373c0c8 100644 --- a/07_Basketball/perl/README.md +++ b/07_Basketball/perl/README.md @@ -1,3 +1,21 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +There are two version of the code here, a "faithful" translation (basketball-orig.pl) and +a "modern" translation (basketball.pl). The main difference between the 2 are is that the +faithful translation has 3 GOTOs in it while the modern version has no GOTO. I have added +a "TIME" print when the score is shown so the Clock is visible. Halftime is at "50" and +end of game is at 100 (per the Basic code). + +The 3 GOTOs in the faitful version are because of the way the original code jumped into +the "middle of logic" that has no obivious way to avoid ... that I can see, at least while +still maintaining something of the look and structure of the original Basic. + +The modern version avoided the GOTOs by restructuring the program in the 2 "play()" subs. +Despite the change, this should play the same way as the faithful version. + +All of the percentages remain the same. If writing this from scratch, we really should +have only a single play() sub which uses the same code for both teams, which would also +make the game more fair ... but that wasn't done so the percent edge to Darmouth has been +maintained here. diff --git a/07_Basketball/perl/basketball-orig.pl b/07_Basketball/perl/basketball-orig.pl new file mode 100755 index 000000000..14627ffc6 --- /dev/null +++ b/07_Basketball/perl/basketball-orig.pl @@ -0,0 +1,415 @@ +#!/usr/bin/perl + +# Basketball program in Perl +# This is fairly faithful translation from the original Basic. +# This becomes apparent because there are actually 3 GOTOs still present +# because of the way the original code jumped into the "middle of logic" +# that has no obivious way to avoid ... that I can see. +# For better structure and no GOTOs, see the other version of this program. +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +# globals +my $Defense=0; # dartmouth defense value +my $Opponent; # name of opponent +my @Score = (0, 0); # scores, dart is [0], opponent is [1] +my $Player = 0; # player, 0 = dart, 1 = opp +my $Timer = 0; # time tick, 100 ticks per game, 50 is end of first half, if tie at end then back to T=93 +my $DoPlay = 1; # true if game is still being played +my $ConTeam; # controlling team, "dart" or "opp" +my $ShotType = 0; # current shot type + + +print "\n"; +print " " x 31, "BASKETBALL"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"; +print "\n\n\n"; + +print "THIS IS DARTMOUTH COLLEGE BASKETBALL. YOU WILL BE DARTMOUTH\n"; +print "CAPTAIN AND PLAYMAKER. CALL SHOTS AS FOLLOWS:\n"; +print " 1. LONG (30 FT.) JUMP SHOT;\n"; +print " 2. SHORT (15 FT.) JUMP SHOT;\n"; +print " 3. LAY UP;\n"; +print " 4. SET SHOT.\n"; +print "BOTH TEAMS WILL USE THE SAME DEFENSE. CALL DEFENSE AS FOLLOWS:\n"; +print " 6. PRESS;\n"; +print " 6.5 MAN-TO MAN;\n"; +print " 7. ZONE;\n"; +print " 7.5 NONE.\n"; +print "TO CHANGE DEFENSE, JUST TYPE 0 AS YOUR NEXT SHOT.\n\n"; +get_defense(); +print "\n"; +print "CHOOSE YOUR OPPONENT: "; +chomp($Opponent = <>); + +$ConTeam = center_jump(); +while ($DoPlay) +{ + print "\n"; + if ($ConTeam eq "dart") + { + $Player = 0; + get_your_shot(); + dartmouth_play(); + } + else + { + opponent_play(); + } + if ($Timer >= 100) + { + check_end_game(); + last if (!$DoPlay); + $Timer = 93; + $ConTeam = center_jump(); + } +} +exit(0); + +############################################################### + +sub dartmouth_play +{ + if ($ShotType == 1 || $ShotType == 2) + { + $Timer++; + if ($Timer == 50) + { + end_first_half(); + return; + } + if ($Timer == 92) + { + two_min_left(); + } + + print "JUMP SHOT\n"; + if (rand(1) <= 0.341 * $Defense / 8) + { + print "SHOT IS GOOD.\n"; + dartmouth_score(); + $ConTeam = "opp"; + return; + } + + if (rand(1) <= 0.682*$Defense/8) + { + print "SHOT IS OFF TARGET.\n"; + if ($Defense/6*rand(1) > 0.45) + { + print "REBOUND TO ", $Opponent, "\n"; + $ConTeam = "opp"; + return; + } + + print "DARTMOUTH CONTROLS THE REBOUND.\n"; + if (rand(1) <= 0.4) { goto L1300; } + if ($Defense == 6) + { + if (rand(1) <= 0.6) + { + print "PASS STOLEN BY $Opponent, EASY LAYUP.\n"; + opp_score(); + $ConTeam = "dart"; return; + return; + } + } + print "BALL PASSED BACK TO YOU.\n"; + $ConTeam = "dart"; + return; + } + + if (rand(1) <= 0.782*$Defense/8) + { + print "SHOT IS BLOCKED. BALL CONTROLLED BY "; # no NL + if (rand(1) > 0.5) + { + print "$Opponent.\n"; + $ConTeam = "opp"; + return; + } + else + { + print "DARTMOUTH.\n"; + $ConTeam = "dart"; + return; + } + } + + if (rand(1) > 0.843*$Defense/8) + { + print "CHARGING FOUL. DARTMOUTH LOSES BALL.\n"; + $ConTeam = "opp"; + return; + } + else + { + print "SHOOTER IS FOULED. TWO SHOTS.\n"; + foul_shooting(); + $ConTeam = "opp"; + return; + } + } + + L1300: + while (1) + { + $Timer++; + if ($Timer == 50) + { + end_first_half(); + return; + } + if ($Timer == 92) { two_min_left(); } + if ($ShotType == 0) + { + get_defense(); + return; + } + print '', ($ShotType > 3 ? "SET SHOT." : "LAY UP."), "\n"; + if (7 / $Defense * rand(1) <= 0.4) + { + print "SHOT IS GOOD. TWO POINTS.\n"; + dartmouth_score(); + $ConTeam = "opp"; + return; + } + + if (7 / $Defense * rand(1) <= 0.7) + { + print "SHOT IS OFF THE RIM.\n"; + if (rand(1) <= 0.667) + { + print "$Opponent CONTROLS THE REBOUND.\n"; + $ConTeam = "opp"; + return; + } + + print "DARTMOUTH CONTROLS THE REBOUND.\n"; + next if (rand(1) <= 0.4); + + print "BALL PASSED BACK TO YOU.\n"; + $ConTeam = "dart"; + return; + } + + if (7 / $Defense * rand(1) <= 0.875) + { + print "SHOOTER FOULED. TWO SHOTS.\n"; + foul_shooting(); + $ConTeam = "opp"; + return; + } + + if (7 / $Defense * rand(1) <= 0.925) + { + print "SHOT BLOCKED. $Opponent\'S BALL.\n"; + $ConTeam = "opp"; + return; + } + + print "CHARGING FOUL. DARTMOUTH LOSES THE BALL.\n"; + $ConTeam = "opp"; + return; + } +} + +sub get_defense +{ + $Defense = 0; + while ($Defense < 6 || $Defense > 7.5) + { + print "YOUR NEW DEFENSIVE ALLIGNMENT IS (6, 6.5, 7. 7.5): "; + chomp($Defense = <>); + ($Defense) =~ m/(\d(\.\d)?)/; + } +} + +sub opponent_play +{ + $Player = 1; + $Timer++; + if ($Timer == 50) + { + end_first_half(); + $ConTeam = center_jump(); + return; + } + + print "\n"; + while (1) + { + my $shot = 10.0 / 4 * rand(1) + 1; + if ($shot <= 2.0) + { + print "JUMP SHOT.\n"; + if (8.0 / $Defense * rand(1) <= 0.35) + { + print "SHOT IS GOOD.\n"; + opp_score(); + $ConTeam = "dart"; + return; + } + + if (8.0 / $Defense * rand(1) <= 0.75) + { + print "SHOT IS OFF RIM.\n"; + + L3110: + if ($Defense / 6.0 * rand(1) <= 0.5) + { + print "DARTMOUTH CONTROLS THE REBOUND.\n"; + $ConTeam = "dart"; + return; + } + print "$Opponent CONTROLS THE REBOUND.\n"; + if ($Defense == 6) + { + if (rand(1) <= 0.75) + { + print "BALL STOLEN. EASY LAY UP FOR DARTMOUTH.\n"; + dartmouth_score(); + $ConTeam = "opp"; + return; + } + } + if (rand(1) <= 0.5) + { + print "PASS BACK TO $Opponent GUARD.\n"; + $ConTeam = "opp"; + return; + } + goto L3500; + } + + if (8.0 / $Defense * rand(1) <= 0.9) + { + print "PLAYER FOULED. TWO SHOTS.\n"; + foul_shooting(); + $ConTeam = "dart"; + return; + } + print "OFFENSIVE FOUL. DARTMOUTH'S BALL.\n"; + $ConTeam = "dart"; + return; + } + + L3500: + print ($shot > 3 ? "SET SHOT.\n" : "LAY UP.\n"); + if (7.0 / $Defense * rand(1) > 0.413) + { + print "SHOT IS MISSED.\n"; + { + no warnings; + goto L3110; + } + } + else + { + print "SHOT IS GOOD.\n"; + opp_score(); + $ConTeam = "dart"; + return; + } + } +} + +sub opp_score +{ + $Score[0] += 2; + print_score(); +} + +sub dartmouth_score +{ + $Score[1] += 2; + print_score(); +} + +sub print_score +{ + print "SCORE: $Score[1] TO $Score[0]\n"; + print "TIME: $Timer\n"; +} + +sub end_first_half +{ + print "\n ***** END OF FIRST HALF *****\n\n"; + print "SCORE: DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n\n"; + center_jump(); +} + +sub get_your_shot +{ + $ShotType = -1; + while ($ShotType < 0 || $ShotType > 4) + { + print "YOUR SHOT (0-4): "; + chomp($ShotType = <>); + $ShotType = int($ShotType); + if ($ShotType < 0 || $ShotType > 4) + { + print "INCORRECT ANSWER. RETYPE IT. "; + } + } +} + +sub center_jump +{ + print "CENTER JUMP\n"; + if (rand(1) <= 0.6) + { + print "$Opponent CONTROLS THE TAP.\n"; + return "opp"; + } + print "DARTMOUTH CONTROLS THE TAP.\n"; + return "dart"; +} + +sub check_end_game +{ + print "\n"; + if ($Score[1] != $Score[0]) + { + print " ***** END OF GAME *****\n"; + print "FINAL SCORE: DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n"; + $DoPlay = 0; + } + else + { + print "\n ***** END OF SECOND HALF *****\n"; + print "SCORE AT END OF REGULATION TIME:\n"; + print " DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n"; + print "BEGIN TWO MINUTE OVERTIME PERIOD\n"; + } +} + +sub two_min_left +{ + print "\n *** TWO MINUTES LEFT IN THE GAME ***\n\n"; +} + +sub foul_shooting +{ + if (rand(1) > 0.49) + { + if (rand(1) > 0.75) + { + print "BOTH SHOTS MISSED.\n"; + } + else + { + print "SHOOTER MAKES ONE SHOT AND MISSES ONE.\n"; + $Score[1 - $Player]++; + } + } + else + { + print "SHOOTER MAKES BOTH SHOTS.\n"; + $Score[1 - $Player] += 2; + } + + print_score(); +} diff --git a/07_Basketball/perl/basketball.pl b/07_Basketball/perl/basketball.pl new file mode 100755 index 000000000..a6f980412 --- /dev/null +++ b/07_Basketball/perl/basketball.pl @@ -0,0 +1,394 @@ +#!/usr/bin/perl + +# Basketball program in Perl +# While this should play the same way as the fairly faithful translation version, +# there are no GOTOs in this code. That was achieved by restructuring the program +# in the 2 *_play() subs. All of the percentages remain the same. If writing this +# from scratch, we really should have only a play() sub which uses the same code +# for both teams, but the percent edge to Darmouth has been maintained here. +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +# globals +my $Defense=0; # dartmouth defense value +my $Opponent; # name of opponent +my @Score = (0, 0); # scores, dart is [0], opponent is [1] +my $Player = 0; # player, 0 = dart, 1 = opp +my $Timer = 0; # time tick, 100 ticks per game, 50 is end of first half, if tie at end then back to T=93 +my $DoPlay = 1; # true if game is still being played +my $ConTeam; # controlling team, "dart" or "opp" +my $ShotType = 0; # current shot type + + +print "\n"; +print " " x 31, "BASKETBALL"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"; +print "\n\n\n"; + +print "THIS IS DARTMOUTH COLLEGE BASKETBALL. YOU WILL BE DARTMOUTH\n"; +print "CAPTAIN AND PLAYMAKER. CALL SHOTS AS FOLLOWS:\n"; +print " 1. LONG (30 FT.) JUMP SHOT;\n"; +print " 2. SHORT (15 FT.) JUMP SHOT;\n"; +print " 3. LAY UP;\n"; +print " 4. SET SHOT.\n"; +print "BOTH TEAMS WILL USE THE SAME DEFENSE. CALL DEFENSE AS FOLLOWS:\n"; +print " 6. PRESS;\n"; +print " 6.5 MAN-TO MAN;\n"; +print " 7. ZONE;\n"; +print " 7.5 NONE.\n"; +print "TO CHANGE DEFENSE, JUST TYPE 0 AS YOUR NEXT SHOT.\n\n"; +get_defense(); +print "\n"; +print "CHOOSE YOUR OPPONENT: "; +chomp($Opponent = <>); + +$ConTeam = center_jump(); +while ($DoPlay) +{ + print "\n"; + if ($ConTeam eq "dart") + { + $Player = 0; + get_your_shot(); + dartmouth_play(); + } + else + { + $ShotType = 10.0 / 4 * rand(1) + 1; + opponent_play(); + } + if ($Timer >= 100) + { + check_end_game(); + last if (!$DoPlay); + $Timer = 93; + $ConTeam = center_jump(); + } +} +exit(0); + +############################################################### + +sub dartmouth_play +{ + $Player = 0; + print "\n"; + while (1) + { + $Timer++; + if ($Timer == 50) { end_first_half(); return; } + if ($Timer == 92) { two_min_left(); } + + if ($ShotType == 0) + { + get_defense(); + return; # for new ShotType + } + elsif ($ShotType == 1 || $ShotType == 2) + { + print "JUMP SHOT\n"; + if (rand(1) <= 0.341 * $Defense / 8) + { + print "SHOT IS GOOD.\n"; + dartmouth_score(); + last; + } + + if (rand(1) <= 0.682*$Defense/8) + { + print "SHOT IS OFF TARGET.\n"; + if ($Defense/6*rand(1) > 0.45) + { + print "REBOUND TO $Opponent\n"; + last; + } + + print "DARTMOUTH CONTROLS THE REBOUND.\n"; + if (rand(1) <= 0.4) + { + $ShotType = (rand(1) <= 0.5) ? 3 : 4; + next; + } + if ($Defense == 6) + { + if (rand(1) <= 0.6) + { + print "PASS STOLEN BY $Opponent, EASY LAYUP.\n"; + opp_score(); + next; + } + } + print "BALL PASSED BACK TO YOU.\n"; + next; + } + + if (rand(1) <= 0.782*$Defense/8) + { + print "SHOT IS BLOCKED. BALL CONTROLLED BY "; # no NL + if (rand(1) > 0.5) + { + print "$Opponent.\n"; + last; + } + else + { + print "DARTMOUTH.\n"; + next; + } + } + + if (rand(1) > 0.843*$Defense/8) + { + print "CHARGING FOUL. DARTMOUTH LOSES BALL.\n"; + last; + } + else + { + print "SHOOTER IS FOULED. TWO SHOTS.\n"; + foul_shooting(); + last; + } + } + else # elsif ($ShotType >= 3) + { + print '', ($ShotType > 3 ? "SET SHOT." : "LAY UP."), "\n"; + if (7 / $Defense * rand(1) <= 0.4) + { + print "SHOT IS GOOD. TWO POINTS.\n"; + dartmouth_score(); + last; + } + + if (7 / $Defense * rand(1) <= 0.7) + { + print "SHOT IS OFF THE RIM.\n"; + if (rand(1) <= 0.667) + { + print "$Opponent CONTROLS THE REBOUND.\n"; + last; + } + + print "DARTMOUTH CONTROLS THE REBOUND.\n"; + next if (rand(1) <= 0.4); + + print "BALL PASSED BACK TO YOU.\n"; + next; + } + + if (7 / $Defense * rand(1) <= 0.875) + { + print "SHOOTER FOULED. TWO SHOTS.\n"; + foul_shooting(); + last; + } + + if (7 / $Defense * rand(1) <= 0.925) + { + print "SHOT BLOCKED. $Opponent\'S BALL.\n"; + last; + } + + print "CHARGING FOUL. DARTMOUTH LOSES THE BALL.\n"; + last; + } + } + $ConTeam = "opp"; +} + +sub get_defense +{ + $Defense = 0; + do { + print "YOUR NEW DEFENSIVE ALLIGNMENT IS (6, 6.5, 7. 7.5): "; + chomp($Defense = <>); + ($Defense) =~ m/(\d(\.\d)?)/; + } while ($Defense < 6.0 || $Defense > 7.5) +} + +sub opponent_play +{ + $Player = 1; + print "\n"; + while (1) + { + $Timer++; + if ($Timer == 50) { end_first_half(); return; } + if ($Timer == 92) { two_min_left(); } + + if ($ShotType <= 2.0) + { + print "JUMP SHOT.\n"; + if (8.0 / $Defense * rand(1) <= 0.35) + { + print "SHOT IS GOOD.\n"; + opp_score(); + last; + } + + if (8.0 / $Defense * rand(1) <= 0.75) + { + print "SHOT IS OFF RIM.\n"; + opp_missed(); + return; # for possible new ShotType or team change + } + + if (8.0 / $Defense * rand(1) <= 0.9) + { + print "PLAYER FOULED. TWO SHOTS.\n"; + foul_shooting(); + last; + } + print "OFFENSIVE FOUL. DARTMOUTH'S BALL.\n"; + last; + } + else # ShotType >= 3 + { + print ($ShotType > 3 ? "SET SHOT.\n" : "LAY UP.\n"); + if (7.0 / $Defense * rand(1) > 0.413) + { + print "SHOT IS MISSED.\n"; + { + opp_missed(); + return; # for possible new ShotType or team change + } + } + else + { + print "SHOT IS GOOD.\n"; + opp_score(); + last; + } + } + } + $ConTeam = "dart"; +} + +sub opp_missed +{ + if ($Defense / 6.0 * rand(1) <= 0.5) + { + print "DARTMOUTH CONTROLS THE REBOUND.\n"; + $ConTeam = "dart"; + } + else + { + print "$Opponent CONTROLS THE REBOUND.\n"; + if ($Defense == 6) + { + if (rand(1) <= 0.75) + { + print "BALL STOLEN. EASY LAY UP FOR DARTMOUTH.\n"; + dartmouth_score(); + #$ConTeam = "opp"; + return; # for possible new ShotType + } + } + if (rand(1) <= 0.5) + { + print "PASS BACK TO $Opponent GUARD.\n"; + #$ConTeam = "opp"; + return; # for possible new ShotType + } + $ShotType = (rand(1) <= 0.5) ? 3 : 4; + } +} + +sub opp_score +{ + $Score[0] += 2; + print_score(); +} + +sub dartmouth_score +{ + $Score[1] += 2; + print_score(); +} + +sub print_score +{ + print "SCORE: $Score[1] TO $Score[0]\n"; + print "TIME: $Timer\n"; +} + +sub end_first_half +{ + print "\n ***** END OF FIRST HALF *****\n\n"; + print "SCORE: DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n\n"; + $ConTeam = center_jump(); +} + +sub get_your_shot +{ + $ShotType = -1; + while ($ShotType < 0 || $ShotType > 4) + { + print "YOUR SHOT (0-4): "; + chomp($ShotType = <>); + $ShotType = int($ShotType); + if ($ShotType < 0 || $ShotType > 4) + { + print "INCORRECT ANSWER. RETYPE IT. "; + } + } +} + +sub center_jump +{ + print "CENTER JUMP\n"; + if (rand(1) <= 0.6) + { + print "$Opponent CONTROLS THE TAP.\n"; + return "opp"; + } + print "DARTMOUTH CONTROLS THE TAP.\n"; + return "dart"; +} + +sub check_end_game +{ + print "\n"; + if ($Score[1] != $Score[0]) + { + print " ***** END OF GAME *****\n"; + print "FINAL SCORE: DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n"; + $DoPlay = 0; + } + else + { + print "\n ***** END OF SECOND HALF *****\n"; + print "SCORE AT END OF REGULATION TIME:\n"; + print " DARTMOUTH: $Score[1] $Opponent: $Score[0]\n\n"; + print "BEGIN TWO MINUTE OVERTIME PERIOD\n"; + } +} + +sub two_min_left +{ + print "\n *** TWO MINUTES LEFT IN THE GAME ***\n\n"; +} + +sub foul_shooting +{ + if (rand(1) > 0.49) + { + if (rand(1) > 0.75) + { + print "BOTH SHOTS MISSED.\n"; + } + else + { + print "SHOOTER MAKES ONE SHOT AND MISSES ONE.\n"; + $Score[1 - $Player]++; + } + } + else + { + print "SHOOTER MAKES BOTH SHOTS.\n"; + $Score[1 - $Player] += 2; + } + + print_score(); +} From f6693474682500052255953a10253b13277679ed Mon Sep 17 00:00:00 2001 From: kbrannen Date: Thu, 20 Apr 2023 12:33:38 -0500 Subject: [PATCH 105/377] removed uneeded line --- 07_Basketball/perl/basketball.pl | 1 - 1 file changed, 1 deletion(-) diff --git a/07_Basketball/perl/basketball.pl b/07_Basketball/perl/basketball.pl index a6f980412..ac3483094 100755 --- a/07_Basketball/perl/basketball.pl +++ b/07_Basketball/perl/basketball.pl @@ -50,7 +50,6 @@ print "\n"; if ($ConTeam eq "dart") { - $Player = 0; get_your_shot(); dartmouth_play(); } From d300d2d851a72fce9470cd8386eec94e38d96a3b Mon Sep 17 00:00:00 2001 From: kbrannen Date: Fri, 21 Apr 2023 00:25:47 -0500 Subject: [PATCH 106/377] added 13-bounce for Perl --- 13_Bounce/perl/README.md | 3 ++ 13_Bounce/perl/bounce.pl | 91 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100755 13_Bounce/perl/bounce.pl diff --git a/13_Bounce/perl/README.md b/13_Bounce/perl/README.md index e69c8b819..6d213dba3 100644 --- a/13_Bounce/perl/README.md +++ b/13_Bounce/perl/README.md @@ -1,3 +1,6 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +Added feature so that if "TIME" value is "0" then it will quit, +so you don't have to hit Control-C. Also added a little error checking of the input. diff --git a/13_Bounce/perl/bounce.pl b/13_Bounce/perl/bounce.pl new file mode 100755 index 000000000..023f6f040 --- /dev/null +++ b/13_Bounce/perl/bounce.pl @@ -0,0 +1,91 @@ +#!/usr/bin/perl + +# Bounce program in Perl +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +print "\n"; +print " " x 31,"BOUNCE\n"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n\n\n"; + +print "THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY\n"; +print "OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF\n"; +print "ELASTICITY OF THE BALL. PLEASE USE A DECIMAL FRACTION\n"; +print "COEFFICIENCY (LESS THAN 1).\n\n"; +print "YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN\n"; +print "'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).\n\n"; + +# deal with basic's tab() for line positioning +# line = line string we're starting with +# pos = position to start writing +# s = string to write +# returns the resultant string, which might not have been changed +sub line_tab +{ + my ($line, $pos, $s) = @_; + my $len = length($line); + # if curser is past position, do nothing + if ($len <= $pos) { $line .= " " x ($pos - $len) . $s; } + return $line; +} + +while (1) +{ + my @T; # time slice? + my $time_inc; # time increment, probably in fractions of seconds + my $velocity; # velocity in feet/sec + my $coeff_elas; # coeeficent of elasticity + my $L; # position on line + + # get input + print "TIME INCREMENT (SEC, 0=QUIT): "; chomp($time_inc = <>); + last if ($time_inc == 0); + print "VELOCITY (FPS): "; chomp($velocity = <>); + print "COEFFICIENT: "; chomp($coeff_elas = <>); + if ($coeff_elas >= 1.0 || $coeff_elas <= 0) + { + print "COEFFICIENT MUST BE > 0 AND < 1.0\n\n\n"; + next; + } + + print "\nFEET\n"; + my $S1 = int(70.0 / ($velocity / (16.0 * $time_inc))); + for my $i (1 .. $S1) + { + $T[$i] = $velocity * $coeff_elas ** ($i - 1) / 16.0; + } + + # draw graph + for (my $height=int(-16.0 * ($velocity / 32.0) ** 2.0 + $velocity ** 2.0 / 32.0 + .5) ; $height >= 0 ; $height -= .5) + { + #print "h=$height\n"; # kevin + if (int($height) == $height) { print sprintf("%2d", $height); } + else { print " "; } + $L = 0; + my $curr_line = ""; + for my $i (1 .. $S1) + { + my $time; + for ($time=0 ; $time <= $T[$i] ; $time += $time_inc) + { + $L += $time_inc; + next if (abs($height - (.5 * (-32) * $time ** 2.0 + $velocity * $coeff_elas ** ($i - 1) * $time)) > .25); + $curr_line = line_tab($curr_line, ($L / $time_inc), "0"); + } + $time = ($T[$i + 1] // 0) / 2; + last if (-16.0 * $time ** 2.0 + $velocity * $coeff_elas ** ($i - 1) * $time < $height); + } + print "$curr_line\n"; + } + + print " ."; + print "." x (int($L + 1) / $time_inc + 1), "\n"; + print " 0"; + my $cl = ""; + for my $i (1 .. int($L + .9995)) { $cl = line_tab($cl, int($i / $time_inc), $i); } + print "$cl\n"; + print " " x (int($L + 1) / (2 * $time_inc) - 2), "SECONDS\n\n"; +} From d24a5feb6b4e72f15016452844884c3355b48620 Mon Sep 17 00:00:00 2001 From: kbrannen Date: Fri, 21 Apr 2023 00:31:04 -0500 Subject: [PATCH 107/377] fixed a var name --- 13_Bounce/perl/bounce.pl | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/13_Bounce/perl/bounce.pl b/13_Bounce/perl/bounce.pl index 023f6f040..0d7995147 100755 --- a/13_Bounce/perl/bounce.pl +++ b/13_Bounce/perl/bounce.pl @@ -38,7 +38,8 @@ sub line_tab my $time_inc; # time increment, probably in fractions of seconds my $velocity; # velocity in feet/sec my $coeff_elas; # coeeficent of elasticity - my $L; # position on line + my $line_pos; # position on line + my $S1 # duration in full seconds? # get input print "TIME INCREMENT (SEC, 0=QUIT): "; chomp($time_inc = <>); @@ -52,7 +53,7 @@ sub line_tab } print "\nFEET\n"; - my $S1 = int(70.0 / ($velocity / (16.0 * $time_inc))); + $S1 = int(70.0 / ($velocity / (16.0 * $time_inc))); for my $i (1 .. $S1) { $T[$i] = $velocity * $coeff_elas ** ($i - 1) / 16.0; @@ -64,28 +65,28 @@ sub line_tab #print "h=$height\n"; # kevin if (int($height) == $height) { print sprintf("%2d", $height); } else { print " "; } - $L = 0; + $line_pos = 0; my $curr_line = ""; for my $i (1 .. $S1) { my $time; for ($time=0 ; $time <= $T[$i] ; $time += $time_inc) { - $L += $time_inc; + $line_pos += $time_inc; next if (abs($height - (.5 * (-32) * $time ** 2.0 + $velocity * $coeff_elas ** ($i - 1) * $time)) > .25); - $curr_line = line_tab($curr_line, ($L / $time_inc), "0"); + $curr_line = line_tab($curr_line, ($line_pos / $time_inc), "0"); } - $time = ($T[$i + 1] // 0) / 2; + $time = ($T[$i + 1] // 0) / 2; # we can reach 1 past the end, use 0 if that happens last if (-16.0 * $time ** 2.0 + $velocity * $coeff_elas ** ($i - 1) * $time < $height); } print "$curr_line\n"; } print " ."; - print "." x (int($L + 1) / $time_inc + 1), "\n"; + print "." x (int($line_pos + 1) / $time_inc + 1), "\n"; print " 0"; - my $cl = ""; - for my $i (1 .. int($L + .9995)) { $cl = line_tab($cl, int($i / $time_inc), $i); } - print "$cl\n"; - print " " x (int($L + 1) / (2 * $time_inc) - 2), "SECONDS\n\n"; + my $curr_line = ""; + for my $i (1 .. int($line_pos + .9995)) { $curr_line = line_tab($curr_line, int($i / $time_inc), $i); } + print "$curr_line\n"; + print " " x (int($line_pos + 1) / (2 * $time_inc) - 2), "SECONDS\n\n"; } From 5ae3fe8774d845079591056ed71033162081e3a1 Mon Sep 17 00:00:00 2001 From: kbrannen Date: Fri, 21 Apr 2023 00:37:09 -0500 Subject: [PATCH 108/377] small fixes to make code look better --- 13_Bounce/perl/bounce.pl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/13_Bounce/perl/bounce.pl b/13_Bounce/perl/bounce.pl index 0d7995147..4aeacf1f7 100755 --- a/13_Bounce/perl/bounce.pl +++ b/13_Bounce/perl/bounce.pl @@ -62,7 +62,6 @@ sub line_tab # draw graph for (my $height=int(-16.0 * ($velocity / 32.0) ** 2.0 + $velocity ** 2.0 / 32.0 + .5) ; $height >= 0 ; $height -= .5) { - #print "h=$height\n"; # kevin if (int($height) == $height) { print sprintf("%2d", $height); } else { print " "; } $line_pos = 0; @@ -73,8 +72,10 @@ sub line_tab for ($time=0 ; $time <= $T[$i] ; $time += $time_inc) { $line_pos += $time_inc; - next if (abs($height - (.5 * (-32) * $time ** 2.0 + $velocity * $coeff_elas ** ($i - 1) * $time)) > .25); - $curr_line = line_tab($curr_line, ($line_pos / $time_inc), "0"); + if (abs($height - (.5 * (-32) * $time ** 2.0 + $velocity * $coeff_elas ** ($i - 1) * $time)) <= .25) + { + $curr_line = line_tab($curr_line, ($line_pos / $time_inc), "0"); + } } $time = ($T[$i + 1] // 0) / 2; # we can reach 1 past the end, use 0 if that happens last if (-16.0 * $time ** 2.0 + $velocity * $coeff_elas ** ($i - 1) * $time < $height); @@ -82,11 +83,15 @@ sub line_tab print "$curr_line\n"; } + # draw scale print " ."; print "." x (int($line_pos + 1) / $time_inc + 1), "\n"; print " 0"; my $curr_line = ""; - for my $i (1 .. int($line_pos + .9995)) { $curr_line = line_tab($curr_line, int($i / $time_inc), $i); } + for my $i (1 .. int($line_pos + .9995)) + { + $curr_line = line_tab($curr_line, int($i / $time_inc), $i); + } print "$curr_line\n"; print " " x (int($line_pos + 1) / (2 * $time_inc) - 2), "SECONDS\n\n"; } From b2de1b09e14bc16df3c6f36d896cc0555b75cfda Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Sat, 22 Apr 2023 07:56:35 +1000 Subject: [PATCH 109/377] CSHARP-77 Add HumnShotSelctor and some fixes --- 77_Salvo/csharp/Game.cs | 143 +++++++++++++++++++++++++++------------- 77_Salvo/salvo.bas | 2 - 2 files changed, 98 insertions(+), 47 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 312796db6..491cebdb7 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -19,7 +19,6 @@ internal void Play() _io.Write(Streams.Title); var hitTurnRecord = new int[13]; - var shots = new Position[8]; var temp = new Position[13]; var hitShipValue = new float[13]; @@ -30,6 +29,7 @@ internal void Play() } var computerGrid = new Grid(_random); var humanGrid = new Grid(_io); + var humanShotSelector = new HumanShotSelector(humanGrid, computerGrid); var startResponse = _io.ReadString("DO YOU WANT TO START"); while (startResponse == "WHERE ARE YOUR SHIPS?") { @@ -47,11 +47,7 @@ internal void Play() L1960: turnNumber++; L1970: _io.WriteLine(); L1980: _io.WriteLine($"TURN {turnNumber}"); -L1990: var maxShotCount = humanGrid.Ships.Sum(s => s.Shots); -L2090: for (var i = 1; i <= 7; i++) - { - shots[i] = temp[i] = 0; - } +L1990: var maxShotCount = humanShotSelector.GetShotCount(); L2220: _io.WriteLine($"YOU HAVE {maxShotCount} SHOTS."); if (maxShotCount == 0) { goto L2270; } L2230: if (maxShotCount > computerGrid.UntriedSquareCount) @@ -59,33 +55,13 @@ internal void Play() _io.WriteLine("YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES."); L2250: goto L2890; } -L2290: for (var i = 1; i <= maxShotCount; i++) + foreach (var shot1 in humanShotSelector.GetShots(_io)) { - while (true) + if (computerGrid.IsHit(shot1, turnNumber, out var shipName)) { - var position = _io.ReadValidPosition(); -L2390: if (computerGrid[position]>10) - { - _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {computerGrid[position]-10}"); - continue; - } - shots[i]= position; - break; + _io.WriteLine($"YOU HIT MY {shipName}."); } } -L2460: for (var W = 1; W <= maxShotCount; W++) - { - var hit = computerGrid[shots[W]] switch - { - 3 => "YOU HIT MY BATTLESHIP.", - 2 => "YOU HIT MY CRUISER.", - 1 => "YOU HIT MY DESTROYER.", - .5F => "YOU HIT MY DESTROYER.", - _ => null - }; - if (hit is not null) { _io.WriteLine(); } -L2510: computerGrid[shots[W]] = 10+turnNumber; - } L2620: if (startResponse == "YES") { goto L2670; } L2640: turnNumber++; L2650: _io.WriteLine(); @@ -100,7 +76,6 @@ internal void Play() L2890: _io.WriteLine("YOU HAVE WON."); L2900: return; - L2960: for (var i = 1; i <= 12; i++) { // if damaged ships @@ -250,6 +225,72 @@ internal void Play() } } +internal abstract class ShotSelector +{ + internal ShotSelector(Grid source, Grid target) + { + Source = source; + Target = target; + } + + protected Grid Source { get; } + protected Grid Target { get; } + + public int GetShotCount() => Source.Ships.Sum(s => s.Shots); +} + +internal abstract class ComputerShotSelector : ShotSelector +{ + private readonly bool _displayShots; + + internal ComputerShotSelector(Grid source, Grid target, bool displayShots) + : base(source, target) + { + _displayShots = displayShots; + } + + private void DisplayShots(IEnumerable shots, IReadWrite io) + { + if (_displayShots) + { + foreach (var shot in shots) + { + io.WriteLine(shot); + } + } + } +} + +internal class HumanShotSelector : ShotSelector +{ + public HumanShotSelector(Grid source, Grid target) + : base(source, target) + { + } + + public IEnumerable GetShots(IReadWrite io) + { + var shots = new Position[GetShotCount()]; + + for (var i = 0; i < shots.Length; i++) + { + while (true) + { + var position = io.ReadValidPosition(); + if (Target.WasTargetedAt(position, out var turnTargeted)) + { + io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {turnTargeted}"); + continue; + } + shots[i] = position; + break; + } + } + + return shots; + } +} + internal abstract class Ship { private readonly List _positions = new(); @@ -276,7 +317,7 @@ protected Ship(IRandom random, string? nameSuffix = null) internal abstract int Size { get; } internal abstract float Value { get; } internal IEnumerable Positions => _positions; - internal bool IsAfloat => _positions.Count > 0; + internal bool IsDestroyed => _positions.Count == 0; internal bool IsHit(Position position) => _positions.Remove(position); @@ -381,7 +422,7 @@ internal Grid() internal Grid(IReadWrite io) { - io.WriteLine("ENTER POSITION FOR..."); + io.WriteLine("ENTER COORDINATES FOR..."); _ships = new() { new Battleship(io), @@ -401,30 +442,23 @@ internal Grid(IRandom random) TryPositionShip(() => new Destroyer("A", random)) && TryPositionShip(() => new Destroyer("B", random))) { - break; + return; } _ships.Clear(); } - foreach (var ship in _ships) - { - foreach (var position in ship.Positions) - { - this[position] = ship.Value; - } - } - bool TryPositionShip(Func shipFactory) { + var shipGenerationAttempts = 0; while (true) { - var shipGenerationAttempts = 0; var ship = shipFactory.Invoke(); shipGenerationAttempts++; if (shipGenerationAttempts > 25) { return false; } - foreach (var previousShip in _ships) + if (_ships.Min(ship.DistanceTo) >= 3.59) { - if (ship.DistanceTo(previousShip) >= 3.59) { return true; } + _ships.Add(ship); + return true; } } } @@ -444,6 +478,22 @@ public float this[Position position] internal int UntriedSquareCount => 100 - _shots.Count; internal IEnumerable Ships => _ships.AsEnumerable(); + + internal bool WasTargetedAt(Position position, out int turnTargeted) + => _shots.TryGetValue(position, out turnTargeted); + + internal bool IsHit(Position position, int turnNumber, out string? shipName) + { + shipName = null; + _shots[position] = turnNumber; + + var ship = _ships.FirstOrDefault(s => s.IsHit(position)); + if (ship == null) { return false; } + + if (ship.IsDestroyed) { _ships.Remove(ship); } + + return true; + } } internal static class IOExtensions @@ -507,7 +557,10 @@ public IEnumerable Neighbours } internal float DistanceTo(Position other) - => (float)Math.Sqrt((X - other.X) * (X - other.Y) + (Y - other.Y) * (Y - other.Y)); + { + var (deltaX, deltaY) = (X - other.X, Y - other.Y); + return (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY); + } internal Position BringIntoRange(IRandom random) => IsInRange ? this : new(X.BringIntoRange(random), Y.BringIntoRange(random)); diff --git a/77_Salvo/salvo.bas b/77_Salvo/salvo.bas index 710360819..6a85d715e 100644 --- a/77_Salvo/salvo.bas +++ b/77_Salvo/salvo.bas @@ -43,8 +43,6 @@ 1410 FOR Z2= U8 TO U8+FNB(K) 1415 IF U8<2 THEN 1450 1420 FOR Z3=1 TO U8-1 -1421 D = SQR((F(Z3)-F(Z2))^2 + (G(Z3)-G(Z2))^2) -1422 PRINT "(";F(Z3);G(Z3);")","(";F(Z2);G(Z2);")",D 1430 IF SQR((F(Z3)-F(Z2))^2 + (G(Z3)-G(Z2))^2) < 3.59 THEN 1260 1440 NEXT Z3 1450 NEXT Z2 From 3e4fb4fe237bbea7232232551a4b36960c418f03 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Sat, 22 Apr 2023 08:09:50 +1000 Subject: [PATCH 110/377] Split classes to files --- 77_Salvo/csharp/Coordinate.cs | 45 ++ 77_Salvo/csharp/Extensions/IOExtensions.cs | 27 ++ .../csharp/Extensions/RandomExtensions.cs | 32 ++ 77_Salvo/csharp/Game.cs | 419 +----------------- 77_Salvo/csharp/Grid.cs | 89 ++++ 77_Salvo/csharp/Offset.cs | 25 ++ 77_Salvo/csharp/Position.cs | 52 +++ 77_Salvo/csharp/Program.cs | 3 +- 77_Salvo/csharp/Ships/Battleship.cs | 18 + 77_Salvo/csharp/Ships/Cruiser.cs | 18 + 77_Salvo/csharp/Ships/Destroyer.cs | 18 + 77_Salvo/csharp/Ships/Ship.cs | 38 ++ .../csharp/Targetting/ComputerShotSelector.cs | 23 + .../csharp/Targetting/HumanShotSelector.cs | 31 ++ 77_Salvo/csharp/Targetting/ShotSelector.cs | 15 + 15 files changed, 434 insertions(+), 419 deletions(-) create mode 100644 77_Salvo/csharp/Coordinate.cs create mode 100644 77_Salvo/csharp/Extensions/IOExtensions.cs create mode 100644 77_Salvo/csharp/Extensions/RandomExtensions.cs create mode 100644 77_Salvo/csharp/Grid.cs create mode 100644 77_Salvo/csharp/Offset.cs create mode 100644 77_Salvo/csharp/Position.cs create mode 100644 77_Salvo/csharp/Ships/Battleship.cs create mode 100644 77_Salvo/csharp/Ships/Cruiser.cs create mode 100644 77_Salvo/csharp/Ships/Destroyer.cs create mode 100644 77_Salvo/csharp/Ships/Ship.cs create mode 100644 77_Salvo/csharp/Targetting/ComputerShotSelector.cs create mode 100644 77_Salvo/csharp/Targetting/HumanShotSelector.cs create mode 100644 77_Salvo/csharp/Targetting/ShotSelector.cs diff --git a/77_Salvo/csharp/Coordinate.cs b/77_Salvo/csharp/Coordinate.cs new file mode 100644 index 000000000..45d149c15 --- /dev/null +++ b/77_Salvo/csharp/Coordinate.cs @@ -0,0 +1,45 @@ +namespace Salvo; + +internal record struct Coordinate(int Value) +{ + public const int MinValue = 0; + public const int MaxValue = 9; + + public static IEnumerable Range => Enumerable.Range(0, 10).Select(v => new Coordinate(v)); + + public bool IsInRange => Value is >= MinValue and <= MaxValue; + + public static Coordinate Create(float value) => new((int)value - 1); + + public static bool TryCreateValid(float value, out Coordinate coordinate) + { + coordinate = default; + if (value != (int)value) { return false; } + + var result = Create(value); + + if (result.IsInRange) + { + coordinate = result; + return true; + } + + return false; + } + + public Coordinate BringIntoRange(IRandom random) + => Value switch + { + < MinValue => new(MinValue + (int)random.NextFloat(2.5F)), + > MaxValue => new(MaxValue - (int)random.NextFloat(2.5F)), + _ => this + }; + + public static implicit operator Coordinate(float value) => new((int)value); + public static implicit operator int(Coordinate coordinate) => coordinate.Value; + + public static Coordinate operator +(Coordinate coordinate, int offset) => new(coordinate.Value + offset); + public static int operator -(Coordinate a, Coordinate b) => a.Value - b.Value; + + public override string ToString() => $" {Value + 1} "; +} diff --git a/77_Salvo/csharp/Extensions/IOExtensions.cs b/77_Salvo/csharp/Extensions/IOExtensions.cs new file mode 100644 index 000000000..b9eaa2c41 --- /dev/null +++ b/77_Salvo/csharp/Extensions/IOExtensions.cs @@ -0,0 +1,27 @@ +namespace Games.Common.IO; + +internal static class IOExtensions +{ + internal static Position ReadPosition(this IReadWrite io) => Position.Create(io.Read2Numbers("")); + + internal static Position ReadValidPosition(this IReadWrite io) + { + while (true) + { + if (Position.TryCreateValid(io.Read2Numbers(""), out var position)) + { + return position; + } + io.WriteLine("ILLEGAL, ENTER AGAIN."); + } + } + + internal static IEnumerable ReadPositions(this IReadWrite io, string shipName, int shipSize) + { + io.WriteLine(shipName); + for (var i = 0; i < shipSize; i++) + { + yield return io.ReadPosition(); + } + } +} diff --git a/77_Salvo/csharp/Extensions/RandomExtensions.cs b/77_Salvo/csharp/Extensions/RandomExtensions.cs new file mode 100644 index 000000000..e83ab2657 --- /dev/null +++ b/77_Salvo/csharp/Extensions/RandomExtensions.cs @@ -0,0 +1,32 @@ +namespace Games.Common.Randomness; + +internal static class RandomExtensions +{ + internal static (Position, Offset) NextShipPosition(this IRandom random) + { + var startX = random.NextCoordinate(); + var startY = random.NextCoordinate(); + var deltaY = random.NextOffset(); + var deltaX = random.NextOffset(); + return (new(startX, startY), new(deltaX, deltaY)); + } + + private static Coordinate NextCoordinate(this IRandom random) + => random.Next(Coordinate.MinValue, Coordinate.MaxValue + 1); + + private static int NextOffset(this IRandom random) => random.Next(-1, 2); + + internal static (Position, Offset) GetRandomShipPositionInRange(this IRandom random, int shipSize) + { + while (true) + { + var (start, delta) = random.NextShipPosition(); + var shipSizeLessOne = shipSize - 1; + var end = start + delta * shipSizeLessOne; + if (delta != 0 && end.IsInRange) + { + return (start, delta); + } + } + } +} diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 491cebdb7..2afac1bda 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -1,5 +1,4 @@ -using System.Collections.Immutable; -using Games.Common.Randomness; +using Salvo.Targetting; namespace Salvo; @@ -224,419 +223,3 @@ internal void Play() L4230: goto L3380; } } - -internal abstract class ShotSelector -{ - internal ShotSelector(Grid source, Grid target) - { - Source = source; - Target = target; - } - - protected Grid Source { get; } - protected Grid Target { get; } - - public int GetShotCount() => Source.Ships.Sum(s => s.Shots); -} - -internal abstract class ComputerShotSelector : ShotSelector -{ - private readonly bool _displayShots; - - internal ComputerShotSelector(Grid source, Grid target, bool displayShots) - : base(source, target) - { - _displayShots = displayShots; - } - - private void DisplayShots(IEnumerable shots, IReadWrite io) - { - if (_displayShots) - { - foreach (var shot in shots) - { - io.WriteLine(shot); - } - } - } -} - -internal class HumanShotSelector : ShotSelector -{ - public HumanShotSelector(Grid source, Grid target) - : base(source, target) - { - } - - public IEnumerable GetShots(IReadWrite io) - { - var shots = new Position[GetShotCount()]; - - for (var i = 0; i < shots.Length; i++) - { - while (true) - { - var position = io.ReadValidPosition(); - if (Target.WasTargetedAt(position, out var turnTargeted)) - { - io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {turnTargeted}"); - continue; - } - shots[i] = position; - break; - } - } - - return shots; - } -} - -internal abstract class Ship -{ - private readonly List _positions = new(); - - protected Ship(IReadWrite io, string? nameSuffix = null) - { - Name = GetType().Name + nameSuffix; - _positions = io.ReadPositions(Name, Size).ToList(); - } - - protected Ship(IRandom random, string? nameSuffix = null) - { - Name = GetType().Name + nameSuffix; - - var (start, delta) = random.GetRandomShipPositionInRange(Size); - for (var i = 0; i < Size; i++) - { - _positions.Add(start + delta * i); - } - } - - internal string Name { get; } - internal abstract int Shots { get; } - internal abstract int Size { get; } - internal abstract float Value { get; } - internal IEnumerable Positions => _positions; - internal bool IsDestroyed => _positions.Count == 0; - - internal bool IsHit(Position position) => _positions.Remove(position); - - internal float DistanceTo(Ship other) - => _positions.SelectMany(a => other._positions.Select(b => a.DistanceTo(b))).Min(); - - public override string ToString() - => string.Join(Environment.NewLine, _positions.Select(p => p.ToString()).Prepend(Name)); -} - -internal sealed class Battleship : Ship -{ - internal Battleship(IReadWrite io) - : base(io) - { - } - - internal Battleship(IRandom random) - : base(random) - { - } - - internal override int Shots => 3; - internal override int Size => 5; - internal override float Value => 3; -} - -internal sealed class Cruiser : Ship -{ - internal Cruiser(IReadWrite io) - : base(io) - { - } - - internal Cruiser(IRandom random) - : base(random) - { - } - - internal override int Shots => 2; - internal override int Size => 3; - internal override float Value => 2; -} - -internal sealed class Destroyer : Ship -{ - internal Destroyer(string nameIndex, IReadWrite io) - : base(io, $"<{nameIndex}>") - { - } - - internal Destroyer(string nameIndex, IRandom random) - : base(random, $"<{nameIndex}>") - { - } - - internal override int Shots => 1; - internal override int Size => 2; - internal override float Value => Name.EndsWith("") ? 1 : 0.5F; -} - -internal static class RandomExtensions -{ - internal static (Position, Offset) NextShipPosition(this IRandom random) - { - var startX = random.NextCoordinate(); - var startY = random.NextCoordinate(); - var deltaY = random.NextOffset(); - var deltaX = random.NextOffset(); - return (new(startX, startY), new(deltaX, deltaY)); - } - - private static Coordinate NextCoordinate(this IRandom random) - => random.Next(Coordinate.MinValue, Coordinate.MaxValue + 1); - - private static int NextOffset(this IRandom random) => random.Next(-1, 2); - - internal static (Position, Offset) GetRandomShipPositionInRange(this IRandom random, int shipSize) - { - while (true) - { - var (start, delta) = random.NextShipPosition(); - var shipSizeLessOne = shipSize - 1; - var end = start + delta * shipSizeLessOne; - if (delta != 0 && end.IsInRange) - { - return (start, delta); - } - } - } -} - -internal class Grid -{ - private readonly List _ships; - private readonly Dictionary _shots = new(); - - internal Grid() - { - _ships = new(); - } - - internal Grid(IReadWrite io) - { - io.WriteLine("ENTER COORDINATES FOR..."); - _ships = new() - { - new Battleship(io), - new Cruiser(io), - new Destroyer("A", io), - new Destroyer("B", io) - }; - } - - internal Grid(IRandom random) - { - _ships = new(); - while (true) - { - _ships.Add(new Battleship(random)); - if (TryPositionShip(() => new Cruiser(random)) && - TryPositionShip(() => new Destroyer("A", random)) && - TryPositionShip(() => new Destroyer("B", random))) - { - return; - } - _ships.Clear(); - } - - bool TryPositionShip(Func shipFactory) - { - var shipGenerationAttempts = 0; - while (true) - { - var ship = shipFactory.Invoke(); - shipGenerationAttempts++; - if (shipGenerationAttempts > 25) { return false; } - if (_ships.Min(ship.DistanceTo) >= 3.59) - { - _ships.Add(ship); - return true; - } - } - } - } - - public float this[Position position] - { - get => _shots.TryGetValue(position, out var value) - ? value + 10 - : _ships.FirstOrDefault(s => s.Positions.Contains(position))?.Value ?? 0; - set - { - _ = _ships.FirstOrDefault(s => s.IsHit(position)); - _shots[position] = (int)value - 10; - } - } - - internal int UntriedSquareCount => 100 - _shots.Count; - internal IEnumerable Ships => _ships.AsEnumerable(); - - internal bool WasTargetedAt(Position position, out int turnTargeted) - => _shots.TryGetValue(position, out turnTargeted); - - internal bool IsHit(Position position, int turnNumber, out string? shipName) - { - shipName = null; - _shots[position] = turnNumber; - - var ship = _ships.FirstOrDefault(s => s.IsHit(position)); - if (ship == null) { return false; } - - if (ship.IsDestroyed) { _ships.Remove(ship); } - - return true; - } -} - -internal static class IOExtensions -{ - internal static Position ReadPosition(this IReadWrite io) => Position.Create(io.Read2Numbers("")); - - internal static Position ReadValidPosition(this IReadWrite io) - { - while (true) - { - if (Position.TryCreateValid(io.Read2Numbers(""), out var position)) - { - return position; - } - io.WriteLine("ILLEGAL, ENTER AGAIN."); - } - } - - internal static IEnumerable ReadPositions(this IReadWrite io, string shipName, int shipSize) - { - io.WriteLine(shipName); - for (var i = 0; i < shipSize; i++) - { - yield return io.ReadPosition(); - } - } -} - -internal record struct Position(Coordinate X, Coordinate Y) -{ - public bool IsInRange => X.IsInRange && Y.IsInRange; - public bool IsOnDiagonal => X == Y; - - public static Position Create((float X, float Y) coordinates) => new(coordinates.X, coordinates.Y); - - public static bool TryCreateValid((float X, float Y) coordinates, out Position position) - { - if (Coordinate.TryCreateValid(coordinates.X, out var x) && Coordinate.TryCreateValid(coordinates.Y, out var y)) - { - position = new(x, y); - return true; - } - - position = default; - return false; - } - - public static IEnumerable All - => Coordinate.Range.SelectMany(x => Coordinate.Range.Select(y => new Position(x, y))); - - public IEnumerable Neighbours - { - get - { - foreach (var offset in Offset.Units) - { - var neighbour = this + offset; - if (neighbour.IsInRange) { yield return neighbour; } - } - } - } - - internal float DistanceTo(Position other) - { - var (deltaX, deltaY) = (X - other.X, Y - other.Y); - return (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY); - } - - internal Position BringIntoRange(IRandom random) - => IsInRange ? this : new(X.BringIntoRange(random), Y.BringIntoRange(random)); - - public static Position operator +(Position position, Offset offset) - => new(position.X + offset.X, position.Y + offset.Y); - - public static implicit operator Position(int value) => new(value, value); - - public override string ToString() => $"{X}{Y}"; -} - -internal record struct Coordinate(int Value) -{ - public const int MinValue = 0; - public const int MaxValue = 9; - - public static IEnumerable Range => Enumerable.Range(0, 10).Select(v => new Coordinate(v)); - - public bool IsInRange => Value is >= MinValue and <= MaxValue; - - public static Coordinate Create(float value) => new((int)value - 1); - - public static bool TryCreateValid(float value, out Coordinate coordinate) - { - coordinate = default; - if (value != (int)value) { return false; } - - var result = Create(value); - - if (result.IsInRange) - { - coordinate = result; - return true; - } - - return false; - } - - public Coordinate BringIntoRange(IRandom random) - => Value switch - { - < MinValue => new(MinValue + (int)random.NextFloat(2.5F)), - > MaxValue => new(MaxValue - (int)random.NextFloat(2.5F)), - _ => this - }; - - public static implicit operator Coordinate(float value) => new((int)value); - public static implicit operator int(Coordinate coordinate) => coordinate.Value; - - public static Coordinate operator +(Coordinate coordinate, int offset) => new(coordinate.Value + offset); - public static int operator -(Coordinate a, Coordinate b) => a.Value - b.Value; - - public override string ToString() => $" {Value + 1} "; -} - -internal record struct Offset(int X, int Y) -{ - public static readonly Offset Zero = 0; - - public static Offset operator *(Offset offset, int scale) => new(offset.X * scale, offset.Y * scale); - - public static implicit operator Offset(int value) => new(value, value); - - public static IEnumerable Units - { - get - { - for (int x = -1; x <= 1; x++) - { - for (int y = -1; y <= 1; y++) - { - var offset = new Offset(x, y); - if (offset != Zero) { yield return offset; } - } - } - } - } -} diff --git a/77_Salvo/csharp/Grid.cs b/77_Salvo/csharp/Grid.cs new file mode 100644 index 000000000..c3d04dff4 --- /dev/null +++ b/77_Salvo/csharp/Grid.cs @@ -0,0 +1,89 @@ +using System.Collections.Immutable; + +namespace Salvo; + +internal class Grid +{ + private readonly List _ships; + private readonly Dictionary _shots = new(); + + internal Grid() + { + _ships = new(); + } + + internal Grid(IReadWrite io) + { + io.WriteLine("ENTER COORDINATES FOR..."); + _ships = new() + { + new Battleship(io), + new Cruiser(io), + new Destroyer("A", io), + new Destroyer("B", io) + }; + } + + internal Grid(IRandom random) + { + _ships = new(); + while (true) + { + _ships.Add(new Battleship(random)); + if (TryPositionShip(() => new Cruiser(random)) && + TryPositionShip(() => new Destroyer("A", random)) && + TryPositionShip(() => new Destroyer("B", random))) + { + return; + } + _ships.Clear(); + } + + bool TryPositionShip(Func shipFactory) + { + var shipGenerationAttempts = 0; + while (true) + { + var ship = shipFactory.Invoke(); + shipGenerationAttempts++; + if (shipGenerationAttempts > 25) { return false; } + if (_ships.Min(ship.DistanceTo) >= 3.59) + { + _ships.Add(ship); + return true; + } + } + } + } + + public float this[Position position] + { + get => _shots.TryGetValue(position, out var value) + ? value + 10 + : _ships.FirstOrDefault(s => s.Positions.Contains(position))?.Value ?? 0; + set + { + _ = _ships.FirstOrDefault(s => s.IsHit(position)); + _shots[position] = (int)value - 10; + } + } + + internal int UntriedSquareCount => 100 - _shots.Count; + internal IEnumerable Ships => _ships.AsEnumerable(); + + internal bool WasTargetedAt(Position position, out int turnTargeted) + => _shots.TryGetValue(position, out turnTargeted); + + internal bool IsHit(Position position, int turnNumber, out string? shipName) + { + shipName = null; + _shots[position] = turnNumber; + + var ship = _ships.FirstOrDefault(s => s.IsHit(position)); + if (ship == null) { return false; } + + if (ship.IsDestroyed) { _ships.Remove(ship); } + + return true; + } +} diff --git a/77_Salvo/csharp/Offset.cs b/77_Salvo/csharp/Offset.cs new file mode 100644 index 000000000..3c873f101 --- /dev/null +++ b/77_Salvo/csharp/Offset.cs @@ -0,0 +1,25 @@ +namespace Salvo; + +internal record struct Offset(int X, int Y) +{ + public static readonly Offset Zero = 0; + + public static Offset operator *(Offset offset, int scale) => new(offset.X * scale, offset.Y * scale); + + public static implicit operator Offset(int value) => new(value, value); + + public static IEnumerable Units + { + get + { + for (int x = -1; x <= 1; x++) + { + for (int y = -1; y <= 1; y++) + { + var offset = new Offset(x, y); + if (offset != Zero) { yield return offset; } + } + } + } + } +} diff --git a/77_Salvo/csharp/Position.cs b/77_Salvo/csharp/Position.cs new file mode 100644 index 000000000..3bafe2179 --- /dev/null +++ b/77_Salvo/csharp/Position.cs @@ -0,0 +1,52 @@ +namespace Salvo; + +internal record struct Position(Coordinate X, Coordinate Y) +{ + public bool IsInRange => X.IsInRange && Y.IsInRange; + public bool IsOnDiagonal => X == Y; + + public static Position Create((float X, float Y) coordinates) => new(coordinates.X, coordinates.Y); + + public static bool TryCreateValid((float X, float Y) coordinates, out Position position) + { + if (Coordinate.TryCreateValid(coordinates.X, out var x) && Coordinate.TryCreateValid(coordinates.Y, out var y)) + { + position = new(x, y); + return true; + } + + position = default; + return false; + } + + public static IEnumerable All + => Coordinate.Range.SelectMany(x => Coordinate.Range.Select(y => new Position(x, y))); + + public IEnumerable Neighbours + { + get + { + foreach (var offset in Offset.Units) + { + var neighbour = this + offset; + if (neighbour.IsInRange) { yield return neighbour; } + } + } + } + + internal float DistanceTo(Position other) + { + var (deltaX, deltaY) = (X - other.X, Y - other.Y); + return (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY); + } + + internal Position BringIntoRange(IRandom random) + => IsInRange ? this : new(X.BringIntoRange(random), Y.BringIntoRange(random)); + + public static Position operator +(Position position, Offset offset) + => new(position.X + offset.X, position.Y + offset.Y); + + public static implicit operator Position(int value) => new(value, value); + + public override string ToString() => $"{X}{Y}"; +} diff --git a/77_Salvo/csharp/Program.cs b/77_Salvo/csharp/Program.cs index b9d6a84cd..6878fd383 100644 --- a/77_Salvo/csharp/Program.cs +++ b/77_Salvo/csharp/Program.cs @@ -1,7 +1,8 @@ global using System; global using Games.Common.IO; global using Games.Common.Randomness; +global using Salvo; +global using Salvo.Ships; global using static Salvo.Resources.Resource; -using Salvo; new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); diff --git a/77_Salvo/csharp/Ships/Battleship.cs b/77_Salvo/csharp/Ships/Battleship.cs new file mode 100644 index 000000000..1e57e59d8 --- /dev/null +++ b/77_Salvo/csharp/Ships/Battleship.cs @@ -0,0 +1,18 @@ +namespace Salvo.Ships; + +internal sealed class Battleship : Ship +{ + internal Battleship(IReadWrite io) + : base(io) + { + } + + internal Battleship(IRandom random) + : base(random) + { + } + + internal override int Shots => 3; + internal override int Size => 5; + internal override float Value => 3; +} diff --git a/77_Salvo/csharp/Ships/Cruiser.cs b/77_Salvo/csharp/Ships/Cruiser.cs new file mode 100644 index 000000000..33f30e381 --- /dev/null +++ b/77_Salvo/csharp/Ships/Cruiser.cs @@ -0,0 +1,18 @@ +namespace Salvo.Ships; + +internal sealed class Cruiser : Ship +{ + internal Cruiser(IReadWrite io) + : base(io) + { + } + + internal Cruiser(IRandom random) + : base(random) + { + } + + internal override int Shots => 2; + internal override int Size => 3; + internal override float Value => 2; +} diff --git a/77_Salvo/csharp/Ships/Destroyer.cs b/77_Salvo/csharp/Ships/Destroyer.cs new file mode 100644 index 000000000..0e2a023bb --- /dev/null +++ b/77_Salvo/csharp/Ships/Destroyer.cs @@ -0,0 +1,18 @@ +namespace Salvo.Ships; + +internal sealed class Destroyer : Ship +{ + internal Destroyer(string nameIndex, IReadWrite io) + : base(io, $"<{nameIndex}>") + { + } + + internal Destroyer(string nameIndex, IRandom random) + : base(random, $"<{nameIndex}>") + { + } + + internal override int Shots => 1; + internal override int Size => 2; + internal override float Value => Name.EndsWith("") ? 1 : 0.5F; +} diff --git a/77_Salvo/csharp/Ships/Ship.cs b/77_Salvo/csharp/Ships/Ship.cs new file mode 100644 index 000000000..58f311c24 --- /dev/null +++ b/77_Salvo/csharp/Ships/Ship.cs @@ -0,0 +1,38 @@ +namespace Salvo.Ships; + +internal abstract class Ship +{ + private readonly List _positions = new(); + + protected Ship(IReadWrite io, string? nameSuffix = null) + { + Name = GetType().Name + nameSuffix; + _positions = io.ReadPositions(Name, Size).ToList(); + } + + protected Ship(IRandom random, string? nameSuffix = null) + { + Name = GetType().Name + nameSuffix; + + var (start, delta) = random.GetRandomShipPositionInRange(Size); + for (var i = 0; i < Size; i++) + { + _positions.Add(start + delta * i); + } + } + + internal string Name { get; } + internal abstract int Shots { get; } + internal abstract int Size { get; } + internal abstract float Value { get; } + internal IEnumerable Positions => _positions; + internal bool IsDestroyed => _positions.Count == 0; + + internal bool IsHit(Position position) => _positions.Remove(position); + + internal float DistanceTo(Ship other) + => _positions.SelectMany(a => other._positions.Select(b => a.DistanceTo(b))).Min(); + + public override string ToString() + => string.Join(Environment.NewLine, _positions.Select(p => p.ToString()).Prepend(Name)); +} diff --git a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs new file mode 100644 index 000000000..1cf2a98a1 --- /dev/null +++ b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs @@ -0,0 +1,23 @@ +namespace Salvo.Targetting; + +internal abstract class ComputerShotSelector : ShotSelector +{ + private readonly bool _displayShots; + + internal ComputerShotSelector(Grid source, Grid target, bool displayShots) + : base(source, target) + { + _displayShots = displayShots; + } + + private void DisplayShots(IEnumerable shots, IReadWrite io) + { + if (_displayShots) + { + foreach (var shot in shots) + { + io.WriteLine(shot); + } + } + } +} diff --git a/77_Salvo/csharp/Targetting/HumanShotSelector.cs b/77_Salvo/csharp/Targetting/HumanShotSelector.cs new file mode 100644 index 000000000..6a50330a9 --- /dev/null +++ b/77_Salvo/csharp/Targetting/HumanShotSelector.cs @@ -0,0 +1,31 @@ +namespace Salvo.Targetting; + +internal class HumanShotSelector : ShotSelector +{ + public HumanShotSelector(Grid source, Grid target) + : base(source, target) + { + } + + public IEnumerable GetShots(IReadWrite io) + { + var shots = new Position[GetShotCount()]; + + for (var i = 0; i < shots.Length; i++) + { + while (true) + { + var position = io.ReadValidPosition(); + if (Target.WasTargetedAt(position, out var turnTargeted)) + { + io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {turnTargeted}"); + continue; + } + shots[i] = position; + break; + } + } + + return shots; + } +} diff --git a/77_Salvo/csharp/Targetting/ShotSelector.cs b/77_Salvo/csharp/Targetting/ShotSelector.cs new file mode 100644 index 000000000..fae30f313 --- /dev/null +++ b/77_Salvo/csharp/Targetting/ShotSelector.cs @@ -0,0 +1,15 @@ +namespace Salvo.Targetting; + +internal abstract class ShotSelector +{ + internal ShotSelector(Grid source, Grid target) + { + Source = source; + Target = target; + } + + protected Grid Source { get; } + protected Grid Target { get; } + + public int GetShotCount() => Source.Ships.Sum(s => s.Shots); +} From d21b41d3a724cca452d65e0c99a168f5c931b6b2 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Sat, 22 Apr 2023 18:33:03 +1000 Subject: [PATCH 111/377] Add string resources --- 77_Salvo/csharp/Extensions/IOExtensions.cs | 2 +- 77_Salvo/csharp/Game.cs | 54 +++++++++---------- 77_Salvo/csharp/Grid.cs | 6 ++- 77_Salvo/csharp/Resources/Coordinates.txt | 1 + .../Resources/IHaveMoreShotsThanSquares.txt | 1 + 77_Salvo/csharp/Resources/IHaveShots.txt | 1 + 77_Salvo/csharp/Resources/IHit.txt | 1 + 77_Salvo/csharp/Resources/IWon.txt | 1 + 77_Salvo/csharp/Resources/Illegal.txt | 1 + 77_Salvo/csharp/Resources/Resource.cs | 21 +++++++- 77_Salvo/csharp/Resources/SeeShots.txt | 1 + 77_Salvo/csharp/Resources/ShotBefore.txt | 1 + 77_Salvo/csharp/Resources/Start.txt | 1 + 77_Salvo/csharp/Resources/Turn.txt | 2 + .../csharp/Resources/WhereAreYourShips.txt | 1 + .../Resources/YouHaveMoreShotsThanSquares.txt | 1 + 77_Salvo/csharp/Resources/YouHaveShots.txt | 1 + 77_Salvo/csharp/Resources/YouHit.txt | 1 + 77_Salvo/csharp/Resources/YouWon.txt | 1 + 19 files changed, 67 insertions(+), 32 deletions(-) create mode 100644 77_Salvo/csharp/Resources/Coordinates.txt create mode 100644 77_Salvo/csharp/Resources/IHaveMoreShotsThanSquares.txt create mode 100644 77_Salvo/csharp/Resources/IHaveShots.txt create mode 100644 77_Salvo/csharp/Resources/IHit.txt create mode 100644 77_Salvo/csharp/Resources/IWon.txt create mode 100644 77_Salvo/csharp/Resources/Illegal.txt create mode 100644 77_Salvo/csharp/Resources/SeeShots.txt create mode 100644 77_Salvo/csharp/Resources/ShotBefore.txt create mode 100644 77_Salvo/csharp/Resources/Start.txt create mode 100644 77_Salvo/csharp/Resources/Turn.txt create mode 100644 77_Salvo/csharp/Resources/WhereAreYourShips.txt create mode 100644 77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt create mode 100644 77_Salvo/csharp/Resources/YouHaveShots.txt create mode 100644 77_Salvo/csharp/Resources/YouHit.txt create mode 100644 77_Salvo/csharp/Resources/YouWon.txt diff --git a/77_Salvo/csharp/Extensions/IOExtensions.cs b/77_Salvo/csharp/Extensions/IOExtensions.cs index b9eaa2c41..6d021deb3 100644 --- a/77_Salvo/csharp/Extensions/IOExtensions.cs +++ b/77_Salvo/csharp/Extensions/IOExtensions.cs @@ -12,7 +12,7 @@ internal static Position ReadValidPosition(this IReadWrite io) { return position; } - io.WriteLine("ILLEGAL, ENTER AGAIN."); + io.Write(Streams.Illegal); } } diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 2afac1bda..2f3ebe8e2 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -29,50 +29,48 @@ internal void Play() var computerGrid = new Grid(_random); var humanGrid = new Grid(_io); var humanShotSelector = new HumanShotSelector(humanGrid, computerGrid); - var startResponse = _io.ReadString("DO YOU WANT TO START"); - while (startResponse == "WHERE ARE YOUR SHIPS?") + var startResponse = _io.ReadString(Prompts.Start); + while (startResponse == Strings.WhereAreYourShips) { foreach (var ship in computerGrid.Ships) { _io.WriteLine(ship); } - startResponse = _io.ReadString("DO YOU WANT TO START"); + startResponse = _io.ReadString(Prompts.Start); } L1890: var turnNumber=0; -L1900: var seeShotsResponse = _io.ReadString("DO YOU WANT TO SEE MY SHOTS"); +L1900: var seeShotsResponse = _io.ReadString(Prompts.SeeShots); L1920: _io.WriteLine(); L1930: if (startResponse != "YES") { goto L2620; } L1950: if (startResponse != "YES") { goto L1990; } L1960: turnNumber++; -L1970: _io.WriteLine(); -L1980: _io.WriteLine($"TURN {turnNumber}"); -L1990: var maxShotCount = humanShotSelector.GetShotCount(); -L2220: _io.WriteLine($"YOU HAVE {maxShotCount} SHOTS."); - if (maxShotCount == 0) { goto L2270; } -L2230: if (maxShotCount > computerGrid.UntriedSquareCount) +L1980: _io.Write(Strings.Turn(turnNumber)); +L1990: var numberOfShots = humanShotSelector.GetShotCount(); +L2220: _io.Write(Strings.YouHaveShots(numberOfShots)); + if (numberOfShots == 0) { goto L2270; } +L2230: if (numberOfShots > computerGrid.UntriedSquareCount) { - _io.WriteLine("YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES."); + _io.WriteLine(Streams.YouHaveMoreShotsThanSquares); L2250: goto L2890; } foreach (var shot1 in humanShotSelector.GetShots(_io)) { if (computerGrid.IsHit(shot1, turnNumber, out var shipName)) { - _io.WriteLine($"YOU HIT MY {shipName}."); + _io.Write(Strings.YouHit(shipName)); } } L2620: if (startResponse == "YES") { goto L2670; } L2640: turnNumber++; -L2650: _io.WriteLine(); -L2660: _io.WriteLine($"TURN {turnNumber}"); -L2670: maxShotCount = computerGrid.Ships.Sum(s => s.Shots); -L2840: _io.WriteLine($"I HAVE {maxShotCount} SHOTS."); -L2850: if (humanGrid.UntriedSquareCount > maxShotCount) { goto L2880; } -L2860: _io.WriteLine("I HAVE MORE SHOTS THAN BLANK SQUARES."); -L2270: _io.WriteLine("I HAVE WON."); +L2660: _io.Write(Strings.Turn(turnNumber)); +L2670: numberOfShots = computerGrid.Ships.Sum(s => s.Shots); +L2840: _io.Write(Strings.IHaveShots(numberOfShots)); +L2850: if (humanGrid.UntriedSquareCount > numberOfShots) { goto L2880; } +L2860: _io.Write(Streams.IHaveMoreShotsThanSquares); +L2270: _io.Write(Streams.IWon); return; -L2880: if (maxShotCount != 0) { goto L2960; } -L2890: _io.WriteLine("YOU HAVE WON."); +L2880: if (numberOfShots != 0) { goto L2960; } +L2890: _io.Write(Streams.YouWon); L2900: return; L2960: for (var i = 1; i <= 12; i++) @@ -91,7 +89,7 @@ internal void Play() L3170: goto L3270; // record shot L3180: temp[shotCount]=shot; -L3200: if (shotCount==maxShotCount) { goto L3380; } +L3200: if (shotCount==numberOfShots) { goto L3380; } L3210: if (strategyNumber==6) { goto L3030; } L3240: //DATA 1,1,-1,1,1,-3,1,1,0,2,-1,1 var data = new Offset[] { new(1,1),new(-1,1),new(1,-3),new(1,1),new(0,2),new(-1,1) }; @@ -111,11 +109,11 @@ internal void Play() L3370: goto L3180; // display shots L3380: if (seeShotsResponse != "YES") { goto L3420; } -L3390: for (var i = 1; i <= maxShotCount; i++) +L3390: for (var i = 1; i <= numberOfShots; i++) { L3400: _io.WriteLine(temp[i]); } -L3420: for (var i = 1; i <= maxShotCount; i++) +L3420: for (var i = 1; i <= numberOfShots; i++) { L3430: if (humanGrid[temp[i]] == 3) { @@ -197,22 +195,22 @@ internal void Play() } } } -L4030: for (var i = 1; i <= maxShotCount; i++) +L4030: for (var i = 1; i <= numberOfShots; i++) { L4040: temp[i]=i; } foreach (var position in Position.All) { L4090: var Q9=1; -L4100: for (var i = 1; i <= maxShotCount; i++) +L4100: for (var i = 1; i <= numberOfShots; i++) { L4110: if (tempGrid[temp[i]]>=tempGrid[temp[Q9]]) { continue; } L4120: Q9=i; } -L4131: if (position.X>maxShotCount) { goto L4140; } +L4131: if (position.X>numberOfShots) { goto L4140; } L4132: if (position.IsOnDiagonal) { goto L4210; } L4140: if (tempGrid[position] _shots.TryGetValue(position, out turnTargeted); - internal bool IsHit(Position position, int turnNumber, out string? shipName) + internal bool IsHit(Position position, int turnNumber, [NotNullWhen(true)] out string? shipName) { shipName = null; _shots[position] = turnNumber; var ship = _ships.FirstOrDefault(s => s.IsHit(position)); if (ship == null) { return false; } + shipName = ship.Name; if (ship.IsDestroyed) { _ships.Remove(ship); } diff --git a/77_Salvo/csharp/Resources/Coordinates.txt b/77_Salvo/csharp/Resources/Coordinates.txt new file mode 100644 index 000000000..387d7a6b4 --- /dev/null +++ b/77_Salvo/csharp/Resources/Coordinates.txt @@ -0,0 +1 @@ +Enter coordinates for... diff --git a/77_Salvo/csharp/Resources/IHaveMoreShotsThanSquares.txt b/77_Salvo/csharp/Resources/IHaveMoreShotsThanSquares.txt new file mode 100644 index 000000000..a6f371107 --- /dev/null +++ b/77_Salvo/csharp/Resources/IHaveMoreShotsThanSquares.txt @@ -0,0 +1 @@ +I have more shots than blank squares. diff --git a/77_Salvo/csharp/Resources/IHaveShots.txt b/77_Salvo/csharp/Resources/IHaveShots.txt new file mode 100644 index 000000000..9157e1a7b --- /dev/null +++ b/77_Salvo/csharp/Resources/IHaveShots.txt @@ -0,0 +1 @@ +I have {0} shots. diff --git a/77_Salvo/csharp/Resources/IHit.txt b/77_Salvo/csharp/Resources/IHit.txt new file mode 100644 index 000000000..a3f3dccf3 --- /dev/null +++ b/77_Salvo/csharp/Resources/IHit.txt @@ -0,0 +1 @@ +I hot your {0} diff --git a/77_Salvo/csharp/Resources/IWon.txt b/77_Salvo/csharp/Resources/IWon.txt new file mode 100644 index 000000000..b3f506348 --- /dev/null +++ b/77_Salvo/csharp/Resources/IWon.txt @@ -0,0 +1 @@ +I have won. diff --git a/77_Salvo/csharp/Resources/Illegal.txt b/77_Salvo/csharp/Resources/Illegal.txt new file mode 100644 index 000000000..6a71787a7 --- /dev/null +++ b/77_Salvo/csharp/Resources/Illegal.txt @@ -0,0 +1 @@ +Illegal, enter again. diff --git a/77_Salvo/csharp/Resources/Resource.cs b/77_Salvo/csharp/Resources/Resource.cs index 0cc550343..c3a0d8ca5 100644 --- a/77_Salvo/csharp/Resources/Resource.cs +++ b/77_Salvo/csharp/Resources/Resource.cs @@ -8,13 +8,32 @@ internal static class Resource internal static class Streams { public static Stream Title => GetStream(); + public static Stream YouHaveMoreShotsThanSquares => GetStream(); + public static Stream YouWon => GetStream(); + public static Stream IHaveMoreShotsThanSquares => GetStream(); + public static Stream IWon => GetStream(); + public static Stream Illegal => GetStream(); + } + + internal static class Strings + { + public static string WhereAreYourShips => GetString(); + public static string YouHaveShots(int number) => Format(number); + public static string IHaveShots(int number) => Format(number); + public static string YouHit(string shipName) => Format(shipName); + public static string ShotBefore(int turnNumber) => Format(turnNumber); + public static string Turn(int number) => Format(number); } internal static class Prompts { + public static string Coordinates => GetString(); + public static string Start => GetString(); + public static string SeeShots => GetString(); } - private static string GetPrompt([CallerMemberName] string? name = null) => GetString($"{name}Prompt"); + private static string Format(T value, [CallerMemberName] string? name = null) + => string.Format(GetString(name), value); private static string GetString([CallerMemberName] string? name = null) { diff --git a/77_Salvo/csharp/Resources/SeeShots.txt b/77_Salvo/csharp/Resources/SeeShots.txt new file mode 100644 index 000000000..7f608b0ba --- /dev/null +++ b/77_Salvo/csharp/Resources/SeeShots.txt @@ -0,0 +1 @@ +Do you want to see my shots \ No newline at end of file diff --git a/77_Salvo/csharp/Resources/ShotBefore.txt b/77_Salvo/csharp/Resources/ShotBefore.txt new file mode 100644 index 000000000..18e90fcbd --- /dev/null +++ b/77_Salvo/csharp/Resources/ShotBefore.txt @@ -0,0 +1 @@ +You shot there before on turn {0} diff --git a/77_Salvo/csharp/Resources/Start.txt b/77_Salvo/csharp/Resources/Start.txt new file mode 100644 index 000000000..283a0fbb0 --- /dev/null +++ b/77_Salvo/csharp/Resources/Start.txt @@ -0,0 +1 @@ +Do you want to start \ No newline at end of file diff --git a/77_Salvo/csharp/Resources/Turn.txt b/77_Salvo/csharp/Resources/Turn.txt new file mode 100644 index 000000000..14bf316ea --- /dev/null +++ b/77_Salvo/csharp/Resources/Turn.txt @@ -0,0 +1,2 @@ + +Turn {0} diff --git a/77_Salvo/csharp/Resources/WhereAreYourShips.txt b/77_Salvo/csharp/Resources/WhereAreYourShips.txt new file mode 100644 index 000000000..797c1144a --- /dev/null +++ b/77_Salvo/csharp/Resources/WhereAreYourShips.txt @@ -0,0 +1 @@ +Where are your ships? diff --git a/77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt b/77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt new file mode 100644 index 000000000..37c068124 --- /dev/null +++ b/77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt @@ -0,0 +1 @@ +You have more shots that there are blank squares. diff --git a/77_Salvo/csharp/Resources/YouHaveShots.txt b/77_Salvo/csharp/Resources/YouHaveShots.txt new file mode 100644 index 000000000..43abeda83 --- /dev/null +++ b/77_Salvo/csharp/Resources/YouHaveShots.txt @@ -0,0 +1 @@ +You have {0} shots. diff --git a/77_Salvo/csharp/Resources/YouHit.txt b/77_Salvo/csharp/Resources/YouHit.txt new file mode 100644 index 000000000..b5b5d7614 --- /dev/null +++ b/77_Salvo/csharp/Resources/YouHit.txt @@ -0,0 +1 @@ +You hit my {0}. diff --git a/77_Salvo/csharp/Resources/YouWon.txt b/77_Salvo/csharp/Resources/YouWon.txt new file mode 100644 index 000000000..1f71343bc --- /dev/null +++ b/77_Salvo/csharp/Resources/YouWon.txt @@ -0,0 +1 @@ +You have won. From aa6a06cdc8400789d549b09e67fdb700df1309de Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Sun, 23 Apr 2023 17:55:48 +1000 Subject: [PATCH 112/377] Add SearchPatternShotSelector --- 77_Salvo/csharp/Game.cs | 73 ++++--------------- 77_Salvo/csharp/Resources/Resource.cs | 1 + .../csharp/Targetting/ComputerShotSelector.cs | 2 +- .../csharp/Targetting/HumanShotSelector.cs | 13 ++-- 77_Salvo/csharp/Targetting/SearchPattern.cs | 22 ++++++ .../Targetting/SearchPatternShotSelector.cs | 54 ++++++++++++++ 77_Salvo/csharp/Targetting/ShotSelector.cs | 4 +- 7 files changed, 105 insertions(+), 64 deletions(-) create mode 100644 77_Salvo/csharp/Targetting/SearchPattern.cs create mode 100644 77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 2f3ebe8e2..616f0cbc1 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -28,7 +28,8 @@ internal void Play() } var computerGrid = new Grid(_random); var humanGrid = new Grid(_io); - var humanShotSelector = new HumanShotSelector(humanGrid, computerGrid); + var humanShotSelector = new HumanShotSelector(humanGrid, computerGrid, _io); + var computerShotSelector = new SearchPatternShotSelector(computerGrid, humanGrid, _random); var startResponse = _io.ReadString(Prompts.Start); while (startResponse == Strings.WhereAreYourShips) { @@ -45,7 +46,7 @@ internal void Play() L1950: if (startResponse != "YES") { goto L1990; } L1960: turnNumber++; L1980: _io.Write(Strings.Turn(turnNumber)); -L1990: var numberOfShots = humanShotSelector.GetShotCount(); +L1990: var numberOfShots = humanShotSelector.NumberOfShots; L2220: _io.Write(Strings.YouHaveShots(numberOfShots)); if (numberOfShots == 0) { goto L2270; } L2230: if (numberOfShots > computerGrid.UntriedSquareCount) @@ -53,7 +54,7 @@ internal void Play() _io.WriteLine(Streams.YouHaveMoreShotsThanSquares); L2250: goto L2890; } - foreach (var shot1 in humanShotSelector.GetShots(_io)) + foreach (var shot1 in humanShotSelector.GetShots()) { if (computerGrid.IsHit(shot1, turnNumber, out var shipName)) { @@ -63,7 +64,7 @@ internal void Play() L2620: if (startResponse == "YES") { goto L2670; } L2640: turnNumber++; L2660: _io.Write(Strings.Turn(turnNumber)); -L2670: numberOfShots = computerGrid.Ships.Sum(s => s.Shots); +L2670: numberOfShots = computerShotSelector.NumberOfShots; L2840: _io.Write(Strings.IHaveShots(numberOfShots)); L2850: if (humanGrid.UntriedSquareCount > numberOfShots) { goto L2880; } L2860: _io.Write(Streams.IHaveMoreShotsThanSquares); @@ -78,70 +79,28 @@ internal void Play() // if damaged ships L2970: if (hitShipValue[i]>0) { goto L3800; } } -L3000: var shotCount=0; -L3010: var shotAttempts=0; -L3020: var (shot, _) = _random.NextShipPosition(); -L3030: var strategyNumber=0; //RESTORE -L3050: shotAttempts++; -L3060: if (shotAttempts>100) { goto L3010; } - // ensure shot is in range -L3070: shot = shot.BringIntoRange(_random); -L3170: goto L3270; - // record shot -L3180: temp[shotCount]=shot; -L3200: if (shotCount==numberOfShots) { goto L3380; } -L3210: if (strategyNumber==6) { goto L3030; } -L3240: //DATA 1,1,-1,1,1,-3,1,1,0,2,-1,1 - var data = new Offset[] { new(1,1),new(-1,1),new(1,-3),new(1,1),new(0,2),new(-1,1) }; -L3220: //READ X1,Y1 - var offset = data[strategyNumber++]; -L3250: shot+=offset; - // is the shot in range? -L3270: if (!shot.IsInRange) { goto L3210; } - // have we fired here before -L3310: if (humanGrid[shot]>10) { goto L3210; } - // have we already selected this shot? -L3320: for (var i = 1; i <= shotCount; i++) - { -L3330: if (temp[i] == shot) { goto L3210; } - } -L3360: shotCount++; -L3370: goto L3180; + temp = computerShotSelector.GetShots().ToArray(); // display shots -L3380: if (seeShotsResponse != "YES") { goto L3420; } -L3390: for (var i = 1; i <= numberOfShots; i++) +L3380: if (seeShotsResponse == "yes") { -L3400: _io.WriteLine(temp[i]); + foreach (var shot in temp) + { + _io.WriteLine(shot); + } } -L3420: for (var i = 1; i <= numberOfShots; i++) + foreach (var shot in temp) { -L3430: if (humanGrid[temp[i]] == 3) - { - _io.WriteLine("I HIT YOUR BATTLESHIP"); - } - else if (humanGrid[temp[i]] == 2) + if (!humanGrid.IsHit(shot, turnNumber, out var shipName)) { - _io.WriteLine("I HIT YOUR CRUISER"); - } - else if (humanGrid[temp[i]] == 1) - { - _io.WriteLine("I HIT YOUR DESTROYER"); - } - else if (humanGrid[temp[i]] == .5F) - { - _io.WriteLine("I HIT YOUR DESTROYER"); - } - else - { - humanGrid[temp[i]]=10+turnNumber; continue; } + _io.WriteLine(Strings.IHit(shipName)); L3570: for (var j = 1; j <= 12; j++) { // record hit L3580: if (hitTurnRecord[j] != -1) { continue; } L3590: hitTurnRecord[j]=10+turnNumber; -L3600: hitShipValue[j]=humanGrid[temp[i]]; +L3600: hitShipValue[j]=humanGrid[shot]; // look for past hits on same ship L3610: var shipHits=0; L3620: for (var k = 1; k <= 12; k++) @@ -169,7 +128,7 @@ internal void Play() L3770: _io.WriteLine($"{nameof(hitShipValue)}( {j} ) = {hitShipValue[j]}"); } return; -L3470: humanGrid[temp[i]]=10+turnNumber; +L3470: humanGrid[shot]=10+turnNumber; } L3490: goto L1950; L3800: //REM************************USINGEARRAY diff --git a/77_Salvo/csharp/Resources/Resource.cs b/77_Salvo/csharp/Resources/Resource.cs index c3a0d8ca5..8be52fdb0 100644 --- a/77_Salvo/csharp/Resources/Resource.cs +++ b/77_Salvo/csharp/Resources/Resource.cs @@ -21,6 +21,7 @@ internal static class Strings public static string YouHaveShots(int number) => Format(number); public static string IHaveShots(int number) => Format(number); public static string YouHit(string shipName) => Format(shipName); + public static string IHit(string shipName) => Format(shipName); public static string ShotBefore(int turnNumber) => Format(turnNumber); public static string Turn(int number) => Format(number); } diff --git a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs index 1cf2a98a1..c8f57d209 100644 --- a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs +++ b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs @@ -1,6 +1,6 @@ namespace Salvo.Targetting; -internal abstract class ComputerShotSelector : ShotSelector +internal class ComputerShotSelector : ShotSelector { private readonly bool _displayShots; diff --git a/77_Salvo/csharp/Targetting/HumanShotSelector.cs b/77_Salvo/csharp/Targetting/HumanShotSelector.cs index 6a50330a9..40812926f 100644 --- a/77_Salvo/csharp/Targetting/HumanShotSelector.cs +++ b/77_Salvo/csharp/Targetting/HumanShotSelector.cs @@ -2,23 +2,26 @@ namespace Salvo.Targetting; internal class HumanShotSelector : ShotSelector { - public HumanShotSelector(Grid source, Grid target) + private readonly IReadWrite _io; + + internal HumanShotSelector(Grid source, Grid target, IReadWrite io) : base(source, target) { + _io = io; } - public IEnumerable GetShots(IReadWrite io) + internal override IEnumerable GetShots() { - var shots = new Position[GetShotCount()]; + var shots = new Position[NumberOfShots()]; for (var i = 0; i < shots.Length; i++) { while (true) { - var position = io.ReadValidPosition(); + var position = _io.ReadValidPosition(); if (Target.WasTargetedAt(position, out var turnTargeted)) { - io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {turnTargeted}"); + _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {turnTargeted}"); continue; } shots[i] = position; diff --git a/77_Salvo/csharp/Targetting/SearchPattern.cs b/77_Salvo/csharp/Targetting/SearchPattern.cs new file mode 100644 index 000000000..ac2071c8f --- /dev/null +++ b/77_Salvo/csharp/Targetting/SearchPattern.cs @@ -0,0 +1,22 @@ +using System.Collections.Immutable; + +namespace Salvo.Targetting; + +internal class SearchPattern +{ + private static readonly ImmutableArray _offsets = + ImmutableArray.Create(new(1, 1), new(-1, 1), new(1, -3), new(1, 1), new(0, 2), new(-1, 1)); + + private int _nextIndex; + + internal bool TryGetOffset(out Offset offset) + { + offset = default; + if (_nextIndex >= _offsets.Length) { return false; } + + offset = _offsets[_nextIndex++]; + return true; + } + + internal void Reset() => _nextIndex = 0; +} \ No newline at end of file diff --git a/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs b/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs new file mode 100644 index 000000000..4e3fcafbf --- /dev/null +++ b/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs @@ -0,0 +1,54 @@ +namespace Salvo.Targetting; + +internal class SearchPatternShotSelector : ShotSelector +{ + private const int MaxSearchPatternAttempts = 100; + private readonly IRandom _random; + private readonly SearchPattern _searchPattern = new(); + private readonly List _shots = new(); + + internal SearchPatternShotSelector(Grid source, Grid target, IRandom random) + : base(source, target) + { + _random = random; + } + + internal override IEnumerable GetShots() + { + while(_shots.Count < NumberOfShots) + { + var (seed, _) = _random.NextShipPosition(); + SearchFrom(seed); + } + return _shots; + } + + private void SearchFrom(Position candidateShot) + { + var attemptsLeft = MaxSearchPatternAttempts; + while (true) + { + _searchPattern.Reset(); + if (attemptsLeft-- == 0) { return; } + candidateShot = candidateShot.BringIntoRange(_random); + if (FindValidShots(candidateShot)) { return; } + } + } + + private bool FindValidShots(Position candidateShot) + { + while (true) + { + if (IsValidShot(candidateShot)) + { + _shots.Add(candidateShot); + if (_shots.Count == NumberOfShots) { return true; } + } + if (!_searchPattern.TryGetOffset(out var offset)) { return false; } + candidateShot += offset; + } + } + + private bool IsValidShot(Position candidate) + => candidate.IsInRange && !Target.WasTargetedAt(candidate, out _) && !_shots.Contains(candidate); +} \ No newline at end of file diff --git a/77_Salvo/csharp/Targetting/ShotSelector.cs b/77_Salvo/csharp/Targetting/ShotSelector.cs index fae30f313..5aaa4753b 100644 --- a/77_Salvo/csharp/Targetting/ShotSelector.cs +++ b/77_Salvo/csharp/Targetting/ShotSelector.cs @@ -11,5 +11,7 @@ internal ShotSelector(Grid source, Grid target) protected Grid Source { get; } protected Grid Target { get; } - public int GetShotCount() => Source.Ships.Sum(s => s.Shots); + internal int NumberOfShots => Source.Ships.Sum(s => s.Shots); + + internal abstract IEnumerable GetShots(); } From e0791fa39576832b86b2d1775cf22c2007ce5b33 Mon Sep 17 00:00:00 2001 From: kbrannen Date: Sun, 23 Apr 2023 13:50:49 -0500 Subject: [PATCH 113/377] added 14_bowling for perl --- 14_Bowling/perl/README.md | 19 +++ 14_Bowling/perl/bowling.pl | 254 +++++++++++++++++++++++++++++++++++++ 2 files changed, 273 insertions(+) create mode 100755 14_Bowling/perl/bowling.pl diff --git a/14_Bowling/perl/README.md b/14_Bowling/perl/README.md index e69c8b819..9e030cb05 100644 --- a/14_Bowling/perl/README.md +++ b/14_Bowling/perl/README.md @@ -1,3 +1,22 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +###Bowling program in Perl + +Run normally, this is a fairly faithful translation of the Basic game. +The only real differences are a few trivial fix-ups on the prints to make it +look better, and the player/frame/ball line was put before the "get the ball +going" line to make it more obvious who's turn it is. + +However, if you run it with "-a" on the command line, it will go into +"advanced" mode, which means that "." is used to show pin down and "!" for +pin up, current running scores are shown at the end of each frame, and the +scoring also looks more normal at the end. This is all done because I think it +looks better and I wanted to see a score. Having a flag says you can play +whichever version of the game you like. + +Note, the original code doesn't do the 10th frame correctly, in that it will +never do more than 2 balls, so the best score you can get is a 290. +This is true in both modes. That being said, it will always give you a mediocre +game; I don't think I've ever seen a score over 140. diff --git a/14_Bowling/perl/bowling.pl b/14_Bowling/perl/bowling.pl new file mode 100755 index 000000000..1a00cd6ba --- /dev/null +++ b/14_Bowling/perl/bowling.pl @@ -0,0 +1,254 @@ +#!/usr/bin/perl + +# Bowling program in Perl +# Run normally, this is a fairly faithful translation of the Basic game. +# The only real differences are a few trivial fix-ups on the prints to make it +# look better, and the player/frame/ball line was put before the "get the ball +# going" line to make it more obvious who's turn it is. +# +# However, if you run it with "-a" on the command line, it will go into +# 'advanced' mode, which means that "." is used to show pin down and "!" for +# pin up, current running scores are shown at the end of each frame, and the +# scoring also looks more normal at the end. This is all done because I think it +# looks better and I wanted to see a score. Having a flag says you can play +# whichever version of the game you like. +# +# Note, the original code doesn't do the 10th frame correctly, in that it will +# never do more than 2 balls, so the best score you can get is a 290. +# This is true in both modes. That being said, it will always give you a mediocre game. +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +print "\n"; +print " " x 34, "BASKETBALL\n"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; + +# globals +my @C; # pin position matraix? +my @Scores; # scores: [player num][frame][ball] # ball3 is end-result, ball4 is frame score (advanced mode) +my $Answer; # get answers +my $Num_players; # number of players +my $Advanced = 0; # flag, 1 to use advanced code, 0 for original code +my $char_down = '0'; # char to show pin is down +my $char_up = '+'; # char to show pin is standing + +if ($ARGV[0] && $ARGV[0] eq "-a") +{ + shift; + $Advanced = 1; + $char_down = '.'; + $char_up = '!'; +} + +print "WELCOME TO THE ALLEY\n"; +print "BRING YOUR FRIENDS\n"; +print "OKAY LET'S FIRST GET ACQUAINTED\n\n"; +print "SEE THE INSTRUCTIONS (Y/N): "; +chomp($Answer = uc(<>)); +if ($Answer eq "Y") +{ + print "THE GAME OF BOWLING TAKES MIND AND SKILL. DURING THE GAME\n"; + print "THE COMPUTER WILL KEEP SCORE.YOU MAY COMPETE WITH\n"; + print "OTHER PLAYERS[UP TO FOUR]. YOU WILL BE PLAYING TEN FRAMES\n"; + print "ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE\n"; + print "PIN IS STANDING. AFTER THE GAME THE COMPUTER WILL SHOW YOUR SCORES.\n"; +} + +do { + print "FIRST OF ALL...HOW MANY ARE PLAYING (1-4): "; + $Num_players = int(<>); +} while ($Num_players < 1 || $Num_players > 4); + +print "\nVERY GOOD...\n"; + +while (1) +{ + # reset all scores + for my $p (1 .. $Num_players) # players + { + for my $f (1 .. 10) # frames + { + for my $b (1 .. 3) # balls + { + $Scores[$p][$f][$b] = 0; + } + } + } + + # play the game + for my $frame (1 .. 10) # frame + { + for my $curr_player (1 .. $Num_players) # player + { + my $last_pins=0; # pins down for last ball + my $ball=1; # ball number, 1 or 2 + my $end_result=0; # result at end of turn: 3=strike, 2=spare, 1=pins-left + for my $i (1 .. 15) { $C[$i] = 0 } + + while (1) # another ball + { + # ARK BALL GENERATOR USING MOD '15' SYSTEM + my $K=0; + my $curr_pins=0; # pins down for this ball + for my $i (1 .. 20) + { + my $x = int(rand(1) * 100); + my $j; + for ($j=1 ; $j <= 10 ; $j++) + { + last if ($x < 15 * $j); + } + $C[15 * $j - $x] = 1; + } + + # ARK PIN DIAGRAM + print "PLAYER: $curr_player FRAME: $frame BALL: $ball\n"; + print "PRESS ENTER TO GET THE BALL GOING."; + $Answer = <>; # not used, just need an enter + for my $i (0 .. 3) + { + print "\n"; + print " " x $i; # avoid the TAB(), just shift each row over for the triangle + for my $j (1 .. 4 - $i) + { + $K++; + print ($C[$K] == 1 ? " $char_down" : " $char_up"); + } + } + print "\n"; + + # ARK ROLL ANALYSIS + for my $i (1 .. 10) + { + $curr_pins += $C[$i]; + } + if ($curr_pins - $last_pins == 0) + { + print "GUTTER!!\n"; + } + if ($ball == 1 && $curr_pins == 10) + { + print "STRIKE!!!!!\a\a\a\a\n"; # \a is for bell + $end_result = 3; + } + elsif ($ball == 2 && $curr_pins == 10) + { + print "SPARE!!!!\n"; + $end_result = 2; + } + elsif ($ball == 2 && $curr_pins < 10) + { + if ($Advanced) { print 10 - $curr_pins, " PENS LEFT!!!\n"; } + else { print "ERROR!!!\n"; } + $end_result = 1; + } + if ($ball == 1 && $curr_pins < 10) + { + print "ROLL YOUR 2ND BALL\n"; + } + print "\n"; + + # ARK STORAGE OF THE SCORES + if ($Advanced) { $Scores[$curr_player][$frame][$ball] = $curr_pins - $last_pins; } + else { $Scores[$curr_player][$frame][$ball] = $curr_pins; } + if ($ball == 1) + { + $ball = 2; + $last_pins = $curr_pins; + + if ($end_result == 3) # strike, no more rolls, goto last + { + $Scores[$curr_player][$frame][$ball] = $curr_pins; + } + else + { + $Scores[$curr_player][$frame][$ball] = $curr_pins - $last_pins; + next if ($end_result == 0); # next roll + } + } + last; + } + $Scores[$curr_player][$frame][3] = $end_result; + } # next player + if ($Advanced) + { + print "Scores:\n"; + for my $p (1 .. $Num_players) + { + my $total = calc_score($p); + print "\tPlayer $p: $total\n"; + } + print "\n"; + } + } # next frame + + # end of game, show full scoreboard + show_scoreboard(); + + print "DO YOU WANT ANOTHER GAME (Y/N): "; + chomp($Answer = uc(<>)); + print "\n"; + last if ($Answer ne "Y"); +} +exit(0); + +sub show_scoreboard +{ + print "FRAMES\n"; + for my $i (1 .. 10) + { + print " $i "; + } + print "\n"; + my @results = ( "-", ".", "/", "X" ); + for my $p (1 .. $Num_players) + { + print "Player $p\n" if ($Advanced); + my $ball_max = ($Advanced ? 4 : 3); + for my $b (1 .. $ball_max) + { + for my $f (1 .. 10) + { + if ($b != 3) { print sprintf("%2d ", $Scores[$p][$f][$b]); } + else { print sprintf("%2s ", $results[$Scores[$p][$f][$b]]); } + } + print "\n"; + } + print "\n"; + } +} + +sub calc_score +{ + my $player = shift; + my $total = 0; + for my $frame (1 .. 10) + { + my $score = 0; + if ($frame == 10 || $Scores[$player][$frame][3] == 1) # pins + { + $score = $Scores[$player][$frame][1] + $Scores[$player][$frame][2]; + } + elsif ($Scores[$player][$frame][3] == 2) # spare + { + $score = 10 + $Scores[$player][$frame+1][1]; + } + elsif ($Scores[$player][$frame][3] == 3) # strike + { + $score = 10 + $Scores[$player][$frame+1][1]; + if ($Scores[$player][$frame+1][1] == 10) + { + $score += ($frame < 9 ? $Scores[$player][$frame+2][1] : $Scores[$player][$frame+1][2]); + } + else + { + $score += $Scores[$player][$frame+1][2]; + } + } + $Scores[$player][$frame][4] = $score; + $total += $score; + } + return $total; +} From 35124a2287831019710e726713b92bc65214eb4a Mon Sep 17 00:00:00 2001 From: kbrannen Date: Sun, 23 Apr 2023 15:39:00 -0500 Subject: [PATCH 114/377] added 34_Digits for perl --- 34_Digits/perl/digits.pl | 125 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100755 34_Digits/perl/digits.pl diff --git a/34_Digits/perl/digits.pl b/34_Digits/perl/digits.pl new file mode 100755 index 000000000..2f49bd0e9 --- /dev/null +++ b/34_Digits/perl/digits.pl @@ -0,0 +1,125 @@ +#!/usr/bin/perl + +# Digits program in Perl +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +# globals +my $Answer; + +print "\n"; +print " " x 33, "DIGITS"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; + +print "THIS IS A GAME OF GUESSING.\n"; +print "FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0': "; +chomp($Answer = <>); +if ($Answer == 1) +{ + print "\nPLEASE TAKE A PIECE OF PAPER AND WRITE DOWN\n"; + print "THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.\n"; + print "ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.\n"; + print "I WILL ASK FOR THEN TEN AT A TIME.\n"; + print "I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR\n"; + print "NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,\n"; + print "I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER\n"; + print "THAN THAT. *****\n\n\n"; +} + +my ($A, $B, $C) = (0, 1, 3); +my (@M, @K, @L); # DIM M(26,2),K(2,2),L(8,2) +while (1) +{ + for my $i (0 .. 26) { for my $j (0 .. 2) { $M[$i][$j] = 1; } } + for my $i (0 .. 2) { for my $j (0 .. 2) { $K[$i][$j] = 9; } } + for my $i (0 .. 8) { for my $j (0 .. 2) { $L[$i][$j] = 3; } } + $L[0][0] = $L[4][1] = $L[8][2] = 2; + my $Z = 26; + my $Z1 = 8; + my $Z2 = 2; + my $X = 0; + my @N; + + for my $T (1 .. 3) + { + my $have_input = 0; + while (!$have_input) + { + $have_input = 1; + print "\nTEN NUMBERS, PLEASE: "; + chomp($Answer = <>); + $Answer = "0 " . $Answer; # need to be 1-based, so prepend a throw-away value for [0] + @N = split(/\s+/, $Answer); + for my $i (1 .. 10) + { + if (!defined($N[$i]) || ($N[$i] != 0 && $N[$i] != 1 && $N[$i] != 2)) + { + print "ONLY USE THE DIGITS '0', '1', OR '2'.\n"; + print "LET'S TRY AGAIN."; + $have_input = 0; + last; + } + } + } + + print "\nMY GUESS\tYOUR NO.\tRESULT\tNO. RIGHT\n\n"; + for my $U (1 .. 10) + { + my $num = $N[$U]; + my $S = 0; + my $G; + for my $J (0 .. 2) + { + my $S1 = $A * $K[$Z2][$J] + $B * $L[$Z1][$J] + $C * $M[$Z][$J]; + next if ($S > $S1); + if ($S >= $S1) + { + next if (rand(1) < .5); + } + $S = $S1; + $G = $J; + } # NEXT J + print " $G\t\t$N[$U]\t\t"; + if ($G == $N[$U]) + { + $X++; + print "RIGHT\t$X\n"; + $M[$Z][$num]++; + $L[$Z1][$num]++; + $K[$Z2][$num]++; + $Z -= int($Z / 9) * 9; + $Z = 3 * $Z + $N[$U]; + } + else + { + print "WRONG\t$X\n"; + } + $Z1 = $Z - int($Z / 9) * 9; + $Z2 = $N[$U]; + } # NEXT U + } # NEXT T + + print "\n"; + if ($X == 10) + { + print "I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.\n"; + print "IT'S A TIE GAME.\n"; + } + elsif ($X > 10) + { + print "I GUESSED MORE THAN 1/3, OR $X, OF YOUR NUMBERS.\n"; + print "I WIN.\a\a\a\a\a\a\a\a\a\a" + } + else + { + print "I GUESSED LESS THAN 1/3, OR $X, OF YOUR NUMBERS.\n"; + print "YOU BEAT ME. CONGRATULATIONS *****\n"; + } + + print "\nDO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO): "; + chomp($Answer = <>); + last if ($Answer != 1); +} +print "\nTHANKS FOR THE GAME.\n"; From 4a26fcc95568ad7772297e019da5142b18cfcd8b Mon Sep 17 00:00:00 2001 From: kbrannen Date: Sun, 23 Apr 2023 22:02:16 -0500 Subject: [PATCH 115/377] added 35-flipflop for perl --- 36_Flip_Flop/perl/flipflop.pl | 124 ++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100755 36_Flip_Flop/perl/flipflop.pl diff --git a/36_Flip_Flop/perl/flipflop.pl b/36_Flip_Flop/perl/flipflop.pl new file mode 100755 index 000000000..63e3f84e7 --- /dev/null +++ b/36_Flip_Flop/perl/flipflop.pl @@ -0,0 +1,124 @@ +#!/usr/bin/perl + +# Flip Flop program in Perl +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; +use Math::Trig; + +print "\n"; +print " " x 32, "FLIPFLOP"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; +# *** CREATED BY MICHAEL CASS + +print "THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\n\n"; +print "X X X X X X X X X X\n\n"; +print "TO THIS:\n\n"; +print "O O O O O O O O O O\n\n"; +print "BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE\n"; +print "LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\n"; +print "OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0\n"; +print "(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE \n"; +print "11 (ELEVEN).\n\n"; + +sub initialize +{ + my @a; + print "1 2 3 4 5 6 7 8 9 10\n"; + print "X X X X X X X X X X\n"; + for my $i (0 .. 10) { $a[$i] = "X"; } # make sure [0] has a value just in case + return @a; +} + +while (1) +{ + my $Q = rand(1); + my $C = 0; + print "HERE IS THE STARTING LINE OF X'S.\n\n"; + my @A = initialize(); + + while (1) + { + my $M = 0; + my $N; + while (1) + { + print "\nINPUT THE NUMBER: "; + chomp($N = <>); + if ($N != int($N) || $N < 0 || $N > 11) + { + print "ILLEGAL ENTRY--TRY AGAIN.\n"; + next; + } + last; + } + if ($N == 11) # start a new game + { + print "\n\n"; + last; + } + if ($N == 0) # reset line + { + @A = initialize(); + next; + } + + if ($M != $N) + { + $M = $N; + $A[$N] = ($A[$N] eq "O") ? "X" : "O"; + while ($M == $N) + { + my $R = tan($Q + $N / $Q - $N) - sin($Q / $N) + 336 * sin(8 * $N); + $N = $R - int($R); + $N = int(10 * $N); + if ($A[$N] eq "O") + { + $A[$N] = "X"; + next; + } + $A[$N] = "O"; + last; # GOTO 610 + + $A[$N] = "X"; + } + } + else + { + if ($A[$N] ne "O") { $A[$N] = "O"; } + while ($M == $N) + { + my $R = .592 * (1 / tan($Q / $N + $Q)) / sin( $N * 2 + $Q) - cos($N); + $N = $R - int($R); + $N = int(10 * $N); + if ($A[$N] eq "O") + { + $A[$N] = "X"; + next; + } + $A[$N] = "O"; + last; + } + } + + print "1 2 3 4 5 6 7 8 9 10\n"; + for my $i (1 .. 10) { print "$A[$i] "; } + print "\n"; + $C++; + my $i; + for ($i=1 ; $i <= 10 ; $i++) { + last if ($A[$i] ne "O"); + } + if ($i == 11) + { + if ($C <= 12) { print "VERY GOOD. YOU GUESSED IT IN ONLY $C GUESSES.\n"; } + else { print "TRY HARDER NEXT TIME. IT TOOK YOU $C GUESSES.\n"; } + last; + } + } + print "DO YOU WANT TO TRY ANOTHER PUZZLE (Y/N): "; + $_ = <>; + print "\n"; + last if (m/^n/i); +} From fbd8aa72e1cc1c8ca5241ac13a1b630755573bc7 Mon Sep 17 00:00:00 2001 From: Chuck Jordan Date: Sat, 29 Apr 2023 19:40:42 -0700 Subject: [PATCH 116/377] Add Lua port of 03_Animal --- 03_Animal/lua/Animal.lua | 181 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 03_Animal/lua/Animal.lua diff --git a/03_Animal/lua/Animal.lua b/03_Animal/lua/Animal.lua new file mode 100644 index 000000000..293c53e41 --- /dev/null +++ b/03_Animal/lua/Animal.lua @@ -0,0 +1,181 @@ +-- +-- Animal.lua +-- + +-- maintain a flat table/list of all the known animals +local animals = { + "FISH", + "BIRD" +} + +-- store the questions as a binary tree with each node having a +-- "y" or "n" branch +-- if the node has a member named "a" it's an answer, with an index +-- into the animals list. +-- Otherwise, it's a question that leads to more nodes. +local questionTree = { + q = "DOES IT SWIM", + y = { a = 1 }, + n = { a = 2 } +} + +-- print the given prompt string and then wait for input +-- loops until a non-empty input is given +-- returns the input as an upper-case string +function askPrompt(promptString) + local answered = false + local a + while (not answered) do + print(promptString) + a = io.read() + a = string.upper(a) + if (string.len(a) > 0) then + answered = true + end + end + return a +end + +-- print the given prompt string and then wait for the +-- user to enter a string beginning with "Y" or "N" +function askYesOrNo(promptString) + local a + while ((a ~= "Y") and (a ~= "N")) do + a = askPrompt(promptString) + a = a:sub(1,1) + end + return a +end + +-- prints the introductory text from the original BASIC program +function printIntro() + print(string.format("%32s", " ") .. "ANIMAL") + print(string.format("%15s", " ") .. "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() + print("PLAY 'GUESS THE ANIMAL'") + print("THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.") + print() +end + +-- prints the animals known in the source list +function listKnownAnimals() + print() + print("ANIMALS I ALREADY KNOW ARE:") + + local x + local item + for x = 1,#animals do + -- use string.format to space each animal in a 12-character-wide "cell" + item = string.format("%-12s", animals[x]) + + -- io.write() works like print(), but doesn't automatically add a carriage return/newline + io.write(item) + + -- every fifth item, start a new line + if ((x % 5) == 0) then + io.write("\n") + end + end + + print() + print() +end + +-- Prompts the user for info about the animal they were thinking of, then +-- uses that to add a new branch to the tree +-- curNode: the node in the tree where the computer made a wrong guess +-- branch: the answer the user gave to curNode's question +function addAnimalToTree(curNode, branch) + local newAnimal + local curResponse = curNode[branch] + local guessedIndex = curResponse.a + local guessedAnimal = animals[guessedIndex] + local newQuestion, newAnswer, newIndex + local newNode + + newAnimal = askPrompt("THE ANIMAL YOU WERE THINKING OF WAS A ?") + newQuestion = askPrompt("PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A ".. + tostring(newAnimal).." FROM A "..tostring(guessedAnimal)) + newAnswer = askYesOrNo("FOR A "..tostring(newAnimal).." THE ANSWER WOULD BE?") + + -- add the new animal to the master list at the end, and + -- save off its index in the list + table.insert(animals, newAnimal) + newIndex = #animals + + -- create a new node for the question we just learned + newNode = {} + newNode.q = newQuestion + if (newAnswer == "Y") then + newNode.y = { a = newIndex } + newNode.n = { a = guessedIndex } + else + newNode.y = { a = guessedIndex } + newNode.n = { a = newIndex } + end + + -- replace the previous answer with our new node + curNode[branch] = newNode +end + +-- Starts at the root of the question tree and asks questions about +-- the user's animal until the computer hits an "a" answer node and tries +-- to make a guess +function askAboutAnimal() + local curNode = questionTree + local finished = false + local response, responseIndex + local nextNode, animalName + while (not finished) do + response = askYesOrNo(curNode.q .. "?") + + -- convert the response "Y" or "N" to the lowercase "y" or "n" that we use to name our branches + branch = string.lower(response) + nextNode = curNode[branch] + + -- is the next node an answer node, or another question? + if (nextNode.a ~= nil) then + -- it's an answer, so make a guess + animalName = animals[nextNode.a] + response = askYesOrNo("IS IT A "..tostring(animalName).."?") + if (response == "Y") then + -- we got the correct answer, so prompt for a new animal + print() + print("WHY NOT TRY ANOTHER ANIMAL?") + else + -- incorrect answer, so add a new entry at this point in the tree + addAnimalToTree(curNode, branch) + end + + -- whether we were right or wrong, we're finished with this round + finished = true + else + -- it's another question, so advance down the tree + curNode = nextNode + end + end +end + +-- MAIN CONTROL SECTION + +printIntro() + +-- loop forever until the player requests an exit by entering a blank line +local exitRequested = false +local answer + +while (not exitRequested) do + print("ARE YOU THINKING OF AN ANIMAL?") + answer = io.read() + answer = string.upper(answer) + + if (string.len(answer) == 0) then + exitRequested = true + elseif (answer:sub(1,4) == "LIST") then + listKnownAnimals() + elseif (answer:sub(1,1) == "Y") then + askAboutAnimal() + end +end From edb3acd3edf24eb4cee7c2008c2308e9d2c3767f Mon Sep 17 00:00:00 2001 From: kbrannen Date: Sat, 6 May 2023 02:42:07 -0500 Subject: [PATCH 117/377] added 38-furtrader for perl --- 38_Fur_Trader/perl/README.md | 2 + 38_Fur_Trader/perl/furtrader.pl | 265 ++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+) create mode 100755 38_Fur_Trader/perl/furtrader.pl diff --git a/38_Fur_Trader/perl/README.md b/38_Fur_Trader/perl/README.md index e69c8b819..c7001be76 100644 --- a/38_Fur_Trader/perl/README.md +++ b/38_Fur_Trader/perl/README.md @@ -1,3 +1,5 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +You can answer yes/no questions in lower case if desired. diff --git a/38_Fur_Trader/perl/furtrader.pl b/38_Fur_Trader/perl/furtrader.pl new file mode 100755 index 000000000..f1e6b01ad --- /dev/null +++ b/38_Fur_Trader/perl/furtrader.pl @@ -0,0 +1,265 @@ +#!/usr/bin/perl + +# Fur Trader program in Perl +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +# globals +my @Pelts = (qw(0 MINK BEAVER ERMINE FOX )); +my $Num_pelts = 4; +my @Quantity; # how many of each fur +my $Money; +my $Max_pelts = 190; +my $Ermine_price; # like we have @Pelts and @Quantity we could have @Prices +my $Beaver_price; # then have 4 constants as index into the arrays to avoid +my $Fox_price; # the magic numbers 1-4, or better have a array of objects (really a hash) +my $Mink_price; # with the 3 keys (name, number, price), but well keep it + # with 4 vars like the basic program did + +print "\n"; +print " " x 31, "FUR TRADER\n"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; + +init(); +while (1) +{ + my $ans = get_yesno(); + last if ($ans ne "YES"); + + $Ermine_price = new_price(.15, 0.95); + $Beaver_price = new_price(.25, 1.00); + + print "\nYOU HAVE \$$Money SAVINGS.\n"; + print "AND $Max_pelts FURS TO BEGIN THE EXPEDITION.\n"; + print "\nYOUR $Max_pelts FURS ARE DISTRIBUTED AMONG THE FOLLOWING\n"; + print "KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.\n"; + reset_furs(); + + my $total = 0; + for my $j ( 1 .. $Num_pelts) + { + print "\nHOW MANY $Pelts[$j] PELTS DO YOU HAVE? "; + chomp(my $ans = <>); + $Quantity[$j] = int($ans); + $total += $Quantity[$j]; + } + if ($total > $Max_pelts) + { + print "\nYOU MAY NOT HAVE THAT MANY FURS.\n"; + print "DO NOT TRY TO CHEAT. I CAN ADD.\n"; + print "YOU MUST START AGAIN.\n"; + init(); + next; + } + + print "\nYOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\n"; + print "OR FORT 3. FORT 1 IS FORT HOCHELAGA (MONTREAL)\n"; + print "AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\n"; + print "FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\n"; + print "PROTECTION OF THE FRENCH ARMY. HOWEVER, YOU MUST\n"; + print "MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\n"; + print "FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\n"; + print "YOU MUST CROSS THROUGH IROQUOIS LAND.\n"; + my $done = 0; + while (!$done) + { + $ans = 0; + while ($ans < 1 || $ans > 3) + { + no warnings; # in case user enters alpha chars, then int() will return 0 with no warnings + print "ANSWER 1, 2, OR 3: "; + $ans = int(<>); + } + # returns 0 if they want to go somewhere else; + # or returns the old basic line number to show what to do + if ($ans == 1) { $done = fort1(); } + elsif ($ans == 2) { $done = fort2(); } + elsif ($ans == 3) { $done = fort3(); } + } + + if ($done == 1410) + { + print "YOUR BEAVER SOLD FOR \$", $Beaver_price * $Quantity[2], "\t"; + } + + if ($done <= 1414) + { + print "YOUR FOX SOLD FOR \$", $Fox_price * $Quantity[4], "\n"; + print "YOUR ERMINE SOLD FOR \$", $Ermine_price * $Quantity[3], "\t"; + print "YOUR MINK SOLD FOR \$", $Mink_price * $Quantity[1], "\n"; + } + + # 1418 is always done + $Money += $Mink_price * $Quantity[1] + $Beaver_price * $Quantity[2] + $Ermine_price * $Quantity[3] + $Fox_price * $Quantity[4]; + print "\nYOU NOW HAVE \$$Money INCLUDING YOUR PREVIOUS SAVINGS\n"; + print "\nDO YOU WANT TO TRADE FURS NEXT YEAR? "; +} +exit(0); + +############################################################### + +sub init +{ + print "YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN\n"; + print "1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\n"; + print "SUPPLIES FOR THE NEXT YEAR. YOU HAVE A CHOICE OF THREE\n"; + print "FORTS AT WHICH YOU MAY TRADE. THE COST OF SUPPLIES\n"; + print "AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\n"; + print "ON THE FORT THAT YOU CHOOSE.\n"; + + $Money = 600; + print "DO YOU WISH TO TRADE FURS?\n"; +} + +sub new_price +{ + my ($base, $factor) = @_; + return int(($base * rand(1) + $factor) * 100 + .5) / 100; +} + +sub supplies_fs +{ + print "SUPPLIES AT FORT STADACONA COST \$125.00.\n"; + print "YOUR TRAVEL EXPENSES TO STADACONA WERE \$15.00.\n"; +} + +sub supplies_ny +{ + print "SUPPLIES AT NEW YORK COST \$80.00.\n"; + print "YOUR TRAVEL EXPENSES TO NEW YORK WERE \$25.00.\n"; +} + +sub reset_furs +{ + for my $j (1 .. $Num_pelts) { $Quantity[$j] = 0; } +} + +sub get_yesno +{ + my $ans; + print "ANSWER YES OR NO: "; + chomp($ans = uc(<>)); + return $ans; +} + +sub trade_elsewhere +{ + print "DO YOU WANT TO TRADE AT ANOTHER FORT? "; + my $ans = get_yesno(); + return $ans; +} + +sub fort1 +{ + print "\nYOU HAVE CHOSEN THE EASIEST ROUTE. HOWEVER, THE FORT\n"; + print "IS FAR FROM ANY SEAPORT. THE VALUE\n"; + print "YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\n"; + print "OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\n"; + my $ans = trade_elsewhere(); + if ($ans eq "YES") { return 0; } + + $Money -= 160; + $Mink_price = new_price(.2, .7 ); + $Ermine_price = new_price(.2, .65); + $Beaver_price = new_price(.2, .75); + $Fox_price = new_price(.2, .8 ); + print "\nSUPPLIES AT FORT HOCHELAGA COST \$150.00.\n"; + print "YOUR TRAVEL EXPENSES TO HOCHELAGA WERE \$10.00.\n"; + return 1410; +} + +sub fort2 +{ + print "\nYOU HAVE CHOSEN A HARD ROUTE. IT IS, IN COMPARSION,\n"; + print "HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\n"; + print "THE ROUTE TO NEW YORK. YOU WILL RECEIVE AN AVERAGE VALUE\n"; + print "FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\n"; + my $ans = trade_elsewhere(); + if ($ans eq "YES") { return 0; } + + $Money -= 140; + print "\n"; + $Mink_price = new_price(.3, .85); + $Ermine_price = new_price(.15, .8); + $Beaver_price = new_price(.2, .9); + my $P = int(10 * rand(1)) + 1; + if ($P <= 2) + { + $Quantity[2] = 0; + print "YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\n"; + print "THE PORTAGE. YOU HAD TO LEAVE THE PELTS, BUT FOUND\n"; + print "THEM STOLEN WHEN YOU RETURNED.\n"; + supplies_fs(); + return 1414; + } + elsif ($P <= 6) + { + print "YOU ARRIVED SAFELY AT FORT STADACONA.\n"; + supplies_fs(); + } + elsif ($P <= 8) + { + reset_furs(); + print "YOUR CANOE UPSET IN THE LACHINE RAPIDS. YOU\n"; + print "LOST ALL YOUR FURS.\n"; + supplies_fs(); + return 1418; + } + elsif ($P <= 10) + { + $Quantity[4] = 0; + print "YOUR FOX PELTS WERE NOT CURED PROPERLY.\n"; + print "NO ONE WILL BUY THEM.\n"; + supplies_fs(); + } + return 1410; +} + +sub fort3 +{ + print "\nYOU HAVE CHOSEN THE MOST DIFFICULT ROUTE. AT\n"; + print "FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\n"; + print "FOR YOUR FURS. THE COST OF YOUR SUPPLIES\n"; + print "WILL BE LOWER THAN AT ALL THE OTHER FORTS.\n"; + my $ans = trade_elsewhere(); + if ($ans eq "YES") { return 0; } + + $Money -= 105; + print "\n"; + $Mink_price = new_price(.15, 1.05); + $Fox_price = new_price(.25, 1.1); + $Fox_price = new_price(.25, 1.1); + my $P = int(10 * rand(1)) + 1; + if ($P <= 2) + { + print "YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\n"; + print "ALL PEOPLE IN YOUR TRADING GROUP WERE\n"; + print "KILLED. THIS ENDS THE GAME.\n"; + exit(0); + } + elsif ($P <= 6) + { + print "YOU WERE LUCKY. YOU ARRIVED SAFELY\n"; + print "AT FORT NEW YORK.\n"; + supplies_ny(); + } + elsif ($P <= 8) + { + reset_furs(); + print "YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\n"; + print "HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\n"; + supplies_ny(); + return 1418; + } + elsif ($P <= 10) + { + $Beaver_price /= 2; + $Mink_price /= 2; + print "YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\n"; + print "YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\n"; + supplies_ny(); + } + return 1410; +} From 405c50e0e7e1594ab9fc01dd434f1c0a077a61d9 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Wed, 10 May 2023 07:54:36 +1000 Subject: [PATCH 118/377] Fix computer targetting errors --- 77_Salvo/csharp/Coordinate.cs | 12 +-- 77_Salvo/csharp/Game.cs | 76 +++++++++++-------- 77_Salvo/csharp/Grid.cs | 6 +- 77_Salvo/csharp/Program.cs | 3 +- 77_Salvo/csharp/Resources/IHit.txt | 2 +- .../csharp/Resources/WhereAreYourShips.txt | 2 +- .../csharp/Targetting/ComputerShotSelector.cs | 5 ++ .../csharp/Targetting/HumanShotSelector.cs | 2 +- .../Targetting/SearchPatternShotSelector.cs | 5 +- 9 files changed, 66 insertions(+), 47 deletions(-) diff --git a/77_Salvo/csharp/Coordinate.cs b/77_Salvo/csharp/Coordinate.cs index 45d149c15..4cd2c4334 100644 --- a/77_Salvo/csharp/Coordinate.cs +++ b/77_Salvo/csharp/Coordinate.cs @@ -2,14 +2,14 @@ namespace Salvo; internal record struct Coordinate(int Value) { - public const int MinValue = 0; - public const int MaxValue = 9; + public const int MinValue = 1; + public const int MaxValue = 10; - public static IEnumerable Range => Enumerable.Range(0, 10).Select(v => new Coordinate(v)); + public static IEnumerable Range => Enumerable.Range(1, 10).Select(v => new Coordinate(v)); public bool IsInRange => Value is >= MinValue and <= MaxValue; - public static Coordinate Create(float value) => new((int)value - 1); + public static Coordinate Create(float value) => new((int)value); public static bool TryCreateValid(float value, out Coordinate coordinate) { @@ -35,11 +35,11 @@ public Coordinate BringIntoRange(IRandom random) _ => this }; - public static implicit operator Coordinate(float value) => new((int)value); + public static implicit operator Coordinate(float value) => Create(value); public static implicit operator int(Coordinate coordinate) => coordinate.Value; public static Coordinate operator +(Coordinate coordinate, int offset) => new(coordinate.Value + offset); public static int operator -(Coordinate a, Coordinate b) => a.Value - b.Value; - public override string ToString() => $" {Value + 1} "; + public override string ToString() => $" {Value} "; } diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 616f0cbc1..c9d537d59 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -56,9 +56,9 @@ internal void Play() } foreach (var shot1 in humanShotSelector.GetShots()) { - if (computerGrid.IsHit(shot1, turnNumber, out var shipName)) + if (computerGrid.IsHit(shot1, turnNumber, out var ship)) { - _io.Write(Strings.YouHit(shipName)); + _io.Write(Strings.YouHit(ship.Name)); } } L2620: if (startResponse == "YES") { goto L2670; } @@ -81,7 +81,7 @@ internal void Play() } temp = computerShotSelector.GetShots().ToArray(); // display shots -L3380: if (seeShotsResponse == "yes") +L3380: if (seeShotsResponse == "YES") { foreach (var shot in temp) { @@ -90,17 +90,17 @@ internal void Play() } foreach (var shot in temp) { - if (!humanGrid.IsHit(shot, turnNumber, out var shipName)) + if (!humanGrid.IsHit(shot, turnNumber, out var ship)) { continue; } - _io.WriteLine(Strings.IHit(shipName)); + _io.Write(Strings.IHit(ship.Name)); L3570: for (var j = 1; j <= 12; j++) { // record hit L3580: if (hitTurnRecord[j] != -1) { continue; } L3590: hitTurnRecord[j]=10+turnNumber; -L3600: hitShipValue[j]=humanGrid[shot]; +L3600: hitShipValue[j]=ship.Value; // look for past hits on same ship L3610: var shipHits=0; L3620: for (var k = 1; k <= 12; k++) @@ -132,51 +132,65 @@ internal void Play() } L3490: goto L1950; L3800: //REM************************USINGEARRAY - var tempGrid = new Grid(); + var tempGrid = Position.All.ToDictionary(x => x, _ => 0); L3860: for (var i = 1; i <= 12; i++) { if (hitTurnRecord[i]<10) { continue; } foreach (var position in Position.All) { - if (humanGrid[position]>=10) + if (humanGrid.WasTargetedAt(position, out _)) { - foreach (var neighbour in position.Neighbours) - { - if (humanGrid[neighbour] == hitTurnRecord[i]) - { - tempGrid[position] += hitTurnRecord[i]-position.Y*(int)(hitShipValue[i]+.5F); - } - } + tempGrid[position]=-10000000; + continue; } - else + + foreach (var neighbour in position.Neighbours) { - tempGrid[position]=-10000000; + if (humanGrid.WasTargetedAt(neighbour, out var turn) && turn == (hitTurnRecord[i] - 10)) + { + tempGrid[position] += hitTurnRecord[i]-position.Y*(int)(hitShipValue[i]+.5F); + } } } } -L4030: for (var i = 1; i <= numberOfShots; i++) +L4030: for (var i = 0; i < numberOfShots; i++) { -L4040: temp[i]=i; +L4040: temp[i]=i+1; } foreach (var position in Position.All) { -L4090: var Q9=1; -L4100: for (var i = 1; i <= numberOfShots; i++) +L4090: var Q9=0; +L4100: for (var i = 0; i < numberOfShots; i++) { -L4110: if (tempGrid[temp[i]]>=tempGrid[temp[Q9]]) { continue; } -L4120: Q9=i; +L4110: if (tempGrid[temp[i]] < tempGrid[temp[Q9]]) + { +L4120: Q9 = i; + } } -L4131: if (position.X>numberOfShots) { goto L4140; } -L4132: if (position.IsOnDiagonal) { goto L4210; } -L4140: if (tempGrid[position] _values = + new(File.ReadAllLines("data.txt").Select(l => float.Parse(l) / 1000000)); + private float _previous; + + public float NextFloat() => _previous = _values.Dequeue(); + + public float PreviousFloat() => _previous; + + public void Reseed(int seed) + { + throw new NotImplementedException(); + } +} + diff --git a/77_Salvo/csharp/Grid.cs b/77_Salvo/csharp/Grid.cs index 85e3f3873..43dd61b4b 100644 --- a/77_Salvo/csharp/Grid.cs +++ b/77_Salvo/csharp/Grid.cs @@ -75,14 +75,12 @@ public float this[Position position] internal bool WasTargetedAt(Position position, out int turnTargeted) => _shots.TryGetValue(position, out turnTargeted); - internal bool IsHit(Position position, int turnNumber, [NotNullWhen(true)] out string? shipName) + internal bool IsHit(Position position, int turnNumber, [NotNullWhen(true)] out Ship? ship) { - shipName = null; _shots[position] = turnNumber; - var ship = _ships.FirstOrDefault(s => s.IsHit(position)); + ship = _ships.FirstOrDefault(s => s.IsHit(position)); if (ship == null) { return false; } - shipName = ship.Name; if (ship.IsDestroyed) { _ships.Remove(ship); } diff --git a/77_Salvo/csharp/Program.cs b/77_Salvo/csharp/Program.cs index 6878fd383..5dde4d052 100644 --- a/77_Salvo/csharp/Program.cs +++ b/77_Salvo/csharp/Program.cs @@ -5,4 +5,5 @@ global using Salvo.Ships; global using static Salvo.Resources.Resource; -new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); +//new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); +new Game(new ConsoleIO(), new DataRandom()).Play(); diff --git a/77_Salvo/csharp/Resources/IHit.txt b/77_Salvo/csharp/Resources/IHit.txt index a3f3dccf3..3b43216cd 100644 --- a/77_Salvo/csharp/Resources/IHit.txt +++ b/77_Salvo/csharp/Resources/IHit.txt @@ -1 +1 @@ -I hot your {0} +I hit your {0} diff --git a/77_Salvo/csharp/Resources/WhereAreYourShips.txt b/77_Salvo/csharp/Resources/WhereAreYourShips.txt index 797c1144a..e8391a465 100644 --- a/77_Salvo/csharp/Resources/WhereAreYourShips.txt +++ b/77_Salvo/csharp/Resources/WhereAreYourShips.txt @@ -1 +1 @@ -Where are your ships? +Where are your ships? \ No newline at end of file diff --git a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs index c8f57d209..c69c36d2a 100644 --- a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs +++ b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs @@ -10,6 +10,11 @@ internal ComputerShotSelector(Grid source, Grid target, bool displayShots) _displayShots = displayShots; } + internal override IEnumerable GetShots() + { + throw new NotImplementedException(); + } + private void DisplayShots(IEnumerable shots, IReadWrite io) { if (_displayShots) diff --git a/77_Salvo/csharp/Targetting/HumanShotSelector.cs b/77_Salvo/csharp/Targetting/HumanShotSelector.cs index 40812926f..b4a0db132 100644 --- a/77_Salvo/csharp/Targetting/HumanShotSelector.cs +++ b/77_Salvo/csharp/Targetting/HumanShotSelector.cs @@ -12,7 +12,7 @@ internal HumanShotSelector(Grid source, Grid target, IReadWrite io) internal override IEnumerable GetShots() { - var shots = new Position[NumberOfShots()]; + var shots = new Position[NumberOfShots]; for (var i = 0; i < shots.Length; i++) { diff --git a/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs b/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs index 4e3fcafbf..329a0a98e 100644 --- a/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs +++ b/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs @@ -15,6 +15,7 @@ internal SearchPatternShotSelector(Grid source, Grid target, IRandom random) internal override IEnumerable GetShots() { + _shots.Clear(); while(_shots.Count < NumberOfShots) { var (seed, _) = _random.NextShipPosition(); @@ -31,11 +32,11 @@ private void SearchFrom(Position candidateShot) _searchPattern.Reset(); if (attemptsLeft-- == 0) { return; } candidateShot = candidateShot.BringIntoRange(_random); - if (FindValidShots(candidateShot)) { return; } + if (FindValidShots(ref candidateShot)) { return; } } } - private bool FindValidShots(Position candidateShot) + private bool FindValidShots(ref Position candidateShot) { while (true) { From 698eff07585d7a227783e875a6d3276fff063f9b Mon Sep 17 00:00:00 2001 From: kbrannen Date: Mon, 15 May 2023 01:11:36 -0500 Subject: [PATCH 119/377] added 96-Target for perl --- 86_Target/perl/target.pl | 107 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 86_Target/perl/target.pl diff --git a/86_Target/perl/target.pl b/86_Target/perl/target.pl new file mode 100644 index 000000000..cb552a39d --- /dev/null +++ b/86_Target/perl/target.pl @@ -0,0 +1,107 @@ +#!/usr/bin/perl + +# Target program in Perl +# Modified so that if the user enters "quit" or "stop" for the input, the program will exit. +# Values can be space and/or comma separated. +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +# globals +my $R = 1; +my $R1 = 57.296; +my $Pi = 3.14159; + +print "\n"; +print " " x 33, "TARGET\n"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; + +print "YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE\n"; +print "AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU\n"; +print "ARE IN A THREE-DIMENSIONAL RANGE. YOU WILL BE TOLD\n"; +print "THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION\n"; +print "OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,\n"; +print "THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z\n"; +print "AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET.\n"; +print "YOU WILL THEN PROCEEED TO SHOOT AT THE TARGET UNTIL IT IS\n"; +print "DESTROYED!\n\n"; +print "GOOD LUCK!!\n\n"; + +while (1) +{ + my $A = rand(1) * 2 * $Pi; + my $B = rand(1) * 2 * $Pi; + my $P1 = 100000 * rand(1) + rand(1); + my $X = sin($B) * cos($A) * $P1; + my $Y = sin($B) * sin($A) * $P1; + my $Z = cos($B) * $P1; + print "RADIANS FROM X AXIS = $A FROM Z AXIS = $B\n"; + print "TARGET SIGHTED: APPROXIMATE COORDINATES: X=$X Y=$Y Z=$Z\n"; + + while (1) + { + my $P3; + $R++; + + if ($R == 1) { $P3 = int($P1 * .05) * 20; } + elsif ($R == 2) { $P3 = int($P1 * .1) * 10; } + elsif ($R == 3) { $P3 = int($P1 * .5) * 2; } + elsif ($R == 4) { $P3 = int($P1); } + else { $P3 = $P1; } + + print " ESTIMATED DISTANCE: $P3\n\n"; + print "INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE: "; + chomp(my $ans = lc(<>)); + exit(0) if ($ans eq "quit" || $ans eq "stop"); + + my ($A1, $B1, $P2) = split(/[,\s]+/, $ans); + print "\n"; + + if ($P2 >= 20) + { + $A1 /= $R1; + $B1 /= $R1; + print "RADIANS FROM X AXIS = $A1 FROM Z AXIS = $B1\n"; + my $X1 = $P2 * sin($B1) * cos($A1); + my $Y1 = $P2 * sin($B1) * sin($A1); + my $Z1 = $P2 * cos($B1); + my $D = (($X1 - $X) ** 2 + ($Y1 - $Y) ** 2 + ($Z1 - $Z) ** 2) ** (0.5); + + if ($D <= 20) + { + print "\n * * * HIT * * * TARGET IS NON-FUNCTIONAL\n"; + print "\nDISTANCE OF EXPLOSION FROM TARGET WAS $D KILOMETERS.\n"; + print "\nMISSION ACCOMPLISHED IN $R SHOTS.\n"; + last; + } + else + { + my $X2 = $X1 - $X; + my $Y2 = $Y1 - $Y; + my $Z2 = $Z1 - $Z; + + if ($X2 < 0) { print "SHOT BEHIND TARGET ", -$X2, " KILOMETERS.\n"; } + else { print "SHOT IN FRONT OF TARGET $X2 KILOMETERS.\n"; } + + if ($Y2 < 0) { print "SHOT TO RIGHT OF TARGET ", -$Y2, " KILOMETERS.\n"; } + else { print "SHOT TO LEFT OF TARGET $Y2 KILOMETERS.\n"; } + + if ($Z2 < 0) { print "SHOT BELOW TARGET ", -$Z2, " KILOMETERS.\n"; } + else { print "SHOT ABOVE TARGET $Z2 KILOMETERS.\n"; } + + print "APPROX POSITION OF EXPLOSION: X=$X1 Y=$Y1 Z=$Z1\n"; + print " DISTANCE FROM TARGET = $D\n\n\n"; + next; + } + } + else + { + print "YOU BLEW YOURSELF UP!!\n"; + last; + } + } + + $R = 0; + print "\n\n\n\n\nNEXT TARGET...\n\n"; +} From 1e5a0454998fedd10d7583937643974f3d2ddbf6 Mon Sep 17 00:00:00 2001 From: kbrannen Date: Mon, 15 May 2023 01:16:01 -0500 Subject: [PATCH 120/377] updated README --- 86_Target/perl/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/86_Target/perl/README.md b/86_Target/perl/README.md index e69c8b819..eca6b9fa7 100644 --- a/86_Target/perl/README.md +++ b/86_Target/perl/README.md @@ -1,3 +1,9 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +Modified so that if the user enters "quit" or "stop" for the input, the program will exit. +This way the user doesn't have to enter Contorl-C to quit. + +Target values can be space and/or comma separated, so "1 2 3" is valid, as is "1,2,3" or even "1, 2, 3". +I believe the original Basic program wanted "1,2,3" or else each on a separate line. From abf052017e6e808c2c260c680ce0613a99fc2866 Mon Sep 17 00:00:00 2001 From: kbrannen Date: Mon, 15 May 2023 12:16:12 -0500 Subject: [PATCH 121/377] added 42-gunner for perl --- 42_Gunner/perl/gunner.pl | 81 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100755 42_Gunner/perl/gunner.pl diff --git a/42_Gunner/perl/gunner.pl b/42_Gunner/perl/gunner.pl new file mode 100755 index 000000000..9df20deb4 --- /dev/null +++ b/42_Gunner/perl/gunner.pl @@ -0,0 +1,81 @@ +#!/usr/bin/perl + +# Gunner program in Perl +# Required extensive restructuring to remove all of the GOTO's. +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +# globals +my $Max_range = int(40000*rand(1)+20000); +my $Total_shots = 0; +my $Games = 0; + +print "\n"; +print " " x 30, "GUNNER\n"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; + +print "YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN\n"; +print "CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE\n"; +print "WILL PLACE A PROJECTILE ON TARGET. A HIT WITHIN 100 YARDS\n"; +print "OF THE TARGET WILL DESTROY IT.\n\n"; +print "MAXIMUM RANGE OF YOUR GUN IS $Max_range YARDS.\n\n"; + +GAME: while (1) +{ + my $target_dist = int($Max_range * (.1 + .8 * rand(1))); + my $shots = 0; + print "DISTANCE TO THE TARGET IS $target_dist YARDS.\n\n"; + while (1) + { + my $elevation = get_elevation(); # in degrees + $shots++; + my $dist = int($target_dist - ($Max_range * sin(2 * $elevation / 57.3))); + if (abs($dist) < 100) + { + print "*** TARGET DESTROYED *** $shots ROUNDS OF AMMUNITION EXPENDED.\n"; + $Total_shots += $shots; + if ($Games++ == 4) + { + print "\n\nTOTAL ROUNDS EXPENDED WERE: $Total_shots\n"; + if ($Total_shots > 18) { print "BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\n"; } + else { print "NICE SHOOTING !!\n"; } + last; + } + print "\nTHE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...\n"; + next GAME; + } + if ($dist > 100) { print "SHORT OF TARGET BY ", abs($dist)," YARDS.\n"; } + else { print "OVER TARGET BY ", abs($dist), " YARDS.\n"; } + + if ($shots >= 5) + { + print "\nBOOM !!!! YOU HAVE JUST BEEN DESTROYED BY THE ENEMY.\n\n\n\n"; + print "BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\n"; + last; + } + } + + print "\nTRY AGAIN (Y OR N): "; + chomp(my $ans=uc(<>)); + if ($ans ne "Y") { last; } + else { $Games = 0; $Total_shots = 0; } +} + +print "\nOK. RETURN TO BASE CAMP.\n"; + +#################################### + +sub get_elevation +{ + my $elevation; + while (1) + { + print "\nELEVATION: "; + chomp($elevation = <>); + if ($elevation > 89) { print "MAXIMUM ELEVATION IS 89 DEGREES.\n"; } + elsif ($elevation < 1) { print "MINIMUM ELEVATION IS ONE DEGREE.\n"; } + else { return $elevation; } + } +} From 6e01ee5b6a3258c5abb244433176ea0e8b98ab0c Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Tue, 16 May 2023 08:05:39 +1000 Subject: [PATCH 122/377] Simplify hit recording --- 77_Salvo/csharp/Game.cs | 40 +++++++++++++--------------------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index c9d537d59..978701cb5 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -95,42 +95,28 @@ internal void Play() continue; } _io.Write(Strings.IHit(ship.Name)); -L3570: for (var j = 1; j <= 12; j++) + for (var j = 1; j <= 12; j++) { - // record hit -L3580: if (hitTurnRecord[j] != -1) { continue; } -L3590: hitTurnRecord[j]=10+turnNumber; -L3600: hitShipValue[j]=ship.Value; - // look for past hits on same ship -L3610: var shipHits=0; -L3620: for (var k = 1; k <= 12; k++) + if (hitTurnRecord[j] == -1) { -L3630: if (hitShipValue[k] != hitShipValue[j]) { continue; } -L3640: shipHits++; + hitTurnRecord[j]=10+turnNumber; + hitShipValue[j]=ship.Value; + break; } - // if ship is not sunk -L3660: if (shipHits != (int)(hitShipValue[j]+.5F)+1+(int)(hitShipValue[j]+.5F)/3) { goto L3470; } - // otherwise, remove ship hit records -L3670: for (var k = 1; k <= 12; k++) + } + if (ship.IsDestroyed) + { + for (var k = 1; k <= 12; k++) { -L3680: if (hitShipValue[k] == hitShipValue[j]) + if (hitShipValue[k] == ship.Value) { -L3700: hitShipValue[k] = hitTurnRecord[k] = -1; + hitShipValue[k] = hitTurnRecord[k] = -1; } } -L3720: goto L3470; - } - // we shouldn't get here -L3740: _io.WriteLine("PROGRAM ABORT:"); -L3750: for (var j = 1; j <= 12; j++) - { -L3760: _io.WriteLine($"{nameof(hitTurnRecord)}( {j} ) = {hitTurnRecord[j]}"); -L3770: _io.WriteLine($"{nameof(hitShipValue)}( {j} ) = {hitShipValue[j]}"); } - return; -L3470: humanGrid[shot]=10+turnNumber; + humanGrid[shot]=10+turnNumber; } -L3490: goto L1950; + goto L1950; L3800: //REM************************USINGEARRAY var tempGrid = Position.All.ToDictionary(x => x, _ => 0); L3860: for (var i = 1; i <= 12; i++) From 30360f278446d0ab2e7f99ec3216fe8a3d3d0d4e Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Tue, 16 May 2023 17:45:48 +1000 Subject: [PATCH 123/377] Improve computer shot tracking/selection --- 77_Salvo/csharp/Game.cs | 41 +++++++---------------------- 77_Salvo/csharp/Grid.cs | 12 --------- 77_Salvo/csharp/Ships/Battleship.cs | 1 - 77_Salvo/csharp/Ships/Cruiser.cs | 1 - 77_Salvo/csharp/Ships/Destroyer.cs | 1 - 77_Salvo/csharp/Ships/Ship.cs | 3 +-- 6 files changed, 10 insertions(+), 49 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 978701cb5..33d750dfe 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -17,15 +17,9 @@ internal void Play() { _io.Write(Streams.Title); - var hitTurnRecord = new int[13]; + var hitRecords = new List<(int Turn, Ship Ship)>(); var temp = new Position[13]; - var hitShipValue = new float[13]; - for (var i = 1; i <= 12; i++) - { - hitTurnRecord[i] = -1; - hitShipValue[i] = -1; - } var computerGrid = new Grid(_random); var humanGrid = new Grid(_io); var humanShotSelector = new HumanShotSelector(humanGrid, computerGrid, _io); @@ -74,11 +68,7 @@ internal void Play() L2890: _io.Write(Streams.YouWon); L2900: return; -L2960: for (var i = 1; i <= 12; i++) - { - // if damaged ships -L2970: if (hitShipValue[i]>0) { goto L3800; } - } +L2960: if (humanGrid.Ships.Any(s => s.IsDamaged)) { goto L3800; } temp = computerShotSelector.GetShots().ToArray(); // display shots L3380: if (seeShotsResponse == "YES") @@ -95,33 +85,20 @@ internal void Play() continue; } _io.Write(Strings.IHit(ship.Name)); - for (var j = 1; j <= 12; j++) + if (ship.IsDestroyed) { - if (hitTurnRecord[j] == -1) - { - hitTurnRecord[j]=10+turnNumber; - hitShipValue[j]=ship.Value; - break; - } + hitRecords = hitRecords.Where(hr => hr.Ship != ship).ToList(); } - if (ship.IsDestroyed) + else { - for (var k = 1; k <= 12; k++) - { - if (hitShipValue[k] == ship.Value) - { - hitShipValue[k] = hitTurnRecord[k] = -1; - } - } + hitRecords.Add((turnNumber, ship)); } - humanGrid[shot]=10+turnNumber; } goto L1950; L3800: //REM************************USINGEARRAY var tempGrid = Position.All.ToDictionary(x => x, _ => 0); -L3860: for (var i = 1; i <= 12; i++) +L3860: foreach (var (hitTurn, ship) in hitRecords) { - if (hitTurnRecord[i]<10) { continue; } foreach (var position in Position.All) { if (humanGrid.WasTargetedAt(position, out _)) @@ -132,9 +109,9 @@ internal void Play() foreach (var neighbour in position.Neighbours) { - if (humanGrid.WasTargetedAt(neighbour, out var turn) && turn == (hitTurnRecord[i] - 10)) + if (humanGrid.WasTargetedAt(neighbour, out var turn) && turn == hitTurn) { - tempGrid[position] += hitTurnRecord[i]-position.Y*(int)(hitShipValue[i]+.5F); + tempGrid[position] += hitTurn + 10 - position.Y * ship.Shots; } } } diff --git a/77_Salvo/csharp/Grid.cs b/77_Salvo/csharp/Grid.cs index 43dd61b4b..0c84d688d 100644 --- a/77_Salvo/csharp/Grid.cs +++ b/77_Salvo/csharp/Grid.cs @@ -57,18 +57,6 @@ bool TryPositionShip(Func shipFactory) } } - public float this[Position position] - { - get => _shots.TryGetValue(position, out var value) - ? value + 10 - : _ships.FirstOrDefault(s => s.Positions.Contains(position))?.Value ?? 0; - set - { - _ = _ships.FirstOrDefault(s => s.IsHit(position)); - _shots[position] = (int)value - 10; - } - } - internal int UntriedSquareCount => 100 - _shots.Count; internal IEnumerable Ships => _ships.AsEnumerable(); diff --git a/77_Salvo/csharp/Ships/Battleship.cs b/77_Salvo/csharp/Ships/Battleship.cs index 1e57e59d8..4f864eb6f 100644 --- a/77_Salvo/csharp/Ships/Battleship.cs +++ b/77_Salvo/csharp/Ships/Battleship.cs @@ -14,5 +14,4 @@ internal Battleship(IRandom random) internal override int Shots => 3; internal override int Size => 5; - internal override float Value => 3; } diff --git a/77_Salvo/csharp/Ships/Cruiser.cs b/77_Salvo/csharp/Ships/Cruiser.cs index 33f30e381..d004f24cf 100644 --- a/77_Salvo/csharp/Ships/Cruiser.cs +++ b/77_Salvo/csharp/Ships/Cruiser.cs @@ -14,5 +14,4 @@ internal Cruiser(IRandom random) internal override int Shots => 2; internal override int Size => 3; - internal override float Value => 2; } diff --git a/77_Salvo/csharp/Ships/Destroyer.cs b/77_Salvo/csharp/Ships/Destroyer.cs index 0e2a023bb..6523395d3 100644 --- a/77_Salvo/csharp/Ships/Destroyer.cs +++ b/77_Salvo/csharp/Ships/Destroyer.cs @@ -14,5 +14,4 @@ internal Destroyer(string nameIndex, IRandom random) internal override int Shots => 1; internal override int Size => 2; - internal override float Value => Name.EndsWith("") ? 1 : 0.5F; } diff --git a/77_Salvo/csharp/Ships/Ship.cs b/77_Salvo/csharp/Ships/Ship.cs index 58f311c24..ee204d3f3 100644 --- a/77_Salvo/csharp/Ships/Ship.cs +++ b/77_Salvo/csharp/Ships/Ship.cs @@ -24,8 +24,7 @@ protected Ship(IRandom random, string? nameSuffix = null) internal string Name { get; } internal abstract int Shots { get; } internal abstract int Size { get; } - internal abstract float Value { get; } - internal IEnumerable Positions => _positions; + internal bool IsDamaged => _positions.Count > 0 && _positions.Count < Size; internal bool IsDestroyed => _positions.Count == 0; internal bool IsHit(Position position) => _positions.Remove(position); From e27b5ec6e5018a051e9c1a85c91fd83875da8817 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Thu, 18 May 2023 19:27:56 +1000 Subject: [PATCH 124/377] Move shot selection into ComputerShotSelector --- 77_Salvo/csharp/Game.cs | 66 ++--------------- .../csharp/Targetting/ComputerShotSelector.cs | 21 ++---- .../KnownHitsShotSelectionStrategy.cs | 71 +++++++++++++++++++ .../Targetting/ShotSelectionStrategy.cs | 16 +++++ 4 files changed, 101 insertions(+), 73 deletions(-) create mode 100644 77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs create mode 100644 77_Salvo/csharp/Targetting/ShotSelectionStrategy.cs diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 33d750dfe..95ccef230 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -17,13 +17,13 @@ internal void Play() { _io.Write(Streams.Title); - var hitRecords = new List<(int Turn, Ship Ship)>(); + var damagedShips = new List<(int Turn, Ship Ship)>(); var temp = new Position[13]; var computerGrid = new Grid(_random); var humanGrid = new Grid(_io); var humanShotSelector = new HumanShotSelector(humanGrid, computerGrid, _io); - var computerShotSelector = new SearchPatternShotSelector(computerGrid, humanGrid, _random); + var computerShotSelector = new ComputerShotSelector(computerGrid, humanGrid, _random); var startResponse = _io.ReadString(Prompts.Start); while (startResponse == Strings.WhereAreYourShips) { @@ -64,12 +64,11 @@ internal void Play() L2860: _io.Write(Streams.IHaveMoreShotsThanSquares); L2270: _io.Write(Streams.IWon); return; -L2880: if (numberOfShots != 0) { goto L2960; } +L2880: if (numberOfShots == 0) { goto L2960; } L2890: _io.Write(Streams.YouWon); L2900: return; -L2960: if (humanGrid.Ships.Any(s => s.IsDamaged)) { goto L3800; } - temp = computerShotSelector.GetShots().ToArray(); +L2960: temp = computerShotSelector.GetShots().ToArray(); // display shots L3380: if (seeShotsResponse == "YES") { @@ -80,64 +79,13 @@ internal void Play() } foreach (var shot in temp) { - if (!humanGrid.IsHit(shot, turnNumber, out var ship)) + if (humanGrid.IsHit(shot, turnNumber, out var ship)) { - continue; - } - _io.Write(Strings.IHit(ship.Name)); - if (ship.IsDestroyed) - { - hitRecords = hitRecords.Where(hr => hr.Ship != ship).ToList(); - } - else - { - hitRecords.Add((turnNumber, ship)); + _io.Write(Strings.IHit(ship.Name)); + computerShotSelector.RecordHit(ship, turnNumber); } } goto L1950; -L3800: //REM************************USINGEARRAY - var tempGrid = Position.All.ToDictionary(x => x, _ => 0); -L3860: foreach (var (hitTurn, ship) in hitRecords) - { - foreach (var position in Position.All) - { - if (humanGrid.WasTargetedAt(position, out _)) - { - tempGrid[position]=-10000000; - continue; - } - - foreach (var neighbour in position.Neighbours) - { - if (humanGrid.WasTargetedAt(neighbour, out var turn) && turn == hitTurn) - { - tempGrid[position] += hitTurn + 10 - position.Y * ship.Shots; - } - } - } - } -L4030: for (var i = 0; i < numberOfShots; i++) - { -L4040: temp[i]=i+1; - } - foreach (var position in Position.All) - { -L4090: var Q9=0; -L4100: for (var i = 0; i < numberOfShots; i++) - { -L4110: if (tempGrid[temp[i]] < tempGrid[temp[Q9]]) - { -L4120: Q9 = i; - } - } -L4131: if (position.X <= numberOfShots && position.IsOnDiagonal) { continue; } -L4140: if (tempGrid[position] GetShots() { - throw new NotImplementedException(); + return _knownHitsStrategy.GetShots(NumberOfShots) ?? _searchPatternShotSelector.GetShots(); } - private void DisplayShots(IEnumerable shots, IReadWrite io) - { - if (_displayShots) - { - foreach (var shot in shots) - { - io.WriteLine(shot); - } - } - } + internal void RecordHit(Ship ship, int turn) => _knownHitsStrategy.RecordHit(ship, turn); } diff --git a/77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs b/77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs new file mode 100644 index 000000000..917b232ec --- /dev/null +++ b/77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs @@ -0,0 +1,71 @@ +namespace Salvo.Targetting; + +internal class KnownHitsShotSelectionStrategy : ShotSelectionStrategy +{ + private readonly List<(int Turn, Ship Ship)> _damagedShips = new(); + + internal KnownHitsShotSelectionStrategy(Grid target) + : base(target) + { + } + + internal IEnumerable? GetShots(int numberOfShots) + { + if (!_damagedShips.Any()) { return null; } + + var tempGrid = Position.All.ToDictionary(x => x, _ => 0); + var shots = Enumerable.Range(1, numberOfShots).Select(x => new Position(x, x)).ToArray(); + + foreach (var (hitTurn, ship) in _damagedShips) + { + foreach (var position in Position.All) + { + if (WasSelectedPreviously(position)) + { + tempGrid[position]=-10000000; + continue; + } + + foreach (var neighbour in position.Neighbours) + { + if (WasSelectedPreviously(neighbour, out var turn) && turn == hitTurn) + { + tempGrid[position] += hitTurn + 10 - position.Y * ship.Shots; + } + } + } + } + + foreach (var position in Position.All) + { + var Q9=0; + for (var i = 0; i < numberOfShots; i++) + { + if (tempGrid[shots[i]] < tempGrid[shots[Q9]]) + { + Q9 = i; + } + } + if (position.X <= numberOfShots && position.IsOnDiagonal) { continue; } + if (tempGrid[position] x.Ship == ship); + } + else + { + _damagedShips.Add((turn, ship)); + } + } +} diff --git a/77_Salvo/csharp/Targetting/ShotSelectionStrategy.cs b/77_Salvo/csharp/Targetting/ShotSelectionStrategy.cs new file mode 100644 index 000000000..f98c7b4fd --- /dev/null +++ b/77_Salvo/csharp/Targetting/ShotSelectionStrategy.cs @@ -0,0 +1,16 @@ +namespace Salvo.Targetting; + +internal abstract class ShotSelectionStrategy +{ + private readonly Grid _target; + protected ShotSelectionStrategy(Grid target) + { + _target = target; + } + + protected bool WasSelectedPreviously(Position position) + => _target.WasTargetedAt(position, out _); + + protected bool WasSelectedPreviously(Position position, out int turn) + => _target.WasTargetedAt(position, out turn); +} From 46f98ca01d565fdd2675694c418833e2bf4acf59 Mon Sep 17 00:00:00 2001 From: kbrannen Date: Fri, 19 May 2023 02:11:02 -0500 Subject: [PATCH 125/377] added 56-life2 for perl added a perl version for the game; fixed a bug in the basic code; updated the game's README; updated perl's README. --- 56_Life_for_Two/README.md | 14 ++ 56_Life_for_Two/lifefortwo.bas | 4 +- 56_Life_for_Two/perl/README.md | 18 +++ 56_Life_for_Two/perl/lifefortwo.pl | 215 +++++++++++++++++++++++++++++ 4 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 56_Life_for_Two/perl/lifefortwo.pl diff --git a/56_Life_for_Two/README.md b/56_Life_for_Two/README.md index 3d9063420..e68c8d64a 100644 --- a/56_Life_for_Two/README.md +++ b/56_Life_for_Two/README.md @@ -48,3 +48,17 @@ http://www.vintage-basic.net/games.html #### Porting Notes (please note any difficulties or challenges in porting here) + +Note: The original program has a bug. The instructions say that if both players +enter the same cell that the cell is set to 0 or empty. However, the original +Basic program tells the player "ILLEGAL COORDINATES" and makes another cell be entered, +giving a slightly unfair advantage to the 2nd player. + +The Perl verson of the program fixes the bug and follows the instructions. + +Note: The original code had "GOTO 800" but label 800 didn't exist; it should have gone to label 999. +The Basic program has been fixed. + +Note: The Basic program is written to assume it's being played on a Teletype, i.e. output is printed +on paper. To play on a terminal the input must not be echoed, which can be a challenge to do portably +and without tying the solution to a specific OS. Some versions may tell you how to do this, others might not. diff --git a/56_Life_for_Two/lifefortwo.bas b/56_Life_for_Two/lifefortwo.bas index e970ef6df..4faf1f127 100644 --- a/56_Life_for_Two/lifefortwo.bas +++ b/56_Life_for_Two/lifefortwo.bas @@ -60,8 +60,8 @@ 571 IF M3=0 THEN B=1: GOTO 575 572 IF M2=0 THEN B=2: GOTO 575 573 GOTO 580 -574 PRINT: PRINT "A DRAW":GOTO 800 -575 PRINT: PRINT "PLAYER";B;"IS THE WINNER":GOTO 800 +574 PRINT: PRINT "A DRAW":GOTO 999 +575 PRINT: PRINT "PLAYER";B;"IS THE WINNER":GOTO 999 580 FOR B=1 TO 2: PRINT: PRINT: PRINT "PLAYER";B;: GOSUB 700 581 IF B=99 THEN 560 582 NEXT B diff --git a/56_Life_for_Two/perl/README.md b/56_Life_for_Two/perl/README.md index e69c8b819..7b3b41a3c 100644 --- a/56_Life_for_Two/perl/README.md +++ b/56_Life_for_Two/perl/README.md @@ -1,3 +1,21 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +Note: The original program has a bug (see the README in the above dir). This Perl version fixes it. + +Note: For input, the X value is to the right while the Y value is down. +Therefore, the top right cell is "5,1", not "1,5". + +The original program was made to be played on a Teletype, i.e. a printer on paper. +That allowed the program to "black out" the input line to hide a user's input from his/her +opponent, assuming the opponent was at least looking away. To do the equivalent on a +terminal would require a Perl module that isn't installed by default (i.e. it is not +part of CORE and would also require a C compiler to install), nor do I want to issue a +shell command to "stty" to hide the input because that would restrict the game to Linux/Unix. +This means it would have to be played on the honor system. + +However, if you want to try it, install the module "Term::ReadKey" ("sudo cpan -i Term::ReadKey" +if on Linux/Unix and you have root access). If the code finds that module, it will automatically +use it and hide the input ... and restore echoing input again when the games ends. If the module +is not found, input will be visible. diff --git a/56_Life_for_Two/perl/lifefortwo.pl b/56_Life_for_Two/perl/lifefortwo.pl new file mode 100644 index 000000000..0c50cdef7 --- /dev/null +++ b/56_Life_for_Two/perl/lifefortwo.pl @@ -0,0 +1,215 @@ +#!/usr/bin/perl + +# Life_For_Two program in Perl +# Required extensive restructuring to remove all of the GOTO's. +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +# try to load module to hide input, set RKey to true if found +my $Rkey = eval { require Term::ReadKey } // 0; +END { Term::ReadKey::ReadMode('normal') if ($Rkey); } + +# globals +my @Board; # 2D board +my @X; # ? +my @Y; # ? +my $Player; # 1 or 2 +my $M2 = 0; # ? +my $M3 = 0; # ? + +# add 0 on front to make data 1 based +my @K = (0,3,102,103,120,130,121,112,111,12,21,30,1020,1030,1011,1021,1003,1002,1012); +my @A = (0,-1,0,1,0,0,-1,0,1,-1,-1,1,-1,-1,1,1,1); + +print "\n"; +print " " x 33, "LIFE2\n"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; +print " " x 10, "U.B. LIFE GAME\n"; +for my $j (1 .. 5) { for my $k (1 .. 5) { $Board[$j][$k] = 0; } } + +for (1 .. 2) +{ + $Player = $_; # if we make $Player the loop var, the global isn't set + my $p1 = ($Player == 2) ? 30 : 3; + print "\nPLAYER $Player - 3 LIVE PIECES.\n"; + for (1 .. 3) + { + get_input(); + $Board[$X[$Player]][$Y[$Player]] = $p1 if ($Player != 99); + } +} +print_board(); # print board after initial input + +while (1) +{ + print "\n"; + calc_board(); # calc new positions + print_board(); # print current board after calc + + if ($M2 == 0 && $M3 == 0) + { + print "\nA DRAW\n"; + last; + } + if ($M3 == 0) + { + win(1); + last; + } + if ($M2 == 0) + { + win(2); + last; + } + + for (1 .. 2) + { + $Player = $_; # if we make $Player the loop var, the global isn't set + print "\n\nPLAYER $Player "; + get_input(); + last if ($Player == 99); + } + next if ($Player == 99); + + $Board[$X[1]][$Y[1]] = 100; + $Board[$X[2]][$Y[2]] = 1000; +} +exit(0); + +########################################################### + +sub win +{ + my $p = shift; + print "\nPLAYER $p IS THE WINNER\n"; +} + +sub calc_board +{ + for my $j (1 .. 5) + { + for my $k (1 .. 5) + { + if ($Board[$j][$k] > 99) + { + $Player = $Board[$j][$k] > 999 ? 10 : 1; + for (my $c = 1 ; $c <= 15 ; $c += 2) + { + $Board[$j+$A[$c]][$k+$A[$c+1]] = ($Board[$j+$A[$c]][$k+$A[$c+1]] // 0) + $Player; + } + } + } + } +} + +sub print_board +{ + $M2 = 0; + $M3 = 0; + for my $j (0 .. 6) + { + print "\n"; + for my $k (0 .. 6) + { + if ($j != 0 && $j != 6) + { + if ($k != 0 && $k != 6) + { + print_row($j, $k); + next; + } + if ($j == 6) + { + print "0\n"; + return; + } + print " $j "; + } + else + { + if ($k == 6) + { + print " 0 "; + last; + } + print " $k "; + } + } + } +} + +sub print_row +{ + my ($j, $k) = @_; + + if ($Board[$j][$k] >= 3) + { + my $c; + for $c (1 .. 18) + { + if ($Board[$j][$k] == $K[$c]) + { + if ($c <= 9) + { + $Board[$j][$k] = 100; + $M2++; + print " * "; + } + else + { + $Board[$j][$k] = 1000; + $M3++; + print " # "; + } + return; + } + } + } + $Board[$j][$k] = 0; + print " "; +} + +sub get_input +{ + while (1) + { + print "X,Y\n"; + my $ans; + + if ($Rkey) + { + # code to hide input + Term::ReadKey::ReadMode('noecho'); + $ans = Term::ReadKey::ReadLine(0); + Term::ReadKey::ReadMode('restore'); + print "\n"; # do this since the one entered was hidden + } + else + { + # normal, input visible + chomp($ans = <>); + } + + ($Y[$Player], $X[$Player]) = split(/[,\s]+/, $ans, 2); + if ($X[$Player] > 5 || $X[$Player] < 1 || $Y[$Player] > 5 || $Y[$Player] < 1) + { + print "ILLEGAL COORDS. RETYPE\n"; + next; + } + # this tells you the cell was already taken not zero it out, bug! + #if ($Board[$X[$Player]][$Y[$Player]] != 0) + #{ + # print "ILLEGAL COORDS. RETYPE\n"; + # next; + #} + last; + } + + return if ($Player == 1 || $X[1] != $X[2] || $Y[1] != $Y[2]); + + print "SAME COORD. SET TO 0\n"; + $Board[$X[$Player]+1][$Y[$Player]+1] = 0; + $Player = 99; +} From 728e6ebaf8f1d242ac9e38dd96d22029904cc781 Mon Sep 17 00:00:00 2001 From: kbrannen Date: Sat, 20 May 2023 00:16:22 -0500 Subject: [PATCH 126/377] added 28-combat for perl --- 28_Combat/perl/combat.pl | 202 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100755 28_Combat/perl/combat.pl diff --git a/28_Combat/perl/combat.pl b/28_Combat/perl/combat.pl new file mode 100755 index 000000000..fc44a0e4c --- /dev/null +++ b/28_Combat/perl/combat.pl @@ -0,0 +1,202 @@ +#!/usr/bin/perl + +# Combat program in Perl +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +# globals +my $User_army; +my $User_navy; +my $User_AF; +my $Comp_army = 30000; +my $Comp_navy = 20000; +my $Comp_AF = 22000; +my $Attack_type; +my $Attack_num; + +print "\n"; +print " " x 33, "COMBAT\n"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; + +print "I AM AT WAR WITH YOU.\nWE HAVE 72000 SOLDIERS APIECE.\n\n"; + +do { + print "DISTRIBUTE YOUR FORCES.\n"; + print "\tME\t YOU\n"; + print "ARMY\t$Comp_army\t"; + chomp($User_army = <>); + print "NAVY\t$Comp_navy\t"; + chomp($User_navy = <>); + print "A. F.\t$Comp_AF\t"; + chomp($User_AF = <>); +} while ($User_army + $User_navy + $User_AF > 72000); + +do { + print "YOU ATTACK FIRST. TYPE (1) FOR ARMY; (2) FOR NAVY;\n"; + print "AND (3) FOR AIR FORCE.\n"; + chomp($Attack_num = <>); +} while ($Attack_type < 1 && $Attack_type > 3); +do { + print "HOW MANY MEN\n"; + chomp($Attack_type = <>); +} while ($Attack_type < 0 + || ($Attack_num == 1 && $Attack_type > $User_army) + || ($Attack_num == 2 && $Attack_type > $User_navy) + || ($Attack_num == 3 && $Attack_type > $User_AF)); + +if ($Attack_num == 1) +{ + if ($Attack_type<$User_army/3) + { + print "YOU LOST $Attack_type MEN FROM YOUR ARMY.\n"; + $User_army = int($User_army-$Attack_type); + } + if ($Attack_type<2*$User_army/3) + { + print "YOU LOST ", int($Attack_type/3), " MEN, BUT I LOST ", int(2*$Comp_army/3), "\n"; + $User_army = int($User_army-$Attack_type/3); + $Comp_army = int(2*$Comp_army/3); + } + else + { + s270(); + } +} +elsif ($Attack_num == 2) +{ + if ($Attack_type < $Comp_navy/3) + { + print "YOUR ATTACK WAS STOPPED!\n"; + $User_navy = int($User_navy-$Attack_type); + } + if ($Attack_type < 2*$Comp_navy/3) + { + print "YOU DESTROYED ", int(2*$Comp_navy/3), " OF MY ARMY.\n"; + $Comp_navy = int(2*$Comp_navy/3); + } + else + { + s270(); + } +} +else # $Attack_num == 3 +{ + if ($Attack_type < $User_AF/3) + { + print "YOUR ATTACK WAS WIPED OUT.\n"; + $User_AF = int($User_AF-$Attack_type); + } + if ($Attack_type < 2*$User_AF/3) + { + print "WE HAD A DOGFIGHT. YOU WON - AND FINISHED YOUR MISSION.\n"; + $Comp_army = int(2*$Comp_army/3); + $Comp_navy = int($Comp_navy/3); + $Comp_AF = int($Comp_AF/3); + } + else + { + print "YOU WIPED OUT ONE OF MY ARMY PATROLS, BUT I DESTROYED\n"; + print "TWO NAVY BASES AND BOMBED THREE ARMY BASES.\n"; + $User_army = int($User_army/4); + $User_navy = int($User_navy/3); + $User_AF = int(2*$User_AF/3); + } +} + +print "\n\tYOU\tME\n"; +print "ARMY\t$User_army\t$Comp_army\n"; +print "NAVY\t$User_navy\t$Comp_navy\n"; +print "A. F.\t$User_AF\t$Comp_AF\n"; +do { + print "WHAT IS YOUR NEXT MOVE?\n"; + print "ARMY=1 NAVY=2 AIR FORCE=3\n"; + chomp($Attack_type = <>); +} while ($Attack_type < 1 && $Attack_type > 3); +do { + print "HOW MANY MEN\n"; + chomp($Attack_num = <>); +} while ($Attack_num < 0 + || ($Attack_type == 1 && $Attack_num > $User_army) + || ($Attack_type == 2 && $Attack_num > $User_navy) + || ($Attack_type == 3 && $Attack_num > $User_AF)); + +if ($Attack_num == 1) +{ + if ($Attack_num < $Comp_army/2) + { + print "I WIPED OUT YOUR ATTACK!\n"; + $User_army -= $Attack_num; + } + else + { + print "YOU DESTROYED MY ARMY!\n"; + $Comp_army = 0; + } +} +elsif ($Attack_num == 2) +{ + if ($Attack_num < $Comp_navy/2) + { + print "I SUNK TWO OF YOUR BATTLESHIPS, AND MY AIR FORCE\n"; + print "WIPED OUT YOUR UNGAURDED CAPITOL.\n"; + $User_army /= 4; + $User_navy /= 2; + } + else + { + print "YOUR NAVY SHOT DOWN THREE OF MY XIII PLANES,\n"; + print "AND SUNK THREE BATTLESHIPS.\n"; + $Comp_AF = 2*$Comp_AF/3; + $Comp_navy /= 2; + } +} +else # $Attack_num == 3 +{ + if ($Attack_num > $Comp_AF/2) + { + print "MY NAVY AND AIR FORCE IN A COMBINED ATTACK LEFT\n"; + print "YOUR COUNTRY IN SHAMBLES.\n"; + $User_army /= 3; + $User_navy /= 3; + $User_AF /= 3; + } + else + { + print "ONE OF YOUR PLANES CRASHED INTO MY HOUSE. I AM DEAD.\n"; + print "MY COUNTRY FELL APART.\n"; + $Comp_army = $Comp_navy = $Comp_AF = 0; + } +} + +print "\nFROM THE RESULTS OF BOTH OF YOUR ATTACKS,\n"; +my $total_user = $User_army+$User_navy+$User_AF; +my $total_comp = $Comp_army+$Comp_navy+$Comp_AF; +if ($total_user > 3/2*($total_comp)) +{ + print "YOU WON, OH! SHUCKS!!!!\n"; +} +elsif ($total_user < 2/3*($total_comp)) +{ + print "YOU LOST-I CONQUERED YOUR COUNTRY. IT SERVES YOU\n"; + print "RIGHT FOR PLAYING THIS STUPID GAME!!!\n"; +} +else +{ + print "THE TREATY OF PARIS CONCLUDED THAT WE TAKE OUR\n"; + print "RESPECTIVE COUNTRIES AND LIVE IN PEACE.\n"; +} +print "\n"; +exit(0); + +####################################################### + +sub s270 +{ + print "YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO\n"; + print "OF YOUR AIR FORCE BASES AND 3 ARMY BASES.\n"; + $User_army = int($User_army/3); + $User_AF = int($User_AF/3); + $Comp_navy = int(2*$Comp_navy/3); +} From e02a4ca5da107752ccbe61d0ff4e58197a303868 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Sat, 20 May 2023 17:12:48 +1000 Subject: [PATCH 127/377] Tidy up shot selection --- 77_Salvo/csharp/Game.cs | 18 ++++++------ 77_Salvo/csharp/Grid.cs | 14 +--------- .../csharp/Targetting/ComputerShotSelector.cs | 18 ++++++------ .../csharp/Targetting/HumanShotSelector.cs | 8 +++--- .../KnownHitsShotSelectionStrategy.cs | 10 +++---- .../Targetting/SearchPatternShotSelector.cs | 22 +++++++-------- .../Targetting/ShotSelectionStrategy.cs | 13 +++++---- 77_Salvo/csharp/Targetting/ShotSelector.cs | 28 ++++++++++++++----- 8 files changed, 67 insertions(+), 64 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 95ccef230..6c0add129 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -22,8 +22,8 @@ internal void Play() var computerGrid = new Grid(_random); var humanGrid = new Grid(_io); - var humanShotSelector = new HumanShotSelector(humanGrid, computerGrid, _io); - var computerShotSelector = new ComputerShotSelector(computerGrid, humanGrid, _random); + var humanShotSelector = new HumanShotSelector(humanGrid, _io); + var computerShotSelector = new ComputerShotSelector(computerGrid, _random); var startResponse = _io.ReadString(Prompts.Start); while (startResponse == Strings.WhereAreYourShips) { @@ -43,14 +43,14 @@ internal void Play() L1990: var numberOfShots = humanShotSelector.NumberOfShots; L2220: _io.Write(Strings.YouHaveShots(numberOfShots)); if (numberOfShots == 0) { goto L2270; } -L2230: if (numberOfShots > computerGrid.UntriedSquareCount) +L2230: if (humanShotSelector.CanTargetAllRemainingSquares) { _io.WriteLine(Streams.YouHaveMoreShotsThanSquares); L2250: goto L2890; } - foreach (var shot1 in humanShotSelector.GetShots()) + foreach (var shot1 in humanShotSelector.GetShots(turnNumber)) { - if (computerGrid.IsHit(shot1, turnNumber, out var ship)) + if (computerGrid.IsHit(shot1, out var ship)) { _io.Write(Strings.YouHit(ship.Name)); } @@ -60,15 +60,15 @@ internal void Play() L2660: _io.Write(Strings.Turn(turnNumber)); L2670: numberOfShots = computerShotSelector.NumberOfShots; L2840: _io.Write(Strings.IHaveShots(numberOfShots)); -L2850: if (humanGrid.UntriedSquareCount > numberOfShots) { goto L2880; } +L2850: if (!computerShotSelector.CanTargetAllRemainingSquares) { goto L2880; } L2860: _io.Write(Streams.IHaveMoreShotsThanSquares); L2270: _io.Write(Streams.IWon); return; -L2880: if (numberOfShots == 0) { goto L2960; } +L2880: if (numberOfShots > 0) { goto L2960; } L2890: _io.Write(Streams.YouWon); L2900: return; -L2960: temp = computerShotSelector.GetShots().ToArray(); +L2960: temp = computerShotSelector.GetShots(turnNumber).ToArray(); // display shots L3380: if (seeShotsResponse == "YES") { @@ -79,7 +79,7 @@ internal void Play() } foreach (var shot in temp) { - if (humanGrid.IsHit(shot, turnNumber, out var ship)) + if (humanGrid.IsHit(shot, out var ship)) { _io.Write(Strings.IHit(ship.Name)); computerShotSelector.RecordHit(ship, turnNumber); diff --git a/77_Salvo/csharp/Grid.cs b/77_Salvo/csharp/Grid.cs index 0c84d688d..f91ae43a2 100644 --- a/77_Salvo/csharp/Grid.cs +++ b/77_Salvo/csharp/Grid.cs @@ -6,12 +6,6 @@ namespace Salvo; internal class Grid { private readonly List _ships; - private readonly Dictionary _shots = new(); - - internal Grid() - { - _ships = new(); - } internal Grid(IReadWrite io) { @@ -57,16 +51,10 @@ bool TryPositionShip(Func shipFactory) } } - internal int UntriedSquareCount => 100 - _shots.Count; internal IEnumerable Ships => _ships.AsEnumerable(); - internal bool WasTargetedAt(Position position, out int turnTargeted) - => _shots.TryGetValue(position, out turnTargeted); - - internal bool IsHit(Position position, int turnNumber, [NotNullWhen(true)] out Ship? ship) + internal bool IsHit(Position position, [NotNullWhen(true)] out Ship? ship) { - _shots[position] = turnNumber; - ship = _ships.FirstOrDefault(s => s.IsHit(position)); if (ship == null) { return false; } diff --git a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs index 41b27a6d6..5a5214dd4 100644 --- a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs +++ b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs @@ -3,19 +3,19 @@ namespace Salvo.Targetting; internal class ComputerShotSelector : ShotSelector { private readonly KnownHitsShotSelectionStrategy _knownHitsStrategy; - private readonly SearchPatternShotSelector _searchPatternShotSelector; + private readonly SearchPatternShotSelectionStrategy _searchPatternStrategy; - internal ComputerShotSelector(Grid source, Grid target, IRandom random) - : base(source, target) + internal ComputerShotSelector(Grid source, IRandom random) + : base(source) { - _knownHitsStrategy = new KnownHitsShotSelectionStrategy(target); - _searchPatternShotSelector = new SearchPatternShotSelector(source, target, random); + _knownHitsStrategy = new KnownHitsShotSelectionStrategy(this); + _searchPatternStrategy = new SearchPatternShotSelectionStrategy(this, random); } - internal override IEnumerable GetShots() - { - return _knownHitsStrategy.GetShots(NumberOfShots) ?? _searchPatternShotSelector.GetShots(); - } + protected override IEnumerable GetShots() => GetSelectionStrategy().GetShots(NumberOfShots); internal void RecordHit(Ship ship, int turn) => _knownHitsStrategy.RecordHit(ship, turn); + + private ShotSelectionStrategy GetSelectionStrategy() + => _knownHitsStrategy.KnowsOfDamagedShips ? _knownHitsStrategy : _searchPatternStrategy; } diff --git a/77_Salvo/csharp/Targetting/HumanShotSelector.cs b/77_Salvo/csharp/Targetting/HumanShotSelector.cs index b4a0db132..f3e5fba28 100644 --- a/77_Salvo/csharp/Targetting/HumanShotSelector.cs +++ b/77_Salvo/csharp/Targetting/HumanShotSelector.cs @@ -4,13 +4,13 @@ internal class HumanShotSelector : ShotSelector { private readonly IReadWrite _io; - internal HumanShotSelector(Grid source, Grid target, IReadWrite io) - : base(source, target) + internal HumanShotSelector(Grid source, IReadWrite io) + : base(source) { _io = io; } - internal override IEnumerable GetShots() + protected override IEnumerable GetShots() { var shots = new Position[NumberOfShots]; @@ -19,7 +19,7 @@ internal override IEnumerable GetShots() while (true) { var position = _io.ReadValidPosition(); - if (Target.WasTargetedAt(position, out var turnTargeted)) + if (WasSelectedPreviously(position, out var turnTargeted)) { _io.WriteLine($"YOU SHOT THERE BEFORE ON TURN {turnTargeted}"); continue; diff --git a/77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs b/77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs index 917b232ec..5e0b9d2ca 100644 --- a/77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs +++ b/77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs @@ -4,15 +4,15 @@ internal class KnownHitsShotSelectionStrategy : ShotSelectionStrategy { private readonly List<(int Turn, Ship Ship)> _damagedShips = new(); - internal KnownHitsShotSelectionStrategy(Grid target) - : base(target) + internal KnownHitsShotSelectionStrategy(ShotSelector shotSelector) + : base(shotSelector) { } - internal IEnumerable? GetShots(int numberOfShots) - { - if (!_damagedShips.Any()) { return null; } + internal bool KnowsOfDamagedShips => _damagedShips.Any(); + internal override IEnumerable GetShots(int numberOfShots) + { var tempGrid = Position.All.ToDictionary(x => x, _ => 0); var shots = Enumerable.Range(1, numberOfShots).Select(x => new Position(x, x)).ToArray(); diff --git a/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs b/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs index 329a0a98e..1eae88f81 100644 --- a/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs +++ b/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs @@ -1,30 +1,30 @@ namespace Salvo.Targetting; -internal class SearchPatternShotSelector : ShotSelector +internal class SearchPatternShotSelectionStrategy : ShotSelectionStrategy { private const int MaxSearchPatternAttempts = 100; private readonly IRandom _random; private readonly SearchPattern _searchPattern = new(); private readonly List _shots = new(); - internal SearchPatternShotSelector(Grid source, Grid target, IRandom random) - : base(source, target) + internal SearchPatternShotSelectionStrategy(ShotSelector shotSelector, IRandom random) + : base(shotSelector) { _random = random; } - internal override IEnumerable GetShots() + internal override IEnumerable GetShots(int numberOfShots) { _shots.Clear(); - while(_shots.Count < NumberOfShots) + while(_shots.Count < numberOfShots) { var (seed, _) = _random.NextShipPosition(); - SearchFrom(seed); + SearchFrom(numberOfShots, seed); } return _shots; } - private void SearchFrom(Position candidateShot) + private void SearchFrom(int numberOfShots, Position candidateShot) { var attemptsLeft = MaxSearchPatternAttempts; while (true) @@ -32,18 +32,18 @@ private void SearchFrom(Position candidateShot) _searchPattern.Reset(); if (attemptsLeft-- == 0) { return; } candidateShot = candidateShot.BringIntoRange(_random); - if (FindValidShots(ref candidateShot)) { return; } + if (FindValidShots(numberOfShots, ref candidateShot)) { return; } } } - private bool FindValidShots(ref Position candidateShot) + private bool FindValidShots(int numberOfShots, ref Position candidateShot) { while (true) { if (IsValidShot(candidateShot)) { _shots.Add(candidateShot); - if (_shots.Count == NumberOfShots) { return true; } + if (_shots.Count == numberOfShots) { return true; } } if (!_searchPattern.TryGetOffset(out var offset)) { return false; } candidateShot += offset; @@ -51,5 +51,5 @@ private bool FindValidShots(ref Position candidateShot) } private bool IsValidShot(Position candidate) - => candidate.IsInRange && !Target.WasTargetedAt(candidate, out _) && !_shots.Contains(candidate); + => candidate.IsInRange && !WasSelectedPreviously(candidate) && !_shots.Contains(candidate); } \ No newline at end of file diff --git a/77_Salvo/csharp/Targetting/ShotSelectionStrategy.cs b/77_Salvo/csharp/Targetting/ShotSelectionStrategy.cs index f98c7b4fd..b4cf14b16 100644 --- a/77_Salvo/csharp/Targetting/ShotSelectionStrategy.cs +++ b/77_Salvo/csharp/Targetting/ShotSelectionStrategy.cs @@ -2,15 +2,16 @@ namespace Salvo.Targetting; internal abstract class ShotSelectionStrategy { - private readonly Grid _target; - protected ShotSelectionStrategy(Grid target) + private readonly ShotSelector _shotSelector; + protected ShotSelectionStrategy(ShotSelector shotSelector) { - _target = target; + _shotSelector = shotSelector; } - protected bool WasSelectedPreviously(Position position) - => _target.WasTargetedAt(position, out _); + internal abstract IEnumerable GetShots(int numberOfShots); + + protected bool WasSelectedPreviously(Position position) => _shotSelector.WasSelectedPreviously(position); protected bool WasSelectedPreviously(Position position, out int turn) - => _target.WasTargetedAt(position, out turn); + => _shotSelector.WasSelectedPreviously(position, out turn); } diff --git a/77_Salvo/csharp/Targetting/ShotSelector.cs b/77_Salvo/csharp/Targetting/ShotSelector.cs index 5aaa4753b..95a5c4bd4 100644 --- a/77_Salvo/csharp/Targetting/ShotSelector.cs +++ b/77_Salvo/csharp/Targetting/ShotSelector.cs @@ -2,16 +2,30 @@ namespace Salvo.Targetting; internal abstract class ShotSelector { - internal ShotSelector(Grid source, Grid target) + private readonly Grid _source; + private readonly Dictionary _previousShots = new(); + + internal ShotSelector(Grid source) { - Source = source; - Target = target; + _source = source; } - protected Grid Source { get; } - protected Grid Target { get; } + internal int NumberOfShots => _source.Ships.Sum(s => s.Shots); + internal bool CanTargetAllRemainingSquares => NumberOfShots >= 100 - _previousShots.Count; + + internal bool WasSelectedPreviously(Position position) => _previousShots.ContainsKey(position); + + internal bool WasSelectedPreviously(Position position, out int turn) + => _previousShots.TryGetValue(position, out turn); - internal int NumberOfShots => Source.Ships.Sum(s => s.Shots); + internal IEnumerable GetShots(int turnNumber) + { + foreach (var shot in GetShots()) + { + _previousShots.Add(shot, turnNumber); + yield return shot; + } + } - internal abstract IEnumerable GetShots(); + protected abstract IEnumerable GetShots(); } From 345584819531546f9beccc110b0fe02eb44011f5 Mon Sep 17 00:00:00 2001 From: kbrannen Date: Sat, 20 May 2023 02:34:58 -0500 Subject: [PATCH 128/377] added 15-boxing for perl --- 15_Boxing/perl/boxing.pl | 252 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 15_Boxing/perl/boxing.pl diff --git a/15_Boxing/perl/boxing.pl b/15_Boxing/perl/boxing.pl new file mode 100644 index 000000000..5068e58a4 --- /dev/null +++ b/15_Boxing/perl/boxing.pl @@ -0,0 +1,252 @@ +#!/usr/bin/perl + +# Boxing program in Perl +# Required extensive restructuring to remove all of the GOTO's. +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +# globals +my $Opp_won = 0; # num rounds opponent has won +my $You_won = 0; # num rounds you have won +my $Opp_name = ""; # opponent name +my $Your_name = ""; # your name +my $Your_best = 0; # your best punch +my $Your_worst = 0; # your worst punch +my $Opp_best; # opponent best punch +my $Opp_worst; # opponent worst punch +my $Opp_damage; # opponent damage ? +my $Your_damage; # your damage ? + +sub get_punch +{ + my $prompt = shift; + my $p; + while (1) + { + print "$prompt: "; + chomp($p = int(<>)); + last if ($p >= 1 && $p <= 4); + print "DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\n"; + } + return $p; +} + +print "\n"; +print " " x 33, "BOXING\n"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; + +print "BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)\n\n"; +print "WHAT IS YOUR OPPONENT'S NAME: "; +chomp($Opp_name = <>); +print "INPUT YOUR MAN'S NAME: "; +chomp($Your_name = <>); +print "DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\n"; +$Your_best = get_punch("WHAT IS YOUR MANS BEST"); +$Your_worst = get_punch("WHAT IS HIS VULNERABILITY"); + +do { + $Opp_best = int(4*rand(1)+1); + $Opp_worst = int(4*rand(1)+1); +} while ($Opp_best == $Opp_worst); +print "$Opp_name\'S ADVANTAGE IS $Opp_best AND VULNERABILITY IS SECRET.\n\n"; + +for my $R (1 .. 3) # rounds +{ + last if ($Opp_won >= 2 || $You_won >= 2); + $Opp_damage = 0; + $Your_damage = 0; + print "ROUND $R BEGINS...\n"; + for my $R1 (1 .. 7) # 7 events per round? + { + if (int(10*rand(1)+1) <= 5) + { + my $your_punch = get_punch("$Your_name\'S PUNCH"); + $Opp_damage += 2 if ($your_punch == $Your_best); + + if ($your_punch == 1) { punch1(); } + elsif ($your_punch == 2) { punch2(); } + elsif ($your_punch == 3) { punch3(); } + else { punch4(); } + next; + } + + my $Opp_punch = int(4*rand(1)+1); + $Your_damage += 2 if ($Opp_punch == $Opp_best); + + if ($Opp_punch == 1) { opp1(); } + elsif ($Opp_punch == 2) { opp2(); } + elsif ($Opp_punch == 3) { opp3(); } + else { opp4(); } + } + + if ($Opp_damage > $Your_damage) + { + print "\n$Your_name WINS ROUND $R\n\n"; + $You_won++; + } + else + { + print "\n$Opp_name WINS ROUND $R\n\n"; + $Opp_won++; + } +} + +if ($Opp_won >= 2) +{ + done("$Opp_name WINS (NICE GOING, $Opp_name)."); +} + +#else # if ($You_won >= 2) +done("$Your_name AMAZINGLY WINS!!"); + +################################################### + +sub done +{ + my $msg = shift; + print $msg; + print "\n\nAND NOW GOODBYE FROM THE OLYMPIC ARENA.\n\n"; + exit(0); +} + +sub punch1 +{ + # $your_punch == 1, full swing + print "$Your_name SWINGS AND "; + if ($Opp_worst == 4 || int(30*rand(1)+1) < 10) + { + print "HE CONNECTS!\n"; + if ($Opp_damage > 35) + { + done("$Opp_name IS KNOCKED COLD AND $Your_name IS THE WINNER AND CHAMP! "); + } + $Opp_damage += 15; + } + else + { + print "HE MISSES\n"; + print "\n\n" if ($Opp_damage != 1); + } +} + +sub punch2 +{ + # $your_punch == 2, hook + print "$Your_name GIVES THE HOOK... "; + if ($Opp_worst == 2) + { + $Opp_damage += 7; + return; + } + if (int(2*rand(1)+1) == 1) + { + print "BUT IT'S BLOCKED!!!!!!!!!!!!!\n"; + } + else + { + print "CONNECTS...\n"; + $Opp_damage += 7; + } +} + +sub punch3 +{ + # $your_punch == 3, uppercut + print "$Your_name TRIES AN UPPERCUT "; + if ($Opp_worst == 3 || int(100*rand(1)+1) < 51) + { + print "AND HE CONNECTS!\n"; + $Opp_damage += 4; + } + else + { + print "AND IT'S BLOCKED (LUCKY BLOCK!)\n"; + } +} + +sub punch4 +{ + # $your_punch == 4, jab + print "$Your_name JABS AT $Opp_name\'S HEAD "; + if ($Opp_worst == 4 || (int(8*rand(1)+1)) >= 4) + { + $Opp_damage += 3; + print "\n"; + } + else + { + print "IT'S BLOCKED.\n"; + } +} + +sub opp1 +{ + # opp_punch == 1 + print "$Opp_name TAKES A FULL SWING AND "; + if ($Your_worst == 1 || int(60*rand(1)+1) < 30) + { + print " POW!!!!! HE HITS HIM RIGHT IN THE FACE!\n"; + if ($Your_damage > 35) + { + done("$Your_name IS KNOCKED COLD AND $Opp_name IS THE WINNER AND CHAMP!"); + } + $Your_damage += 15; + } + else + { + print " IT'S BLOCKED!\n"; + } +} + +sub opp2 +{ + # opp_punch == 2 + print "$Opp_name GETS $Your_name IN THE JAW (OUCH!)\n"; + $Your_damage += 7; + print "....AND AGAIN!\n"; + $Your_damage += 5; + if ($Your_damage > 35) + { + done("$Your_name IS KNOCKED COLD AND $Opp_name IS THE WINNER AND CHAMP!"); + } + print "\n"; + # 2 continues into opp_punch == 3 + opp3(); +} + +sub opp3() +{ + # opp_punch == 3 + print "$Your_name IS ATTACKED BY AN UPPERCUT (OH,OH)...\n"; + if ($Your_worst != 3 && int(200*rand(1)+1) > 75) + { + print " BLOCKS AND HITS $Opp_name WITH A HOOK.\n"; + $Opp_damage += 5; + } + else + { + print "AND $Opp_name CONNECTS...\n"; + $Your_damage += 8; + } +} + +sub opp4 +{ + # opp_punch == 4 + print "$Opp_name JABS AND "; + if ($Your_worst == 4) + { + $Your_damage += 5; + } + elsif (int(7*rand(1)+1) > 4) + { + print " BLOOD SPILLS !!!\n"; + $Your_damage += 5; + } + else + { + print "IT'S BLOCKED!\n"; + } +} From ce013cfad91705e8a26010a3a8e34a3de0745798 Mon Sep 17 00:00:00 2001 From: kbrannen Date: Sun, 21 May 2023 15:12:41 -0500 Subject: [PATCH 129/377] added checkers for perl --- 23_Checkers/perl/README.md | 6 + 23_Checkers/perl/checkers.pl | 343 +++++++++++++++++++++++++++++++++++ 2 files changed, 349 insertions(+) create mode 100755 23_Checkers/perl/checkers.pl diff --git a/23_Checkers/perl/README.md b/23_Checkers/perl/README.md index e69c8b819..4323cf4ad 100644 --- a/23_Checkers/perl/README.md +++ b/23_Checkers/perl/README.md @@ -1,3 +1,9 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +Note: This version has lines and columns numbers to help you with choosing the cell +to move from and to, so you don't have to continually count. It also puts a "." only for +blank cells you can move to, which I think makes for a more pleasing look and makes +it easier to play. If you want the original behavior, start the program with an arg +of "-o" for the original behavior. diff --git a/23_Checkers/perl/checkers.pl b/23_Checkers/perl/checkers.pl new file mode 100755 index 000000000..9e87f1fe4 --- /dev/null +++ b/23_Checkers/perl/checkers.pl @@ -0,0 +1,343 @@ +#!/usr/bin/perl + +# Boxing program in Perl +# Started with checkers.annotated.bas +# Translated by Kevin Brannen (kbrannen) + +use strict; +use warnings; + +# globals +# +# The current move: (rating, current x, current y, new x, new y) +# 'rating' represents how good the move is; higher is better. +my @r = (-99); # (4); # Start with minimum score +# The board. Pieces are represented by numeric values: +# +# - 0 = empty square +# - -1,-2 = X (-1 for regular piece, -2 for king) +# - 1,2 = O (1 for regular piece, 2 for king) +# +# This program's player ("me") plays X. +my @s; # (7,7) +# chars to print for the board, add 2 to the board value as an index to the char +my @chars = ("X*", "X", ".", "O", "O*"); +my $g = -1; # constant holding -1 +my $winner = ""; +my $upgrade = shift(@ARGV) // ""; +$upgrade = $upgrade eq "-o" ? 0 : 1; + +##### + +print "\n"; +print " " x 32, "CHECKERS\n"; +print " " x 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; + + +print "THIS IS THE GAME OF CHECKERS. THE COMPUTER IS X,\n"; +print "AND YOU ARE O. THE COMPUTER WILL MOVE FIRST.\n"; +print "SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM.\n"; +print "(0,0) IS THE LOWER LEFT CORNER\n"; +print "(0,7) IS THE UPPER LEFT CORNER\n"; +print "(7,0) IS THE LOWER RIGHT CORNER\n"; +print "(7,7) IS THE UPPER RIGHT CORNER\n"; +print "THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER\n"; +print "JUMP. TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\n\n\n"; + +# Initialize the board. Data is 2 length-wise strips repeated. +my @data = (); +for (1 .. 32) { push(@data, (1,0,1,0,0,0,-1,0, 0,1,0,0,0,-1,0,-1)); } +for my $x (0 .. 7) +{ + for my $y (0 .. 7) + { + $s[$x][$y] = shift(@data); + } +} + +# Start of game loop. First, my turn. +while (1) +{ + + # For each square on the board, search for one of my pieces + # and if it can make the best move so far, store that move in 'r' + for my $x (0 .. 7) + { + for my $y (0 .. 7) + { + # Skip if this is empty or an opponent's piece + next if ($s[$x][$y] > -1); + + # If this is one of my ordinary pieces, analyze possible + # forward moves. + if ($s[$x][$y] == -1) + { + for (my $a = -1 ; $a <= 1 ; $a +=2) + { + $b = $g; + find_move($x, $y, $a, $b); + } + } + + # If this is one of my kings, analyze possible forward + # and backward moves. + if ($s[$x][$y] == -2) + { + for (my $a = -1 ; $a <= 1 ; $a += 2) + { + for (my $b = -1 ; $a <= 1 ; $b += 2) { find_move($x, $y, $a, $b); } + } + } + } + } + + + if ($r[0] == -99) # Game is lost if no move could be found. + { + $winner = "you"; + last; + } + + # Print the computer's move. (Note: chr$(30) is an ASCII RS + # (record separator) code; probably no longer relevant.) + print "FROM $r[1],$r[2] TO $r[3],$r[4] "; + $r[0] = -99; + + # Make the computer's move. If the piece finds its way to the + # end of the board, crown it. + LOOP1240: { + if ($r[4] == 0) + { + $s[$r[3]][$r[4]] = -2; + last LOOP1240; + } + $s[$r[3]][$r[4]] = $s[$r[1]][$r[2]]; + $s[$r[1]][$r[2]] = 0; + + # If the piece has jumped 2 squares, it means the computer has + # taken an opponents' piece. + if (abs($r[1] - $r[3]) == 2) + { + $s [($r[1]+$r[3])/2] [($r[2]+$r[4])/2] = 0; # Delete the opponent's piece + + # See if we can jump again. Evaluate all possible moves. + my $x = $r[3]; + my $y = $r[4]; + for (my $a = -2 ; $a <= 2 ; $a += 4) + { + if ($s[$x][$y] == -1) + { + $b = -2; + eval_move($x, $y, $a, $b); + } + if ($s[$x][$y] == -2) + { + for (my $b = -2 ; $b <= 2 ; $b += 4) { eval_move($x, $y, $a, $b); } + } + } + + # If we've found a move, go back and make that one as well + if ($r[0] != -99) + { + print "TO $r[3], $r[4] "; + $r[0] = -99; + next LOOP1240; + } + } + } # LOOP1240 + + # Now, print the board + print "\n\n\n"; + for (my $y = 7 ; $y >= 0 ; $y--) + { + my $line = ""; + $line = "$y|" if ($upgrade); + for my $x (0 .. 7) + { + my $c = $chars[$s[$x][$y] + 2]; + $c = ' ' if ($upgrade && (($y % 2 == 0 && $x % 2 == 1) || ($y % 2 == 1 && $x % 2 == 0))); + $line = tab($line, 5*$x+7, $c); + } + print $line; + print " \n\n"; + } + print " _ _ _ _ _ _ _ _\n" if ($upgrade); + print " 0 1 2 3 4 5 6 7\n" if ($upgrade); + print "\n"; + + # Check if either player is out of pieces. If so, announce the + # winner. + my ($z, $t) = (0, 0); + for my $x (0 .. 7) + { + for my $y (0 .. 7) + { + if ($s[$x][$y] == 1 || $s[$x][$y] == 2) { $z = 1; } + if ($s[$x][$y] == -1 || $s[$x][$y] == -2) { $t = 1; } + } + } + if ($z != 1) { $winner = "comp"; last; } + if ($t != 1) { $winner = "you"; last; } + + # Prompt the player for their move. + ($z, $t) = (0, 0); + my ($x, $y, $e, $h, $a, $b); + do { + print "FROM: "; + chomp(my $ans = <>); + ($e,$h) = split(/[, ]/, $ans); + $x = $e; + $y = $h; + } while ($s[$x][$y] <= 0); + do { + print "TO: "; + chomp(my $ans = <>); + ($a,$b) = split(/[, ]/, $ans); + $x = $a; + $y = $b; + } while (!($s[$x][$y] == 0 && abs($a-$e) <= 2 && abs($a-$e) == abs($b-$h))); + + LOOP1750: { + # Make the move and stop unless it might be a jump. + $s[$a][$b] = $s[$e][$h]; + $s[$e][$h] = 0; + if (abs($e-$a) != 2) { last LOOP1750; } + + # Remove the piece jumped over + $s[($e+$a)/2][($h+$b)/2] = 0; + + # Prompt for another move; -1 means player can't, so I've won. + # Keep prompting until there's a valid move or the player gives + # up. + my ($a1, $b1); + do { + print "+TO "; + chomp(my $ans = <>); + ($a1,$b1) = split(/[, ]/, $ans); + if ($a1 < 0) { last LOOP1750; } + } while ($s[$a1][$b1] != 0 || abs($a1-$a) != 2 || abs($b1-$b) != 2); + + # Update the move variables to correspond to the next jump + $e = $a; + $h = $b; + $a = $a1; + $b = $b1; + } + + # If the player has reached the end of the board, crown this piece + if ($b == 7) { $s[$a][$b] = 2; } + + # And play the next turn. +} + +# Endgame: +print "\n", ($winner eq "you" ? "YOU" : "I"), " WIN\n"; +exit(0); + +########################################### + +# deal with basic's tab() for line positioning +# line = line string we're starting with +# pos = position to start writing +# s = string to write +# returns the resultant string, which might not have been changed +sub tab +{ + my ($line, $pos, $s) = @_; + my $len = length($line); + # if curser is past position, do nothing + if ($len <= $pos) { $line .= " " x ($pos - $len) . $s; } + return $line; +} + +# Analyze a move from (x,y) to (x+a, y+b) and schedule it if it's +# the best candidate so far. +sub find_move +{ + my ($x, $y, $a, $b) = @_; + my $u = $x+$a; + my $v = $y+$b; + + # Done if it's off the board + return if ($u < 0 || $u > 7 || $v < 0 || $ v> 7); + + # Consider the destination if it's empty + eval_jump($x, $y, $u, $v) if ($s[$u][$v] == 0); + + # If it's got an opponent's piece, jump it instead + if ($s[$u][$v] > 0) + { + + # Restore u and v, then return if it's off the board + $u += $a; + $v += $b; + return if ($u < 0 || $v < 0 || $u > 7 || $v > 7); + + # Otherwise, consider u,v + eval_jump($x, $y, $u, $v) if ($s[$u][$v] == 0); + } +} + +# Evaluate jumping (x,y) to (u,v). +# +# Computes a score for the proposed move and if it's higher +# than the best-so-far move, uses that instead by storing it +# and its score in @r. +sub eval_jump +{ + my ($x, $y, $u, $v) = @_; + + # q is the score; it starts at 0 + my $q = 0; + + # +2 if it promotes this piece + $q += 2 if ($v == 0 && $s[$x][$y] == -1); + + # +5 if it takes an opponent's piece + $q += 5 if (abs($y-$v) == 2); + + # -2 if the piece is moving away from the top boundary + $q -= 2 if ($y == 7); + + # +1 for putting the piece against a vertical boundary + $q++ if ($u == 0 || $u == 7); + + for (my $c = -1 ; $c <= 1 ; $c += 2) + { + next if ($u+$c < 0 || $u+$c > 7 || $v+$g < 0); + + # +1 for each adjacent friendly piece + if ($s[$u+$c][$v+$g] < 0) + { + $q++; + next; + } + + # Prevent out-of-bounds testing + next if ($u-$c < 0 || $u-$c > 7 || $v-$g > 7); + + # -2 for each opponent piece that can now take this piece here + $q -= 2 if ($s[$u+$c][$v+$g] > 0 && ($s[$u-$c][$v-$g] == 0 || ($u-$c == $x && $v-$g == $y))); + } + + # Use this move if it's better than the previous best + if ($q > $r[0]) + { + $r[0] = $q; + $r[1] = $x; + $r[2] = $y; + $r[3] = $u; + $r[4] = $v; + } +} + +# If (u,v) is in the bounds, evaluate it as a move using +# the sub at 910, so storing eval in @r. +sub eval_move +{ + my ($x, $y, $a, $b) = @_; + my $u = $x+$a; + my $v = $y+$b; + return if ($u < 0 || $u > 7 || $v < 0 || $v > 7); + eval_jump($x, $y, $u, $v) if ($s[$u][$v] == 0 && $s[$x+$a/2][$y+$b/2] > 0); +} From b45ad8544c3b67c0c5751f1a25436b68fcba41aa Mon Sep 17 00:00:00 2001 From: kbrannen Date: Sun, 21 May 2023 15:14:10 -0500 Subject: [PATCH 130/377] fixed typo --- 23_Checkers/perl/checkers.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/23_Checkers/perl/checkers.pl b/23_Checkers/perl/checkers.pl index 9e87f1fe4..94643f76f 100755 --- a/23_Checkers/perl/checkers.pl +++ b/23_Checkers/perl/checkers.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl -# Boxing program in Perl +# Checkers program in Perl # Started with checkers.annotated.bas # Translated by Kevin Brannen (kbrannen) From 1ae84a67df0bb5d4f92f218160ab43518168824c Mon Sep 17 00:00:00 2001 From: kbrannen Date: Sun, 21 May 2023 15:33:25 -0500 Subject: [PATCH 131/377] cleaned up --- 23_Checkers/perl/checkers.pl | 134 +++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 63 deletions(-) diff --git a/23_Checkers/perl/checkers.pl b/23_Checkers/perl/checkers.pl index 94643f76f..46b8f2d4c 100755 --- a/23_Checkers/perl/checkers.pl +++ b/23_Checkers/perl/checkers.pl @@ -11,7 +11,7 @@ # # The current move: (rating, current x, current y, new x, new y) # 'rating' represents how good the move is; higher is better. -my @r = (-99); # (4); # Start with minimum score +my @ratings = (-99); # (4); # Start with minimum score # The board. Pieces are represented by numeric values: # # - 0 = empty square @@ -19,10 +19,10 @@ # - 1,2 = O (1 for regular piece, 2 for king) # # This program's player ("me") plays X. -my @s; # (7,7) +my @board; # (7,7) # chars to print for the board, add 2 to the board value as an index to the char my @chars = ("X*", "X", ".", "O", "O*"); -my $g = -1; # constant holding -1 +my $neg1 = -1; # constant holding -1 my $winner = ""; my $upgrade = shift(@ARGV) // ""; $upgrade = $upgrade eq "-o" ? 0 : 1; @@ -42,7 +42,8 @@ print "(7,0) IS THE LOWER RIGHT CORNER\n"; print "(7,7) IS THE UPPER RIGHT CORNER\n"; print "THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER\n"; -print "JUMP. TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\n\n\n"; +print "JUMP. TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.\n"; +print "ENTER YOUR MOVE POSITION LIKE '0 0' OR '0,0'.\n\n\n"; # Initialize the board. Data is 2 length-wise strips repeated. my @data = (); @@ -51,7 +52,7 @@ { for my $y (0 .. 7) { - $s[$x][$y] = shift(@data); + $board[$x][$y] = shift(@data); } } @@ -66,22 +67,22 @@ for my $y (0 .. 7) { # Skip if this is empty or an opponent's piece - next if ($s[$x][$y] > -1); + next if ($board[$x][$y] > -1); # If this is one of my ordinary pieces, analyze possible # forward moves. - if ($s[$x][$y] == -1) + if ($board[$x][$y] == -1) { for (my $a = -1 ; $a <= 1 ; $a +=2) { - $b = $g; + $b = $neg1; find_move($x, $y, $a, $b); } } # If this is one of my kings, analyze possible forward # and backward moves. - if ($s[$x][$y] == -2) + if ($board[$x][$y] == -2) { for (my $a = -1 ; $a <= 1 ; $a += 2) { @@ -92,7 +93,7 @@ } - if ($r[0] == -99) # Game is lost if no move could be found. + if ($ratings[0] == -99) # Game is lost if no move could be found. { $winner = "you"; last; @@ -100,47 +101,47 @@ # Print the computer's move. (Note: chr$(30) is an ASCII RS # (record separator) code; probably no longer relevant.) - print "FROM $r[1],$r[2] TO $r[3],$r[4] "; - $r[0] = -99; + print "FROM $ratings[1],$ratings[2] TO $ratings[3],$ratings[4] "; + $ratings[0] = -99; # Make the computer's move. If the piece finds its way to the # end of the board, crown it. LOOP1240: { - if ($r[4] == 0) + if ($ratings[4] == 0) { - $s[$r[3]][$r[4]] = -2; + $board[$ratings[3]][$ratings[4]] = -2; last LOOP1240; } - $s[$r[3]][$r[4]] = $s[$r[1]][$r[2]]; - $s[$r[1]][$r[2]] = 0; + $board[$ratings[3]][$ratings[4]] = $board[$ratings[1]][$ratings[2]]; + $board[$ratings[1]][$ratings[2]] = 0; # If the piece has jumped 2 squares, it means the computer has # taken an opponents' piece. - if (abs($r[1] - $r[3]) == 2) + if (abs($ratings[1] - $ratings[3]) == 2) { - $s [($r[1]+$r[3])/2] [($r[2]+$r[4])/2] = 0; # Delete the opponent's piece + $board [($ratings[1]+$ratings[3])/2] [($ratings[2]+$ratings[4])/2] = 0; # Delete the opponent's piece # See if we can jump again. Evaluate all possible moves. - my $x = $r[3]; - my $y = $r[4]; + my $x = $ratings[3]; + my $y = $ratings[4]; for (my $a = -2 ; $a <= 2 ; $a += 4) { - if ($s[$x][$y] == -1) + if ($board[$x][$y] == -1) { $b = -2; eval_move($x, $y, $a, $b); } - if ($s[$x][$y] == -2) + if ($board[$x][$y] == -2) { for (my $b = -2 ; $b <= 2 ; $b += 4) { eval_move($x, $y, $a, $b); } } } # If we've found a move, go back and make that one as well - if ($r[0] != -99) + if ($ratings[0] != -99) { - print "TO $r[3], $r[4] "; - $r[0] = -99; + print "TO $ratings[3], $ratings[4] "; + $ratings[0] = -99; next LOOP1240; } } @@ -154,7 +155,7 @@ $line = "$y|" if ($upgrade); for my $x (0 .. 7) { - my $c = $chars[$s[$x][$y] + 2]; + my $c = $chars[$board[$x][$y] + 2]; $c = ' ' if ($upgrade && (($y % 2 == 0 && $x % 2 == 1) || ($y % 2 == 1 && $x % 2 == 0))); $line = tab($line, 5*$x+7, $c); } @@ -172,8 +173,8 @@ { for my $y (0 .. 7) { - if ($s[$x][$y] == 1 || $s[$x][$y] == 2) { $z = 1; } - if ($s[$x][$y] == -1 || $s[$x][$y] == -2) { $t = 1; } + if ($board[$x][$y] == 1 || $board[$x][$y] == 2) { $z = 1; } + if ($board[$x][$y] == -1 || $board[$x][$y] == -2) { $t = 1; } } } if ($z != 1) { $winner = "comp"; last; } @@ -183,39 +184,33 @@ ($z, $t) = (0, 0); my ($x, $y, $e, $h, $a, $b); do { - print "FROM: "; - chomp(my $ans = <>); - ($e,$h) = split(/[, ]/, $ans); + ($e,$h) = get_pos("FROM:"); $x = $e; $y = $h; - } while ($s[$x][$y] <= 0); + } while ($board[$x][$y] <= 0); do { - print "TO: "; - chomp(my $ans = <>); - ($a,$b) = split(/[, ]/, $ans); + ($a,$b) = get_pos("TO:"); $x = $a; $y = $b; - } while (!($s[$x][$y] == 0 && abs($a-$e) <= 2 && abs($a-$e) == abs($b-$h))); + } while (!($board[$x][$y] == 0 && abs($a-$e) <= 2 && abs($a-$e) == abs($b-$h))); LOOP1750: { # Make the move and stop unless it might be a jump. - $s[$a][$b] = $s[$e][$h]; - $s[$e][$h] = 0; + $board[$a][$b] = $board[$e][$h]; + $board[$e][$h] = 0; if (abs($e-$a) != 2) { last LOOP1750; } # Remove the piece jumped over - $s[($e+$a)/2][($h+$b)/2] = 0; + $board[($e+$a)/2][($h+$b)/2] = 0; # Prompt for another move; -1 means player can't, so I've won. # Keep prompting until there's a valid move or the player gives # up. my ($a1, $b1); do { - print "+TO "; - chomp(my $ans = <>); - ($a1,$b1) = split(/[, ]/, $ans); + ($a1,$b1) = get_pos("+TO:"); if ($a1 < 0) { last LOOP1750; } - } while ($s[$a1][$b1] != 0 || abs($a1-$a) != 2 || abs($b1-$b) != 2); + } while ($board[$a1][$b1] != 0 || abs($a1-$a) != 2 || abs($b1-$b) != 2); # Update the move variables to correspond to the next jump $e = $a; @@ -225,7 +220,7 @@ } # If the player has reached the end of the board, crown this piece - if ($b == 7) { $s[$a][$b] = 2; } + if ($b == 7) { $board[$a][$b] = 2; } # And play the next turn. } @@ -236,6 +231,19 @@ ########################################### +# make sure we get a 2 value position +sub get_pos +{ + my $prompt = shift; + my ($p1, $p2); + do { + print "$prompt "; + chomp(my $ans = <>); + ($p1,$p2) = split(/[, ]/, $ans); + } while (!defined($p1) || !defined($p2) || $p1 < -1 || $p2 < -1 || $p1 > 7 || $p2 > 7); + return ($p1,$p2); +} + # deal with basic's tab() for line positioning # line = line string we're starting with # pos = position to start writing @@ -243,10 +251,10 @@ # returns the resultant string, which might not have been changed sub tab { - my ($line, $pos, $s) = @_; + my ($line, $pos, $str) = @_; my $len = length($line); # if curser is past position, do nothing - if ($len <= $pos) { $line .= " " x ($pos - $len) . $s; } + if ($len <= $pos) { $line .= " " x ($pos - $len) . $str; } return $line; } @@ -262,10 +270,10 @@ sub find_move return if ($u < 0 || $u > 7 || $v < 0 || $ v> 7); # Consider the destination if it's empty - eval_jump($x, $y, $u, $v) if ($s[$u][$v] == 0); + eval_jump($x, $y, $u, $v) if ($board[$u][$v] == 0); # If it's got an opponent's piece, jump it instead - if ($s[$u][$v] > 0) + if ($board[$u][$v] > 0) { # Restore u and v, then return if it's off the board @@ -274,7 +282,7 @@ sub find_move return if ($u < 0 || $v < 0 || $u > 7 || $v > 7); # Otherwise, consider u,v - eval_jump($x, $y, $u, $v) if ($s[$u][$v] == 0); + eval_jump($x, $y, $u, $v) if ($board[$u][$v] == 0); } } @@ -282,7 +290,7 @@ sub find_move # # Computes a score for the proposed move and if it's higher # than the best-so-far move, uses that instead by storing it -# and its score in @r. +# and its score in @ratings. sub eval_jump { my ($x, $y, $u, $v) = @_; @@ -291,7 +299,7 @@ sub eval_jump my $q = 0; # +2 if it promotes this piece - $q += 2 if ($v == 0 && $s[$x][$y] == -1); + $q += 2 if ($v == 0 && $board[$x][$y] == -1); # +5 if it takes an opponent's piece $q += 5 if (abs($y-$v) == 2); @@ -304,40 +312,40 @@ sub eval_jump for (my $c = -1 ; $c <= 1 ; $c += 2) { - next if ($u+$c < 0 || $u+$c > 7 || $v+$g < 0); + next if ($u+$c < 0 || $u+$c > 7 || $v+$neg1 < 0); # +1 for each adjacent friendly piece - if ($s[$u+$c][$v+$g] < 0) + if ($board[$u+$c][$v+$neg1] < 0) { $q++; next; } # Prevent out-of-bounds testing - next if ($u-$c < 0 || $u-$c > 7 || $v-$g > 7); + next if ($u-$c < 0 || $u-$c > 7 || $v-$neg1 > 7); # -2 for each opponent piece that can now take this piece here - $q -= 2 if ($s[$u+$c][$v+$g] > 0 && ($s[$u-$c][$v-$g] == 0 || ($u-$c == $x && $v-$g == $y))); + $q -= 2 if ($board[$u+$c][$v+$neg1] > 0 && ($board[$u-$c][$v-$neg1] == 0 || ($u-$c == $x && $v-$neg1 == $y))); } # Use this move if it's better than the previous best - if ($q > $r[0]) + if ($q > $ratings[0]) { - $r[0] = $q; - $r[1] = $x; - $r[2] = $y; - $r[3] = $u; - $r[4] = $v; + $ratings[0] = $q; + $ratings[1] = $x; + $ratings[2] = $y; + $ratings[3] = $u; + $ratings[4] = $v; } } # If (u,v) is in the bounds, evaluate it as a move using -# the sub at 910, so storing eval in @r. +# the sub at 910, so storing eval in @ratings. sub eval_move { my ($x, $y, $a, $b) = @_; my $u = $x+$a; my $v = $y+$b; return if ($u < 0 || $u > 7 || $v < 0 || $v > 7); - eval_jump($x, $y, $u, $v) if ($s[$u][$v] == 0 && $s[$x+$a/2][$y+$b/2] > 0); + eval_jump($x, $y, $u, $v) if ($board[$u][$v] == 0 && $board[$x+$a/2][$y+$b/2] > 0); } From 1d3fd94ae6a80ab75c5082d7974533660677ef77 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Mon, 22 May 2023 08:42:22 +1000 Subject: [PATCH 132/377] Simplify shot selection and evaluation --- 77_Salvo/csharp/{Grid.cs => Fleet.cs} | 21 ++++++----- 77_Salvo/csharp/Game.cs | 37 +++++-------------- .../csharp/Targetting/ComputerShotSelector.cs | 16 +++++++- .../csharp/Targetting/HumanShotSelector.cs | 2 +- 77_Salvo/csharp/Targetting/ShotSelector.cs | 4 +- 5 files changed, 38 insertions(+), 42 deletions(-) rename 77_Salvo/csharp/{Grid.cs => Fleet.cs} (75%) diff --git a/77_Salvo/csharp/Grid.cs b/77_Salvo/csharp/Fleet.cs similarity index 75% rename from 77_Salvo/csharp/Grid.cs rename to 77_Salvo/csharp/Fleet.cs index f91ae43a2..5f267225f 100644 --- a/77_Salvo/csharp/Grid.cs +++ b/77_Salvo/csharp/Fleet.cs @@ -3,11 +3,11 @@ namespace Salvo; -internal class Grid +internal class Fleet { private readonly List _ships; - internal Grid(IReadWrite io) + internal Fleet(IReadWrite io) { io.WriteLine(Prompts.Coordinates); _ships = new() @@ -19,7 +19,7 @@ internal Grid(IReadWrite io) }; } - internal Grid(IRandom random) + internal Fleet(IRandom random) { _ships = new(); while (true) @@ -53,13 +53,14 @@ bool TryPositionShip(Func shipFactory) internal IEnumerable Ships => _ships.AsEnumerable(); - internal bool IsHit(Position position, [NotNullWhen(true)] out Ship? ship) + internal void ReceiveShots(IEnumerable shots, Action reportHit) { - ship = _ships.FirstOrDefault(s => s.IsHit(position)); - if (ship == null) { return false; } - - if (ship.IsDestroyed) { _ships.Remove(ship); } - - return true; + foreach (var position in shots) + { + var ship = _ships.FirstOrDefault(s => s.IsHit(position)); + if (ship == null) { continue; } + if (ship.IsDestroyed) { _ships.Remove(ship); } + reportHit(ship); + } } } diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 6c0add129..5004cacbb 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -20,21 +20,20 @@ internal void Play() var damagedShips = new List<(int Turn, Ship Ship)>(); var temp = new Position[13]; - var computerGrid = new Grid(_random); - var humanGrid = new Grid(_io); - var humanShotSelector = new HumanShotSelector(humanGrid, _io); - var computerShotSelector = new ComputerShotSelector(computerGrid, _random); + var computerFleet = new Fleet(_random); + var humanFleet = new Fleet(_io); var startResponse = _io.ReadString(Prompts.Start); while (startResponse == Strings.WhereAreYourShips) { - foreach (var ship in computerGrid.Ships) + foreach (var ship in computerFleet.Ships) { _io.WriteLine(ship); } startResponse = _io.ReadString(Prompts.Start); } L1890: var turnNumber=0; -L1900: var seeShotsResponse = _io.ReadString(Prompts.SeeShots); + var humanShotSelector = new HumanShotSelector(humanFleet, _io); + var computerShotSelector = new ComputerShotSelector(computerFleet, _random, _io); L1920: _io.WriteLine(); L1930: if (startResponse != "YES") { goto L2620; } L1950: if (startResponse != "YES") { goto L1990; } @@ -48,13 +47,7 @@ internal void Play() _io.WriteLine(Streams.YouHaveMoreShotsThanSquares); L2250: goto L2890; } - foreach (var shot1 in humanShotSelector.GetShots(turnNumber)) - { - if (computerGrid.IsHit(shot1, out var ship)) - { - _io.Write(Strings.YouHit(ship.Name)); - } - } + computerFleet.ReceiveShots(humanShotSelector.GetShots(turnNumber), ship => _io.Write(Strings.YouHit(ship.Name))); L2620: if (startResponse == "YES") { goto L2670; } L2640: turnNumber++; L2660: _io.Write(Strings.Turn(turnNumber)); @@ -68,23 +61,13 @@ internal void Play() L2890: _io.Write(Streams.YouWon); L2900: return; -L2960: temp = computerShotSelector.GetShots(turnNumber).ToArray(); - // display shots -L3380: if (seeShotsResponse == "YES") - { - foreach (var shot in temp) - { - _io.WriteLine(shot); - } - } - foreach (var shot in temp) - { - if (humanGrid.IsHit(shot, out var ship)) +L2960: humanFleet.ReceiveShots( + computerShotSelector.GetShots(turnNumber), + ship => { _io.Write(Strings.IHit(ship.Name)); computerShotSelector.RecordHit(ship, turnNumber); - } - } + }); goto L1950; } } diff --git a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs index 5a5214dd4..721f50c50 100644 --- a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs +++ b/77_Salvo/csharp/Targetting/ComputerShotSelector.cs @@ -4,15 +4,27 @@ internal class ComputerShotSelector : ShotSelector { private readonly KnownHitsShotSelectionStrategy _knownHitsStrategy; private readonly SearchPatternShotSelectionStrategy _searchPatternStrategy; + private readonly IReadWrite _io; + private readonly bool _showShots; - internal ComputerShotSelector(Grid source, IRandom random) + internal ComputerShotSelector(Fleet source, IRandom random, IReadWrite io) : base(source) { _knownHitsStrategy = new KnownHitsShotSelectionStrategy(this); _searchPatternStrategy = new SearchPatternShotSelectionStrategy(this, random); + _io = io; + _showShots = io.ReadString(Prompts.SeeShots).Equals("yes", StringComparison.InvariantCultureIgnoreCase); } - protected override IEnumerable GetShots() => GetSelectionStrategy().GetShots(NumberOfShots); + protected override IEnumerable GetShots() + { + var shots = GetSelectionStrategy().GetShots(NumberOfShots).ToArray(); + if (_showShots) + { + _io.WriteLine(string.Join(Environment.NewLine, shots)); + } + return shots; + } internal void RecordHit(Ship ship, int turn) => _knownHitsStrategy.RecordHit(ship, turn); diff --git a/77_Salvo/csharp/Targetting/HumanShotSelector.cs b/77_Salvo/csharp/Targetting/HumanShotSelector.cs index f3e5fba28..ea49bf124 100644 --- a/77_Salvo/csharp/Targetting/HumanShotSelector.cs +++ b/77_Salvo/csharp/Targetting/HumanShotSelector.cs @@ -4,7 +4,7 @@ internal class HumanShotSelector : ShotSelector { private readonly IReadWrite _io; - internal HumanShotSelector(Grid source, IReadWrite io) + internal HumanShotSelector(Fleet source, IReadWrite io) : base(source) { _io = io; diff --git a/77_Salvo/csharp/Targetting/ShotSelector.cs b/77_Salvo/csharp/Targetting/ShotSelector.cs index 95a5c4bd4..695dbc42d 100644 --- a/77_Salvo/csharp/Targetting/ShotSelector.cs +++ b/77_Salvo/csharp/Targetting/ShotSelector.cs @@ -2,10 +2,10 @@ namespace Salvo.Targetting; internal abstract class ShotSelector { - private readonly Grid _source; + private readonly Fleet _source; private readonly Dictionary _previousShots = new(); - internal ShotSelector(Grid source) + internal ShotSelector(Fleet source) { _source = source; } From 461b4e2b64dd94754212c8e0b7f0992349c34b48 Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Mon, 22 May 2023 08:50:27 +1000 Subject: [PATCH 133/377] Simplify game start seelection --- 77_Salvo/csharp/Game.cs | 50 +++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index 5004cacbb..dd1a49b9b 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -17,28 +17,19 @@ internal void Play() { _io.Write(Streams.Title); - var damagedShips = new List<(int Turn, Ship Ship)>(); - var temp = new Position[13]; - var computerFleet = new Fleet(_random); var humanFleet = new Fleet(_io); - var startResponse = _io.ReadString(Prompts.Start); - while (startResponse == Strings.WhereAreYourShips) - { - foreach (var ship in computerFleet.Ships) - { - _io.WriteLine(ship); - } - startResponse = _io.ReadString(Prompts.Start); - } + var humanStarts = AskWhoStarts(computerFleet); L1890: var turnNumber=0; var humanShotSelector = new HumanShotSelector(humanFleet, _io); var computerShotSelector = new ComputerShotSelector(computerFleet, _random, _io); L1920: _io.WriteLine(); -L1930: if (startResponse != "YES") { goto L2620; } -L1950: if (startResponse != "YES") { goto L1990; } -L1960: turnNumber++; -L1980: _io.Write(Strings.Turn(turnNumber)); +L1930: if (!humanStarts) { goto L2620; } +L1950: if (humanStarts) + { +L1960: turnNumber++; +L1980: _io.Write(Strings.Turn(turnNumber)); + } L1990: var numberOfShots = humanShotSelector.NumberOfShots; L2220: _io.Write(Strings.YouHaveShots(numberOfShots)); if (numberOfShots == 0) { goto L2270; } @@ -48,9 +39,11 @@ internal void Play() L2250: goto L2890; } computerFleet.ReceiveShots(humanShotSelector.GetShots(turnNumber), ship => _io.Write(Strings.YouHit(ship.Name))); -L2620: if (startResponse == "YES") { goto L2670; } -L2640: turnNumber++; -L2660: _io.Write(Strings.Turn(turnNumber)); +L2620: if (!humanStarts) + { +L2640: turnNumber++; +L2660: _io.Write(Strings.Turn(turnNumber)); + } L2670: numberOfShots = computerShotSelector.NumberOfShots; L2840: _io.Write(Strings.IHaveShots(numberOfShots)); L2850: if (!computerShotSelector.CanTargetAllRemainingSquares) { goto L2880; } @@ -70,6 +63,25 @@ internal void Play() }); goto L1950; } + + private bool AskWhoStarts(Fleet computerFleet) + { + while (true) + { + var startResponse = _io.ReadString(Prompts.Start); + if (startResponse.Equals(Strings.WhereAreYourShips, StringComparison.InvariantCultureIgnoreCase)) + { + foreach (var ship in computerFleet.Ships) + { + _io.WriteLine(ship); + } + } + else + { + return startResponse.Equals("yes", StringComparison.InvariantCultureIgnoreCase); + } + } + } } internal class DataRandom : IRandom From d1be351045e2b3e0288935252d6a42492053b8be Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Tue, 23 May 2023 07:55:41 +1000 Subject: [PATCH 134/377] Simplify game loop --- 77_Salvo/csharp/Game.cs | 11 ++++++++++- .../csharp/Resources/YouHaveMoreShotsThanSquares.txt | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index dd1a49b9b..ff43c2686 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -38,7 +38,9 @@ internal void Play() _io.WriteLine(Streams.YouHaveMoreShotsThanSquares); L2250: goto L2890; } - computerFleet.ReceiveShots(humanShotSelector.GetShots(turnNumber), ship => _io.Write(Strings.YouHit(ship.Name))); + computerFleet.ReceiveShots( + humanShotSelector.GetShots(turnNumber), + ship => _io.Write(Strings.YouHit(ship.Name))); L2620: if (!humanStarts) { L2640: turnNumber++; @@ -84,6 +86,13 @@ private bool AskWhoStarts(Fleet computerFleet) } } +internal enum Winner +{ + None, + Human, + Computer +} + internal class DataRandom : IRandom { private readonly Queue _values = diff --git a/77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt b/77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt index 37c068124..04d58f92e 100644 --- a/77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt +++ b/77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt @@ -1 +1 @@ -You have more shots that there are blank squares. +You have more shots than there are blank squares. From 2e52c6e1878a4d63e20c590c6d494b6ac06009bb Mon Sep 17 00:00:00 2001 From: drewjcooper Date: Wed, 24 May 2023 20:58:37 +1000 Subject: [PATCH 135/377] Add TurnHandler --- 77_Salvo/csharp/Game.cs | 96 +++------------------------------- 77_Salvo/csharp/TurnHandler.cs | 92 ++++++++++++++++++++++++++++++++ 77_Salvo/csharp/Winner.cs | 7 +++ 3 files changed, 106 insertions(+), 89 deletions(-) create mode 100644 77_Salvo/csharp/TurnHandler.cs create mode 100644 77_Salvo/csharp/Winner.cs diff --git a/77_Salvo/csharp/Game.cs b/77_Salvo/csharp/Game.cs index ff43c2686..a0223d8ba 100644 --- a/77_Salvo/csharp/Game.cs +++ b/77_Salvo/csharp/Game.cs @@ -1,5 +1,3 @@ -using Salvo.Targetting; - namespace Salvo; internal class Game @@ -17,95 +15,15 @@ internal void Play() { _io.Write(Streams.Title); - var computerFleet = new Fleet(_random); - var humanFleet = new Fleet(_io); - var humanStarts = AskWhoStarts(computerFleet); -L1890: var turnNumber=0; - var humanShotSelector = new HumanShotSelector(humanFleet, _io); - var computerShotSelector = new ComputerShotSelector(computerFleet, _random, _io); -L1920: _io.WriteLine(); -L1930: if (!humanStarts) { goto L2620; } -L1950: if (humanStarts) - { -L1960: turnNumber++; -L1980: _io.Write(Strings.Turn(turnNumber)); - } -L1990: var numberOfShots = humanShotSelector.NumberOfShots; -L2220: _io.Write(Strings.YouHaveShots(numberOfShots)); - if (numberOfShots == 0) { goto L2270; } -L2230: if (humanShotSelector.CanTargetAllRemainingSquares) - { - _io.WriteLine(Streams.YouHaveMoreShotsThanSquares); -L2250: goto L2890; - } - computerFleet.ReceiveShots( - humanShotSelector.GetShots(turnNumber), - ship => _io.Write(Strings.YouHit(ship.Name))); -L2620: if (!humanStarts) - { -L2640: turnNumber++; -L2660: _io.Write(Strings.Turn(turnNumber)); - } -L2670: numberOfShots = computerShotSelector.NumberOfShots; -L2840: _io.Write(Strings.IHaveShots(numberOfShots)); -L2850: if (!computerShotSelector.CanTargetAllRemainingSquares) { goto L2880; } -L2860: _io.Write(Streams.IHaveMoreShotsThanSquares); -L2270: _io.Write(Streams.IWon); - return; -L2880: if (numberOfShots > 0) { goto L2960; } -L2890: _io.Write(Streams.YouWon); -L2900: return; - -L2960: humanFleet.ReceiveShots( - computerShotSelector.GetShots(turnNumber), - ship => - { - _io.Write(Strings.IHit(ship.Name)); - computerShotSelector.RecordHit(ship, turnNumber); - }); - goto L1950; - } + var turnHandler = new TurnHandler(_io, _random); + _io.WriteLine(); - private bool AskWhoStarts(Fleet computerFleet) - { - while (true) + Winner? winner; + do { - var startResponse = _io.ReadString(Prompts.Start); - if (startResponse.Equals(Strings.WhereAreYourShips, StringComparison.InvariantCultureIgnoreCase)) - { - foreach (var ship in computerFleet.Ships) - { - _io.WriteLine(ship); - } - } - else - { - return startResponse.Equals("yes", StringComparison.InvariantCultureIgnoreCase); - } - } - } -} + winner = turnHandler.PlayTurn(); + } while (winner == null); -internal enum Winner -{ - None, - Human, - Computer -} - -internal class DataRandom : IRandom -{ - private readonly Queue _values = - new(File.ReadAllLines("data.txt").Select(l => float.Parse(l) / 1000000)); - private float _previous; - - public float NextFloat() => _previous = _values.Dequeue(); - - public float PreviousFloat() => _previous; - - public void Reseed(int seed) - { - throw new NotImplementedException(); + _io.Write(winner == Winner.Computer ? Streams.IWon : Streams.YouWon); } } - diff --git a/77_Salvo/csharp/TurnHandler.cs b/77_Salvo/csharp/TurnHandler.cs new file mode 100644 index 000000000..afde96133 --- /dev/null +++ b/77_Salvo/csharp/TurnHandler.cs @@ -0,0 +1,92 @@ +using Salvo.Targetting; + +namespace Salvo; + +internal class TurnHandler +{ + private readonly IReadWrite _io; + private readonly Fleet _humanFleet; + private readonly Fleet _computerFleet; + private readonly bool _humanStarts; + private readonly HumanShotSelector _humanShotSelector; + private readonly ComputerShotSelector _computerShotSelector; + private readonly Func _turnAction; + private int _turnNumber; + + public TurnHandler(IReadWrite io, IRandom random) + { + _io = io; + _computerFleet = new Fleet(random); + _humanFleet = new Fleet(io); + _turnAction = AskWhoStarts() + ? () => PlayHumanTurn() ?? PlayComputerTurn() + : () => PlayComputerTurn() ?? PlayHumanTurn(); + _humanShotSelector = new HumanShotSelector(_humanFleet, io); + _computerShotSelector = new ComputerShotSelector(_computerFleet, random, io); + } + + public Winner? PlayTurn() + { + _io.Write(Strings.Turn(++_turnNumber)); + return _turnAction.Invoke(); + } + + private bool AskWhoStarts() + { + while (true) + { + var startResponse = _io.ReadString(Prompts.Start); + if (startResponse.Equals(Strings.WhereAreYourShips, StringComparison.InvariantCultureIgnoreCase)) + { + foreach (var ship in _computerFleet.Ships) + { + _io.WriteLine(ship); + } + } + else + { + return startResponse.Equals("yes", StringComparison.InvariantCultureIgnoreCase); + } + } + } + + private Winner? PlayComputerTurn() + { + var numberOfShots = _computerShotSelector.NumberOfShots; + _io.Write(Strings.IHaveShots(numberOfShots)); + if (numberOfShots == 0) { return Winner.Human; } + if (_computerShotSelector.CanTargetAllRemainingSquares) + { + _io.Write(Streams.IHaveMoreShotsThanSquares); + return Winner.Computer; + } + + _humanFleet.ReceiveShots( + _computerShotSelector.GetShots(_turnNumber), + ship => + { + _io.Write(Strings.IHit(ship.Name)); + _computerShotSelector.RecordHit(ship, _turnNumber); + }); + + return null; + } + + private Winner? PlayHumanTurn() + { + var numberOfShots = _humanShotSelector.NumberOfShots; + _io.Write(Strings.YouHaveShots(numberOfShots)); + if (numberOfShots == 0) { return Winner.Computer; } + if (_humanShotSelector.CanTargetAllRemainingSquares) + { + _io.WriteLine(Streams.YouHaveMoreShotsThanSquares); + return Winner.Human; + } + + _computerFleet.ReceiveShots( + _humanShotSelector.GetShots(_turnNumber), + ship => _io.Write(Strings.YouHit(ship.Name))); + + return null; + } +} diff --git a/77_Salvo/csharp/Winner.cs b/77_Salvo/csharp/Winner.cs new file mode 100644 index 000000000..a5a73eb47 --- /dev/null +++ b/77_Salvo/csharp/Winner.cs @@ -0,0 +1,7 @@ +namespace Salvo; + +internal enum Winner +{ + Human, + Computer +} From 282f5600184bf031a1da7b3b1a67e70654702daf Mon Sep 17 00:00:00 2001 From: amjadkofahi <119040835+amjadkofahi@users.noreply.github.com> Date: Thu, 25 May 2023 01:52:51 +0300 Subject: [PATCH 136/377] Update README.md --- 84_Super_Star_Trek/javascript/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/84_Super_Star_Trek/javascript/README.md b/84_Super_Star_Trek/javascript/README.md index 49b7ece64..1ddcc1d64 100644 --- a/84_Super_Star_Trek/javascript/README.md +++ b/84_Super_Star_Trek/javascript/README.md @@ -1,3 +1,6 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) +Original source downloaded [from Vintage Basic][def] -Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) +Conversion to [**J**avaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) + + +[def]: http://www.vintage-basic.net/games.html \ No newline at end of file From 02cdc6102ab21be751a4121b49ed5b980c885e70 Mon Sep 17 00:00:00 2001 From: amjadkofahi <119040835+amjadkofahi@users.noreply.github.com> Date: Thu, 25 May 2023 01:54:55 +0300 Subject: [PATCH 137/377] Update README.md --- 84_Super_Star_Trek/javascript/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/84_Super_Star_Trek/javascript/README.md b/84_Super_Star_Trek/javascript/README.md index 1ddcc1d64..06f53f122 100644 --- a/84_Super_Star_Trek/javascript/README.md +++ b/84_Super_Star_Trek/javascript/README.md @@ -1,6 +1,6 @@ Original source downloaded [from Vintage Basic][def] -Conversion to [**J**avaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) +Conversion to [****J****avaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) [def]: http://www.vintage-basic.net/games.html \ No newline at end of file From 06d058892970404525dfb84352b268d0a591017c Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 6 Jul 2023 15:48:16 -0700 Subject: [PATCH 138/377] Updated README files; added MiniScript implementation of 94_War. --- .../29_Craps/MiniScript/README.md | 13 ++++ .../31_Depth_Charge/MiniScript/README.md | 13 ++++ .../32_Diamond/MiniScript/README.md | 13 ++++ .../33_Dice/MiniScript/README.md | 16 +++++ .../41_Guess/MiniScript/README.md | 16 +++++ .../52_Kinema/MiniScript/README.md | 16 +++++ .../54_Letter/MiniScript/README.md | 16 +++++ .../64_Nicomachus/MiniScript/README.md | 16 +++++ .../66_Number/MiniScript/README.md | 16 +++++ .../66_Number/MiniScript/number.ms | 2 +- .../78_Sine_Wave/MiniScript/README.md | 13 ++++ .../87_3-D_Plot/MiniScript/README.md | 13 ++++ .../91_Train/MiniScript/README.md | 16 +++++ .../92_Trap/MiniScript/README.md | 13 ++++ .../94_War/MiniScript/README.md | 16 +++++ .../94_War/MiniScript/war.ms | 65 +++++++++++++++++++ 16 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/94_War/MiniScript/README.md create mode 100644 00_Alternate_Languages/94_War/MiniScript/war.ms diff --git a/00_Alternate_Languages/29_Craps/MiniScript/README.md b/00_Alternate_Languages/29_Craps/MiniScript/README.md index f52e8746d..69e82be16 100644 --- a/00_Alternate_Languages/29_Craps/MiniScript/README.md +++ b/00_Alternate_Languages/29_Craps/MiniScript/README.md @@ -1,3 +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 craps.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 "craps" + run diff --git a/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md b/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md index f52e8746d..af1047033 100644 --- a/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md +++ b/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md @@ -1,3 +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 depthcharge.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 "depthcharge.ms" + run diff --git a/00_Alternate_Languages/32_Diamond/MiniScript/README.md b/00_Alternate_Languages/32_Diamond/MiniScript/README.md index f52e8746d..552120d31 100644 --- a/00_Alternate_Languages/32_Diamond/MiniScript/README.md +++ b/00_Alternate_Languages/32_Diamond/MiniScript/README.md @@ -1,3 +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 diamond.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 "diamond" + run diff --git a/00_Alternate_Languages/33_Dice/MiniScript/README.md b/00_Alternate_Languages/33_Dice/MiniScript/README.md index f52e8746d..abe65f49a 100644 --- a/00_Alternate_Languages/33_Dice/MiniScript/README.md +++ b/00_Alternate_Languages/33_Dice/MiniScript/README.md @@ -1,3 +1,19 @@ 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 dice.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 "dice" + run + +3. "Try-It!" page on the web: +Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of dice.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/41_Guess/MiniScript/README.md b/00_Alternate_Languages/41_Guess/MiniScript/README.md index f52e8746d..e8c6e3d2e 100644 --- a/00_Alternate_Languages/41_Guess/MiniScript/README.md +++ b/00_Alternate_Languages/41_Guess/MiniScript/README.md @@ -1,3 +1,19 @@ 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 guess.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 "guess" + run + +3. "Try-It!" page on the web: +Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of guess.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/52_Kinema/MiniScript/README.md b/00_Alternate_Languages/52_Kinema/MiniScript/README.md index f52e8746d..9052a1cb0 100644 --- a/00_Alternate_Languages/52_Kinema/MiniScript/README.md +++ b/00_Alternate_Languages/52_Kinema/MiniScript/README.md @@ -1,3 +1,19 @@ 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 kinema.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 "kinema" + run + +3. "Try-It!" page on the web: +Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of kinema.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/54_Letter/MiniScript/README.md b/00_Alternate_Languages/54_Letter/MiniScript/README.md index f52e8746d..b64d108a6 100644 --- a/00_Alternate_Languages/54_Letter/MiniScript/README.md +++ b/00_Alternate_Languages/54_Letter/MiniScript/README.md @@ -1,3 +1,19 @@ 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 letter.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 "letter" + run + +3. "Try-It!" page on the web: +Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of letter.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md b/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md index f52e8746d..fd2583939 100644 --- a/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md +++ b/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md @@ -1,3 +1,19 @@ 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 nicomachus.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 "nicomachus" + run + +3. "Try-It!" page on the web: +Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of nicomachus.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/66_Number/MiniScript/README.md b/00_Alternate_Languages/66_Number/MiniScript/README.md index f52e8746d..230b0a4ba 100644 --- a/00_Alternate_Languages/66_Number/MiniScript/README.md +++ b/00_Alternate_Languages/66_Number/MiniScript/README.md @@ -1,3 +1,19 @@ 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 number.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 "number" + run + +3. "Try-It!" page on the web: +Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of number.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/66_Number/MiniScript/number.ms b/00_Alternate_Languages/66_Number/MiniScript/number.ms index 23d88de34..0f242d682 100644 --- a/00_Alternate_Languages/66_Number/MiniScript/number.ms +++ b/00_Alternate_Languages/66_Number/MiniScript/number.ms @@ -38,7 +38,7 @@ while true end if if P > 500 then print "!!!!You win!!!! with " + P + " points." - exit + break end if print "You have " + P + " points."; print end while diff --git a/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md b/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md index f52e8746d..98d5cac98 100644 --- a/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md +++ b/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md @@ -1,3 +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 sinewave.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 "sinewave" + run diff --git a/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md b/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md index f52e8746d..e10c4f998 100644 --- a/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md +++ b/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md @@ -1,3 +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 number.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 "number" + run diff --git a/00_Alternate_Languages/91_Train/MiniScript/README.md b/00_Alternate_Languages/91_Train/MiniScript/README.md index f52e8746d..bc083a8a6 100644 --- a/00_Alternate_Languages/91_Train/MiniScript/README.md +++ b/00_Alternate_Languages/91_Train/MiniScript/README.md @@ -1,3 +1,19 @@ 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 train.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 "train" + run + +3. "Try-It!" page on the web: +Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of train.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/92_Trap/MiniScript/README.md b/00_Alternate_Languages/92_Trap/MiniScript/README.md index f52e8746d..84dc58cd7 100644 --- a/00_Alternate_Languages/92_Trap/MiniScript/README.md +++ b/00_Alternate_Languages/92_Trap/MiniScript/README.md @@ -1,3 +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 trap.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 "trap" + run diff --git a/00_Alternate_Languages/94_War/MiniScript/README.md b/00_Alternate_Languages/94_War/MiniScript/README.md new file mode 100644 index 000000000..d525f33ed --- /dev/null +++ b/00_Alternate_Languages/94_War/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 war.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 "war" + run diff --git a/00_Alternate_Languages/94_War/MiniScript/war.ms b/00_Alternate_Languages/94_War/MiniScript/war.ms new file mode 100644 index 000000000..acc432157 --- /dev/null +++ b/00_Alternate_Languages/94_War/MiniScript/war.ms @@ -0,0 +1,65 @@ +print " "*33 + "WAR" +print " "*15 + "CREATIVE COMPUTER MORRISTOWN, NEW JERSEY" +print; print; print + +print "This is the card game of War. Each card is given by SUIT-#" +print "as S-7 for Spade 7." + +// Get a yes/no (or at least y/n) response from the user. +askYesNo = function(prompt) + while true + answer = input(prompt + "? ").lower[:1] + if answer == "y" or answer == "n" then return answer + print "Answer yes or no, please." + end while +end function + +if askYesNo("Do you want directions") == "y" then + print "The computer gives you and it a 'card'. The higher card" + print "(numerically) wins. The game ends when you choose not to" + print "continue or when you have finished the pack." +end if +print +print + +cardValues = "2 3 4 5 6 7 8 9 10 J Q K A".split +deck = [] +for suits in "SHCD" + for value in cardValues + deck.push suits + "-" + value + end for +end for +deck.shuffle + +playerScore = 0 +computerScore = 0 + +while true + m1 = deck.pop + m2 = deck.pop + print "You: " + m1 + "; Computer: " + m2 + n1 = cardValues.indexOf(m1[2:]) + n2 = cardValues.indexOf(m2[2:]) + if n1 > n2 then + playerScore += 1 + print "You win. You have " + playerScore + " and the computer has " + computerScore + else if n2 > n1 then + computerScore += 1 + print "The computer wins!!! You have " + playerScore + " and the computer has " + computerScore + else + print "Tie. No score change." + end if + if not deck then break + if askYesNo("Do you want to continue") == "n" then break +end while + +if not deck then + print + print + print "We have run out of cards. Final score: You: " + playerScore + + " The computer: " + computerScore + print +end if +print "Thanks for playing. It was fun." +print + \ No newline at end of file From 5a886283aafb06bd750a4aa59b0fee7e9167ede6 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 10 Jul 2023 21:24:15 -0700 Subject: [PATCH 139/377] 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 000000000..a15b86d99 --- /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 000000000..c00684ce7 --- /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 000000000..a93e33d1b --- /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 000000000..3c3589791 --- /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 000000000..cb7892f60 --- /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 000000000..5aafdddb4 --- /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 000000000..269d12154 --- /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 000000000..e01c2d6cc --- /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 26856f717..0fabfb087 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 b53cbbf50..b8e4b9b41 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 140/377] 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 000000000..91c9fda25 --- /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 000000000..93b33b010 --- /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 141/377] 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 000000000..0ec35b382 --- /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 000000000..d5d57e187 --- /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 3acbf7fc7..f01b876d1 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 142/377] 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 000000000..408b74952 --- /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 000000000..d152cb105 --- /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 143/377] 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 000000000..2a7ed1b45 --- /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 000000000..d1019717b --- /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 840529867..bb74a4ec7 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 042864528..1f011a466 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 144/377] 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 1f011a466..29d2622e7 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 145/377] 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 000000000..16b06b724 --- /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 000000000..e082b25b5 --- /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 52e1bf49984960f0030f81bf968029c78b9729c9 Mon Sep 17 00:00:00 2001 From: Serge Vakulenko Date: Fri, 14 Jul 2023 14:19:05 -0700 Subject: [PATCH 146/377] Fix bug in Lunar: wrong capsule weight. Must be 32500 lbs, not 33000. --- 59_Lunar_LEM_Rocket/javascript/lunar.js | 2 +- 59_Lunar_LEM_Rocket/lunar.bas | 2 +- 59_Lunar_LEM_Rocket/python/lunar.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/59_Lunar_LEM_Rocket/javascript/lunar.js b/59_Lunar_LEM_Rocket/javascript/lunar.js index 69306aa28..de0840270 100644 --- a/59_Lunar_LEM_Rocket/javascript/lunar.js +++ b/59_Lunar_LEM_Rocket/javascript/lunar.js @@ -113,7 +113,7 @@ async function main() print("\n"); a = 120; v = 1; - m = 33000; + m = 32500; n = 16500; g = 1e-3; z = 1.8; diff --git a/59_Lunar_LEM_Rocket/lunar.bas b/59_Lunar_LEM_Rocket/lunar.bas index b12037187..dac096074 100644 --- a/59_Lunar_LEM_Rocket/lunar.bas +++ b/59_Lunar_LEM_Rocket/lunar.bas @@ -12,7 +12,7 @@ 110 PRINT: PRINT: PRINT: PRINT "GOOD LUCK" 120 L=0 130 PRINT: PRINT "SEC","MI + FT","MPH","LB FUEL","BURN RATE":PRINT -140 A=120:V=1:M=33000:N=16500:G=1E-03:Z=1.8 +140 A=120:V=1:M=32500:N=16500:G=1E-03:Z=1.8 150 PRINT L,INT(A);INT(5280*(A-INT(A))),3600*V,M-N,:INPUT K:T=10 160 IF M-N<1E-03 THEN 240 170 IF T<1E-03 THEN 150 diff --git a/59_Lunar_LEM_Rocket/python/lunar.py b/59_Lunar_LEM_Rocket/python/lunar.py index 82f21fc01..5e24697df 100644 --- a/59_Lunar_LEM_Rocket/python/lunar.py +++ b/59_Lunar_LEM_Rocket/python/lunar.py @@ -127,7 +127,7 @@ def advance(self, delta_t: float) -> None: class Capsule: altitude: float = 120 # in miles above the surface velocity: float = 1 # downward - m: float = 33000 # mass_with_fuel + m: float = 32500 # mass_with_fuel n: float = 16500 # mass_without_fuel g: float = 1e-3 z: float = 1.8 From ff2b9479a62d06bddc088909415843d407ed27a5 Mon Sep 17 00:00:00 2001 From: Serge Vakulenko Date: Fri, 14 Jul 2023 16:45:39 -0700 Subject: [PATCH 147/377] Also update the fiel weight in the initial message. --- 59_Lunar_LEM_Rocket/javascript/lunar.js | 2 +- 59_Lunar_LEM_Rocket/lunar.bas | 2 +- 59_Lunar_LEM_Rocket/python/lunar.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/59_Lunar_LEM_Rocket/javascript/lunar.js b/59_Lunar_LEM_Rocket/javascript/lunar.js index de0840270..4f693d009 100644 --- a/59_Lunar_LEM_Rocket/javascript/lunar.js +++ b/59_Lunar_LEM_Rocket/javascript/lunar.js @@ -102,7 +102,7 @@ async function main() print("0 (FREE FALL) AND 200 (MAXIMUM BURN) POUNDS PER SECOND.\n"); print("SET NEW BURN RATE EVERY 10 SECONDS.\n"); print("\n"); - print("CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,500 LBS.\n"); + print("CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,000 LBS.\n"); print("\n"); print("\n"); print("\n"); diff --git a/59_Lunar_LEM_Rocket/lunar.bas b/59_Lunar_LEM_Rocket/lunar.bas index dac096074..256eedffc 100644 --- a/59_Lunar_LEM_Rocket/lunar.bas +++ b/59_Lunar_LEM_Rocket/lunar.bas @@ -8,7 +8,7 @@ 70 PRINT: PRINT "SET BURN RATE OF RETRO ROCKETS TO ANY VALUE BETWEEN" 80 PRINT "0 (FREE FALL) AND 200 (MAXIMUM BURN) POUNDS PER SECOND." 90 PRINT "SET NEW BURN RATE EVERY 10 SECONDS.": PRINT -100 PRINT "CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,500 LBS." +100 PRINT "CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,000 LBS." 110 PRINT: PRINT: PRINT: PRINT "GOOD LUCK" 120 L=0 130 PRINT: PRINT "SEC","MI + FT","MPH","LB FUEL","BURN RATE":PRINT diff --git a/59_Lunar_LEM_Rocket/python/lunar.py b/59_Lunar_LEM_Rocket/python/lunar.py index 5e24697df..fa7da3de8 100644 --- a/59_Lunar_LEM_Rocket/python/lunar.py +++ b/59_Lunar_LEM_Rocket/python/lunar.py @@ -85,7 +85,7 @@ def print_intro() -> None: print("SET BURN RATE OF RETRO ROCKETS TO ANY VALUE BETWEEN") print("0 (FREE FALL) AND 200 (MAXIMUM BURN) POUNDS PER SECOND.") print("SET NEW BURN RATE EVERY 10 SECONDS.\n") - print("CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,500 LBS.\n\n\n") + print("CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,000 LBS.\n\n\n") print("GOOD LUCK\n") From 67f0527692856014d699879a6e2945b449c1802d Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 17 Jul 2023 16:25:18 -0700 Subject: [PATCH 148/377] 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 000000000..449006a96 --- /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 000000000..bbbb92574 --- /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 dcbe53bb9..ebed2a88b 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 149/377] 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 bbbb92574..98bb0b902 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 150/377] 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 98bb0b902..6c44cf7c3 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 151/377] 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 449006a96..5b04b3a09 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: From 4f13cc39b0e945bb43742fe0b50a375dfcbd3951 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 20 Jul 2023 07:14:41 -0700 Subject: [PATCH 152/377] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed typo (“it’s” —> “its”). --- 11_Bombardment/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/11_Bombardment/README.md b/11_Bombardment/README.md index d0d05bf9b..de2a69e72 100644 --- a/11_Bombardment/README.md +++ b/11_Bombardment/README.md @@ -2,7 +2,7 @@ BOMBARDMENT is played on two, 5x5 grids or boards with 25 outpost locations numbered 1 to 25. Both you and the computer have four platoons of troops that can be located at any four outposts on your respective grids. -At the start of the game, you locate (or hide) your four platoons on your grid. The computer does the same on it’s grid. You then take turns firing missiles or bombs at each other’s outposts trying to destroy all four platoons. The one who finds all four opponents’ platoons first, wins. +At the start of the game, you locate (or hide) your four platoons on your grid. The computer does the same on its grid. You then take turns firing missiles or bombs at each other’s outposts trying to destroy all four platoons. The one who finds all four opponents’ platoons first, wins. This program was slightly modified from the original written by Martin Burdash of Parlin, New Jersey. From 8647d74a392dd1eb3369dd9749aeb4c415f883c6 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 20 Jul 2023 07:29:12 -0700 Subject: [PATCH 153/377] Update README.md Added one known bug and one porting note. --- 11_Bombardment/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/11_Bombardment/README.md b/11_Bombardment/README.md index de2a69e72..d4bd08d74 100644 --- a/11_Bombardment/README.md +++ b/11_Bombardment/README.md @@ -15,6 +15,12 @@ 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 you can't place two platoons on the same outpost, the code does not enforce this. So the player can "cheat" and guarantee a win by entering the same outpost number two or more times. + #### Porting Notes +- To ensure the instructions don't scroll off the top of the screen, we may want to insert a "(Press Return)" or similar prompt before printing the tear-off matrix. + (please note any difficulties or challenges in porting here) From 63af1a106676a5f65c90d6f623fe315d5a536170 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 20 Jul 2023 15:15:02 -0700 Subject: [PATCH 154/377] Added MiniScript implementation of Bombardment and Bombs Away. Also fixed a minor issue with Blackjack. --- .../10_Blackjack/MiniScript/blackjack.ms | 24 ++-- .../11_Bombardment/MiniScript/README.md | 16 +++ .../11_Bombardment/MiniScript/bombardment.ms | 101 ++++++++++++++++ .../12_Bombs_Away/MiniScript/README.md | 16 +++ .../12_Bombs_Away/MiniScript/bombsaway.ms | 112 ++++++++++++++++++ 10_Blackjack/README.md | 1 + 12_Bombs_Away/README.md | 4 + 7 files changed, 265 insertions(+), 9 deletions(-) create mode 100644 00_Alternate_Languages/11_Bombardment/MiniScript/README.md create mode 100644 00_Alternate_Languages/11_Bombardment/MiniScript/bombardment.ms create mode 100644 00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md create mode 100644 00_Alternate_Languages/12_Bombs_Away/MiniScript/bombsaway.ms diff --git a/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms b/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms index 6c44cf7c3..f6d7959b7 100644 --- a/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms +++ b/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms @@ -11,6 +11,8 @@ 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) +cardNames = " A 2 3 4 5 6 7 8 9 10 J Q K".split + reshuffle = function print "Reshuffling" globals.deck = range(1,13)*4 @@ -23,6 +25,12 @@ getCard = function return deck.pop end function +// Function to get a name for the given card, preceded by "a" or "an" +a = function(cardNum) + article = "a" + "n" * (cardNum == 1 or cardNum == 8) + return article + " " + cardNames[cardNum] +end function + // Function to evaluate the given hand. Total is usually put into // handValue(handNum). Totals have the following meaning: // 2-10...Hard 2-10 @@ -123,7 +131,7 @@ playOneRound = function // Test for dealer blackjack 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" + print; print "Dealer has " + a(dealerCard1) + " in the hole for Blackjack" for i in range(0, numPlayers) handValue[i] = evalHand(i) end for @@ -144,11 +152,11 @@ playOneRound = function if hands[i] or hands[i+8] then anyLeft = true end for if not anyLeft then - print "Dealer had a " + cardNames[hands[numPlayers][1]] + " concealed." + print "Dealer had " + a(hands[numPlayers][1]) + " concealed." else // Play dealer's hand. dispTotal = displayTotal(handValue[numPlayers]) - print "Dealer has a " + cardNames[hands[numPlayers][1]] + " concealed" + + print "Dealer has " + a(hands[numPlayers][1]) + " concealed" + " for a total of " + dispTotal + "." while handValue[numPlayers] > 0 and dispTotal <= 16 card = getCard @@ -187,7 +195,7 @@ playHand = function(handNum, prompt=null, allowSplit=true) handValue[handNum] = evalHand(handNum) if choice == "D" then betPerHand[handNum] *= 2 card = getCard - print "Received a " + cardNames[card], " " + print "Received " + a(card), " " hands[handNum].push card handValue[handNum] = evalHand(handNum) if handValue[handNum] < 0 then @@ -209,10 +217,10 @@ playHand = function(handNum, prompt=null, allowSplit=true) hands[hand2] = [hands[handNum].pop] betPerHand[hand2] = betPerHand[handNum] card = getCard - print "First hand receives a " + cardNames[card] + print "First hand receives " + a(card) hands[handNum].push card card = getCard - print "Second hand receives a " + cardNames[card] + print "Second hand receives " + a(card) hands[hand2].push card if card1 != 1 then // Now play the two hands @@ -252,9 +260,7 @@ tallyResults = function 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 +// Main program starts here if getYesNo("Do you want instructions? ") == "Y" then print "This is the game of 21. As many as 7 players may play the" diff --git a/00_Alternate_Languages/11_Bombardment/MiniScript/README.md b/00_Alternate_Languages/11_Bombardment/MiniScript/README.md new file mode 100644 index 000000000..1db2e68d2 --- /dev/null +++ b/00_Alternate_Languages/11_Bombardment/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 bombardment.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 "bombardment" + run diff --git a/00_Alternate_Languages/11_Bombardment/MiniScript/bombardment.ms b/00_Alternate_Languages/11_Bombardment/MiniScript/bombardment.ms new file mode 100644 index 000000000..a6f75009b --- /dev/null +++ b/00_Alternate_Languages/11_Bombardment/MiniScript/bombardment.ms @@ -0,0 +1,101 @@ +print " "*33 + "Bombardment" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "You are on a battlefield with 4 platoons and you" +print "have 25 outposts available where they may be placed." +print "You can only place one platoon at any one outpost." +print "The computer does the same with its four platoons." +print +print "The object of the game is to fire missiles at the" +print "outposts of the computer. It will do the same to you." +print "The one who destroys all four of the enemy's platoons" +print "first is the winner." +print +print "Good luck... and tell us where you want the bodies sent!" +print +input "(Press Return.)" // (so user can read the above) +print +print "Tear off matrix and use it to check off the numbers." +for i in range(1,5); print; end for +memory = [] // records computer's guesses +for row in range(1,5) + for i in range(row*5-4, row*5) + print (" " + i)[-6:], "" + end for + print +end for +print + +// Define a helper function to pick a random position (1-25) +// that is not already in the given list. +pickOutpost = function(excludingThese) + while true + pick = floor(rnd * 25) + 1 + if excludingThese.indexOf(pick) == null then return pick + end while +end function + +// Choose the computer's four positions. +computerOutposts = [] +for i in range(1,4) + computerOutposts.push pickOutpost(computerOutposts) +end for + +playerOutposts = [] +while playerOutposts.len != 4 + inp = input("What are your four positions? ") + inp = inp.replace(", ", " ").replace(",", " ") + inp = inp.split + for pos in inp + pos = pos.val + playerOutposts.push pos + if pos < 1 or pos > 25 then playerOutposts=[] + end for +end while + +// Main loop. +while true + // player's attack + pos = input("Where do you wish to fire your missile? ").val + if computerOutposts.indexOf(pos) == null then + print "Ha, ha you missed. My turn now:" + else + print "You got one of my outposts!" + computerOutposts.remove computerOutposts.indexOf(pos) + left = computerOutposts.len + if left == 3 then + print "One down, three to go." + else if left == 2 then + print "Two down, two to go." + else if left == 3 then + print "Three down, one to go." + else + print "You got me, I'm going fast. ButI'll get you when" + print "My transisto&s recup%ra*e!" + break + end if + end if + + // computer's attack + pos = pickOutpost(memory) + memory.push pos + if playerOutposts.indexOf(pos) == null then + print "I missed you, you dirty rat. I picked " + pos + ". Your turn:" + else + playerOutposts.remove playerOutposts.indexOf(pos) + left = playerOutposts.len + if left == 0 then + print "You're dead. Your last outpost was at " + pos + ". Ha, ha, ha." + print "Better luck next time." + break + end if + print "I got you. It won't be long now. Post " + pos + " was hit." + if left == 3 then + print "You have only three outposts left." + else if left == 2 then + print "You have only two outposts left." + else if left == 1 then + print "You have only one outpost left." + end if + end if +end while diff --git a/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md b/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md new file mode 100644 index 000000000..a654cb2a8 --- /dev/null +++ b/00_Alternate_Languages/12_Bombs_Away/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 bombsaway.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 "bombsaway" + run diff --git a/00_Alternate_Languages/12_Bombs_Away/MiniScript/bombsaway.ms b/00_Alternate_Languages/12_Bombs_Away/MiniScript/bombsaway.ms new file mode 100644 index 000000000..ea06ea48d --- /dev/null +++ b/00_Alternate_Languages/12_Bombs_Away/MiniScript/bombsaway.ms @@ -0,0 +1,112 @@ + +getNum = function(prompt, maxVal=5) + while true + num = floor(input(prompt + "? ").val) + if num > 0 and num <= maxVal then return num + print "Try again..." + end while +end function + +showReturn = function + print "You made it through tremendous flak!!" +end function + +showShotDown = function + print "* * * * boom * * * *" + print "You have been shot down....." + print "Dearly beloved, we are gathered here today to pay our" + print "last tribute..." +end function + +showSuccess = function + print "Direct hit!!!! " + floor(100*rnd) + " killed." + print "Mission successful." +end function + +// Function to calculate the mission result for all nations except Japan. +doNonJapanResult = function + print + d = input("How many missions have you flown? ").val + while d >= 160 + print "Missions, not miles..." + print "150 missions is high even for old-timers." + d = input("Now then, how many missions have you flown? ").val + end while + print + if d >= 100 then print "That's pushing the odds!" + if d < 25 then print "Fresh out of training, eh?" + print + if d >= 160 * rnd then + showSuccess + else + print "Missed target by " + floor(2+30*rnd) + " miles!" + print "Now you're really in for it !!"; print + r = getNum("Does the enemy have guns(1), missiles(2), or both(3)") + print + if r != 2 then + s = input("What's the percent hit rate of enemy gunners (10 to 50)? ").val + if s<10 then + print "You lie, but you'll pay..." + showShotDown + return + end if + end if + print + print + if r > 1 then t = 35 else t = 0 + if s + t > 100 * rnd then + showShotDown + else + showReturn + end if + end if +end function + +s = 0 // hit rate of enemy gunners +r = 0 // whether enemy has guns(1), missiles(2), or both(3) + +// Main Loop +while true + print "You are a pilot in a World War II bomber." + a = getNum("What side -- Italy(1), Allies(2), Japan(3), Germany(4)", 4) + + if a == 1 then // Italy + b = getNum("Your target -- Albania(1), Greece(2), North Africa(3)") + print + print ["Should be easy -- you're flying a nazi-made plane.", + "Be careful!!!", "You're going for the oil, eh?"][b-1] + doNonJapanResult + + else if a == 2 then // Allies + g = getNum("Aircraft -- Liberator(1), B-29(2), B-17(3), Lancaster(4)", 4) + print ["You've got 2 tons of bombs flying for Ploesti.", + "You're dumping the A-bomb on Hiroshima.", + "You're chasing the Aismark in the North Sea.", + "You're busting a German heavy water plant in the Ruhr."][g-1] + doNonJapanResult + + else if a == 3 then // Japan (different logic than all others) + print "You're flying a kamikaze mission over the USS Lexington." + isFirst = input("Your first kamikaze mission(y or n)? ").lower + if isFirst and isFirst[0] == "n" then + s = 0 + showReturn + else + print + if rnd > 0.65 then showSuccess else showShotDown + end if + + else // Germany + m = getNum("A nazi, eh? Oh well. Are you going for Russia(1)," + + char(13) + "England(2), or France(3)") + print ["You're nearing Stalingrad.", + "Nearing London. Be careful, they've got radar.", + "Nearing Versailles. Duck soup. They're nearly defenseless."][m-1] + doNonJapanResult + end if + + print; print; print; another = input("Another mission (y or n)? ").lower + if not another or another[0] != "y" then + print "Chicken !!!" ; print ; break + end if +end while diff --git a/10_Blackjack/README.md b/10_Blackjack/README.md index ebed2a88b..66cfee65c 100644 --- a/10_Blackjack/README.md +++ b/10_Blackjack/README.md @@ -19,6 +19,7 @@ http://www.vintage-basic.net/games.html #### Porting Notes 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: + - 10 - 570 - 590 - 2220 diff --git a/12_Bombs_Away/README.md b/12_Bombs_Away/README.md index 8a2decaa1..603516fb1 100644 --- a/12_Bombs_Away/README.md +++ b/12_Bombs_Away/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 + +- If you play as Japan and say it is not your first mission, it is impossible to complete your mission; the only possible outcomes are "you made it through" or "boom". Moreover, the odds of each outcome depend on a variable (R) that is only set if you played a previous mission as a different side. It's possible this is an intentional layer of complexity meant to encourage repeat play, but it's more likely just a logical error. + #### Porting Notes (please note any difficulties or challenges in porting here) From 088226f316aee9a75c75d043e309ba80d09b9b44 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 20 Jul 2023 16:27:32 -0700 Subject: [PATCH 155/377] Added MiniScript version of 13_Bounce. --- .../13_Bounce/MiniScript/README.md | 16 ++++++ .../13_Bounce/MiniScript/bounce.ms | 55 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 00_Alternate_Languages/13_Bounce/MiniScript/README.md create mode 100644 00_Alternate_Languages/13_Bounce/MiniScript/bounce.ms diff --git a/00_Alternate_Languages/13_Bounce/MiniScript/README.md b/00_Alternate_Languages/13_Bounce/MiniScript/README.md new file mode 100644 index 000000000..22e4e41a9 --- /dev/null +++ b/00_Alternate_Languages/13_Bounce/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 bounce.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 "bounce" + run diff --git a/00_Alternate_Languages/13_Bounce/MiniScript/bounce.ms b/00_Alternate_Languages/13_Bounce/MiniScript/bounce.ms new file mode 100644 index 000000000..64174be62 --- /dev/null +++ b/00_Alternate_Languages/13_Bounce/MiniScript/bounce.ms @@ -0,0 +1,55 @@ +print " "*33 + "Bounce" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +t = [0]*21 +print "This simulation lets you specify the initial velocity" +print "of a ball thrown straight up, and the coefficient of" +print "elasticity of the ball. Please use a decimal fraction" +print "coefficiency (less than 1)." +print +print "You also specify the time increment to be used in" +print "'strobing' the ball's flight (try .1 initially)." +print + +addToLine = function(line, tabPos, textToAdd) + return line + " " * (floor(tabPos) - line.len) + textToAdd +end function + +while true + s2 = input("Time increment (sec)? ").val + print + v = input("Velocity (fps)? ").val + print + c = input("Coefficient? ").val + print + print "feet" + print + s1 = floor(70/(v/(16*s2))) + for i in range(1, s1) + t[i]=v*c^(i-1)/16 + end for + for h in range(floor(-16*(v/32)^2+v^2/32+.5), 0, -0.5) + line = "" + if floor(h)==h then line = str(h) + l=0 + for i in range(1, s1) + for time in range(0, t[i], s2) + l=l+s2 + if abs(h-(.5*(-32)*time^2+v*c^(i-1)*time))<=.25 then + line = addToLine(line, l/s2, "0") + end if + end for + time = t[i+1]/2 + if -16*time^2+v*c^(i-1)*time < h then break + end for + print line + end for + print " " + "." * floor((l+1)/s2+1) + line = " 0" + for i in range(1, l+.9995) + line = addToLine(line, i/s2, i) + end for + print line + print " " * floor((l+1)/(2*s2)-2) + "seconds" + print +end while From 52d58c8e751465968629235107bf90de7cc7c5df Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 20 Jul 2023 21:48:12 -0700 Subject: [PATCH 156/377] Implemented 14_Bowling for MiniScript. --- .../14_Bowling/MiniScript/README.md | 16 ++ .../14_Bowling/MiniScript/bowling.ms | 138 ++++++++++++++++++ 14_Bowling/README.md | 10 +- 3 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/14_Bowling/MiniScript/README.md create mode 100644 00_Alternate_Languages/14_Bowling/MiniScript/bowling.ms diff --git a/00_Alternate_Languages/14_Bowling/MiniScript/README.md b/00_Alternate_Languages/14_Bowling/MiniScript/README.md new file mode 100644 index 000000000..8ac592e76 --- /dev/null +++ b/00_Alternate_Languages/14_Bowling/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 bowling.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 "bowling" + run diff --git a/00_Alternate_Languages/14_Bowling/MiniScript/bowling.ms b/00_Alternate_Languages/14_Bowling/MiniScript/bowling.ms new file mode 100644 index 000000000..139ec225e --- /dev/null +++ b/00_Alternate_Languages/14_Bowling/MiniScript/bowling.ms @@ -0,0 +1,138 @@ +import "listUtil" + +print " "*34 + "Bowl" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +pinDown = [0]*10 // state of each pin: 1=down, 0=standing +player = 1 +frame = 1 +ball = 1 +scores = list.init3d(10, 4, 3, 0) // index by [frame][player][ball], all 0-based + +printInstructions = function + print "The game of bowling takes mind and skill. During the game" + print "the computer will keep score. You may compete with" + print "other players [up to four]. You will be playing ten frames." + print "On the pin diagram 'O' means the pin is down...'+' means the" + print "pin is standing. After the game the computer will show your" + print "scores." +end function + +printPinDiagram = function + print "Player: " + (player+1) + " Frame: " + (frame+1) + " Ball: " + (ball+1) + print + k = 0 + for row in range (0, 3) + line = " " * row + for j in range(1, 4-row) + line += "+O"[pinDown[k]] + " " + k += 1 + end for + print line + end for +end function + +printAnalysis = function(previousDown=0) + pinsLeft = 10 - pinDown.sum + if pinDown.sum == previousDown then print "Gutter!!" + if ball == 0 and pinsLeft == 0 then + print "Strike!!!!!" + char(7)*4 + globals.status = 3 + else if ball == 1 and pinsLeft == 0 then + print "Spare!!!!" + globals.status = 2 + else if ball == 1 and pinsLeft > 0 then + print "Error!!!" // (i.e., didn't clear all the pins in 2 balls) + globals.status = 1 + end if +end function + +rollOneBall = function + print "Type roll to get the ball going." + input // (response ignored) + for i in range(1, 20) + // Generate a random number from 0-99, then take this mod 15. + // This gives us a slightly higher chance of hitting a non-existent + // pin than one of the actual 10. + x = floor(rnd*100) + if x % 15 < 10 then pinDown[x % 15] = 1 + end for + printPinDiagram +end function + +doOneFrame = function + globals.pinDown = [0]*10 + globals.ball = 0 + rollOneBall + printAnalysis + hitOnBall0 = pinDown.sum + scores[frame][player][ball] = hitOnBall0 + + globals.ball = 1 + if hitOnBall0 < 10 then + print "Roll your 2nd ball" + print + rollOneBall + printAnalysis hitOnBall0 + end if + // Note: scoring in this program is not like real bowling. + // It just stores the number of pins down at the end of each ball, + // and a status code (1, 2, or 3). + scores[frame][player][ball] = pinDown.sum + scores[frame][player][2] = status +end function + +pad = function(n, width=3) + return (" "*width + n)[-width:] +end function + +printFinalScores = function + print "FRAMES" + for i in range(1,10) + print pad(i), "" + end for + print + for player in range(0, numPlayers-1) + for i in range(0, 2) + for frame in range(0, 9) + print pad(scores[frame][player][i]), "" + end for + print + end for + print + end for +end function + +playOneGame = function + for f in range(0, 9) + globals.frame = f + for p in range(0, numPlayers-1) + globals.player = p + doOneFrame + end for + end for + print + printFinalScores +end function + +// Main program +print "Welcome to the alley" +print "Bring your friends" +print "Okay let's first get acquainted" +print +ans = input("The instructions (Y/N)? ").upper +if not ans or ans[0] != "N" then printInstructions +while true + numPlayers = input("First of all...How many are playing? ").val + if 0 < numPlayers < 5 then break + print "Please enter a number from 1 to 4." +end while +print +print "Very good..." +while true + playOneGame + print + ans = input("Do you want another game? ").upper + if not ans or ans[0] != "Y" then break +end while diff --git a/14_Bowling/README.md b/14_Bowling/README.md index d5492077b..52a0ab448 100644 --- a/14_Bowling/README.md +++ b/14_Bowling/README.md @@ -17,6 +17,14 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- In the original code, scores is not kept accurately in multiplayer games. It stores scores in F*P, where F is the frame and P is the player. So, for example, frame 8 player 1 (index 16) clobbers the score from frame 4 player 2 (also index 16). + +- Even when scores are kept accurately, they don't match normal bowling rules. In this game, the score for each ball is just the total number of pins down after that ball, and the third row of scores is a status indicator (3 for strike, 2 for spare, 1 for anything else). + +- The program crashes with a "NEXT without FOR" error if you elect to play again after the first game. + #### Porting Notes -(please note any difficulties or challenges in porting here) +- The funny control characters in the "STRIKE!" string literal are there to make the terminal beep. From 73137781aacf0708e5cc6816cc1e142b320360e6 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sun, 23 Jul 2023 21:30:37 -0700 Subject: [PATCH 157/377] Added MiniScript version of 15_Boxing. --- .../15_Boxing/MiniScript/README.md | 16 ++ .../15_Boxing/MiniScript/boxing.ms | 174 ++++++++++++++++++ 15_Boxing/README.md | 10 +- 3 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/15_Boxing/MiniScript/README.md create mode 100644 00_Alternate_Languages/15_Boxing/MiniScript/boxing.ms diff --git a/00_Alternate_Languages/15_Boxing/MiniScript/README.md b/00_Alternate_Languages/15_Boxing/MiniScript/README.md new file mode 100644 index 000000000..0904fdae8 --- /dev/null +++ b/00_Alternate_Languages/15_Boxing/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 boxing.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 "boxing" + run diff --git a/00_Alternate_Languages/15_Boxing/MiniScript/boxing.ms b/00_Alternate_Languages/15_Boxing/MiniScript/boxing.ms new file mode 100644 index 000000000..948a3bdde --- /dev/null +++ b/00_Alternate_Languages/15_Boxing/MiniScript/boxing.ms @@ -0,0 +1,174 @@ +print " "*33 + "Boxing" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "Boxing Olympic Style (3 Rounds -- 2 out of 3 Wins)" + +playerWins = 0 +opponentWins = 0 +print +opponentName = input("What is your opponent's name? ") +playerName = input("Input your man's name? ") +print "Different punches are: (1) full swing; (2) hook; (3) uppercut; (4) jab." +playerBest = input("What is your man's best? ").val +playerWeakness = input("What is his vulnerability? " ).val +while true + opponentBest = floor(4 * rnd + 1) + opponentWeakness = floor(4 * rnd + 1) + if opponentBest != opponentWeakness then break +end while +print opponentName + "'s advantage is " + opponentBest + " and vulnerability is secret." +print + +playerConnects = function + print "He connects!" + if playerPoints > 35 then + print opponentName + " is knocked cold and " + playerName + " is the winner and champ!" + globals.done = true + return + end if + globals.playerPoints += 15 +end function + +doPlayerPunch = function + p = input(playerName + "'s punch? ").val + if p == playerBest then globals.playerPoints += 2 + if p == 1 then // Full Swing + print playerName + " swings and ", "" + if opponentWeakness == 4 then // (probably a bug in original code) + playerConnects + else + x3 = floor(30 * rnd+1) + if x3 < 10 then + playerConnects + else + print "he misses " + if playerPoints != 1 then + print + print + end if + end if + end if + else if p == 2 then // Hook + print playerName + " gives the hook... ", "" + if opponentWeakness == 2 then + globals.playerPoints += 7 + else + h1 = floor(2 * rnd + 1) + if h1 == 1 then + print "But it's blocked!!!!!!!!!!!!!" + else + print "Connects..." + globals.playerPoints += 7 + end if + end if + else if p == 3 then // Uppercut + print playerName + " tries an uppercut ", "" + if opponentWeakness == 3 or floor(100 * rnd + 1) < 51 then + print "and he connects!" + globals.playerPoints += 4 + else + print "and it's blocked (lucky block!)" + end if + else // Jab + print playerName + " jabs at " + opponentName + "'s head ", "" + if opponentWeakness != 4 and floor(8 * rnd + 1) >= 4 then + print "It's blocked." + else + globals.playerPoints += 3 + end if + end if +end function + +playerKnockedOut = function + print playerName + " is knocked cold and " + opponentName + " is the winner and champ!" + globals.done = true +end function + +doOpponentPunch = function + j7 = floor(4 * rnd + 1) + if j7 == playerBest then globals.opponentPoints += 2 + if j7 == 1 then // Full swing + print opponentName + " takes a full swing and ", "" + if playerWeakness == 1 or floor(60 * rnd + 1) < 30 then + print "POW!!!!! He hits him right in the face!" + if opponentPoints > 35 then + playerKnockedOut + else + globals.opponentPoints += 15 + end if + else + print "it's blocked!" + end if + end if + if j7 == 2 then // Hook + print opponentName + " gets " + playerName + " in the jaw (ouch!)" + globals.playerPoints += 7 + print "....and again!" + globals.playerPoints += 5 + if opponentPoints > 35 then + playerKnockedOut + return + end if + print + // continue below as if an Uppercut (probably a bug in the original code) + end if + if j7 == 2 or j7 == 3 then // Uppercut, or Hook + print playerName + " is attacked by an uppercut (oh,oh)..." + if playerWeakness == 3 or floor(200*rnd+1) <= 75 then + print "and " + opponentName + " connects..." + globals.opponentPoints += 8 + else + print " blocks and hits " + opponentName + " with a hook." + globals.playerPoints += 5 + end if + end if + if j7 == 4 then // Jab + print opponentName + " jabs and ", "" + if playerWeakness == 4 or floor(7 * rnd + 1) > 4 then + print "blood spills !!!" + globals.opponentPoints += 5 + else + print "It's blocked!" + end if + end if +end function + +playOneRound = function + globals.playerPoints = 0 + globals.opponentPoints = 0 + print "Round " + round + " begins..." + for r1 in range(1, 7) + i = floor(10 * rnd + 1) + if i <= 5 then + doPlayerPunch + else + doOpponentPunch + end if + if done then return + end for // next R1 (sub-round) + if playerPoints > opponentPoints then + print; print playerName + " wins round " + round + globals.playerWins += 1 + else + print; print opponentName + " wins round " + round + globals.opponentWins += 1 + end if +end function + +done = false +for round in range(1,3) + playOneRound + if done then break + if opponentWins >= 2 then + print opponentName + " wins (nice going, " + opponentName + ")." + break + else if playerWins >= 2 then + print playerName + " amazingly wins!!" + break + end if +end for // next round + +print +print +print "and now goodbye from the Olympic arena." +print diff --git a/15_Boxing/README.md b/15_Boxing/README.md index 12ecab4f1..f0e6692dd 100644 --- a/15_Boxing/README.md +++ b/15_Boxing/README.md @@ -2,7 +2,7 @@ This program simulates a three-round Olympic boxing match. The computer coaches one of the boxers and determines his punches and defences, while you do the same for your boxer. At the start of the match, you may specify your man’s best punch and his vulnerability. -There are approximately seven major punches per round, although this may be varied. The best out if three rounds wins. +There are approximately seven major punches per round, although this may be varied. The best out of three rounds wins. Jesse Lynch of St. Paul, Minnesota created this program. @@ -15,6 +15,14 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- The code that handles player punch type 1 checks for opponent weakness type 4; this is almost certainly a mistake. + +- Line breaks or finishing messages are omitted in various cases. For example, if the player does a hook, and that's the opponent's weakness, then 7 points are silently awarded without outputting any description or line break, and the next sub-round will begin on the same line. + +- When the opponent selects a hook, control flow falls through to the uppercut case. Perhaps related, a player weakness of type 2 (hook) never has any effect on the game. + #### Porting Notes (please note any difficulties or challenges in porting here) From 7ed81c1496e11041074e09d3b6f27a7457e7c185 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 24 Jul 2023 16:41:22 -0700 Subject: [PATCH 158/377] Added MiniScript version of 16_Bug. --- .../16_Bug/MiniScript/README.md | 16 ++ .../16_Bug/MiniScript/bug.ms | 192 ++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 00_Alternate_Languages/16_Bug/MiniScript/README.md create mode 100644 00_Alternate_Languages/16_Bug/MiniScript/bug.ms diff --git a/00_Alternate_Languages/16_Bug/MiniScript/README.md b/00_Alternate_Languages/16_Bug/MiniScript/README.md new file mode 100644 index 000000000..d668b53ee --- /dev/null +++ b/00_Alternate_Languages/16_Bug/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 bug.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 "bug" + run diff --git a/00_Alternate_Languages/16_Bug/MiniScript/bug.ms b/00_Alternate_Languages/16_Bug/MiniScript/bug.ms new file mode 100644 index 000000000..29349b2a2 --- /dev/null +++ b/00_Alternate_Languages/16_Bug/MiniScript/bug.ms @@ -0,0 +1,192 @@ +print " "*34 + "Bug" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "The game Bug" +print "I hope you enjoy this game." +print +ans = input("Do you want instructions? ").lower +if not ans or ans[0] != "n" then + print "The object of bug is to finish your bug before i finish" + print "mine. Each number stands for a part of the bug body." + print "I will roll the die for you, tell you what i rolled for you" + print "what the number stands for, and if you can get the part." + print "If you can get the part I will give it to you." + print "The same will happen on my turn." + print "If there is a change in either bug I will give you the" + print "option of seeing the pictures of the bugs." + print "Ihe numbers stand for parts as follows:" + print "Number Part Number of part needed" + print "1 body 1" + print "2 neck 1" + print "3 head 1" + print "4 feelers 2" + print "5 tail 1" + print "6 legs 6" + print + input "(Press Return.)" // (wait before starting the game) + print +end if + +// define a class to represent a bug (with all its body parts) +Bug = {} +Bug.body = false +Bug.neck = false +Bug.head = false +Bug.feelers = 0 +Bug.tail = false +Bug.legs = 0 +Bug.feelerLetter = "F" +Bug.pronoun = "I" + +// add a method to determine if the bug is complete +Bug.complete = function + return self.tail and self.feelers >= 2 and self.legs >= 6 +end function + +// add a method to draw the bug using print +Bug.draw = function + if self.feelers then + for row in range(1,4) + print " "*10 + (self.feelerLetter + " ") * self.feelers + end for + end if + if self.head then + print " HHHHHHH" + print " H H" + print " H O O H" + print " H H" + print " H V H" + print " HHHHHHH" + end if + if self.neck then + print " N N" + print " N N" + end if + if self.body then + print " BBBBBBBBBBBB" + print " B B" + print " B B" + if self.tail then print "TTTTTB B" + print " BBBBBBBBBBBB" + end if + if self.legs then + for row in [1,2] + print " "*5 + "L " * self.legs + end for + end if +end function + +// add a method to add a part, if possible; return true if bug changed +Bug.addPart = function(partNum) + if partNum == 1 then + print "1=Body" + if self.body then + print self.pronoun + " do not need a body." + else + print self.pronoun + " now have a body." + self.body = true + return true + end if + else if partNum == 2 then + print "2=neck" + if self.neck then + print self.pronoun + " do not need a neck." + else if not self.body then + print self.pronoun + " do not have a body." + else + print self.pronoun + " now have a neck." + self.neck = true + return true + end if + else if partNum == 3 then + print "3=head" + if self.head then + print self.pronoun + " have a head." + else if not self.neck then + print self.pronoun + " do not have a neck." + else + print self.pronoun + " needed a head." + self.head = true + return true + end if + else if partNum == 4 then + print "4=feelers" + if self.feelers >= 2 then + print self.pronoun + " have two feelers already." + else if not self.head then + print self.pronoun + " do not have a head." + else + if self.pronoun == "You" then + print "I now give you a feeler." + else + print "I get a feeler." + end if + self.feelers += 1 + return true + end if + else if partNum == 5 then + print "5=tail" + if self.tail then + print self.pronoun + " already have a tail." + else if not self.body then + print self.pronoun + " do not have a body." + else + if self.pronoun == "You" then + print "I now give you a tail." + else + print "I now have a tail." + end if + self.tail = true + return true + end if + else if partNum == 6 then + print "6=legs" + if self.legs >= 6 then + print self.pronoun + " have 6 feet." + else if not self.body then + print self.pronoun + " do not have a body." + else + self.legs += 1 + print self.pronoun + " now have " + self.legs + " leg" + "s"*(self.legs>1) + "." + return true + end if + end if + return 0 +end function + + +// ...then, instantiate a bug for You (human player) and Me (computer) +you = new Bug +you.feelerLetter = "A" // (don't ask me why) +you.pronoun = "You" +me = new Bug + +// Main loop +while not you.complete and not me.complete + anyChange = false + die = floor(6 * rnd + 1) + print; print "You rolled a " + die + if you.addPart(die) then anyChange = true + wait 2 + die = floor(6 * rnd + 1) + print; print "I rolled a " + die + if me.addPart(die) then anyChange = true + if you.complete then print "Your bug is finished." + if me.complete then print "My bug is finished." + if anyChange then + ans = input("Do you want the pictures? ").lower + if not ans or ans[0] != "n" then + print "*****Your Bug*****" + print; print + you.draw + wait 2 + print + print "*****My Bug*****" + print; print + me.draw + wait 2 + end if + end if +end while +print "I hope you enjoyed the game, play it again soon!!" + From 8442755142d60520aab308731d080941bddda73f Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 25 Jul 2023 09:08:00 -0700 Subject: [PATCH 159/377] Added MiniScript version of 17_Bullfight. --- .../17_Bullfight/MiniScript/README.md | 16 ++ .../17_Bullfight/MiniScript/bull.ms | 188 ++++++++++++++++++ 17_Bullfight/README.md | 4 +- 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 00_Alternate_Languages/17_Bullfight/MiniScript/README.md create mode 100644 00_Alternate_Languages/17_Bullfight/MiniScript/bull.ms diff --git a/00_Alternate_Languages/17_Bullfight/MiniScript/README.md b/00_Alternate_Languages/17_Bullfight/MiniScript/README.md new file mode 100644 index 000000000..d791a463c --- /dev/null +++ b/00_Alternate_Languages/17_Bullfight/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 bull.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 "bull" + run diff --git a/00_Alternate_Languages/17_Bullfight/MiniScript/bull.ms b/00_Alternate_Languages/17_Bullfight/MiniScript/bull.ms new file mode 100644 index 000000000..1259d651f --- /dev/null +++ b/00_Alternate_Languages/17_Bullfight/MiniScript/bull.ms @@ -0,0 +1,188 @@ +print " "*34 + "Bull" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +getYesNo = function(prompt) + while true + ans = input(prompt + "? ").lower + if ans and (ans[0] == "y" or ans[0] == "n") then return ans[0] + print "Incorrect answer - - please type 'yes' or 'no'." + end while +end function + +if getYesNo("Do you want instructions") == "y" then + print "Hello, all you bloodlovers and aficionados." + print "Here is your big chance to kill a bull." + print + print "On each pass of the bull, you may try" + print "0 - Veronica (dangerous inside move of the cape)" + print "1 - Less dangerous outside move of the cape" + print "2 - Ordinary swirl of the cape." + print + print "Instead of the above, you may try to kill the bull" + print "on any turn: 4 (over the horns), 5 (in the chest)." + print "But if I were you," + print "I wouldn't try it before the seventh pass." + print + print "The crowd will determine what award you deserve" + print "(posthumously if necessary)." + print "The braver you are, the better the award you receive." + print + print "The better the job the picadores and toreadores do," + print "the better your chances are." + print; input "(Press return.)" +end if +print; print +bravery = 1 +outcome = 1 +qualities = [null, "superb", "good", "fair", "poor", "awful"] + +// Select a bull (level 1-5, lower numbers are tougher) +bullLevel = floor(rnd*5+1) +print "You have drawn a " + qualities[bullLevel] + " bull." +if bullLevel > 4 then print "You're lucky." +if bullLevel < 2 then print "Good luck. You'll need it." +print + +// Simulate one of the preliminary types of bullfighters +// (picodores or toreadores). Return their effect, 0.1 - 0.5. +simPreliminary = function(fighterType) + effect = 0.1 + temp = 3 / bullLevel * rnd + if temp < 0.87 then effect = 0.2 + if temp < 0.63 then effect = 0.3 + if temp < 0.5 then effect = 0.4 + if temp < 0.37 then effect = 0.5 + t = floor(10 * effect + 0.2) // (get quality in range 1 - 5) + print "The " + fighterType + " did a " + qualities[t] + " job." + if t == 5 then + if fighterType == "picadores" then + print floor(rnd*2+1) + " of the horses of the picadores killed." + end if + print floor(rnd*2+1) + " of the " + fighterType + " killed." + else if t == 4 then + if rnd > 0.5 then + print "One of the " + fighterType + " killed." + else + print "No " + fighterType + " were killed." + end if + end if + print + return effect +end function + +picaEffect = simPreliminary("picadores") +toreEffect = simPreliminary("toreadores") + +getGored = function + while not done + if rnd > 0.5 then + print "You are dead." + globals.bravery = 1.5 + globals.done = true + else + print "You are still alive."; print + if getYesNo("Do you run from the ring") == "y" then + print "Coward" + globals.bravery = 0 + globals.done = true + else + print "You are brave. Stupid, but brave." + if rnd > 0.5 then + globals.bravery = 2 + break + else + print "You are gored again!" + end if + end if + end if + end while +end function + +pass = 0 +courage = 1 // cumulative effect of cape choices +bravery = 1 // set mainly by outcomes after getting gored +victory = false // true if we kill the bull +done = false + +while not done + pass += 1 + print + print "Pass number " + pass + if pass < 3 then + print "The bull is charging at you! You are the matador--" + tryKill = (getYesNo("do you want to kill the bull") == "y") + else + tryKill = (getYesNo("Here comes the bull. Try for a kill") == "y") + end if + if tryKill then + print; print "It is the moment of truth."; print + h = input("How do you try to kill the bull? " ).val + if h != 4 and h != 5 then + print "You panicked. The bull gored you." + getGored + break + end if + k = (6-bullLevel) * 10 * rnd / ((picaEffect + toreEffect) * 5 * pass) + if h == 4 then + victory = (k <= 0.8) + else + victory = (k <= 0.2) + end if + if victory then + print "You killed the bull!" + else + print "The bull has gored you!" + getGored + end if + done = true + else + if pass < 3 then + capeMove = input("What move do you make with the cape? ").val + else + capeMove = input("Cape move? ").val + end if + while capeMove < 0 or capeMove > 2 or capeMove != floor(capeMove) + print "Don't panic, you idiot! Put down a correct number" + capeMove = input.val + end while + m = [3, 2, 0.5][capeMove] + courage += m + f = (6-bullLevel+m/10)*rnd / ((picaEffect+toreEffect+pass/10)*5) + if f >= 0.51 then + print "The bull has gored you!" + getGored + end if + end if +end while + +// Final outcome +if bravery == 0 then + print "The crowd boos for ten minutes. If you ever dare to show" + print "your face in a ring again, they swear they will kill you--" + print "unless the bull does first." +else + fnd = (4.5+courage/6-(picaEffect+toreEffect)*2.5+4*bravery+2*(victory+1)-pass^2/120-bullLevel) + fnc = function; return fnd * rnd; end function + if bravery == 2 then + print "The crowd cheers wildly!" + else if victory then + print "The crowd cheers!"; print + end if + print "The crowd awards you" + if fnc < 2.4 then + print "nothing at all." + else if fnc < 4.9 then + print "one ear of the bull." + else if fnc < 7.4 then + print "Both ears of the bull!" + print "Ole!" + else + print "Ole! You are 'Muy Hombre!"" Ole! Ole!" + end if +end if +print +print "Adios"; print; print; print + + + diff --git a/17_Bullfight/README.md b/17_Bullfight/README.md index c801b16e5..b81aab0b7 100644 --- a/17_Bullfight/README.md +++ b/17_Bullfight/README.md @@ -26,6 +26,6 @@ http://www.vintage-basic.net/games.html #### Porting Notes -(please note any difficulties or challenges in porting here) +- There is a fundamental assumption in the pre-fight subroutine at line 1610, that the Picadores and Toreadores are more likely to do a bad job (and possibly get killed) with a low-quality bull. This appears to be a mistake in the original code, but should be retained. -- There is a fundamental assumption in the pre-fight subroutine at line 1610, that the Picadores and Toreadores are more likely to do a bad job (and possibly get killed) with a low-quality bull. This appears to be a mistake in the original code, but should be retained. \ No newline at end of file +- Lines 1800-1820 (part of the pre-fight subroutine) can never be reached. From cbbf23d5b5b9f6714b557049117cc7c4e6382db2 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 25 Jul 2023 09:24:42 -0700 Subject: [PATCH 160/377] Added MiniScript version of 18_Bullseye. --- .../18_Bullseye/MiniScript/README.md | 19 ++++++ .../18_Bullseye/MiniScript/bullseye.ms | 59 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 00_Alternate_Languages/18_Bullseye/MiniScript/README.md create mode 100644 00_Alternate_Languages/18_Bullseye/MiniScript/bullseye.ms diff --git a/00_Alternate_Languages/18_Bullseye/MiniScript/README.md b/00_Alternate_Languages/18_Bullseye/MiniScript/README.md new file mode 100644 index 000000000..2c353d260 --- /dev/null +++ b/00_Alternate_Languages/18_Bullseye/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of bullseye.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 bullseye.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 "bullseye" + run diff --git a/00_Alternate_Languages/18_Bullseye/MiniScript/bullseye.ms b/00_Alternate_Languages/18_Bullseye/MiniScript/bullseye.ms new file mode 100644 index 000000000..10dc95cac --- /dev/null +++ b/00_Alternate_Languages/18_Bullseye/MiniScript/bullseye.ms @@ -0,0 +1,59 @@ +print " "*32 + "Bullseye" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +print "In this game, up to 20 players throw darts at a target" +print "with 10, 20, 30, and 40 point zones. the objective is" +print "to get 200 points."; print +print "throw description probable score" +print " 1 fast overarm bullseye or complete miss" +print " 2 controlled overarm 10, 20 or 30 points" +print " 3 underarm anything";print +names = [] +n = input("How many players? ").val; print +for i in range(0, n-1) + names.push input("Name of player #" + (i+1) + "? ") +end for +scores = [0] * n + +round = 0 +while true + round += 1; print; print "round " + round; print "---------" + for i in range(0, n-1) + while true + print; t = input(names[i] + "'s throw? ").val + if 1 <= t <= 3 then break + print "Input 1, 2, or 3!" + end while + if t == 1 then + p1=.65; p2=.55; p3=.5; p4=.5 + else if t == 2 then + p1=.99; p2=.77; p3=.43; p4=.01 + else + p1=.95; p2=.75; p3=.45; p4=.05 + end if + u = rnd + if u>=p1 then + print "Bullseye!! 40 points!"; b=40 + else if u>=p2 then + print "30-point zone!"; b=30 + else if u>=p3 then + print "20-point zone"; b=20 + else if u>=p4 then + print "Whew! 10 points."; b=10 + else + print "Missed the target! too bad."; b=0 + end if + scores[i] += b; print "Total score = " + scores[i] + end for + winners = [] + for i in range(0, n-1) + if scores[i] >= 200 then winners.push i + end for + if winners then break +end while + +print; print "We have a winner!!"; print +for i in winners; print names[i] + " scored " + scores[i] + " points."; end for +print; print "Thanks for the game." + From 15e033e65c0d3dac0071d8a2f304387ef5e82cea Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 25 Jul 2023 10:32:13 -0700 Subject: [PATCH 161/377] Added MiniScript version of 19_Bunny. --- .../19_Bunny/MiniScript/README.md | 19 ++++++++ .../19_Bunny/MiniScript/bunny.ms | 43 +++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 00_Alternate_Languages/19_Bunny/MiniScript/README.md create mode 100644 00_Alternate_Languages/19_Bunny/MiniScript/bunny.ms diff --git a/00_Alternate_Languages/19_Bunny/MiniScript/README.md b/00_Alternate_Languages/19_Bunny/MiniScript/README.md new file mode 100644 index 000000000..963066058 --- /dev/null +++ b/00_Alternate_Languages/19_Bunny/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of bunny.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 bunny.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 "bunny" + run diff --git a/00_Alternate_Languages/19_Bunny/MiniScript/bunny.ms b/00_Alternate_Languages/19_Bunny/MiniScript/bunny.ms new file mode 100644 index 000000000..176e1e6cf --- /dev/null +++ b/00_Alternate_Languages/19_Bunny/MiniScript/bunny.ms @@ -0,0 +1,43 @@ +print " "*33 + "Bunny" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +data = [] +data += [1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1] +data += [1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1] +data += [5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1] +data += [9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1] +data += [13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1] +data += [19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1] +data += [8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1] +data += [4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1] +data += [2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1] +data += [14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1] +data += [14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1] +data += [12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1] +data += [10,11,17,18,22,22,24,24,29,29,-1] +data += [22,23,26,29,-1,27,29,-1,28,29,-1,4096] + +string.pad = function(w) + return self + " " * (w - self.len) +end function + +for i in range(5); print; end for + +line = "" +while true + x = data.pull + if x > 128 then break + if x >= 0 then + line = line.pad(x) + y = data.pull + for i in range(x, y) + line += "BUNNY"[i % 5] + end for + else + print line + line = "" + wait 0.1 // optional delay to make printing more visible + end if +end while + From 8426a39c486f541cfb1e7e88a5b1570b1b29ecb6 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 25 Jul 2023 13:17:14 -0700 Subject: [PATCH 162/377] Added MiniScript version of 20_Buzzword. --- .../20_Buzzword/MiniScript/README.md | 19 ++++++++++ .../20_Buzzword/MiniScript/buzzword.ms | 38 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 00_Alternate_Languages/20_Buzzword/MiniScript/README.md create mode 100644 00_Alternate_Languages/20_Buzzword/MiniScript/buzzword.ms diff --git a/00_Alternate_Languages/20_Buzzword/MiniScript/README.md b/00_Alternate_Languages/20_Buzzword/MiniScript/README.md new file mode 100644 index 000000000..963066058 --- /dev/null +++ b/00_Alternate_Languages/20_Buzzword/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of bunny.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 bunny.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 "bunny" + run diff --git a/00_Alternate_Languages/20_Buzzword/MiniScript/buzzword.ms b/00_Alternate_Languages/20_Buzzword/MiniScript/buzzword.ms new file mode 100644 index 000000000..26a377755 --- /dev/null +++ b/00_Alternate_Languages/20_Buzzword/MiniScript/buzzword.ms @@ -0,0 +1,38 @@ +print " "*26 + "Buzzword Generator" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +print "This program prints highly acceptable phrases in" +print "'educator-speak' that you can work into reports" +print "and speeches. Whenever a question mark is printed," +print "type a 'y' for another phrase or 'n' to quit." + +words1 = ["ability","basal","behavioral","child-centered", + "differentiated","discovery","flexible","heterogeneous", + "homogeneous","manipulative","modular","tavistock", + "individualized"] + +words2 = ["learning", "evaluative","objective", + "cognitive","enrichment","scheduling","humanistic", + "integrated","non-graded","training","vertical age", + "motivational","creative"] + +words3 = ["grouping","modification", + "accountability","process","core curriculum","algorithm", + "performance","reinforcement","open classroom","resource", + "structure","facility","environment"] + +list.any = function + return self[self.len * rnd] +end function + +print; print; print "Here's the first phrase:" + +while true + print [words1.any, words2.any, words3.any].join + print + yn = input("?").lower + if yn != "y" then break +end while + +print "Come back when you need help with another report!" From 6a611c04d7b30300a11812e0237d6608b3fed7ab Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 25 Jul 2023 17:27:50 -0700 Subject: [PATCH 163/377] Added MiniScript version of 21_Calendar. --- .../21_Calendar/MiniScript/README.md | 16 ++++ .../21_Calendar/MiniScript/calendar.ms | 89 +++++++++++++++++++ 21_Calendar/README.md | 4 +- 3 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/21_Calendar/MiniScript/README.md create mode 100644 00_Alternate_Languages/21_Calendar/MiniScript/calendar.ms diff --git a/00_Alternate_Languages/21_Calendar/MiniScript/README.md b/00_Alternate_Languages/21_Calendar/MiniScript/README.md new file mode 100644 index 000000000..6d7f8ca58 --- /dev/null +++ b/00_Alternate_Languages/21_Calendar/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 calendar.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 "calendar" + run diff --git a/00_Alternate_Languages/21_Calendar/MiniScript/calendar.ms b/00_Alternate_Languages/21_Calendar/MiniScript/calendar.ms new file mode 100644 index 000000000..27691bdb9 --- /dev/null +++ b/00_Alternate_Languages/21_Calendar/MiniScript/calendar.ms @@ -0,0 +1,89 @@ +import "stringUtil" + +print " "*32 + "Calendar" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +startingDOW = 0 +leapYear = false + +// Note: while the original program required changes to the code to configure +// it for the current year, in this port we choose to ask the user. +// Here's the function to do that. +getParameters = function + days = "sunday monday tuesday wednesday thursday friday saturday".split + globals.startingDOW = 999 + while startingDOW == 999 + ans = input("What is the first day of the week of the year? ").lower + if not ans then continue + for i in days.indexes + if days[i].startsWith(ans) then + globals.startingDOW = -i + break + end if + end for + end while + + while true + ans = input("Is it a leap year? ").lower + if ans and (ans[0] == "y" or ans[0] == "n") then break + end while + globals.leapYear = (ans[0] == "y") + + while true + ans = input("Pause after each month? ").lower + if ans and (ans[0] == "y" or ans[0] == "n") then break + end while + globals.pause = (ans[0] == "y") +end function + +getParameters +monthNames = [ + " JANUARY ", + " FEBRUARY", + " MARCH ", + " APRIL ", + " MAY ", + " JUNE ", + " JULY ", + " AUGUST ", + "SEPTEMBER", + " OCTOBER ", + " NOVEMBER", + " DECEMBER", + ] +monthDays = [31, 28 + leapYear, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + +// Function to print one month calendar. +// month: numeric month number, 0-based (0-11) +printMonth = function(month) + daysSoFar = monthDays[:month].sum + daysLeft = monthDays[month:].sum + print "** " + str(daysSoFar).pad(4) + "*"*18 + " " + monthNames[month] + + " " + "*"*18 + " " + str(daysLeft).pad(4) + "**" + print + print " S M T W T F S" + print + print "*" * 61 + // calculate the day of the week, from 0=Sunday to 6=Saturday + dow = (daysSoFar - startingDOW) % 7 + print " " * 5 + " " * (8*dow), "" + for i in range(1, monthDays[month]) + print str(i).pad(8), "" + dow += 1 + if dow == 7 then + dow = 0 + print + if i == monthDays[month] then break + print; print " " * 5, "" + end if + end for + print +end function + +// Main loop. +for month in range(0, 11) + printMonth month + print + if month < 11 and pause then input +end for diff --git a/21_Calendar/README.md b/21_Calendar/README.md index 05c3ab965..5f5b04eac 100644 --- a/21_Calendar/README.md +++ b/21_Calendar/README.md @@ -24,4 +24,6 @@ http://www.vintage-basic.net/games.html #### Porting Notes -(please note any difficulties or challenges in porting here) +- While many modern environments have time/date functions that would make this program both easier and more automatic, in these ports we are choosing to do without them, as in the original program. + +- Some ports choose to ask the user the starting day of week, and whether it's a leap year, rather than force changes to the code to fit the desired year. From f98fffc19f6dd40ca1246b7e57636224759bf3ac Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 25 Jul 2023 20:59:51 -0700 Subject: [PATCH 164/377] Added MiniScript version of 22_Change. --- .../22_Change/MiniScript/README.md | 19 +++++++ .../22_Change/MiniScript/change.ms | 57 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 00_Alternate_Languages/22_Change/MiniScript/README.md create mode 100644 00_Alternate_Languages/22_Change/MiniScript/change.ms diff --git a/00_Alternate_Languages/22_Change/MiniScript/README.md b/00_Alternate_Languages/22_Change/MiniScript/README.md new file mode 100644 index 000000000..5caa0d947 --- /dev/null +++ b/00_Alternate_Languages/22_Change/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of change.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 change.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 "change" + run diff --git a/00_Alternate_Languages/22_Change/MiniScript/change.ms b/00_Alternate_Languages/22_Change/MiniScript/change.ms new file mode 100644 index 000000000..675a179aa --- /dev/null +++ b/00_Alternate_Languages/22_Change/MiniScript/change.ms @@ -0,0 +1,57 @@ +print " "*33 + "Change" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +print "I, your friendly microcomputer, will determine" +print "the correct change for items costing up to $100." +print; print +while true + itemCost = input("Cost of item? ").val + if itemCost == 0 then break + payment = input("Amount of payment? ").val + change = payment - itemCost + if change < 0 then + print "Sorry, you have short-changed me $" + (itemCost - payment) + continue + else if change == 0 then + print "Correct amount, thank you." + continue + end if + + print "Your change, $" + change + + dollars = floor(change/10) + if dollars then print dollars + " ten dollar bill(s)" + change -= dollars * 10 + + fivers = floor(change/5) + if fivers then print fivers + " five dollar bill(s)" + change -= fivers * 5 + + ones = floor(change) + if ones then print ones + " one dollar bill(s)" + change -= ones + + change *= 100 // (now working in cents) + + halfs = floor(change / 50) + if halfs then print halfs + " one half dollar(s)" + change -= halfs * 50 + + quarters = floor(change / 25) + if quarters then print quarters + " quarter(s)" + change -= quarters * 25 + + dimes = floor(change / 10) + if dimes then print dimes + " dime(s)" + change -= dimes * 10 + + nickels = floor(change / 5) + if nickels then print nickels + " nickel(s)" + change -= nickels * 5 + + pennies = round(change) + if pennies then print pennies + " penny(s)" + print "Thank you, come again." + print; print +end while \ No newline at end of file From 01e1cc964a882fe1099a79f9804cf3c738569c09 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 26 Jul 2023 15:07:15 -0700 Subject: [PATCH 165/377] Added MiniScript version of 23_Checkers. --- .../23_Checkers/MiniScript/README.md | 16 ++ .../23_Checkers/MiniScript/checkers.ms | 243 ++++++++++++++++++ 23_Checkers/README.md | 3 +- 3 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/23_Checkers/MiniScript/README.md create mode 100644 00_Alternate_Languages/23_Checkers/MiniScript/checkers.ms diff --git a/00_Alternate_Languages/23_Checkers/MiniScript/README.md b/00_Alternate_Languages/23_Checkers/MiniScript/README.md new file mode 100644 index 000000000..51188bb1c --- /dev/null +++ b/00_Alternate_Languages/23_Checkers/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 checkers.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 "checkers" + run diff --git a/00_Alternate_Languages/23_Checkers/MiniScript/checkers.ms b/00_Alternate_Languages/23_Checkers/MiniScript/checkers.ms new file mode 100644 index 000000000..dc7527128 --- /dev/null +++ b/00_Alternate_Languages/23_Checkers/MiniScript/checkers.ms @@ -0,0 +1,243 @@ +print " "*32 + "Checkers" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +print "This is the game of Checkers. The computer is X," +print "and you are O. The computer will move first." +print "Squares are referred to by a coordinate system." +print "(0,0) is the lower left corner" +print "(0,7) is the upper left corner" +print "(7,0) is the lower right corner" +print "(7,7) is the upper right corner" +print "The computer will type '+TO' when you have another" +print "jump. Type two negative numbers if you cannot jump." +print; print; print + +input "(Press Return.)"; print // (give player a chance to read) + +// The board. Pieces are represented by numeric values: +// - 0 = empty square +// - -1,-2 = computer (X) (-1 for regular piece, -2 for king) +// - 1,2 = human (O) (1 for regular piece, 2 for king) +// Board is indexed by [x][y], so we have to initialize it sideways: +board = [ + [ 1, 0, 1, 0, 0, 0, -1, 0], + [ 0, 1, 0, 0, 0, -1, 0, -1], + [ 1, 0, 1, 0, 0, 0, -1, 0], + [ 0, 1, 0, 0, 0, -1, 0, -1], + [ 1, 0, 1, 0, 0, 0, -1, 0], + [ 0, 1, 0, 0, 0, -1, 0, -1], + [ 1, 0, 1, 0, 0, 0, -1, 0], + [ 0, 1, 0, 0, 0, -1, 0, -1]] + +// Function to print the board +printBoard = function + for y in range(7, 0) + for x in range(0, 7) + // We print by indexing with the board entry (-2 to 2) into a list + // of possible representations. Remember that in MiniScript, a + // negative index counts from the end. + print [". ", "O ", "O*", "X*", "X "][board[x][y]], " " + end for + print; print + end for +end function + +// Function to get x,y coordinates from the player. +// This is written to allow the two numbers to be +// separated by any combination of ',' and ' '. +// Returns input as [x,y]. +inputPosition = function(prompt, requiredPieceSign, allowCancel=false) + while true + ans = input(prompt + "? ").replace(",", " ").split + if ans.len < 2 then + print "Enter two coordinates, for example: 4 0" + continue + end if + x = val(ans[0]) + y = val(ans[-1]) + if x < 0 and y < 0 and allowCancel then + return [x, y] + else if x < 0 or x > 7 or y < 0 or y > 7 then + print "Coordinates must be in the range 0-7" + else if x%2 != y%2 then + print "Invalid coordinates (both must be odd, or both even)" + else if sign(board[x][y]) != requiredPieceSign then + print "Invalid coordinates" + else + return [x, y] + end if + end while +end function + +// Evaluate a potential (computer) move. +evalMove = function(fromX, fromY, toX, toY) + score = 0 + + // +2 if it promotes this piece + if toY == 0 and board[fromX][fromY] == -1 then score += 2 + + // +5 if it jumps an opponent's piece + if abs(fromY-toY) == 2 then score += 5 + + // -2 if the piece is moving away from the top boundary + if fromY == 7 then score -= 2 + + // +1 for putting the piece against a vertical boundary + if toX == 0 or toX == 7 then score += 1 + + // check neighboring pieces of the target position + for c in [-1, 1] + if toX+c < 0 or toX+c > 7 or toY-1 < 0 then continue + // +1 for each adjacent friendly piece + if board[toX+c][toY-1] < 0 then score += 1 + + // -1 for each opponent piece that could now jump this one + if toX-c >= 0 and toX-c <= 7 and toY+1 <= 7 and board[toX+c][toY-1] > 0 and ( + board[toX-c][toY+1] == 0 or (toX-c == fromX and toY+1 == fromY)) then score -= 2 + end for + return score +end function + +// Consider a possible (computer) move, including whether it's even valid. +// Return it or the previous best, whichever is better. +consider = function(fromX, fromY, toX, toY, previousBest) + + // make sure it's within the bounds of the board + if toX < 0 or toX > 7 or toY < 0 or toY > 7 then return previousBest + + // if it's an opponent's piece, consider jumping it instead + dx = toX - fromX + if board[toX][toY] > 0 and abs(dx) == 1 then + dy = toY - fromY + return consider(fromX, fromY, fromX + dx*2, fromY + dy*2, previousBest) + end if + + // if it's a jump, make sure it's over an opponent piece + if abs(dx) == 2 then + midX = (fromX + toX)/2; midY = (fromY + toY)/2 + if board[midX][midY] < 1 then return previousBest + end if + + // make sure the destination is empty + if board[toX][toY] then return previousBest + + // all checks passed; score it, and return whichever is better + rating = evalMove(fromX, fromY, toX, toY) + if not previousBest or rating > previousBest.rating then + newBest = {} + newBest.fromX = fromX; newBest.fromY = fromY + newBest.toX = toX; newBest.toY = toY + newBest.rating = rating + return newBest + else + return previousBest + end if +end function + +// Do the computer's turn +doComputerTurn = function + // For each square on the board containing one of my pieces, consider + // possible moves and keep the best one so far. Start with a step + // size of 1 (ordinary move), but if we jump, then keep jumping. + stepSize = 1 + while true + bestMove = null + for x in range(0, 7) + for y in range(0, 7) + if board[x][y] >= 0 then continue // not my piece + move = {} + move.fromPos = [x,y] + + // Consider forward moves; if it's a king, also consider backward moves + for dx in [-stepSize, stepSize] + move.toPos = [dx, -stepSize] + bestMove = consider(x, y, x+dx, y-stepSize, bestMove) + if board[x][y] == -2 then bestMove = consider(x, y, x+dx, y+stepSize, bestMove) + end for + end for + end for + + if not bestMove then + // No valid move -- if step size is still 1, this means we + // couldn't find ANY move on our turn, and we have lost. + // Otherwise, we're done. + if stepSize == 1 then + globals.gameOver = true + globals.winner = 1 + end if + break + end if + + // Do the move, and stop if we did not jump. + if stepSize == 1 then + print "From " + bestMove.fromX + " " + bestMove.fromY, "" + end if + print " to " + bestMove.toX + " " + bestMove.toY, "" + + movePiece bestMove.fromX, bestMove.fromY, bestMove.toX, bestMove.toY + if abs(bestMove.toX - bestMove.fromX) == 1 then break + stepSize = 2 + end while + print +end function + +// Move one piece (including captures and crowning +movePiece = function(fromX, fromY, toX, toY) + piece = board[fromX][fromY] + board[toX][toY] = piece + board[fromX][fromY] = 0 + // capture piece jumped over + if abs(toX - fromX) == 2 then + board[(fromX+toX)/2][(fromY+toY)/2] = 0 + end if + // crown (make into a king) a piece that reaches the back row + if (toY == 7 and piece > 0) or (toY == 0 and piece < 0) then + board[toX][toY] = 2 * sign(piece) + end if +end function + +// Handle the player's move. +doPlayerTurn = function + fromPos = inputPosition("From", 1, true) + fromX = fromPos[0]; fromY = fromPos[1] + if fromX < 0 then + // Player concedes the game. + globals.gameOver = true + globals.winner = -1 + return + end if + while true + toPos = inputPosition("To", 0) + toX = toPos[0]; toY = toPos[1] + dist = abs(toX - fromX) + if dist <= 2 and abs(toY - fromY) == dist then break + end while + while true + // Make the move, and continue as long as we have a jump + movePiece fromX, fromY, toX, toY + if dist != 2 then break + + // Prompt for another move, allowing a cancel (negative input). + fromX = toX; fromY = toX + toPos = inputPosition("+To", 0, true) + if toPos[0] < 0 or toPos[1] < 0 then break + toX = toPos[0]; toY = toPos[1] + end while + // If piece has reached the end of the board, crown this piece + if toY == 7 then board[toX][toY] = 2 +end function + +// Main loop. +gameOver = false +while not gameOver + doComputerTurn + if gameOver then break + printBoard + doPlayerTurn + if gameOver then break + printBoard +end while + +print +if winner > 0 then print "You win." else print "I win." diff --git a/23_Checkers/README.md b/23_Checkers/README.md index 1d9143ca2..f2263df51 100644 --- a/23_Checkers/README.md +++ b/23_Checkers/README.md @@ -24,5 +24,6 @@ should be more readable. - If the computer moves a checker to the bottom row, it promotes, but leaves the original checker in place. (See line 1240) - Human players may move non-kings as if they were kings. (See lines 1590 to 1810) - - Human players are not required to jump if it is possible. + - Human players are not required to jump if it is possible, and may make a number + other illegal moves (jumping their own pieces, jumping empty squares, etc.). - Curious writing to "I" variable without ever reading it. (See lines 1700 and 1806) From 98b62bd11433562abfca0855c607a1615e8d7627 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 26 Jul 2023 15:20:25 -0700 Subject: [PATCH 166/377] Added MiniScript version of 24_Chemist. --- .../24_Chemist/MiniScript/README.md | 19 ++++++++++++ .../24_Chemist/MiniScript/chemist.ms | 30 +++++++++++++++++++ 24_Chemist/README.md | 6 ++-- 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 00_Alternate_Languages/24_Chemist/MiniScript/README.md create mode 100644 00_Alternate_Languages/24_Chemist/MiniScript/chemist.ms diff --git a/00_Alternate_Languages/24_Chemist/MiniScript/README.md b/00_Alternate_Languages/24_Chemist/MiniScript/README.md new file mode 100644 index 000000000..88d26f88e --- /dev/null +++ b/00_Alternate_Languages/24_Chemist/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of chemist.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 chemist.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 "chemist" + run diff --git a/00_Alternate_Languages/24_Chemist/MiniScript/chemist.ms b/00_Alternate_Languages/24_Chemist/MiniScript/chemist.ms new file mode 100644 index 000000000..712792ce9 --- /dev/null +++ b/00_Alternate_Languages/24_Chemist/MiniScript/chemist.ms @@ -0,0 +1,30 @@ +print " "*33 + "Chemist" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "The fictitious chemical kryptocyanic acid can only be" +print "diluted by the ratio of 7 parts water to 3 parts acid." +print "If any other ratio is attempted, the acid becomes unstable" +print "and soon explodes. Given the amount of acid, you must" +print "decide how much water to add for dilution. If you miss" +print "you face the consequences." + +deaths = 0 +while deaths < 9 + acid = floor(rnd * 50) + water = 7 * acid/3 + response = input(acid +" liters of kryptocyanic acid. How much water? ").val + diff = abs(water - response) + if diff > water/20 then + print " SIZZLE! You have just been desalinated into a blob" + print " of quivering protoplasm!" + deaths += 1 + if deaths < 9 then + print " However, you may try again with another life." + end if + else + print " Good job! You may breathe now, but don't inhale the fumes!" + print + end if +end while +print " Your 9 lives are used, but you will be long remembered for" +print " your contributions to the field of comic book chemistry." diff --git a/24_Chemist/README.md b/24_Chemist/README.md index fc62425a1..8871a0acb 100644 --- a/24_Chemist/README.md +++ b/24_Chemist/README.md @@ -13,11 +13,13 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- There is a typo in the original Basic, "...DECIDE **WHO** MUCH WATER..." should be "DECIDE **HOW** MUCH WATER" + #### Porting Notes (please note any difficulties or challenges in porting here) -There is a type in the original Basic, "...DECIDE **WHO** MUCH WATER..." should be "DECIDE **HOW** MUCH WATER" - #### External Links - C: https://github.com/ericfischer/basic-computer-games/blob/main/24%20Chemist/c/chemist.c From 547aa39a2c376c45d92bf6c7d98522156cb88984 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 26 Jul 2023 15:36:09 -0700 Subject: [PATCH 167/377] Added MiniScript version of 25_Chief. --- .../25_Chief/MiniScript/README.md | 21 ++++++++ .../25_Chief/MiniScript/chief.ms | 50 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 00_Alternate_Languages/25_Chief/MiniScript/README.md create mode 100644 00_Alternate_Languages/25_Chief/MiniScript/chief.ms diff --git a/00_Alternate_Languages/25_Chief/MiniScript/README.md b/00_Alternate_Languages/25_Chief/MiniScript/README.md new file mode 100644 index 000000000..f31bfa516 --- /dev/null +++ b/00_Alternate_Languages/25_Chief/MiniScript/README.md @@ -0,0 +1,21 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +NOTE: I have added `wait` statements before and while printing the lightning bolt, without which it appears too quickly to be properly dramatic. + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of chief.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 chief.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 "chief" + run diff --git a/00_Alternate_Languages/25_Chief/MiniScript/chief.ms b/00_Alternate_Languages/25_Chief/MiniScript/chief.ms new file mode 100644 index 000000000..272e6699e --- /dev/null +++ b/00_Alternate_Languages/25_Chief/MiniScript/chief.ms @@ -0,0 +1,50 @@ +print " "*30 + "Chief" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "I am chief Numbers Freek, the great Indian math god." +yn = input("Are you ready to take the test you called me out for? ").lower +if not yn or yn[0] != "y" then + print "Shut up, pale face with wise tongue." +end if +print " Take a number and add 3. Divide this number by 5 and" +print "multiply by 8. Divide by 5 and add the same. Subtract 1." +b = input(" What do you have? ").val +c = (b+1-5)*5/8*5-3 +yn = input("I bet your number was " + c + ". Am I right? ").lower +if yn and yn[0] == "y" then + print "Bye!!!" +else + k = input("What was your original number? ").val + f=k+3 + g=f/5 + h=g*8 + i=h/5+5 + j=i-1 + print "So you think you're so smart, eh?" + print "Now watch." + print k + " plus 3 equals " + f +". This divided by 5 equals " + g + ";" + print "this times 8 equals " + h + ". If we divide by 5 and add 5," + print "we get " + i + ", which, minus 1, equals " + j + "." + yn = input("Now do you believe me? ").lower + if yn and yn[0] == "y" then + print "Bye!!!" + else + print "You have made me mad!!!" + print "There must be a great lightning bolt!" + print; print; wait 2 + for x in range(30, 22) + print " "*x + "x x"; wait 0.1 + end for + print " "*21 + "x xxx"; wait 0.1 + print " "*20 + "x x"; wait 0.1 + print " "*19 + "xx x"; wait 0.1 + for y in range(20, 13) + print " "*y + "x x"; wait 0.1 + end for + print " "*12 + "xx"; wait 0.1 + print " "*11 + "x"; wait 0.1 + print " "*10 + "*"; wait 0.1 + print; print"#########################"; print + print "I hope you believe me now, for your sake!!" + end if +end if From 63eba400cc5a961fbcfbe99b0044b1ea681194a2 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 26 Jul 2023 17:46:42 -0700 Subject: [PATCH 168/377] Added MiniScript version of 26_Chomp. --- .../26_Chomp/MiniScript/README.md | 19 ++++ .../26_Chomp/MiniScript/chomp.ms | 102 ++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 00_Alternate_Languages/26_Chomp/MiniScript/README.md create mode 100644 00_Alternate_Languages/26_Chomp/MiniScript/chomp.ms diff --git a/00_Alternate_Languages/26_Chomp/MiniScript/README.md b/00_Alternate_Languages/26_Chomp/MiniScript/README.md new file mode 100644 index 000000000..88d26f88e --- /dev/null +++ b/00_Alternate_Languages/26_Chomp/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of chemist.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 chemist.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 "chemist" + run diff --git a/00_Alternate_Languages/26_Chomp/MiniScript/chomp.ms b/00_Alternate_Languages/26_Chomp/MiniScript/chomp.ms new file mode 100644 index 000000000..01b12f815 --- /dev/null +++ b/00_Alternate_Languages/26_Chomp/MiniScript/chomp.ms @@ -0,0 +1,102 @@ +print " "*33 + "Chomp" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +// *** THE GAME OF CHOMP *** COPYRIGHT PCC 1973 *** + +initBoard = function(rows, columns) + globals.rows = rows + globals.columns = columns + globals.board = [[null]] // indexed as [row][column], 1-based + for i in range(1, rows) + board.push ["."] + ["*"] * columns + end for + board[1][1] = "P" +end function + +printBoard = function + print + print " "*7 + "1 2 3 4 5 6 7 8 9" + for i in range(1, rows) + print i + " "*6 + board[i][1:].join + end for + print +end function + +introduction = function + print + print "This is the game of chomp (Scientific American, Jan 1973)" + r = input("Do you want the rules (1=yes, 0=no!)? ").val + if r == 0 then return + print "Chomp is for 1 or more players (humans only)." + print + print "Here's how a board looks (this one is 5 by 7):" + initBoard 5, 7 + printBoard + print + print "The board is a big cookie - R rows high and C columns" + print "wide. You input R and C at the start. In the upper left" + print "corner of the cookie is a poison square (P). The one who" + print "chomps the poison square loses. To take a chomp, type the" + print "row and column of one of the squares on the cookie." + print "All of the squares below and to the right of that square" + print "(including that square, too) disappear -- chomp!!" + print "No fair chomping squares that have already been chomped," + print "or that are outside the original dimensions of the cookie." + print +end function + +setup = function + print + globals.numPlayers = input("How many players? ").val + rows = input("How many rows? ").val + while rows > 9 + rows = input("Too many rows (9 is maximum). Now, how many rows? ").val + end while + columns = input("How many columns? ").val + while rows > 9 + columns = input("Too many columns (9 is maximum). Now, how many columns? ").val + end while + print + initBoard rows, columns +end function + +doOneTurn = function(player) + printBoard + print "Player " + player + while true + inp = input("Coordinates of chomp (row,column)? ") + inp = inp.replace(",", " ").split + if inp.len < 2 then continue + r = inp[0].val + c = inp[-1].val + if 1 <= r <= rows and 1 <= c <= columns and board[r][c] != " " then break + print "No fair. You're trying to chomp on empty space!" + end while + if board[r][c] == "P" then + print "You lose, player " + player + globals.gameOver = true + else + + end if + for row in range(r, rows) + for col in range(c, columns) + board[row][col] = " " + end for + end for +end function + +// Main program +introduction +while true + setup + gameOver = false + player = 0 + while not gameOver + player += 1 + if player > numPlayers then player = 1 + doOneTurn player + end while + print + r = input("Again (1=yes, 0=no!)? ").val + if r != 1 then break +end while From 667c88d4c800000c635321759a50b22262722762 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 26 Jul 2023 17:47:23 -0700 Subject: [PATCH 169/377] Fixed README for MiniScript Chomp. --- 00_Alternate_Languages/26_Chomp/MiniScript/README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/00_Alternate_Languages/26_Chomp/MiniScript/README.md b/00_Alternate_Languages/26_Chomp/MiniScript/README.md index 88d26f88e..f9800b1ed 100644 --- a/00_Alternate_Languages/26_Chomp/MiniScript/README.md +++ b/00_Alternate_Languages/26_Chomp/MiniScript/README.md @@ -4,16 +4,13 @@ Conversion to [MiniScript](https://miniscript.org). Ways to play: -0. Try-It! Page: -Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of chemist.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. - 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 chemist.ms + miniscript chomp.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 "chemist" + load "chomp" run From 382df64a7788e1eef32d96c42d74a69f256f89cd Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sun, 30 Jul 2023 21:18:59 -0700 Subject: [PATCH 170/377] Added MiniScript version of 27_Civil_War. --- .../27_Civil_War/MiniScript/README.md | 16 + .../27_Civil_War/MiniScript/civilwar.ms | 437 ++++++++++++++++++ 27_Civil_War/README.md | 4 + 3 files changed, 457 insertions(+) create mode 100644 00_Alternate_Languages/27_Civil_War/MiniScript/README.md create mode 100644 00_Alternate_Languages/27_Civil_War/MiniScript/civilwar.ms diff --git a/00_Alternate_Languages/27_Civil_War/MiniScript/README.md b/00_Alternate_Languages/27_Civil_War/MiniScript/README.md new file mode 100644 index 000000000..205467edb --- /dev/null +++ b/00_Alternate_Languages/27_Civil_War/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 civilwar.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 "civilwar" + run diff --git a/00_Alternate_Languages/27_Civil_War/MiniScript/civilwar.ms b/00_Alternate_Languages/27_Civil_War/MiniScript/civilwar.ms new file mode 100644 index 000000000..30b1ce829 --- /dev/null +++ b/00_Alternate_Languages/27_Civil_War/MiniScript/civilwar.ms @@ -0,0 +1,437 @@ +print " "*26 + "Civil War" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +// ORIGINAL GAME DESIGN: CRAM, GOODIE, HIBBARD LEXINGTON H.S. +// MODIFICATIONS: G. PAUL, R. HESS (TIES), 1973 +// Conversion to MiniScript: J. Strout, 2023 + +sides = ["Confederate", "Union"] + +getYesNo = function(prompt) + while true + yn = input(prompt + "? ").lower + if yn and yn[0] == "y" then return "YES" + if yn and yn[0] == "n" then return "NO" + print "Yes or no -- " + end while +end function + +instructions = function + print; print; print; print + print "This is a civil war simulation." + print "To play type a response when the computer asks." + print "Remember that all factors are interrelated and that your" + print "responses could change history. Facts and figures used are" + print "based on the actual occurrence. Most battles tend to result" + print "as they did in the civil war, but it all depends on you!!" + print + print "The object of the game is to win as many battles as "; + print "possible." + print + print "Your choices for defensive strategy are:" + print " (1) artillery attack" + print " (2) fortification against frontal attack" + print " (3) fortification against flanking maneuvers" + print " (4) falling back" + print " Your choices for offensive strategy are:" + print " (1) artillery attack" + print " (2) frontal attack" + print " (3) flanking maneuvers" + print " (4) encirclement" + print "You may surrender by typing a '5' for your strategy." +end function + +historicalBattles = [] +addBattle = function(name, men0, men1, cas0, cas1, offDef, desc) + battle = {} + battle.name = name + battle.men = [men0, men1] + battle.casualties = [cas0, cas1] + battle.offDef = offDef // 1=Confederate Defense, 2=both Offense, 3=Confederate Offense + battle.description = desc + historicalBattles.push battle +end function + +loadData = function + // Historical data + addBattle "Bull Run",18000,18500,1967,2708,1, [ +"July 21, 1861. Gen. Beauregard, commanding the South, met", +"Union forces with Gen. Mcdowell in a premature battle at", +"Bull Run. Gen. Jackson helped push back the Union attack."] + + addBattle "Shiloh",40000.,44894.,10699,13047,3, [ +"April 6-7, 1862. The Confederate surprise attack at", +"Shiloh failed due to poor organization."] + + addBattle "Seven Days",95000.,115000.,20614,15849,3, [ +"June 25-july 1, 1862. General Lee (CSA) upheld the", +"offensive throughout the battle and forced Gen. McClellan", +"and the Union forces away from Richmond."] + + addBattle "Second Bull Run",54000.,63000.,10000,14000,2, [ +"Aug 29-30, 1862. The combined Confederate forces under Lee", +"and Jackson drove the Union forces back into washington."] + + addBattle "Antietam",40000.,50000.,10000,12000,3, [ +"Sept 17, 1862. The South failed to incorporate Maryland", +"into the Confederacy."] + + addBattle "Fredericksburg",75000.,120000.,5377,12653,1, [ +"Dec 13, 1862. The Confederacy under Lee successfully", +"repulsed an attack by the Union under Gen. Burnside."] + + addBattle "Murfreesboro",38000.,45000.,11000,12000,1, [ +"Dec 31, 1862. The South under Gen. Bragg won a close battle."] + + addBattle "Chancellorsville",32000,90000.,13000,17197,2, [ +"May 1-6, 1863. The South had a costly victory and lost", +"one of their outstanding generals, 'Stonewall' Jackson."] + + addBattle "Vicksburg",50000.,70000.,12000,19000,1, [ +"July 4, 1863. Vicksburg was a costly defeat for the South", +"because it gave the Union access to the Mississippi."] + + addBattle "Gettysburg",72500.,85000.,20000,23000,3, [ +"July 1-3, 1863. A Southern mistake by Gen. Lee at Gettysburg", +"cost them one of the most crucial battles of the war."] + + addBattle "Chickamauga",66000.,60000.,18000,16000,2, [ +"Sept. 15, 1863. Confusion in a forest near Chickamauga led", +"to a costly Southern victory."] + + addBattle "Chattanooga",37000.,60000.,36700.,5800,2, [ +"Nov. 25, 1863. After the South had sieged Gen. Rosencrans'", +"army for three months, Gen. Grant broke the siege."] + + addBattle "Spotsylvania",62000.,110000.,17723,18000,2, [ +"May 5, 1864. Grant's plan to keep Lee isolated began to", +"fail here, and continued at Cold Harbor and Petersburg."] + + addBattle "Atlanta",65000.,100000.,8500,3700,1, [ +"August, 1864. Sherman and three veteran armies converged", +"on Atlanta and dealt the death blow to the Confederacy."] + +end function + +setup = function + print; print; print + if getYesNo("Are there two generals present") == "YES" then + globals.numPlayers = 2 + else + globals.numPlayers = 1 + print; print "You are the Confederacy. Good luck!" + print + end if + print "Select a battle by typing a number from 1 to 14 on" + print "request. Type any other number to end the simulation." + print "But '0' brings back exact previous battle situation" + print "allowing you to replay it." + print + print "Note: a negative food$ entry causes the program to " + print "use the entries from the previous battle." + print + yn = getYesNo("After requesting a battle, do you wish battle descriptions") + globals.battleDesc = (yn == "YES") +end function + +// Game variables -- the 2-element arrays below represent the stats for +// player 0 (Confederacy) and 1 (Union) +D = [0,0] // money +F = [0,0] // food budget +H = [0,0] // salary budget +B = [0,0] // ammo budget +men = [0,0] // men at start of battle? (M1, M2) +menAdded = [0,0] // men added (M3, M4) +menAvail = [0,0] // men available (M5, M6) +P = [0,0] // casualties? +T = [0,0] // total losses? +resources = [0,0] // total resources (money) available to each side (R1, R2) +spending = [0,0] // total expenditures for each side (Q1, Q2) +morale = [0,0] // troop morale (O) +strategy = [0,0] // strategy choice (Y1, Y2) +inflation = [0,0] // inflation (I1, I2) + +R = 0 // previous battle +losses = 0 // Confederate losses +wins = 0 // Confederate wins +unresolved = 0 // battles where neither side clearly won + +printInColumns = function(a, b, c) + print (a + " "*20)[:20] + (b + " "*16)[:16] + c +end function + +pickBattle = function + print; print; print + globals.replay = false + while true + num = input("Which battle do you wish to simulate? ").val + if num == 0 and R > 0 then + num = R + globals.replay = true + end if + if 0 < num <= historicalBattles.len then break + end while + globals.bat = historicalBattles[num - 1] + if not replay then + men[0] = bat.men[0] + men[1] = bat.men[1] + + // inflation calc + inflation[0] = 10 + (losses - wins) * 2 + inflation[1] = 10 + (wins - losses) * 2 + + // money available + D[0] = 100 * floor((men[0]*(100-inflation[0])/2000) * (1+(resources[0]-spending[0])/(resources[0]+1))+0.5) + D[1] = 100 * floor(men[1]*(100-inflation[1])/2000 + 0.5) + if numPlayers == 2 then + D[1] = 100 * floor((men[1]*(100-inflation[1])/2000) * (1+(resources[1]-spending[1])/(resources[1]+1))+0.5) + end if + + // men available + menAvail[0] = floor(men[0]*(1 + (P[0]-T[0])/(menAdded[0]+1))) + menAvail[1] = floor(men[1]*(1 + (P[1]-T[1])/(menAdded[1]+1))) + globals.F1 = 5/6 * men[0] // ?!? + print; print; print; print; print +print "P:" + P + "; T:" + T + "; menAdded:" + menAdded +print "men[0]:" + men[0] + " ...F1:" + F1 + + print "This is the battle of " + bat.name + if battleDesc then + for line in bat.description + print line + end for + end if + else + print bat.name + " Instant Replay" + end if + print + printInColumns " ", "CONFEDERACY", " UNION" + printInColumns "MEN", " "+menAvail[0], " "+menAvail[1] + printInColumns "MONEY", "$ "+D[0], "$ "+D[1] + printInColumns "INFLATION", " "+(inflation[0]+15)+" %", " " +inflation[1]+" %" + // (Note: printout lies and shows confederate inflation 15% higher than actual) + print +end function + +getBudget = function(player) + print sides[player] + " General---How much do you wish to spend for" + getNum = function(prompt, allowNegative) + while true + n = input(prompt) + if not n then continue + if n[-1] == "k" then n = n[:-1] + "000" // (allow entries like "60k") + if n.val >= 0 or allowNegative then return n.val + print "Negative values are not allowed." + end while + end function + + while true + f = getNum(" - Food......? ", true) + if f < 0 then + if resources[player] == 0 then + print "No previous entries." + print "How much do you wish to spend for" + continue + end if + break // keep all previous entries + end if + F[player] = f + H[player] = getNum(" - Salaries..? ", false) + B[player] = getNum(" - Ammunition? ", false) + if F[player] + H[player] + B[player] <= D[player] then break + print "Think again! You have only $" + D[player] + end while +end function + +calcMorale = function(player) + m = ((2*F[player]^2 + H[player]^2) / F1^2 + 1) + print (" "*11 + sides[player])[-11:], " " + if m >= 10 then + print "morale is high" + else if m >= 5 then + print "morale is fair" + else + print "morale is poor" + end if + morale[player] = m +end function + +getStrategy = function(player) + if numPlayers == 1 then prompt = "Your strategy" else prompt = sides[player] + " strategy" + while true + strat = input(prompt + "? ").val + if 0 < strat < 6 then break + print "Strategy " + strat + " not allowed." + end while + strategy[player] = strat + if strat == 5 then + print "The " + ["Confederacy", "Union"][player] + " has surrendered." + globals.gameOver = true + end if +end function + +calcComputerStrategy = function + // Union strategy is computer chosen + print "Union strategy is ", "" + s0 = 0 + r = 100 * rnd + for i in range(0, 3) + s0 += unionStrats[i] + if r < s0 then + strategy[1] = i+1 + break + end if + end for + print strategy[1] +end function + +learnStrategy = function + // Learn present strategy, start forgetting old ones. + // - Present strategy of south gains 3*s, others lose s + // probability points, unless a strategy falls below 5%. + s = 3; s0 = 0 + for i in range(0,3) + if unionStrats[i] < 5 then continue + unionStrats[i] -= s + s0 += s + end for + unionStrats[strategy[1]-1] += s0 +end function + +doBattle = function + U = 0; U2 = 0 + // simulated losses -- North + C6 = (2 * bat.casualties[1]/5) * (1+1/(2*(abs(strategy[1]-strategy[0])+1))) + C6 = C6 * (1.28 + (5*men[1]/6) / (B[1]+1)) + C6 = floor(C6 * (1+1/morale[1]) + .5) + // - IF LOSS > MEN PRESENT, RESCALE LOSSES + E2 = 100/morale[1] // desertions (Union) + if floor(C6 + E2) >= menAvail[1] then + C6 = floor(13*menAvail[1]/20) + E2 = 7 * C6/13 + U2=1 // Union loss + end if + // simulated losses -- South + C5 = (2 * bat.casualties[0]/5) * (1+1/(2*(abs(strategy[1]-strategy[0])+1))) + print "step A:" + C5 + C5 = floor(C5 * (1+1/morale[0])*(1.28+F1/(B[0]+1))+.5) + print "step B:" + C5 + print "based on morale[0]:"+morale[0]+", F1:"+F1+", B[0]:"+B[0] + E=100/morale[0] + if C5+100/morale[0] >= men[0]*(1+(P1-T1)/(menAdded[0]+1)) then + C5 = floor(13*men[0]/20 * (1+(P1-T1)/(menAdded[0]+1))) + print "step C:" + C5 + print "men: " + men; print "menAdded: " + menAdded; print "P1,T1:" + P1 + "," + T1 + E=7*C5/13 // desertions (Confed) + U=1 // Confederate loss + end if + print + print; print; printInColumns "", "CONFEDERACY", "UNION" + if numPlayers == 1 then + C6 = floor(17 * bat.casualties[1] * bat.casualties[0] / (C5*20)) + E2 = 5 * morale[0] + end if + printInColumns "CASUALTIES", C5, C6 + printInColumns "DESERTIONS", floor(E), floor(E2) + print + if numPlayers == 2 then + print "Compared to the actual casualties at " + bat.name + print "Confederate: " + round(100*C5/bat.casualties[0]) + "% of the original" + print "Union: " + round(100*C6/bat.casualties[1]) + "% of the original" + print + // Who won? + print "U:"+U+ " U2:"+U2 + if (U == 1 and U2 != 1) or (U == U2 and C5+E > C6+E2) then + print "The Union wins " + bat.name + globals.losses += 1 + else if (U2 == 1 and U != 1) or (U == U2 and C5+E < C6+E2) then + print "The confederacy wins " + bat.name + globals.wins += 1 + else + print "Battle outcome unresolved" + globals.unresolved += 1 + end if + else + print "Your casualties were " + round(100*C5/bat.casualties[0]) + "% of" + print "the actual casualties at " + bat.name + print + if U == 1 or C5+E >= 17*bat.casualties[1]*bat.casualties[0]/(C5*20)+5*morale[0] then + print "You lose " + bat.name + if not replay then globals.losses += 1 + else + print "You win " + bat.name + if not replay then globals.wins += 1 + end if + end if + if not replay then + // Cumulative battle factors which alter historical + // resources availeble. (If a replay, don't update.) + T[0] += C5 + E + T[1] += C6 + E2 + P[0] += bat.casualties[0] + P[1] += bat.casualties[1] + spending[0] += F[0] + H[0] + B[0] + spending[1] += F[1] + H[1] + B[1] + resources[0] += men[0]*(100-inflation[0])/20 + resources[1] += men[1]*(100-inflation[1])/20 + menAdded[0] += men[0] + menAdded[1] += men[1] + + learnStrategy + end if + print "---------------" +end function + +// Main Program +loadData +unionStrats = [25, 25, 25, 25] +P1=0; P2=0; T1=0; T2=0 // cumulative stat thingies +print +if getYesNo("Do you want instructions") == "YES" then instructions +setup +gameOver = false +while not gameOver + pickBattle + if gameOver then break + for i in range(0, numPlayers-1) + getBudget i + end for + for i in range(0, numPlayers-1) + calcMorale i + end for + print "Confederate General---", "" + if bat.offDef == 3 then + print "you are on the offensive" + else if bat.offDef == 1 then + print "you are on the defensive" + else + print "both sides are on the offensive " + end if + print + getStrategy 0 + if numPlayers == 2 then getStrategy 1 else calcComputerStrategy + if gameOver then break + doBattle +end while + +// Finish off +print; print; print; print; print; print +print "The Confederacy has won " + wins + " battles and lost " + losses +if strategy[0] == 5 or (strategy[1] != 5 and losses > wins) then + print "The Union has won the war" +else + print "The Confederacy has won the war" +end if +print "For the " + (wins + losses + unresolved) + " battles fought (excluding reruns)" +print +printInColumns "", "Confederacy", "Union" +printInColumns "Historical Losses", round(P[0]), round(P[1]) +printInColumns "Simulated Losses", round(T[0]), round(T[1]) +print +printInColumns " % of Original", round(100*T[0]/P[0]), round(100*T[1]/P[1]) +if numPlayers == 1 then + print + print "Union intelligence suggsets that the South used " + print "strategies 1, 2, 3, 4 in the following percentages" + print unionStrats.join +end if diff --git a/27_Civil_War/README.md b/27_Civil_War/README.md index 3a609ea86..7cbd62e2a 100644 --- a/27_Civil_War/README.md +++ b/27_Civil_War/README.md @@ -17,6 +17,10 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- At the end of a single-player game, the program reports strategies used by "THE SOUTH", but these are in fact strategies used by the North (the computer player) -- the South is always a human player. + #### Porting Notes (please note any difficulties or challenges in porting here) From 461a727e98b258d119108c697c6cd105fb52b8e3 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 31 Jul 2023 08:04:25 -0700 Subject: [PATCH 171/377] Added MiniScript version of 28_Combat. And holy cows, this is the dumbest program yet. --- .../28_Combat/MiniScript/README.md | 16 ++ .../28_Combat/MiniScript/combat.ms | 165 ++++++++++++++++++ 28_Combat/README.md | 5 + 3 files changed, 186 insertions(+) create mode 100644 00_Alternate_Languages/28_Combat/MiniScript/README.md create mode 100644 00_Alternate_Languages/28_Combat/MiniScript/combat.ms diff --git a/00_Alternate_Languages/28_Combat/MiniScript/README.md b/00_Alternate_Languages/28_Combat/MiniScript/README.md new file mode 100644 index 000000000..f9800b1ed --- /dev/null +++ b/00_Alternate_Languages/28_Combat/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 chomp.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 "chomp" + run diff --git a/00_Alternate_Languages/28_Combat/MiniScript/combat.ms b/00_Alternate_Languages/28_Combat/MiniScript/combat.ms new file mode 100644 index 000000000..c5f6596af --- /dev/null +++ b/00_Alternate_Languages/28_Combat/MiniScript/combat.ms @@ -0,0 +1,165 @@ +print " "*33 + "Combat" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +printInColumns2 = function(a, b, lineBreak=true) + print (a+" "*16)[:16] + (b+" "*16)[:16], "" + if lineBreak then print +end function + +printInColumns3 = function(a, b, c, lineBreak=true) + print (a+" "*16)[:16] + (b+" "*16)[:16] + (c+" "*16)[:16], "" + if lineBreak then print +end function + +// computer forces: +d = 30000 // army +e = 20000 // navy +f = 22000 // air force + +print "I am at war with you."; print "We have 72000 soldiers apiece." +while true + print; print "Distribute your forces." + printInColumns3 "", "ME", "YOU" + printInColumns2 "army", d, false + a = input("?").val + printInColumns2 "navy", e, false + b = input("?").val + printInColumns2 "a. f.", f, false + c = input("?").val + if a+b+c <= 72000 then break +end while + + +print "You attack first. Type (1) for army; (2) for navy;" +print "and (3) for air force." +y = input.val +while true + x = input("How many men? ").val + if x < 0 then continue + if y <= 1 or y > 3 then + // Army attack + if x > a then continue + if x < a/3 then + print "You lost "+x+" men from your army." + a=floor(a-x) + else if x < 2*a/3 then + print "You lost " + floor(x/3) + " men, but I lost " + floor(2*d/3) + a=floor(a-x/3) + d=0 // (message above lied!) + else + print "You sunk one of my patrol boats, but I wiped out two" + print "of your air force bases and 3 army bases." + a=floor(a/3) + c=floor(c/3) + e=floor(2*e/3) + end if + else if y == 2 then + // Naval attack + if x > b then continue + if x < e/3 then + print "Your attack was stopped!" + b = floor(b-x) + else if x < 2*e/3 then + print "You destroyed " + floor(2*e/3) + "of my army." + e=floor(e/3) + else + print "You sunk one of my patrol boats, but I wiped out two" + print "of your air force bases and 3 army bases." + a=floor(a/3) + c=floor(c/3) + e=floor(2*e/3) + end if + else + // Air force attack + if x > c then continue + if x < c/3 then + print "Your attack was wiped out." + c = floor(c-x) + else if x < 2*c/3 then + print "We had a dogfight. You won - and finished your mission." + d=floor(2*d/3) + e=floor(e/3) + f=floor(f/3) + else + print "You wiped out one of my army patrols, but I destroyed" + print "two navy bases and bombed three army bases." + a=floor(a/4) + b=floor(b/3) + d=floor(2*d/3) + end if + end if + break +end while + +result = null // 1 you win, -1 you lose, 0 tie (treaty) +print +printInColumns3 "", "YOU", "ME" +printInColumns3 "army", a, d +printInColumns3 "navy", b, e +printInColumns3 "a. f.", c, f +print "What is your next move?" +print "army=1 navy=2 air force=3" +g = input.val +while true + t = input("How many men? ").val + if t < 0 then continue + if g <= 1 or g > 3 then + // Army attack + if t > a then continue + if t < d/2 then + print "I wiped out your attack!" + a = a-t + else + print "You destroyed my army!" + d=0 + end if + else if g == 2 then + // Naval attack + if t > b then continue + if t < e/2 then + print "I sunk two of your battleships, and my air force" + print "wiped out your ungaurded capitol." // (sic) + a = a/4 + b = b/2 + else + print "Your navy shot down three of my xiii planes," + print "and sunk three battleships." + f = 2*f/3 + e = (e/2) + end if + else + // Air Force attack + if t > c then continue + if t > f/2 then + print "My navy and air force in a combined attack left" + print "your country in shambles." + a = a/3 + b = b/3 + c = c/3 + else + print "One of your planes crashed into my house. I am dead." + print "My country fell apart." + result = 1 + end if + end if + break +end while + +if result == null then + print + print "From the results of both of your attacks," + result = 0 + if a+b+c > 3/2*(d+e+f) then result = 1 + if a+b+c < 2/3*(d+e+f) then result = -1 +end if + +if result == 0 then + print "the treaty of paris concluded that we take our" + print "respective countries and live in peace." +else if result == 1 then + print "You won, oh! shucks!!!!" +else + print "You lost-I conquered your country. It serves you" + print "right for playing this stupid game!!!" +end if diff --git a/28_Combat/README.md b/28_Combat/README.md index 10918fc45..e4463ab23 100644 --- a/28_Combat/README.md +++ b/28_Combat/README.md @@ -15,6 +15,11 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- The original game misspells "unguarded" on line 1751. +- In an initial army attack, the program claims that the computer loses 2/3 of its army, but it actually loses its entire army (lines 150-155). + #### Porting Notes (please note any difficulties or challenges in porting here) From 86df6af1f08a35423f93d52f17ec844eabcbdd0d Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Tue, 1 Aug 2023 00:21:14 -0700 Subject: [PATCH 172/377] Acey Ducey in Nim --- .../01_Acey_Ducey/nim/aceyducey.nim | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim diff --git a/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim b/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim new file mode 100644 index 000000000..a36aacf96 --- /dev/null +++ b/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim @@ -0,0 +1,86 @@ +import std/[random,strutils] + +var + bet, cardA, cardB, cardC, stash: int + retry: bool = true + +proc printGreeting() = + echo(spaces(26),"ACEY DUCEY CARD GAME") + echo(spaces(15),"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + echo("\n") + echo("ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER ") + echo("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP") + echo("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING") + echo("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE") + echo("A VALUE BETWEEN THE FIRST TWO.") + echo("IF YOU DO NOT WANT TO BET, INPUT A 0") + echo("") + +proc printBalance() = + echo("YOU NOW HAVE ", stash," DOLLARS.") + echo("") + +proc printCard(aCard: int) = + case aCard: + of 11: echo("=== JACK ===") + of 12: echo("=== QUEEN ===") + of 13: echo("=== KING ===") + of 14: echo("=== ACE ===") + else: echo("=== ", aCard, " ===") + +proc drawDealerCards() = + echo("HERE ARE YOUR NEXT TWO CARDS: ") + cardA = rand(2..14) + cardB = cardA # Copy cardA, so we can test cardB to be different + while cardB == cardA: + cardB = rand(2..14) + if cardA > cardB: # Make sure cardA is the smaller card + swap(cardA, cardB) + echo("") + printCard(cardA) + echo("") + printCard(cardB) + echo("") + +proc drawPlayerCard() = + cardC = rand(2..14) + printCard(cardC) + echo("") + +proc getBet(): int = + result = stash + 1 #ensure we enter the loop + while (result < 0) or (result > stash): + echo("WHAT IS YOUR BET: ") + result = readLine(stdin).parseInt() + if result > stash: + echo("SORRY, MY FRIEND, BUT YOU BET TOO MUCH.") + echo("YOU HAVE ONLY ", stash," DOLLARS TO BET.") + if bet == 0: + echo("CHICKEN!!") + +proc tryAgain(): bool = + echo("TRY AGAIN (YES OR NO)") + var answer = readLine(stdin).normalize() + case answer: + of "yes", "y": result = true + else: result = false + +printGreeting() +while retry: + stash = 100 + while stash > 0: + printBalance() + drawDealerCards() + bet = getBet() + echo("") + drawPlayerCard() + if (cardC >= cardA) and (cardC <= cardB): + echo("YOU WIN!!!") + stash += bet + else: + echo("SORRY, YOU LOSE") + stash -= bet + echo("SORRY, FRIEND, BUT YOU BLEW YOUR WAD."); + echo("") + retry = tryAgain() +echo("O.K., HOPE YOU HAD FUN!"); From 13d28f51ba26e9558e9a0d7bf42c92cda82955d7 Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Tue, 1 Aug 2023 01:05:45 -0700 Subject: [PATCH 173/377] Nim version of Dice --- 00_Alternate_Languages/33_Dice/nim/dice.nim | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 00_Alternate_Languages/33_Dice/nim/dice.nim diff --git a/00_Alternate_Languages/33_Dice/nim/dice.nim b/00_Alternate_Languages/33_Dice/nim/dice.nim new file mode 100644 index 000000000..e853c3245 --- /dev/null +++ b/00_Alternate_Languages/33_Dice/nim/dice.nim @@ -0,0 +1,36 @@ +import std/[random,strutils] + +var + a,b,r,x: int + f: array[2..12, int] + z: string + retry: bool = true + +echo(spaces(34), "DICE") +echo(spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") +echo("\n") +echo("THIS PROGRAM SIMULATES THE ROLLING OF A PAIR OF DICE.") +echo("YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO") +echo("'ROLL' THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE") +echo("A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000.") + +while(retry): + echo("\n") + echo("HOW MANY ROLLS") + x = readLine(stdin).parseInt() + for s in 1..x: + a = rand(1..6) # Die 1 + b = rand(1..6) # Die 2 + r = a + b # Sum of dice + f[r] += 1 # Increment array count of dice sum result + echo() + echo("TOTAL SPOTS: ", "NUMBER OF TIMES") + for v in 2..12: + echo(v, ": ", f[v]) # Print out counts for each possible result + echo("\n") + echo("TRY AGAIN?") + z = readLine(stdin).normalize() + if (z=="yes") or (z=="y"): + retry = true + else: + retry = false From e0dc9d61ceac71b08a0513d37aa0e62f04eb4d26 Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Tue, 1 Aug 2023 01:35:45 -0700 Subject: [PATCH 174/377] Fix missing array clear in Dice --- 00_Alternate_Languages/33_Dice/nim/dice.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/00_Alternate_Languages/33_Dice/nim/dice.nim b/00_Alternate_Languages/33_Dice/nim/dice.nim index e853c3245..a1e5fa450 100644 --- a/00_Alternate_Languages/33_Dice/nim/dice.nim +++ b/00_Alternate_Languages/33_Dice/nim/dice.nim @@ -18,6 +18,8 @@ while(retry): echo("\n") echo("HOW MANY ROLLS") x = readLine(stdin).parseInt() + for v in 2..12: + f[v] = 0 # Initialize array to 0 for s in 1..x: a = rand(1..6) # Die 1 b = rand(1..6) # Die 2 From 18ea2cd928c41254551601b077d2b4dada8f35dc Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 1 Aug 2023 07:37:02 -0700 Subject: [PATCH 175/377] Added MiniScript version of 30_Cube. --- .../28_Combat/MiniScript/README.md | 4 +- .../30_Cube/MiniScript/README.md | 16 +++ .../30_Cube/MiniScript/cube.ms | 100 ++++++++++++++++++ 30_Cube/README.md | 8 ++ 4 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 00_Alternate_Languages/30_Cube/MiniScript/README.md create mode 100644 00_Alternate_Languages/30_Cube/MiniScript/cube.ms diff --git a/00_Alternate_Languages/28_Combat/MiniScript/README.md b/00_Alternate_Languages/28_Combat/MiniScript/README.md index f9800b1ed..1db41ab16 100644 --- a/00_Alternate_Languages/28_Combat/MiniScript/README.md +++ b/00_Alternate_Languages/28_Combat/MiniScript/README.md @@ -7,10 +7,10 @@ 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 chomp.ms + miniscript combat.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 "chomp" + load "combat" run diff --git a/00_Alternate_Languages/30_Cube/MiniScript/README.md b/00_Alternate_Languages/30_Cube/MiniScript/README.md new file mode 100644 index 000000000..56422df07 --- /dev/null +++ b/00_Alternate_Languages/30_Cube/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 cube.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 "cube" + run diff --git a/00_Alternate_Languages/30_Cube/MiniScript/cube.ms b/00_Alternate_Languages/30_Cube/MiniScript/cube.ms new file mode 100644 index 000000000..1639ce43f --- /dev/null +++ b/00_Alternate_Languages/30_Cube/MiniScript/cube.ms @@ -0,0 +1,100 @@ +print " "*34 + "Bullseye" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +if input("Do you want to see the instructions? (yes--1,no--0) ").val then + print "This is a game in which you will be playing against the" + print "random decision of the computer. The field of play is a" + print "cube of size 3. Any of the locations can be designated" + print "by inputing three numbers such as 2,3,1. At the start," + print "you are automatically at location 1,1,1. The object of" + print "the game is to get to location 3,3,3. One minor detail:" + print "the computer will pick, at random, locations at which" + print "it will plant land mines. If you hit one of these locations" + print "you lose. One other detail: you may move only one space " + print "in one direction each move. For example: from 1,1,2 you" + print "may move to 2,1,2 or 1,1,3. You may not change" + print "two of the numbers on the same move. If you make an illegal" + print "move, you lose and the computer takes the money you may" + print "have bet on that round." + print + print + print "All yes or no questions will be answered by a 1 for yes" + print "or a 0 (zero) for no." + print + print "When stating the amount of a wager, print only the number" + print "of dollars (example: 250). You are automatically started with" + print "500 dollars in your account." + print + print "Good luck!" +end if + +money = 500 + +while money >= 0 + mineLocs = [] + // Note: unlike the original BASIC program, which doesn't actually pick random + // numbers unless you manually set X to a positive value before running the + // program, we do pick five random mine locations here. + // But like that program, we make no attempt to avoid 1,1,1 or 3,3,3, or to + // ensure that we have picked five DIFFERENT locations. + for i in range(1,5) + mineLocs.push [floor(3 * rnd + 1), floor(3 * rnd + 1), floor(3 * rnd + 1)] + end for + wager = 0 + if input("Want to make a wager? ").val then + wager = input("How much? ").val + while money < wager + wager = input("Tried to fool me; bet again? ").val + end while + end if + position = [1,1,1] + print + inp = input("It's your move: ") + won = 0 + while true + inp = inp.replace(",", " ").replace(" ", " ").split + newPos = [] + if inp.len == 3 then newPos = [inp[0].val, inp[1].val, inp[2].val] + legal = newPos.len == 3 + totalChange = 0 + for i in newPos.indexes + // The original game allowed you to walk outside the 1-3 range, + // thus safely avoiding all the mines. To disallow this exploit, + // uncomment the following line. + //if newPos[i] < 1 or newPos[i] > 3 then legal = false + totalChange += abs(newPos[i] - position[i]) + end for + if totalChange > 1 then legal = false + if not legal then + print; print "Illegal move. You lose." + won = -wager + break + end if + if newPos == [3,3,3] then + print "Congratulations!" + won = wager + break + else if mineLocs.indexOf(newPos) != null then + print "******BANG******" + print "You lose!" + print + print + won = -wager + break + end if + position = newPos + inp = input("Next move: ") + end while + if won != 0 then + globals.money += won + if money <= 0 then print "You bust." + end if + if wager then + print " You now have " + money + " dollars." + end if + if not input("Do you want to try again? ").val then break +end while +print "Tough luck!" +print +print "Goodbye." diff --git a/30_Cube/README.md b/30_Cube/README.md index c220c8d4d..a257f1105 100644 --- a/30_Cube/README.md +++ b/30_Cube/README.md @@ -17,6 +17,14 @@ http://www.vintage-basic.net/games.html (please note any difficulties or challenges in porting here) +##### Known Bugs + +This program does very little validation of its input, enabling the user to cheat in two ways: +- One can enter a large negative wager, purposely lose, and gain that much money. +- One can move outside the cube (using coordinates 0 or 4), then safely walk "around" the standard play volume to the destination square. + +It's remotely possible that these are clever solutions the user is intended to find, solving an otherwise purely random game. + ##### Randomization Logic The BASIC code uses an interesting technique for choosing the random coordinates for the mines. The first coordinate is From 2c2b1996edde8f799d3a123e2716a073c417acf5 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 1 Aug 2023 08:19:51 -0700 Subject: [PATCH 176/377] Added MiniScript version of 34_Digits. --- .../34_Digits/MiniScript/README.md | 16 +++ .../34_Digits/MiniScript/digits.ms | 99 +++++++++++++++++++ 34_Digits/README.md | 3 +- 3 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/34_Digits/MiniScript/README.md create mode 100644 00_Alternate_Languages/34_Digits/MiniScript/digits.ms diff --git a/00_Alternate_Languages/34_Digits/MiniScript/README.md b/00_Alternate_Languages/34_Digits/MiniScript/README.md new file mode 100644 index 000000000..290b4b7c8 --- /dev/null +++ b/00_Alternate_Languages/34_Digits/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 digits.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 "digits" + run diff --git a/00_Alternate_Languages/34_Digits/MiniScript/digits.ms b/00_Alternate_Languages/34_Digits/MiniScript/digits.ms new file mode 100644 index 000000000..2abde907d --- /dev/null +++ b/00_Alternate_Languages/34_Digits/MiniScript/digits.ms @@ -0,0 +1,99 @@ +import "listUtil" + +print " "*33 + "Digits" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +printInColumns = function(a, b, c, d) + print (a+" "*16)[:16] + (b+" "*16)[:16] + (c+" "*16)[:16] + (d+" "*16)[:16] +end function + +print "This is a game of guessing." +print "For instructions, type '1', else type '0'" +if input != "0" then + print + print "Please take a piece of paper and write down" + print "the digits '0', '1', or '2' thirty times at random." + print "Arrange them in three lines of ten digits each." + print "I will ask for then ten at a time." + print "I will always guess them first and then look at your" + print "next number to see if i was right. By pure luck," + print "I ought to be right ten times. But i hope to do better" + print "than that *****" + print; print +end if + +a = 0; b = 1; c = 3 + +while true + m = list.init2d(27, 3, 1) + k = list.init2d(3, 3, 9) + l = list.init2d(9, 3, 3) + l[0][0] = 2; l[4][1] = 2; l[8][2] = 2 + z=26; z1=8; z2=2 + qtyRight = 0 + guess = 0 + for t in range(1,3) + while true + print + print "Ten numbers, please"; + n = input.replace(",", " ").replace(" ", "").split + if n.len != 10 then continue + valid = true + for i in n.indexes + n[i] = n[i].val + if n[i] < 0 or n[i] > 2 then + print "Only use the digits '0', '1', or '2'." + print "Let's try again." + valid = false + break + end if + end for + if valid then break + end while + + print; printInColumns "My guess","Your no.","Result","No. right"; print + for u in range(0, 9) + yourNum = n[u]; s=0 + for j in range(0,2) + s1 = a*k[z2][j] + b*l[z1][j] + c*m[z][j] + if s > s1 then continue + if s < s1 or rnd >= 0.5 then + s = s1; guess = j + end if + end for + if guess == yourNum then + outcome = " right" + qtyRight += 1 + else + outcome = " wrong" + end if + printInColumns " "+guess, " " + yourNum, outcome, qtyRight + + m[z][yourNum] += 1 + l[z1][yourNum] += 1 + k[z2][yourNum] += 1 + z -= floor(z/9)*9 + z = 3*z + yourNum + z1 = z - floor(z/9)*9 + z2 = yourNum + end for + end for + + print + if qtyRight > 10 then + print "I guessed more than 1/3 of your numbers." + print "I win." + print char(7) * 10 + else if qtyRight < 10 then + print "I guessed less than 1/3 of your numbers." + print "You beat me. Congratulations *****" + else + print "I guessed exactly 1/3 of your numbers." + print "It's a tie game." + end if + print "Do you want to try again (1 for yes, 0 for no)"; + if input != "1" then break +end while + +print; print "Thanks for the game." diff --git a/34_Digits/README.md b/34_Digits/README.md index 569122c8e..6e82efda5 100644 --- a/34_Digits/README.md +++ b/34_Digits/README.md @@ -18,4 +18,5 @@ http://www.vintage-basic.net/games.html #### Porting Notes -(please note any difficulties or challenges in porting here) +- The program contains a lot of mysterious and seemingly arbitrary constants. It's not clear there is any logic or rationality behind it. +- The key equation involved in the guess (line 700) involves a factor of `A`, but `A` is always 0, making that term meaningless. As a result, all the work to build and update array K and value Z2 appear to be meaningless, too. From 9bc066d31ea5d456fc6d49fb771f414f7a1403f7 Mon Sep 17 00:00:00 2001 From: Jadi Date: Tue, 1 Aug 2023 20:59:04 +0330 Subject: [PATCH 177/377] Added Rust version of 57_Literature_Quiz --- 57_Literature_Quiz/rust/Cargo.toml | 8 ++ 57_Literature_Quiz/rust/README.md | 3 + 57_Literature_Quiz/rust/src/main.rs | 127 ++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 57_Literature_Quiz/rust/Cargo.toml create mode 100644 57_Literature_Quiz/rust/README.md create mode 100644 57_Literature_Quiz/rust/src/main.rs diff --git a/57_Literature_Quiz/rust/Cargo.toml b/57_Literature_Quiz/rust/Cargo.toml new file mode 100644 index 000000000..1ec696335 --- /dev/null +++ b/57_Literature_Quiz/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/57_Literature_Quiz/rust/README.md b/57_Literature_Quiz/rust/README.md new file mode 100644 index 000000000..fc6468b9f --- /dev/null +++ b/57_Literature_Quiz/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) diff --git a/57_Literature_Quiz/rust/src/main.rs b/57_Literature_Quiz/rust/src/main.rs new file mode 100644 index 000000000..a9e3923e5 --- /dev/null +++ b/57_Literature_Quiz/rust/src/main.rs @@ -0,0 +1,127 @@ +use std::io; + + +fn print_instructions() { + println!("TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE."); + println!(); + println!("THIS IS A MULTIPLE-CHOICE QUIZ."); + println!("TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK."); + println!(); + println!("GOOD LUCK!"); + println!(); + println!(); +} + + +fn print_center(text: String, width: usize) { + let pad_size; + if width > text.len() { + pad_size = (width - text.len()) / 2; + } else { + pad_size = 0; + } + println!("{}{}", " ".repeat(pad_size), text); +} + + +fn print_results(score: usize, number_of_questions: usize) { + if score == number_of_questions { + println!("WOW! THAT'S SUPER! YOU REALLY KNOW YOUR NURSERY"); + println!("YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE"); + println!("LITERATURE (HA, HA, HA)"); + } else if score < number_of_questions / 2 { + println!("UGH. THAT WAS DEFINITELY NOT TOO SWIFT. BACK TO"); + println!("NURSERY SCHOOL FOR YOU, MY FRIEND."); + } else { + println!("NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME"); + println!("READING THE NURSERY GREATS."); + } +} + +fn main() { + let page_width: usize = 64; + + struct Question<'a> { + question: &'a str, + choices: Vec<&'a str>, + answer: u8, + correct_response: &'a str, + wrong_response: &'a str, + } + + impl Question<'_>{ + fn ask(&self) -> bool { + println!("{}", self.question); + for i in 0..4 { + print!("{}){}", i+1, self.choices[i]); + if i != 3 { print!(", ")}; + } + println!(""); + let mut user_input: String = String::new(); + io::stdin() + .read_line(&mut user_input) + .expect("Failed to read the line"); + + if user_input.starts_with(&self.answer.to_string()) { + println!("{}", self.correct_response); + true + } else { + println!("{}", self.wrong_response); + false + } + } + } + + let questions: Vec = vec![ + Question{ + question: "IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT?", + choices: vec!["TIGGER", "CICERO", "FIGARO", "GUIPETTO"], + answer: 3, + wrong_response: "SORRY...FIGARO WAS HIS NAME.", + correct_response: "VERY GOOD! HERE'S ANOTHER.", + }, + Question{ + question: "FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?", + choices: vec!["MR. NIXON'S", "ELMER FUDD'S", "CLEM JUDD'S", "STROMBOLI'S"], + answer: 2, + wrong_response: "TOO BAD...IT WAS ELMER FUDD'S GARDEN.", + correct_response: "PRETTY GOOD!", + }, + Question{ + question: "IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED?", + choices: vec!["CICERO", "TRIXIA", "KING", "TOTO"], + answer: 4, + wrong_response: "BACK TO THE BOOKS,...TOTO WAS HIS NAME.", + correct_response: "YEA! YOU'RE A REAL LITERATURE GIANT.", + }, + Question{ + question: "WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE?", + choices: vec!["SLEEPING BEAUTY", "CINDERELLA", "SNOW WHITE", "WENDY"], + answer: 3, + wrong_response: "OH, COME ON NOW...IT WAS SNOW WHITE.", + correct_response: "GOOD MEMORY!", + }, + ]; + let number_of_questions: usize = questions.len(); + + print_center("LITERATURE QUIZ".to_string(), page_width); + print_center("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".to_string(), page_width); + println!(); + println!(); + println!(); + print_instructions(); + + let mut score = 0; + for question in questions { + if question.ask() { + score += 1; + } + println!(); + } + + print_results(score, number_of_questions); + +} + + + From 42b63cd94b2e72f86ad85cd81ceb4fd0091640f6 Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Wed, 2 Aug 2023 02:06:10 -0700 Subject: [PATCH 178/377] Bagels ported to Nim --- .../05_Bagels/nim/bagels.nim | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 00_Alternate_Languages/05_Bagels/nim/bagels.nim diff --git a/00_Alternate_Languages/05_Bagels/nim/bagels.nim b/00_Alternate_Languages/05_Bagels/nim/bagels.nim new file mode 100644 index 000000000..d18669132 --- /dev/null +++ b/00_Alternate_Languages/05_Bagels/nim/bagels.nim @@ -0,0 +1,95 @@ +import std/[random,strutils] + +# BAGLES NUMBER GUESSING GAME +# ORIGINAL SOURCE UNKNOWN BUT SUSPECTED TO BE +# LAWRENCE HALL OF SCIENCE, U.C. BERKELY + +var + a, b: array[1..3, int] + wincount: int = 0 + prompt: string + stillplaying: bool = true + +# Seed 3 unique random numbers; indicate if they're all unique +proc genSeed(): bool = + for i in 1..3: + a[i] = rand(0..9) + if (a[1] == a[2]) or (a[2] == a[3]) or (a[3] == a[1]): + return false + return true + +# Primary game logic +proc playGame() = + var youwin, unique: bool = false + # We want 3 unique random numbers: loop until we get them! + while unique == false: + unique = genSeed() + echo("O.K. I HAVE A NUMBER IN MIND.") + for i in 1..20: + var c, d: int = 0 + echo("GUESS #", i) + prompt = readLine(stdin).normalize() + if (prompt.len() != 3): + echo("TRY GUESSING A THREE-DIGIT NUMBER.") + continue + for z in 1..3: + b[z] = prompt.substr(z-1, z-1).parseInt() # Convert string digits to array ints + if (b[1] == b[2]) or (b[2] == b[3]) or (b[3] == b[1]): + echo("OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND") + echo("HAS NO TWO DIGITS THE SAME.") + # Figure out the PICOs + if (a[1] == b[2]): c += 1 + if (a[1] == b[3]): c += 1 + if (a[2] == b[1]): c += 1 + if (a[2] == b[3]): c += 1 + if (a[3] == b[1]): c += 1 + if (a[3] == b[2]): c += 1 + # Determine FERMIs + for j in 1..3: + if (a[j] == b[j]): d += 1 + # Reveal clues + if (d != 3): + if (c != 0): + for j in 1..c: + echo("PICO") + if (d != 0): + for j in 1..d: + echo("FERMI") + if (c == 0) and (d == 0): + echo("BAGELS") + # If we have 3 FERMIs, we win! + else: + echo("YOU GOT IT!!!") + echo("") + wincount += 1 + youwin = true + break + # Only invoke if we've tried 20 guesses without winning + if (youwin == false): + echo("OH WELL.") + echo("THAT'S TWENTY GUESSES. MY NUMBER WAS ", a[1], a[2], a[3]) + +# main program +echo(spaces(33), "BAGELS") +echo(spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") +echo("\n\n") +echo("WOULD YOU LIKE THE RULES (YES OR NO)") +prompt = readLine(stdin).normalize() +if (prompt.substr(0, 0) == "y"): + echo("I AM THINKING OF A THREE-DIGIT NUMBER. TRY TO GUESS") + echo("MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:") + echo(" PICO - ONE DIGIT CORRECT BUT IN THE WRONG POSITION") + echo(" FERMI - ONE DIGIT CORRECT AND IN THE RIGHT POSITION") + echo(" BAGELS - NO DIGITS CORRECT") + echo("") +while(stillplaying == true): + playGame() + echo("PLAY AGAIN (YES OR NO)") + prompt = readLine(stdin).normalize() + if (prompt.substr(0, 0) != "y"): + stillplaying = false +if wincount > 0: + echo("") + echo("A ", wincount, " POINT BAGELS BUFF!!") +echo("") +echo("HOPE YOU HAD FUN. BYE.") From 82c81afaed52a85e33c67c6e78f1cc63bb23f2bd Mon Sep 17 00:00:00 2001 From: Jadi Date: Wed, 2 Aug 2023 12:43:58 +0330 Subject: [PATCH 179/377] Adding 20_Buzzword in Rust --- 20_Buzzword/rust/Cargo.toml | 9 +++ 20_Buzzword/rust/README.md | 3 + 20_Buzzword/rust/src/main.rs | 112 +++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 20_Buzzword/rust/Cargo.toml create mode 100644 20_Buzzword/rust/README.md create mode 100644 20_Buzzword/rust/src/main.rs diff --git a/20_Buzzword/rust/Cargo.toml b/20_Buzzword/rust/Cargo.toml new file mode 100644 index 000000000..3b1d02f52 --- /dev/null +++ b/20_Buzzword/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" diff --git a/20_Buzzword/rust/README.md b/20_Buzzword/rust/README.md new file mode 100644 index 000000000..fc6468b9f --- /dev/null +++ b/20_Buzzword/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) diff --git a/20_Buzzword/rust/src/main.rs b/20_Buzzword/rust/src/main.rs new file mode 100644 index 000000000..dae4b8198 --- /dev/null +++ b/20_Buzzword/rust/src/main.rs @@ -0,0 +1,112 @@ +use rand::seq::SliceRandom; +use std::io::{self, Write}; + +fn main() { + let words = vec![ + vec![ + "Ability", + "Basal", + "Behavioral", + "Child-centered", + "Differentiated", + "Discovery", + "Flexible", + "Heterogeneous", + "Homogenous", + "Manipulative", + "Modular", + "Tavistock", + "Individualized", + ], + vec![ + "learning", + "evaluative", + "objective", + "cognitive", + "enrichment", + "scheduling", + "humanistic", + "integrated", + "non-graded", + "training", + "vertical age", + "motivational", + "creative", + ], + vec![ + "grouping", + "modification", + "accountability", + "process", + "core curriculum", + "algorithm", + "performance", + "reinforcement", + "open classroom", + "resource", + "structure", + "facility", + "environment", + ], + ]; + + // intro text + println!("\n Buzzword Generator"); + println!("Creative Computing Morristown, New Jersey"); + println!("\n\n"); + println!("This program prints highly acceptable phrases in"); + println!("'educator-speak' that you can work into reports"); + println!("and speeches. Whenever a question mark is printed,"); + println!("type a 'Y' for another phrase or 'N' to quit."); + println!("\n\nHere's the first phrase:"); + + let mut continue_running: bool = true; + + while continue_running { + let mut first_word: bool = true; + for section in &words { + if !first_word { + print!(" "); + } + first_word = false; + print!("{}", section.choose(&mut rand::thread_rng()).unwrap()); + } + print!("\n\n? "); + io::stdout().flush().unwrap(); + + let mut cont_question: String = String::new(); + io::stdin() + .read_line(&mut cont_question) + .expect("Failed to read the line"); + if !cont_question.to_uppercase().starts_with("Y") { + continue_running = false; + } + } + println!("Come back when you need help with another report!\n"); + +} + + +///////////////////////////////////////////////////////////////////////// +// +// Porting Notes +// +// The original program stored all 39 words in one array, then +// built the buzzword phrases by randomly sampling from each of the +// three regions of the array (1-13, 14-26, and 27-39). +// +// Here, we're storing the words for each section in separate +// tuples. That makes it easy to just loop through the sections +// to stitch the phrase together, and it easily accommodates adding +// (or removing) elements from any section. They don't all need to +// be the same length. +// +// The author of this program (and founder of Creative Computing +// magazine) first started working at DEC--Digital Equipment +// Corporation--as a consultant helping the company market its +// computers as educational products. He later was editor of a DEC +// newsletter named "EDU" that focused on using computers in an +// educational setting. No surprise, then, that the buzzwords in +// this program were targeted towards educators! +// +///////////////////////////////////////////////////////////////////////// From 42c780dbb2e158dc18d8cec1a1e55ab780fbf7bd Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 2 Aug 2023 12:29:53 -0700 Subject: [PATCH 180/377] Added MiniScript versions of 35_Even_Wins. --- .../35_Even_Wins/MiniScript/README.md | 28 ++++ .../35_Even_Wins/MiniScript/evenwins.ms | 140 ++++++++++++++++++ .../35_Even_Wins/MiniScript/gameofevenwins.ms | 90 +++++++++++ 3 files changed, 258 insertions(+) create mode 100644 00_Alternate_Languages/35_Even_Wins/MiniScript/README.md create mode 100644 00_Alternate_Languages/35_Even_Wins/MiniScript/evenwins.ms create mode 100644 00_Alternate_Languages/35_Even_Wins/MiniScript/gameofevenwins.ms diff --git a/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md b/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md new file mode 100644 index 000000000..ef01ce022 --- /dev/null +++ b/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md @@ -0,0 +1,28 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Note that this folder (like the original BASIC programs) contains TWO different programs based on the same idea. evenwins.ms plays deterministically; gameofevenwins.ms learns from its failures over multiple games. + +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 evenwins.ms + +or + + miniscript gameofevenwins.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 "evenwins" + run + +or + + load "gameofevenwins" + run diff --git a/00_Alternate_Languages/35_Even_Wins/MiniScript/evenwins.ms b/00_Alternate_Languages/35_Even_Wins/MiniScript/evenwins.ms new file mode 100644 index 000000000..0712b830f --- /dev/null +++ b/00_Alternate_Languages/35_Even_Wins/MiniScript/evenwins.ms @@ -0,0 +1,140 @@ +print " "*31 + "Digits" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print + +y1 = 0 +m1 = 0 +print " This is a two person game called 'Even Wins.'" +print "To play the game, the players need 27 marbles or" +print "other objects on a table." +print +print +print " The 2 players alternate turns, with each player" +print "removing from 1 to 4 marbles on each move. The game" +print "ends when there are no marbles left, and the winner" +print "is the one with an even number of marbles." +print +print +print " The only rules are that (1) you must alternate turns," +print "(2) you must take between 1 and 4 marbles each turn," +print "and (3) you cannot skip a turn." +print +print +print +while true + print " Type a '1' if you want to go first, and type" + print "a '0' if you want me to go first." + c = input.val + print + if c != 0 then + t = 27 + print + print + print + print "Total=" + t + print + print + print "What is your first move?" + m = 0 + else + t = 27 + m = 2 + print + print "Total= " + t + print + m1 += m + t -= m + end if + while true + if m then + print "I pick up " + m + " marbles." + if t == 0 then break + print + print "Total=" + t + print + print " And what is your next move, my total is " + m1 + end if + while true + y = input.val + print + if y < 1 or y > 4 then + print + print "The number of marbles you must take be a positive" + print "integer between 1 and 4." + print + print " What is your next move?" + print + else if y > t then + print " You have tried to take more marbles than there are" + print "left. Try again." + else + break + end if + end while + + y1 += y + t -= y + if t == 0 then break + print "Total=" + t + print + print "Your total is " + y1 + if t < 0.5 then break + r = t % 6 + if y1 % 2 != 0 then + if t >= 4.2 then + if r <= 3.4 then + m = r + 1 + m1 += m + t -= m + else if r < 4.7 or r > 3.5 then + m = 4 + m1 += m + t -= m + else + m = 1 + m1 += m + t -= m + end if + else + m = t + t -= m + print "I pick up " + m + " marbles." + print + print "Total = 0" + m1 += m + break + end if + else + if r < 1.5 or r > 5.3 then + m = 1 + m1 += m + t -= m + else + m = r - 1 + m1 += m + t -= m + if t < 0.2 then + print "I pick up " + m + " marbles." + print + break + end if + end if + end if + end while + print "That is all of the marbles." + print + print " My total is " + m1 + ", your total is " + y1 + print + if m1 % 2 then + print " You won. Do you want to play" + else + print " I won. Do you want to play" + end if + print "again? Type 1 for yes and 0 for no." + a1 = input.val + if a1 == 0 then break + m1 = 0 + y1 = 0 +end while +print +print "OK. See you later" diff --git a/00_Alternate_Languages/35_Even_Wins/MiniScript/gameofevenwins.ms b/00_Alternate_Languages/35_Even_Wins/MiniScript/gameofevenwins.ms new file mode 100644 index 000000000..e533550d1 --- /dev/null +++ b/00_Alternate_Languages/35_Even_Wins/MiniScript/gameofevenwins.ms @@ -0,0 +1,90 @@ +print " "*28 + "Game Of Even Wins" +print " "*15 + "Creative Computing Morristown, New Jersey" +print +print +yesNo = input("Do you want instructions (yes or no)? ").lower +if not yesNo or yesNo[0] != "n" then + print "The game is played as follows:" + print + print "At the beginning of the game, a random number of chips are" + print "placed on the board. The number of chips always starts" + print "as an odd number. On each turn, a player must take one," + print "two, three, or four chips. The winner is the player who" + print "finishes with a total number of chips that is even." + print "The computer starts out knowing only the rules of the" + print "game. It gradually learns to play well. It should be" + print "difficult to beat the computer after twenty games in a row." + print "Try it!!!!" + print + print "To quit at any time, type a '0' as your move." + print +end if + +l = 0 +b = 0 +r = [[4]*6, [4]*6] + +while true + a = 0 + b = 0 + e = 0 + l = 0 + p = floor((13 * rnd + 9) / 2) * 2 + 1; + while true + if p == 1 then + print "There is 1 chip on the board." + else + print "There are " + p + " chips on the board." + end if + e1 = e + l1 = l + e = a % 2 + l = p % 6 + if r[e][l] < p then + m = r[e][l] + if m <= 0 then + m = 1 + b = 1 + break + end if + p -= m + if m == 1 then + prompt = "Computer takes 1 chip leaving " + p + "... Your move? " + else + prompt = "Computer takes " + m + " chips leaving " + p + "... Your move? " + end if + b += m + while true + m = input(prompt).val + if m == 0 then break + if 1 <= m <= p and m <= 4 then break + prompt = m + " is an illegal move ... Your move? " + end while + if m == 0 then break + if m == p then break // <-- Really? Before we've done the math? + p -= m + a += m + else + if p == 1 then + print "Computer takes 1 chip." + else + print "Computer takes " + p + " chips." + end if + r[e][l] = p + b += p + break + end if + end while + if m == 0 then break + if b % 2 != 0 then + print "Game over ... you win!!!" + if r[e][l] != 1 then + r[e][l] -= 1 + else if (r[e1][l1] != 1) then + r[e1][l1] -= 1 + end if + else + print "Game over ... I win!!!" + end if + print +end while From e5683b085aaebbee53a2b9a9a75e1d9c4093a985 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 2 Aug 2023 15:54:02 -0700 Subject: [PATCH 181/377] Added MiniScript version of 36_Flip_Flop. (This game is too hard for me!) --- .../36_Flip_Flop/MiniScript/README.md | 19 ++++ .../36_Flip_Flop/MiniScript/flipflop.ms | 97 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md create mode 100644 00_Alternate_Languages/36_Flip_Flop/MiniScript/flipflop.ms diff --git a/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md b/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md new file mode 100644 index 000000000..d6ee2a4ef --- /dev/null +++ b/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of flipflop.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 flipflop.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 "flipflop" + run diff --git a/00_Alternate_Languages/36_Flip_Flop/MiniScript/flipflop.ms b/00_Alternate_Languages/36_Flip_Flop/MiniScript/flipflop.ms new file mode 100644 index 000000000..6fb07cc0a --- /dev/null +++ b/00_Alternate_Languages/36_Flip_Flop/MiniScript/flipflop.ms @@ -0,0 +1,97 @@ +print " "*32 + "FlipFlop" +print " "*15 + "Creative Computing Morristown, New Jersey" +print +// Created by Michael Cass (1978) +// Ported to MiniScript by Joe Strout (2023) + +print "The object of this puzzle is to change this:" +print +print "X X X X X X X X X X" +print +print "to this:" +print +print "O O O O O O O O O O" +print +print "By typing the number corresponding to the position of the" +print "letter on some numbers, one position will change, on" +print "others, two will change. To reset line to all X's, type 0" +print "(zero) and to start over in the middle of a game, type " +print "11 (eleven)." +print + +startNewGame = function + globals.q = rnd + globals.guesses = 0 + print "Here is the starting line of X's." + print + print "1 2 3 4 5 6 7 8 9 10" + print "X X X X X X X X X X" + print +end function + +getInput = function + while true + n = input("Input the number: ").val + if n == floor(n) and 0 <= n <= 11 then break + print "Illegal entry--try again." + end while + return n +end function + +startNewGame +while true + A = [""] + ["X"] * 10 // (include empty 0th element so we can index 1-based + m = 0 // (previous input) + while true + n = getInput + if n == 11 then + startNewGame + continue + else if n == 0 then + A = ["X"] * 10 + continue + end if + + if n != m then + // when user enters a different number from previous time + m = n + if A[n] == "O" then A[n] = "X" else A[n] = "O" + while m == n + r = tan(q + n/q - n) - sin(q/n) + 336*sin(8*n) + n = floor(10 * (r - floor(r))) + if A[n] != "O" then + A[n] = "O" + break + end if + A[n] = "X" + end while + else + // when n == m, i.e., user entered the same number twice in a row + while m == n + if A[n] == "O" then A[n] = "X" else A[n] = "O" + r = 0.592 * (1 / tan(q/n + q)) / sin(n*2 + q) - cos(n) + n = floor(10 * (r - floor(r))) + if A[n] != "O" then + A[n] = "O" + break + end if + A[n] = "X" + end while + end if + + print "1 2 3 4 5 6 7 8 9 10" + print A[1:].join + guesses += 1 + if A[1:] == ["O"]*10 then break + end while + + if guesses <= 12 then + print "Very good. You guessed it in only " + guesses + " guesses." + else + print "Try harder next time. It took you " + guesses + " guesses." + end if + + yesNo = input("Do you want to try another puzzle? ").lower + if not yesNo or yesNo[0] == "n" then break + print +end while From 575c183fc70310b8e01eb1924a50bcb29620dd8e Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 2 Aug 2023 15:58:56 -0700 Subject: [PATCH 182/377] Corrected README for MiniScript FlipFlop. --- 00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md b/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md index d6ee2a4ef..911c1441b 100644 --- a/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md +++ b/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md @@ -4,9 +4,6 @@ Conversion to [MiniScript](https://miniscript.org). Ways to play: -0. Try-It! Page: -Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of flipflop.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. - 1. Command-Line MiniScript: Download for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as: From c4960df508bcdc3b647916f81b11d15356dd305b Mon Sep 17 00:00:00 2001 From: azemetre Date: Wed, 2 Aug 2023 21:30:06 -0400 Subject: [PATCH 183/377] docs: adding table of language completions --- README.md | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/README.md b/README.md index c56d18862..b4532cf8b 100644 --- a/README.md +++ b/README.md @@ -71,3 +71,108 @@ Please note that on the back of the Basic Computer Games book it says **Microsof Thank you for taking part in this project to update a classic programming book – one of the most influential programming books in computing history – for 2022 and beyond! NOTE: per [the official blog post announcement](https://blog.codinghorror.com/updating-the-single-most-influential-book-of-the-basic-era/), I will be **donating $5 for each contributed program in the 10 agreed upon languages to [Girls Who Code](https://girlswhocode.com/)**. + +### Current Progress + +
toggle for game by language table + +| Name | csharp | java | javascript | kotlin | lua | perl | python | ruby | rust | vbnet | +| ---------------------- | ------ | ---- | ---------- | ------ | --- | ---- | ------ | ---- | ---- | ----- | +| 01_Acey_Ducey | x | x | x | x | x | x | x | x | x | x | +| 02_Amazing | x | x | x | | | x | x | x | x | x | +| 03_Animal | x | x | x | x | x | x | x | x | x | x | +| 04_Awari | x | x | x | | | x | x | x | x | x | +| 05_Bagels | x | x | x | x | x | x | x | x | x | x | +| 06_Banner | x | x | x | | | x | x | x | | x | +| 07_Basketball | x | x | x | | | x | x | x | | x | +| 08_Batnum | x | x | x | | | x | x | x | | x | +| 09_Battle | x | x | x | | | | x | | | x | +| 10_Blackjack | x | x | x | | | | x | x | x | x | +| 11_Bombardment | x | x | x | | | x | x | x | x | x | +| 12_Bombs_Away | x | x | x | | x | x | x | | | x | +| 13_Bounce | x | x | x | | | x | x | x | | x | +| 14_Bowling | x | x | x | | | x | x | | | x | +| 15_Boxing | x | x | x | | | x | x | | | x | +| 16_Bug | x | x | x | | | | x | x | | x | +| 17_Bullfight | x | | x | x | | | x | | | x | +| 18_Bullseye | x | x | x | | | x | x | | x | x | +| 19_Bunny | x | x | x | | | x | x | x | | x | +| 20_Buzzword | x | x | x | | x | x | x | x | x | x | +| 21_Calendar | x | x | x | | | x | x | x | x | x | +| 22_Change | x | x | x | | | x | x | | x | x | +| 23_Checkers | x | | x | | | x | x | x | | x | +| 24_Chemist | x | x | x | | | x | x | | x | x | +| 25_Chief | x | x | x | | x | x | x | x | | x | +| 26_Chomp | x | x | x | | | x | x | | | x | +| 27_Civil_War | x | x | x | | | | x | | | x | +| 28_Combat | x | x | x | | | x | x | | | x | +| 29_Craps | x | x | x | | x | x | x | x | x | x | +| 30_Cube | x | x | x | | | | x | x | x | x | +| 31_Depth_Charge | x | x | x | | | x | x | x | | x | +| 32_Diamond | x | x | x | x | | x | x | x | x | x | +| 33_Dice | x | x | x | | x | x | x | x | x | x | +| 34_Digits | x | x | x | | | x | x | | | x | +| 35_Even_Wins | x | | x | | | x | x | | x | x | +| 36_Flip_Flop | x | x | x | | | x | x | x | x | x | +| 37_Football | x | | x | | | | x | | | x | +| 38_Fur_Trader | x | x | x | | | x | x | | | x | +| 39_Golf | x | | x | | | | x | | | x | +| 40_Gomoko | x | x | x | | | x | x | | | x | +| 41_Guess | x | x | x | | | x | x | x | x | x | +| 42_Gunner | x | x | x | | | x | x | | | x | +| 43_Hammurabi | x | x | x | | | | x | | | x | +| 44_Hangman | x | x | x | | | x | x | x | | x | +| 45_Hello | x | x | x | | x | x | x | x | | x | +| 46_Hexapawn | x | | | | | | x | | | x | +| 47_Hi-Lo | x | | x | x | x | x | x | x | x | x | +| 48_High_IQ | x | x | x | | | | x | | | x | +| 49_Hockey | x | | x | | | | x | | | x | +| 50_Horserace | x | | x | | | | | | x | x | +| 51_Hurkle | x | x | x | | | x | x | x | x | x | +| 52_Kinema | x | x | x | | | x | x | x | | x | +| 53_King | x | | x | | | | x | | | x | +| 54_Letter | x | x | x | | | x | x | x | x | x | +| 55_Life | x | x | x | | | x | x | x | x | x | +| 56_Life_for_Two | x | x | x | | | x | x | | | x | +| 57_Literature_Quiz | x | x | x | | | x | x | | x | x | +| 58_Love | x | x | x | | | x | x | x | | x | +| 59_Lunar_LEM_Rocket | x | | x | | | | x | | x | x | +| 60_Mastermind | x | x | x | | | x | x | | x | x | +| 61_Math_Dice | x | x | x | | | x | x | x | x | x | +| 62_Mugwump | x | x | x | | | x | x | | x | x | +| 63_Name | x | x | x | x | | x | x | x | | x | +| 64_Nicomachus | x | x | x | | | x | x | | x | x | +| 65_Nim | x | | x | | | | x | x | x | x | +| 66_Number | x | x | x | | | x | x | | x | x | +| 67_One_Check | x | x | x | | | x | x | | | x | +| 68_Orbit | x | x | x | | | x | x | x | x | x | +| 69_Pizza | x | x | x | | | x | x | x | | x | +| 70_Poetry | x | x | x | | | x | x | x | | x | +| 71_Poker | x | x | x | | | | | | | x | +| 72_Queen | x | | x | | | x | x | | x | x | +| 73_Reverse | x | x | x | | | x | x | x | | x | +| 74_Rock_Scissors_Paper | x | x | x | x | | x | x | x | x | x | +| 75_Roulette | x | x | x | | | x | x | | x | x | +| 76_Russian_Roulette | x | x | x | x | | x | x | x | x | x | +| 77_Salvo | x | | x | | | | x | | | x | +| 78_Sine_Wave | x | x | x | x | | x | x | x | x | x | +| 79_Slalom | x | | x | | | | x | | | x | +| 80_Slots | x | x | x | | | x | x | x | | x | +| 81_Splat | x | x | x | | | x | x | | x | x | +| 82_Stars | x | x | x | | | x | x | x | x | x | +| 83_Stock_Market | x | x | x | | | | x | | | x | +| 84_Super_Star_Trek | x | x | x | | | | x | | x | x | +| 85_Synonym | x | x | x | | | x | x | x | | x | +| 86_Target | x | x | x | | | x | x | | | x | +| 87_3-D_Plot | x | x | x | | | x | x | x | | x | +| 88_3-D_Tic-Tac-Toe | x | | x | | | | x | | | x | +| 89_Tic-Tac-Toe | x | x | x | x | | x | x | | x | x | +| 90_Tower | x | x | x | | | x | x | | x | x | +| 91_Train | x | x | x | | | x | x | x | x | x | +| 92_Trap | x | x | x | | | x | x | x | x | x | +| 93_23_Matches | x | x | x | | | x | x | x | | x | +| 94_War | x | x | x | x | | x | x | x | x | x | +| 95_Weekday | x | x | x | | | x | x | | x | x | +| 96_Word | x | x | x | | | x | x | x | x | x | + +
From 340eefe778bd0cafcc99b4c597c78ef35a5bdae6 Mon Sep 17 00:00:00 2001 From: Jadi Date: Fri, 4 Aug 2023 14:59:28 +0330 Subject: [PATCH 184/377] Adding Rust for 85-Synonyms --- 85_Synonym/rust/Cargo.toml | 9 ++++ 85_Synonym/rust/README.md | 3 ++ 85_Synonym/rust/src/main.rs | 102 ++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 85_Synonym/rust/Cargo.toml create mode 100644 85_Synonym/rust/README.md create mode 100644 85_Synonym/rust/src/main.rs diff --git a/85_Synonym/rust/Cargo.toml b/85_Synonym/rust/Cargo.toml new file mode 100644 index 000000000..3b1d02f52 --- /dev/null +++ b/85_Synonym/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" diff --git a/85_Synonym/rust/README.md b/85_Synonym/rust/README.md new file mode 100644 index 000000000..4c54b94cb --- /dev/null +++ b/85_Synonym/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) by [Jadi](https://github.com/jadijadi) diff --git a/85_Synonym/rust/src/main.rs b/85_Synonym/rust/src/main.rs new file mode 100644 index 000000000..184f51bd9 --- /dev/null +++ b/85_Synonym/rust/src/main.rs @@ -0,0 +1,102 @@ +use rand::seq::SliceRandom; +use rand::thread_rng; +use rand::Rng; +use std::io::{self, Write}; + +fn print_centered(text: &str, width: usize) { + let pad_size: usize = if width > text.len() { + (width - text.len()) / 2 + } else { + 0 + }; + println!("{}{}", " ".repeat(pad_size), text); +} + +fn print_instructions() { + println!("A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH"); + println!("LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME MEANING."); + println!("I CHOOSE A WORD -- YOU TYPE A SYNONYM."); + println!("IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'"); + println!("AND I WILL TELL YOU A SYNONYM.\n"); +} + +fn ask_question(mut this_question: Vec<&str>) { + let right_words = ["RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK"]; + + // use the first one in the main question + let base_word = this_question.remove(0); + + loop { + print!(" WHAT IS A SYNONYM OF {base_word}? "); + io::stdout().flush().unwrap(); + let mut answer: String = String::new(); + io::stdin() + .read_line(&mut answer) + .expect("Failed to read the line"); + let answer = answer.trim(); + if answer == "HELP" { + // remove one random from the answers and show it + let random_index = thread_rng().gen_range(0..this_question.len()); + println!( + "**** A SYNONYM OF {base_word} IS {}.", + this_question.remove(random_index) + ); + } else if this_question.contains(&answer) { + println!("{}", right_words.choose(&mut rand::thread_rng()).unwrap()); + break; + } + } +} + +fn main() { + const PAGE_WIDTH: usize = 64; + + let mut synonyms = vec![ + vec!["FIRST", "START", "BEGINNING", "ONSET", "INITIAL"], + vec!["SIMILAR", "ALIKE", "SAME", "LIKE", "RESEMBLING"], + vec!["MODEL", "PATTERN", "PROTOTYPE", "STANDARD", "CRITERION"], + vec!["SMALL", "INSIGNIFICANT", "LITTLE", "TINY", "MINUTE"], + vec!["STOP", "HALT", "STAY", "ARREST", "CHECK", "STANDSTILL"], + vec![ + "HOUSE", + "DWELLING", + "RESIDENCE", + "DOMICILE", + "LODGING", + "HABITATION", + ], + vec!["PIT", "HOLE", "HOLLOW", "WELL", "GULF", "CHASM", "ABYSS"], + vec!["PUSH", "SHOVE", "THRUST", "PROD", "POKE", "BUTT", "PRESS"], + vec!["RED", "ROUGE", "SCARLET", "CRIMSON", "FLAME", "RUBY"], + vec![ + "PAIN", + "SUFFERING", + "HURT", + "MISERY", + "DISTRESS", + "ACHE", + "DISCOMFORT", + ], + ]; + + synonyms.shuffle(&mut thread_rng()); + + print_centered("SYNONYM", PAGE_WIDTH); + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY", PAGE_WIDTH); + println!("\n\n\n"); + + print_instructions(); + + for this_question in synonyms { + ask_question(this_question) + } + println!("SYNONYM DRILL COMPLETED."); +} + +//////////////////////////////////////////////////////////// +// Poring Notes +// Poring Note: The "HELP" function .removes a variable +// from lists and shows it. This can lead to errors when +// the list becomes empty. But since the same issue happens +// on the original BASIC program, kept it intact +//////////////////////////////////////////////////////////// From 168e07261537eea7ea1eef079f10cc8c356f99f8 Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Fri, 4 Aug 2023 16:58:25 -0700 Subject: [PATCH 185/377] Nim code more idiomatic; fix errors --- .../01_Acey_Ducey/nim/aceyducey.nim | 84 +++++++++---------- .../05_Bagels/nim/bagels.nim | 60 ++++++------- 00_Alternate_Languages/33_Dice/nim/dice.nim | 33 ++++---- 3 files changed, 87 insertions(+), 90 deletions(-) diff --git a/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim b/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim index a36aacf96..ed180de4e 100644 --- a/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim +++ b/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim @@ -5,65 +5,65 @@ var retry: bool = true proc printGreeting() = - echo(spaces(26),"ACEY DUCEY CARD GAME") - echo(spaces(15),"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - echo("\n") - echo("ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER ") - echo("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP") - echo("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING") - echo("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE") - echo("A VALUE BETWEEN THE FIRST TWO.") - echo("IF YOU DO NOT WANT TO BET, INPUT A 0") - echo("") + echo spaces(26),"ACEY DUCEY CARD GAME" + echo spaces(15),"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + echo """ + +ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER +THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP +YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING +ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE +A VALUE BETWEEN THE FIRST TWO. +IF YOU DO NOT WANT TO BET, INPUT A 0 + +""" proc printBalance() = - echo("YOU NOW HAVE ", stash," DOLLARS.") - echo("") + echo "YOU NOW HAVE ", stash," DOLLARS." + echo "" proc printCard(aCard: int) = case aCard: - of 11: echo("=== JACK ===") - of 12: echo("=== QUEEN ===") - of 13: echo("=== KING ===") - of 14: echo("=== ACE ===") - else: echo("=== ", aCard, " ===") + of 11: echo "=== JACK ===" + of 12: echo "=== QUEEN ===" + of 13: echo "=== KING ===" + of 14: echo "=== ACE ===" + else: echo "=== ", aCard, " ===" proc drawDealerCards() = - echo("HERE ARE YOUR NEXT TWO CARDS: ") + echo "HERE ARE YOUR NEXT TWO CARDS: " cardA = rand(2..14) cardB = cardA # Copy cardA, so we can test cardB to be different while cardB == cardA: cardB = rand(2..14) if cardA > cardB: # Make sure cardA is the smaller card - swap(cardA, cardB) - echo("") - printCard(cardA) - echo("") - printCard(cardB) - echo("") + swap cardA, cardB + echo "" + printCard cardA + echo "" + printCard cardB + echo "" proc drawPlayerCard() = - cardC = rand(2..14) - printCard(cardC) - echo("") + cardC = rand 2..14 + printCard cardC + echo "" proc getBet(): int = result = stash + 1 #ensure we enter the loop while (result < 0) or (result > stash): - echo("WHAT IS YOUR BET: ") + echo "WHAT IS YOUR BET: " result = readLine(stdin).parseInt() if result > stash: - echo("SORRY, MY FRIEND, BUT YOU BET TOO MUCH.") - echo("YOU HAVE ONLY ", stash," DOLLARS TO BET.") - if bet == 0: - echo("CHICKEN!!") + echo "SORRY, MY FRIEND, BUT YOU BET TOO MUCH." + echo "YOU HAVE ONLY ", stash, " DOLLARS TO BET." + if result == 0: + echo "CHICKEN!!" proc tryAgain(): bool = - echo("TRY AGAIN (YES OR NO)") + echo "TRY AGAIN (YES OR NO)" var answer = readLine(stdin).normalize() - case answer: - of "yes", "y": result = true - else: result = false + result = (answer == "y") or (answer == "yes") printGreeting() while retry: @@ -72,15 +72,15 @@ while retry: printBalance() drawDealerCards() bet = getBet() - echo("") + echo "" drawPlayerCard() if (cardC >= cardA) and (cardC <= cardB): - echo("YOU WIN!!!") + echo "YOU WIN!!!" stash += bet else: - echo("SORRY, YOU LOSE") + echo "SORRY, YOU LOSE" stash -= bet - echo("SORRY, FRIEND, BUT YOU BLEW YOUR WAD."); - echo("") + echo "SORRY, FRIEND, BUT YOU BLEW YOUR WAD." + echo "" retry = tryAgain() -echo("O.K., HOPE YOU HAD FUN!"); +echo "O.K., HOPE YOU HAD FUN!" diff --git a/00_Alternate_Languages/05_Bagels/nim/bagels.nim b/00_Alternate_Languages/05_Bagels/nim/bagels.nim index d18669132..dd260e3da 100644 --- a/00_Alternate_Languages/05_Bagels/nim/bagels.nim +++ b/00_Alternate_Languages/05_Bagels/nim/bagels.nim @@ -24,19 +24,19 @@ proc playGame() = # We want 3 unique random numbers: loop until we get them! while unique == false: unique = genSeed() - echo("O.K. I HAVE A NUMBER IN MIND.") + echo "O.K. I HAVE A NUMBER IN MIND." for i in 1..20: var c, d: int = 0 - echo("GUESS #", i) + echo "GUESS #", i prompt = readLine(stdin).normalize() if (prompt.len() != 3): - echo("TRY GUESSING A THREE-DIGIT NUMBER.") + echo "TRY GUESSING A THREE-DIGIT NUMBER." continue for z in 1..3: b[z] = prompt.substr(z-1, z-1).parseInt() # Convert string digits to array ints if (b[1] == b[2]) or (b[2] == b[3]) or (b[3] == b[1]): - echo("OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND") - echo("HAS NO TWO DIGITS THE SAME.") + echo "OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND" + echo "HAS NO TWO DIGITS THE SAME." # Figure out the PICOs if (a[1] == b[2]): c += 1 if (a[1] == b[3]): c += 1 @@ -51,45 +51,45 @@ proc playGame() = if (d != 3): if (c != 0): for j in 1..c: - echo("PICO") + echo "PICO" if (d != 0): for j in 1..d: - echo("FERMI") + echo "FERMI" if (c == 0) and (d == 0): - echo("BAGELS") + echo "BAGELS" # If we have 3 FERMIs, we win! else: - echo("YOU GOT IT!!!") - echo("") + echo "YOU GOT IT!!!" + echo "" wincount += 1 youwin = true break # Only invoke if we've tried 20 guesses without winning - if (youwin == false): - echo("OH WELL.") - echo("THAT'S TWENTY GUESSES. MY NUMBER WAS ", a[1], a[2], a[3]) + if not youwin: + echo "OH WELL." + echo "THAT'S TWENTY GUESSES. MY NUMBER WAS ", a[1], a[2], a[3] # main program -echo(spaces(33), "BAGELS") -echo(spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") -echo("\n\n") -echo("WOULD YOU LIKE THE RULES (YES OR NO)") +echo spaces(33), "BAGELS" +echo spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +echo "\n\n" +echo "WOULD YOU LIKE THE RULES (YES OR NO)" prompt = readLine(stdin).normalize() -if (prompt.substr(0, 0) == "y"): - echo("I AM THINKING OF A THREE-DIGIT NUMBER. TRY TO GUESS") - echo("MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:") - echo(" PICO - ONE DIGIT CORRECT BUT IN THE WRONG POSITION") - echo(" FERMI - ONE DIGIT CORRECT AND IN THE RIGHT POSITION") - echo(" BAGELS - NO DIGITS CORRECT") - echo("") +if prompt.substr(0, 0) == "y": + echo "I AM THINKING OF A THREE-DIGIT NUMBER. TRY TO GUESS" + echo "MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:" + echo " PICO - ONE DIGIT CORRECT BUT IN THE WRONG POSITION" + echo " FERMI - ONE DIGIT CORRECT AND IN THE RIGHT POSITION" + echo " BAGELS - NO DIGITS CORRECT" + echo "" while(stillplaying == true): playGame() - echo("PLAY AGAIN (YES OR NO)") + echo "PLAY AGAIN (YES OR NO)" prompt = readLine(stdin).normalize() - if (prompt.substr(0, 0) != "y"): + if prompt.substr(0, 0) != "y": stillplaying = false if wincount > 0: - echo("") - echo("A ", wincount, " POINT BAGELS BUFF!!") -echo("") -echo("HOPE YOU HAD FUN. BYE.") + echo "" + echo "A ", wincount, " POINT BAGELS BUFF!!" +echo "" +echo "HOPE YOU HAD FUN. BYE." diff --git a/00_Alternate_Languages/33_Dice/nim/dice.nim b/00_Alternate_Languages/33_Dice/nim/dice.nim index a1e5fa450..f19903a18 100644 --- a/00_Alternate_Languages/33_Dice/nim/dice.nim +++ b/00_Alternate_Languages/33_Dice/nim/dice.nim @@ -6,17 +6,17 @@ var z: string retry: bool = true -echo(spaces(34), "DICE") -echo(spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") -echo("\n") -echo("THIS PROGRAM SIMULATES THE ROLLING OF A PAIR OF DICE.") -echo("YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO") -echo("'ROLL' THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE") -echo("A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000.") +echo spaces(34), "DICE" +echo spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +echo "\n" +echo "THIS PROGRAM SIMULATES THE ROLLING OF A PAIR OF DICE." +echo "YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO" +echo "'ROLL' THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE" +echo "A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000." while(retry): - echo("\n") - echo("HOW MANY ROLLS") + echo "\n" + echo "HOW MANY ROLLS" x = readLine(stdin).parseInt() for v in 2..12: f[v] = 0 # Initialize array to 0 @@ -25,14 +25,11 @@ while(retry): b = rand(1..6) # Die 2 r = a + b # Sum of dice f[r] += 1 # Increment array count of dice sum result - echo() - echo("TOTAL SPOTS: ", "NUMBER OF TIMES") + echo "" + echo "TOTAL SPOTS: ", "NUMBER OF TIMES" for v in 2..12: - echo(v, ": ", f[v]) # Print out counts for each possible result - echo("\n") - echo("TRY AGAIN?") + echo v, ": ", f[v] # Print out counts for each possible result + echo "\n" + echo "TRY AGAIN?" z = readLine(stdin).normalize() - if (z=="yes") or (z=="y"): - retry = true - else: - retry = false + retry = (z=="yes") or (z=="y") From 44e47744d7d6a8bf9b4db46e261e203d2a5e63d7 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Fri, 4 Aug 2023 21:46:43 -0700 Subject: [PATCH 186/377] Added MiniScript verions of 37_Football and 38_Fur_Trader. --- .../37_Football/MiniScript/README.md | 30 ++ .../37_Football/MiniScript/football.ms | 402 ++++++++++++++++ .../37_Football/MiniScript/ftball.ms | 431 ++++++++++++++++++ .../38_Fur_Trader/MiniScript/README.md | 16 + .../38_Fur_Trader/MiniScript/furtrader.ms | 171 +++++++ 38_Fur_Trader/README.md | 4 + 6 files changed, 1054 insertions(+) create mode 100644 00_Alternate_Languages/37_Football/MiniScript/README.md create mode 100644 00_Alternate_Languages/37_Football/MiniScript/football.ms create mode 100644 00_Alternate_Languages/37_Football/MiniScript/ftball.ms create mode 100644 00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md create mode 100644 00_Alternate_Languages/38_Fur_Trader/MiniScript/furtrader.ms diff --git a/00_Alternate_Languages/37_Football/MiniScript/README.md b/00_Alternate_Languages/37_Football/MiniScript/README.md new file mode 100644 index 000000000..ade04dd8b --- /dev/null +++ b/00_Alternate_Languages/37_Football/MiniScript/README.md @@ -0,0 +1,30 @@ +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 football.ms +or + miniscript ftball.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 "football" + run +or + load "ftball" + run + + +#### Apology from the Translator + +These MiniScript programs were actually ported from the JavaScript ports of the original BASIC programs. I did that because the BASIC code (of both programs) was incomprehensible spaghetti. The JavaScript port, however, was essentially the same — and so are the MiniScript ports. The very structure of these programs makes them near-impossible to untangle. + +If I were going to write a football simulation from scratch, I would approach it very differently. But in that case I would have either a detailed specification of how the program should behave, or at least enough understanding of American football to design it myself as I go. Neither is the case here (and we're supposed to be porting the original programs, not making up our own). + +So, I'm sorry. Please take these programs as proof that you can write bad code even in the most simple, elegant languages. And I promise to try harder on future translations! diff --git a/00_Alternate_Languages/37_Football/MiniScript/football.ms b/00_Alternate_Languages/37_Football/MiniScript/football.ms new file mode 100644 index 000000000..e2b4583f6 --- /dev/null +++ b/00_Alternate_Languages/37_Football/MiniScript/football.ms @@ -0,0 +1,402 @@ +player_data = [17,8,4,14,19,3,10,1,7,11,15,9,5,20,13,18,16,2,12,6, + 20,2,17,5,8,18,12,11,1,4,19,14,10,7,9,15,6,13,16,3] +aa = [0]*21 +ba = [0]*21 +ca = [0]*41 +ha = [0]*3 +ta = [0]*3 +wa = [0]*3 +xa = [0]*3 +ya = [0]*3 +za = [0]*3 +ms = [null, "",""] +da = [0]*3 +ps = ["", "PITCHOUT","TRIPLE REVERSE","DRAW","QB SNEAK","END AROUND", + "DOUBLE REVERSE","LEFT SWEEP","RIGHT SWEEP","OFF TACKLE", + "WISHBONE OPTION","FLARE PASS","SCREEN PASS", + "ROLL OUT OPTION","RIGHT CURL","LEFT CURL","WISHBONE OPTION", + "SIDELINE PASS","HALF-BACK OPTION","RAZZLE-DAZZLE","BOMB!!!!"] +globals.p = 0 +globals.t = 0 + +printFieldHeaders = function + print "TEAM 1 [0 10 20 30 40 50 60 70 80 90 100] TEAM 2" + print +end function + +printSeparator = function + print "+" * 67 +end function + +showBall = function + print " " * (da[t] + 5 + p / 2) + ms[t] + printFieldHeaders +end function + +showScores = function + print + print "TEAM 1 SCORE IS " + ha[1] + print "TEAM 2 SCORE IS " + ha[2] + print + if ha[t] >= e then + print "TEAM " + t + " WINS*******************" + return true + end if + return false +end function + +losePossession = function + print + print "** LOSS OF POSSESSION FROM TEAM " + t + " TO TEAM " + ta[t] + print + printSeparator + print + globals.t = ta[t] +end function + +touchdown = function + print + print "TOUCHDOWN BY TEAM " + t + " *********************YEA TEAM" + q = 7 + if rnd <= 0.1 then + q = 6 + print "EXTRA POINT NO GOOD" + else + print "EXTRA POINT GOOD" + end if + ha[t] += q +end function + +askYesNo = function(prompt) + while true + yn = input(prompt + "? ").lower + if not yn then continue + if yn[0] == "y" then return "YES" + if yn[0] == "n" then return "NO" + end while +end function + + +print " "*32 + "FOOTBALL" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "Presenting N.F.U. Football (No FORTRAN Used)" +print; print +if askYesNo("Do you want instructions") == "YES" then + print "This is a football game for two teams in which players must" + print "prepare a tape with a data statement (1770 for team 1," + print "1780 for team 2) in which each team scrambles nos. 1-20" + print "These numbers are then assigned to twenty given plays." + print "A list of nos. and their plays is provided with" + print "both teams having the same plays. The more similar the" + print "plays the less yardage gained. Scores are given" + print "whenever scores are made. Scores may also be obtained" + print "by inputting 99,99 for play nos. To punt or attempt a" + print "field goal, input 77,77 for play numbers. Questions will be" + print "asked then. On 4th down, you will also be asked whether" + print "you want to punt or attempt a field goal. If the answer to" + print "both questions is no it will be assumed you want to" + print "try and gain yardage. Answer all questions Yes or No." + print "The game is played until players terminate (control-c)." + print "Please prepare a tape and run." +end if +print +e = input("Please input score limit on game: ").val +for i in range(1, 40) + if i <= 20 then + aa[player_data[i - 1]] = i + else + ba[player_data[i - 1]] = i - 20 + end if + ca[i] = player_data[i - 1] +end for +l = 0 +globals.t = 1 +while true + print "TEAM " + t + " PLAY CHART" + print "NO. PLAY" + for i in range(1, 20) + print (ca[i+1] + " "*6)[:6] + ps[i] + end for + l += 20 + globals.t = 2 + print + print "TEAR OFF HERE----------------------------------------------" + for x in range(1, 11); print; end for + wait 3 + if l != 20 then break +end while + +playGame = function + da[1] = 0 + da[2] = 3 + ms[1] = "--->" + ms[2] = "<---" + ha[1] = 0 + ha[2] = 0 + ta[1] = 2 + ta[2] = 1 + wa[1] = -1 + wa[2] = 1 + xa[1] = 100 + xa[2] = 0 + ya[1] = 1 + ya[2] = -1 + za[1] = 0 + za[2] = 100 + globals.p = 0 + printFieldHeaders + print "TEAM 1 defend 0 YD goal -- TEAM 2 defends 100 YD goal." + globals.t = floor(2 * rnd + 1) + print + print "The coin is flipped" + routine = 1 + while true + if routine <= 1 then + globals.p = xa[t] - ya[t] * 40 + printSeparator + print + print "Team " + t + " receives kick-off" + k = floor(26 * rnd + 40) + end if + if routine <= 2 then + globals.p = p - ya[t] * k + end if + if routine <= 3 then + if wa[t] * p >= za[t] + 10 then + print + print "Ball went out of endzone --automatic touchback--" + globals.p = za[t] - wa[t] * 20 + if routine <= 4 then routine = 5 + else + print "Ball went " + k + " yards. Now on " + p + showBall + end if + end if + if routine <= 4 then + if askYesNo("Team " + t + " do you want to runback") == "YES" then + k = floor(9 * rnd + 1) + r = floor(((xa[t] - ya[t] * p + 25) * rnd - 15) / k) + globals.p = p - wa[t] * r + print + print "Runback team " + t + " " + r + " yards" + g = rnd + if g < 0.25 then + losePossession + routine = 4 + continue + else if ya[t] * p >= xa[t] then + touchdown + if showScores then return + globals.t = ta[t] + routine = 1 + continue + else if wa[t] * p >= za[t] then + print + print "Safety against team " + t + " **********************OH-OH" + ha[ta[t]] += 2 + if showScores then return + globals.p = za[t] - wa[t] * 20 + if askYesNo("Team " + t + " do you want to punt instead of a kickoff") == "YES" then + print + print "Team " + t + " will punt" + g = rnd + if g < 0.25 then + losePossession + routine = 4 + continue + end if + print + printSeparator + k = floor(25 * rnd + 35) + globals.t = ta[t] + routine = 2 + continue + end if + touchdown + if showScores then return + globals.t = ta[t] + routine = 1 + continue + else + routine = 5 + continue + end if + else // player does not want to runback + if wa[t] * p >= za[t] then globals.p = za[t] - wa[t] * 20 + end if + end if + if routine <= 5 then + d = 1 + s = p + end if + if routine <= 6 then + print "=" * 67 + print "TEAM " + t + " DOWN " + d + " ON " + p + if d == 1 then + if ya[t] * (p + ya[t] * 10) >= xa[t] then + c = 8 + else + c = 4 + end if + end if + if c != 8 then + print " "*27 + (10 - (ya[t] * p - ya[t] * s)) + " yards to 1st down" + else + print " "*27 + (xa[t] - ya[t] * p) + " yards" + end if + showBall + if d == 4 then routine = 8 + end if + if routine <= 7 then + u = floor(3 * rnd - 1) + while true + str = input("Input offensive play, defensive play: ") + str = str.replace(",", " ").replace(" ", " ").split + if t == 1 then + p1 = str[0].val + p2 = str[1].val + else + p2 = str[0].val + p1 = str[1].val + end if + if p1 == 99 then + if showScores then return + continue + end if + if 1 <= p1 <= 20 and 1 <= p2 <= 20 then break + print "Illegal play number, check and" + end while + end if + if d == 4 or p1 == 77 then + if askYesNo("Does team " + t + " want to punt") == "YES" then + print + print "Team " + t + " will punt" + if rnd < 0.25 then + losePossession + routine = 4 + continue + end if + print + printSeparator + k = floor(25 * rnd + 35) + globals.t = ta[t] + routine = 2 + continue + end if + if askYesNo("Does team " + t + " want to attempt a field goal") == "YES" then + print + print "Team " + t + " will attempt a field goal" + if rnd < 0.025 then + losePossession + routine = 4 + continue + else + f = floor(35 * rnd + 20) + print + print "Kick is " + f + " yards long" + globals.p = p - wa[t] * f + if rnd < 0.35 then + print "Ball went wide" + else if ya[t] * p >= xa[t] then + print "FIELD GOLD GOOD FOR TEAM " + t + " *********************YEA" + q = 3 + ha[t] = ha[t] + q + if showScores then return + globals.t = ta[t] + routine = 1 + continue + end if + print "Field goal unsuccesful team " + t + "-----------------too bad" + print + printSeparator + if ya[t] * p < xa[t] + 10 then + print + print "Ball now on " + p + globals.t = ta[t] + showBall + routine = 4 + continue + else + globals.t = ta[t] + routine = 3 + continue + end if + end if + else + routine = 7 + continue + end if + end if + y = floor(abs(aa[p1] - ba[p2]) / 19 * ((xa[t] - ya[t] * p + 25) * rnd - 15)) + print + if t == 1 and aa[p1] < 11 or t == 2 and ba[p2] < 11 then + print "The ball was run" + else if u == 0 then + print "Pass incomplete team " + t + y = 0 + else + if rnd <= 0.025 and y > 2 then + print "Pass completed" + else + print "Quarterback scrambled" + end if + end if + globals.p = p - wa[t] * y + print + print "Net yards gained on down " + d + " are " + y + + if rnd <= 0.025 then + losePossession + routine = 4 + continue + else if ya[t] * p >= xa[t] then + touchdown + if showScores then return + globals.t = ta[t] + routine = 1 + continue + else if wa[t] * p >= za[t] then + print + print "SAFETY AGAINST TEAM " + t + " **********************OH-OH" + ha[ta[t]] = ha[ta[t]] + 2 + if showScores then return + globals.p = za[t] - wa[t] * 20 + if askYesNo("Team " + t + " do you want to punt instead of a kickoff") == "YES" then + print + print "Team " + t + " will punt" + if rnd < 0.25 then + losePossession + routine = 4 + continue + end if + print + printSeparator + k = floor(25 * rnd + 35) + globals.t = ta[t] + routine = 2 + continue + end if + touchdown + if showScores then return + globals.t = ta[t] + routine = 1 + else if ya[t] * p - ya[t] * s >= 10 then + routine = 5 + else + d += 1 + if d != 5 then + routine = 6 + else + print + print "Conversion unsuccessful team " + t + globals.t = ta[t] + print + printSeparator + routine = 5 + end if + end if + end while +end function + +playGame diff --git a/00_Alternate_Languages/37_Football/MiniScript/ftball.ms b/00_Alternate_Languages/37_Football/MiniScript/ftball.ms new file mode 100644 index 000000000..31d3f8299 --- /dev/null +++ b/00_Alternate_Languages/37_Football/MiniScript/ftball.ms @@ -0,0 +1,431 @@ +os = ["Dartmouth", ""] +sa = [0, 1] +ls = ["", "Kick","receive"," yard ","run back for ","ball on ", + "yard line"," simple run"," tricky run"," short pass", + " long pass","punt"," quick kick "," place kick"," loss ", + " no gain","gain "," touchdown "," touchback ","safety***", + "junk"] +p = 0 +x = 0 +x1 = 0 + +fnf = function(x); return 1 - 2 * p; end function +fng = function(z); return p * (x1 - x) + (1 - p) * (x - x1); end function + +show_score = function + print + print "SCORE: " + sa[0] + " TO " + sa[1] + print + print +end function + +show_position = function + if x <= 50 then + print ls[5] + os[0] + " " + x + " " + ls[6] + else + print ls[5] + os[1] + " " + (100 - x) + " " + ls[6] + end if +end function + +offensive_td = function + print ls[17] + "***" + if rnd <= 0.8 then + sa[p] += 7 + print "Kick is good." + else + print "Kick is off to the side" + sa[p] += 6 + end if + show_score + print os[p] + " kicks off" + globals.p = 1 - p +end function + +// Main program +main = function + print " "*33 + "FTBALL" + print " "*15 + "Creative Computing Morristown, New Jersey" + print + print + print "This is Dartmouth championship football." + print + print "You will quarterback Dartmouth. Call plays as follows:" + print "1= simple run; 2= tricky run; 3= short pass;" + print "4= long pass; 5= punt; 6= quick kick; 7= place kick." + print + os[1] = input("Choose your opponent: ").upper + os[0] = "DARMOUTH" + print + sa[0] = 0 + sa[1] = 0 + globals.p = floor(rnd * 2) + print os[p] + " won the toss" + if p != 0 then + print os[1] + " Elects to receive." + print + else + print "Do you elect to kick or receive? " + while true + str = input.lower + if str and (str[0] == "k" or str[0] == "r") then break + print "Incorrect answer. Please type 'kick' or 'receive'" + end while + if str[0] == "k" then e = 1 else e = 2 + if e == 1 then globals.p = 1 + end if + globals.t = 0 + start = 1 + while true + if start <= 1 then + x = 40 + (1 - p) * 20 + end if + if start <= 2 then + y = floor(200 * ((rnd - 0.5))^3 + 55) + print " " + y + " " + ls[3] + " kickoff" + x = x - fnf(1) * y + if abs(x - 50) >= 50 then + print "Touchback for " + os[p] + "." + x = 20 + p * 60 + start = 4 + else + start = 3 + end if + end if + if start <= 3 then + y = floor(50 * (rnd)^2) + (1 - p) * floor(50 * (rnd)^4) + x = x + fnf(1) * y + if abs(x - 50) < 50 then + print " " + y + " " + ls[3] + " runback" + else + print ls[4] + offensive_td + start = 1 + continue + end if + end if + if start <= 4 then + // First down + show_position + end if + if start <= 5 then + x1 = x + d = 1 + print + print "First down " + os[p] + "***" + print + print + end if + // New play + globals.t += 1 + if t == 30 then + if rnd <= 1.3 then + print "Game delayed. Dog on field." + print + end if + end if + if t >= 50 and rnd <= 0.2 then break + if p != 1 then + // Opponent's play + if d <= 1 then + if rnd > 1/3 then z = 1 else z = 3 + else if d != 4 then + if 10 + x - x1 < 5 or x < 5 then + if rnd > 1/3 then z = 1 else z = 3 + else if x <= 10 then + a = floor(2 * rnd) + z = 2 + a + else if x <= x1 or d < 3 or x < 45 then + a = floor(2 * rnd) + z = 2 + a * 2 + else + if (rnd > 1 / 4) then + z = 4 + else + z = 6 + end if + end if + else + if x <= 30 then + z = 5 + else if 10 + x - x1 < 3 or x < 3 then + if rnd > 1/3 then z = 1 else z = 3 + else + z = 7 + end if + end if + else + while true + z = input("Next play? ").val + if 1 <= z <= 7 then break + print "Illegal play number, retype" + end while + end if + f = 0 + print ls[z + 6] + ". " + r = rnd * (0.98 + fnf(1) * 0.02) + r1 = rnd + if z == 1 or z == 2 then // Simple Run or Tricky Run + done = false + if z == 1 then + y = floor(24 * (r - 0.5)^3 + 3) + if rnd >= 0.05 then + routine = 1 + done = true + end if + else + y = floor(20 * r - 5) + if rnd > 0.1 then + routine = 1 + done = true + end if + end if + if not done then + f = -1 + x3 = x + x = x + fnf(1) * y + if abs(x - 50) < 50 then + print "*** Fumble after " + routine = 2 + else + print "*** Fumble." + routine = 4 + end if + end if + else if z == 3 or z == 4 then // Short Pass or Long Pass + if z == 3 then + y = floor(60 * (r1 - 0.5)^3 + 10) + else + y = floor(160 * ((r1 - 0.5))^3 + 30) + end if + if z == 3 and r < 0.05 or z == 4 and r < 0.1 then + if d != 4 then + print "Intercepted." + f = -1 + x = x + fnf(1) * y + if abs(x - 50) >= 50 then + routine = 4 + else + routine = 3 + end if + else + y = 0 + if rnd < 0.3 then + print "Batted down. ", "" + else + print "Incomplete. ", "" + end if + routine = 1 + end if + else if z == 4 and r < 0.3 then + print "Passer tackled. ", "" + y = -floor(15 * r1 + 3) + routine = 1 + else if z == 3 and r < 0.15 then + print "Passer taclked. ", "" + y = -floor(10 * r1) + routine = 1 + else if z == 3 and r < 0.55 or z == 4 and r < 0.75 then + y = 0 + if rnd < 0.3 then + print "Batted down. ", "" + else + print "Incomplete. ", "" + end if + routine = 1 + else + print "Complete. ", "" + routine = 1 + end if + else if z == 5 or z == 6 then // Punt or Quick Kick + y = floor(100 * ((r - 0.5))^3 + 35) + if (d != 4) then y = floor(y * 1.3) + print " " + y + " " + ls[3] + " punt" + if abs(x + y * fnf(1) - 50) < 50 and d >= 4 then + y1 = floor((r1)^2 * 20) + print " " + y1 + " " + ls[3] + " Run back" + y = y - y1 + end if + f = -1 + x = x + fnf(1) * y + if abs(x - 50) >= 50 then routine = 4 else routine = 3 + else if z == 7 then // Place kick + y = floor(100 * ((r - 0.5))^3 + 35) + if r1 <= 0.15 then + print "Kick is blocked ***" + x = x - 5 * fnf(1) + globals.p = 1 - p + start = 4 + continue + end if + x = x + fnf(1) * y + if abs(x - 50) >= 60 then + if r1 <= 0.5 then + print "Kick is off to the side." + print ls[18] + globals.p = 1 - p + x = 20 + p * 60 + start = 4 + continue + else + print "Field goal ***" + sa[p] = sa[p] + 3 + show_score + print os[p] + " kicks off" + globals.p = 1 - p + start = 1 + continue + end if + else + print "Kick is short." + if abs(x - 50) >= 50 then + // Touchback + print ls[18] + globals.p = 1 - p + x = 20 + p * 60 + start = 4 + continue + end if + globals.p = 1 - p + start = 3 + continue + end if + end if + // Gain or loss + if routine <= 1 then + x3 = x + x = x + fnf(1) * y + if abs(x - 50) >= 50 then + routine = 4 + end if + end if + if routine <= 2 then + if y != 0 then + print " " + abs(y) + " " + ls[3] + if (y < 0) then + yt = -1 + else if y > 0 then + yt = 1 + else + yt = 0 + end if + print ls[15 + yt] + if abs(x3 - 50) <= 40 and rnd < 0.1 then + // Penalty + p3 = floor(2 * rnd) + print os[p3] + " offsides -- penalty of 5 yards." + print + print + if p3 != 0 then + print "Do you accept the penalty?" + while true + str = input.lower + if str and (str[0] == "y" or str[0] == "n") then break + print "Yype 'yes' or 'no'" + end while + if str[0] == "y" then + f = 0 + d = d - 1 + if (p != p3) then + x = x3 + fnf(1) * 5 + else + x = x3 - fnf(1) * 5 + end if + end if + else + // opponent's strategy on penalty + if ((p != 1 and (y <= 0 or f < 0 or fng(1) < 3 * d - 2)) or + (p == 1 and ((y > 5 and f >= 0) or d < 4 or fng(1) >= 10))) then + print "penalty refused." + else + print "penalty accepted." + f = 0 + d = d - 1 + if (p != p3) then + x = x3 + fnf(1) * 5 + else + x = x3 - fnf(1) * 5 + end if + end if + end if + routine = 3 + end if + end if + end if + if routine <= 3 then + show_position + if f != 0 then + globals.p = 1 - p + start = 5 + continue + else if fng(1) >= 10 then + start = 5 + continue + else if d == 4 then + globals.p = 1 - p + start = 5 + continue + else + d += 1 + print "DOWN: " + d + " " + if (x1 - 50) * fnf(1) >= 40 then + print "Goal to go" + else + print "Yards to go: " + (10 - fng(1)) + end if + print + print + start = 6 + continue + end if + end if + if routine <= 4 then + // Ball in end-zone + e = (x >= 100) + case = 1 + e - f * 2 + p * 4 + if case == 1 or case == 5 then + // Safety + sa[1 - p] = sa[1 - p] + 2 + print ls[19] + show_score + print os[p] + " kicks off from its 20 yard line." + x = 20 + p * 60 + globals.p = 1 - p + start = 2 + continue + end if + if case == 3 or case == 6 then + // defensive td + print ls[17] + "for " + os[1 - p] + "***" + globals.p = 1 - p + end if + if case == 3 or case == 6 or case == 2 or case == 8 then + // offensive td + print ls[17] + "***" + if rnd <= 0.8 then + sa[p] = sa[p] + 7 + print "kick is good." + else + print "kick is off to the side" + sa[p] = sa[p] + 6 + end if + show_score + print os[p] + " kicks off" + globals.p = 1 - p + start = 1 + continue + end if + if case == 4 or case == 7 then + // Touchback + print ls[18] + globals.p = 1 - p + x = 20 + p * 60 + start = 4 + continue + end if + end if + end while + print "END OF GAME ***" + print "FINAL SCORE: " + os[0] + ": " + sa[0] + " " + os[1] + ": " + sa[1] +end function + +main diff --git a/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md b/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md new file mode 100644 index 000000000..54956e39f --- /dev/null +++ b/00_Alternate_Languages/38_Fur_Trader/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 furtrader.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 "furtrader" + run diff --git a/00_Alternate_Languages/38_Fur_Trader/MiniScript/furtrader.ms b/00_Alternate_Languages/38_Fur_Trader/MiniScript/furtrader.ms new file mode 100644 index 000000000..6fb85e1a2 --- /dev/null +++ b/00_Alternate_Languages/38_Fur_Trader/MiniScript/furtrader.ms @@ -0,0 +1,171 @@ +print " "*31 + "Fur Trader" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +furs = [0,0,0,0] // how many of each type of fur you have +value = [0,0,0,0] // value of each type of fur +furNames = "mink beaver ermine fox".split + +getYesNo = function + while true + ans = input("Answer yes or no: ").upper + if not ans then continue + if ans[0] == "Y" then return "YES" + if ans[0] == "N" then return "NO" + end while +end function + +printInstructions = function + print "You are the leader of a French fur trading expedition in " + print "1776 leaving the Lake Ontario area to sell furs and get" + print "supplies for the next year. You have a choice of three" + print "forts at which you may trade. The cost of supplies" + print "and the amount you receive for your furs will depend" + print "on the fort that you choose." + print +end function + +pickFort = function + print + while true + print "You may trade your furs at fort 1, fort 2," + print "or fort 3. Fort 1 is Fort Hochelaga (Montreal)" + print "and is under the protection of the French army." + print "Fort 2 is Fort Stadacona (Quebec) and is under the" + print "protection of the French Army. However, you must" + print "make a portage and cross the Lachine rapids." + print "Fort 3 is Fort New York and is under Dutch control." + print "You must cross through Iroquois land." + b = input("Answer 1, 2, or 3: ").val + if b == 1 then + print "You have chosen the easiest route. However, the fort" + print "is far from any seaport. The value" + print "you receive for your furs will be low and the cost" + print "of supplies higher than at Forts Stadacona or New York." + else if b == 2 then + print "You have chosen a hard route. It is, in comparsion," + print "harder than the route to Hochelaga but easier than" + print "the route to New York. You will receive an average value" + print "for your furs and the cost of your supplies will be average." + else if b == 3 then + print "You have chosen the most difficult route. At" + print "Fort New York you will receive the highest value" + print "for your furs. The cost of your supplies" + print "will be lower than at all the other forts." + else + continue + end if + print "Do you want to trade at another fort?" + if getYesNo == "NO" then return b + end while +end function + +visitFort = function(fort) + print + if fort == 1 then + value[0] = floor((.2*rnd+.7)*100+.5)/100 + value[2] = floor((.2*rnd+.65)*100+.5)/100 + value[1] = floor((.2*rnd+.75)*100+.5)/100 + value[3] = floor((.2*rnd+.8)*100+.5)/100 + print "Supplies at Fort Hochelaga cost $150.00." + print "Your travel expenses to Hochelaga were $10.00." + globals.money -= 150 + 10 + else if fort == 2 then + value[0] = floor((.3*rnd+.85)*100+.5)/100 + value[2] = floor((.15*rnd+.8)*100+.5)/100 + value[1] = floor((.2*rnd+.9)*100+.5)/100 + p = floor(10*rnd)+1 + if p <= 2 then + furs[1] = 0 + print "Your beaver were too heavy to carry across" + print "the portage. You had to leave the pelts, but found" + print "them stolen when you returned." + else if p <= 6 then + print "You arrived safely at Fort Stadacona." + else if p <= 8 then + for j in range(0,3); furs[j] = 0; end for + print "Your canoe upset in the Lachine rapids. You" + print "lost all your furs." + else if furs[3] then + furs[3] = 0 + print "Your fox pelts were not cured properly." + print "No one will buy them." + end if + print "Supplies at Fort Stadacona cost $125.00." + print "Your travel expenses to Stadacona were $15.00." + globals.money -= 125 + 15 + else + value[0] = floor((.15*rnd+1.05)*100+.5)/100 + value[3] = floor((.25*rnd+1.1)*100+.5)/100 + p = floor(10*rnd)+1 + if p <= 2 then + print "You were attacked by a party of Iroquois." + print "All people in your trading group were" + print "killed. This ends the game." + globals.gameOver = true + return + else if p<=6 then + print "You were lucky. You arrived safely" + print "at Fort New York." + else if p<=8 then + for j in range(0,3); furs[j] = 0; end for + print "You narrowly escaped an iroquois raiding party." + print "However, you had to leave all your furs behind." + else + value[1] /= 2 + value[0] /= 2 + print "Your mink and beaver were damaged on your trip." + print "You receive only half the current price for these furs." + end if + print "Supplies at New York cost $80.00." + print "Your travel expenses to New York were $25.00." + globals.money -= 80 + 25 + end if +end function + +printInstructions + +gameOver = false +money=600 +while not gameOver + print "Do you wish to trade furs?" + if getYesNo == "NO" then break + + value[2]=floor((.15*rnd+.95)*100+.5)/100 // ermine value + value[1]=floor((.25*rnd+1.00)*100+.5)/100 // beaver value + + print + print "You have $" + money + " savings." + print "And 190 furs to begin the expedition." + print + print "Your 190 furs are distributed among the following" + print "kinds of pelts: mink, beaver, ermine and fox." + print + furs = [0,0,0,0] + for j in range(0, 3) + furs[j] = input("How many " + furNames[j] + " do you have? ").val + if furs.sum >= 190 then break + end for + if furs.sum > 190 then + print "You may not have that many furs." + print "Do not try to cheat. I can add." + print "You must start again." + continue + end if + + fort = pickFort + visitFort fort + if gameOver then break + + print + for j in [1, 3, 2, 0] + if not furs[j] then continue + revenue = value[j] * furs[j] + print "Your " + furNames[j] + " sold for $" + revenue + "." + money += revenue + end for + print + print "You now have $" + money + " including your previous savings." +end while + + diff --git a/38_Fur_Trader/README.md b/38_Fur_Trader/README.md index 8406487e7..6b08911ae 100644 --- a/38_Fur_Trader/README.md +++ b/38_Fur_Trader/README.md @@ -15,6 +15,10 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- The value of some furs are not changed from the previous fort when you select fort 2 or 3. As a result, you will get a different value for your firs depending on whether you have previously visited a different fort. (All fur values are set when you visit Fort 1.) + #### Porting Notes (please note any difficulties or challenges in porting here) From 2d3ebc98a3dcd101e1066e084a99a61a1e74068a Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Fri, 4 Aug 2023 23:01:38 -0700 Subject: [PATCH 187/377] Port Train to Nim --- 00_Alternate_Languages/91_Train/nim/train.nim | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 00_Alternate_Languages/91_Train/nim/train.nim diff --git a/00_Alternate_Languages/91_Train/nim/train.nim b/00_Alternate_Languages/91_Train/nim/train.nim new file mode 100644 index 000000000..062e6dd13 --- /dev/null +++ b/00_Alternate_Languages/91_Train/nim/train.nim @@ -0,0 +1,37 @@ +import std/[random,strutils] + +var + carSpeed, diff, err, guess, trainSpeed, carTime: int + stillplaying: bool = true + +# Return a tuple that'll be carSpeed, diff, trainSpeed +proc randomNumbers(): (int,int,int) = + randomize() + result = (rand(1..25)+40 , rand(1..15)+5 , rand(1..19)+20) + +# Do we want to play again? +proc tryAgain(): bool = + echo "ANOTHER PROBLEM (YES OR NO)" + var answer = readLine(stdin).normalize() + result = (answer == "y") or (answer == "yes") + +echo spaces(33), "TRAIN" +echo spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +echo "\n" +echo "TIME - SPEED DISTANCE EXERCISE" + +while stillplaying: + echo "" + (carSpeed, diff, trainSpeed) = randomNumbers() # Get random numbers for prompt + echo "A CAR TRAVELING ", carSpeed, " MPH CAN MAKE A CERTAIN TRIP IN" + echo diff, " HOURS LESS THAN A TRAIN TRAVELING AT ", trainSpeed, " MPH." + echo "HOW LONG DOES THE TRIP TAKE BY CAR?" + guess = readLine(stdin).parseInt() # Get guess + carTime = (diff * trainSpeed / (carSpeed - trainSpeed)).toInt() # Calculate answer + err = (((carTime - guess) * 100) / guess).toInt().abs() # Calculate error to an absolute value + if err > 5: # Error within 5%? + echo "SORRY. YOU WERE OFF BY ", err, " PERCENT." + else: + echo "GOOD! ANSWER WITHIN ", err, " PERCENT." + echo "CORRECT ANSWER IS ", carTime, " HOURS." + stillplaying = tryAgain() From 76d65ddcb2e8d52190b78887d6ecd9658ad31f0d Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Sat, 5 Aug 2023 01:33:44 -0700 Subject: [PATCH 188/377] Craps ported to Nim --- 00_Alternate_Languages/29_Craps/nim/craps.nim | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 00_Alternate_Languages/29_Craps/nim/craps.nim diff --git a/00_Alternate_Languages/29_Craps/nim/craps.nim b/00_Alternate_Languages/29_Craps/nim/craps.nim new file mode 100644 index 000000000..133ee590b --- /dev/null +++ b/00_Alternate_Languages/29_Craps/nim/craps.nim @@ -0,0 +1,66 @@ +import std/[random,strutils] + +var + wager, winnings, rollResult: int + stillplaying: bool = true + +proc tryAgain(): bool = + echo "WANT TO PLAY AGAIN? (YES OR NO)" + var answer = readLine(stdin).normalize() + result = (answer == "y") or (answer == "yes") + +proc takePoint(point: int) = + var flag = true + while flag: + var pointRoll: int = (rand 1..6) + (rand 1..6) # roll dice, then add the sum + if pointRoll == 7: + echo pointRoll, "- CRAPS. YOU LOSE." + echo "YOU LOSE ", wager, " DOLLARS." + winnings -= wager + flag = false + if pointRoll == point: + echo point, "- A WINNER.........CONGRATS!!!!!!!!" + echo "AT 2 TO 1 ODDS PAYS YOU...LET ME SEE... ", 2*wager, " DOLLARS" + winnings += (2*wager) + flag = false + if flag: + echo pointRoll, " - NO POINT. I WILL ROLL AGAIN" + +echo spaces(33), "CRAPS" +echo spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +echo "\n" +echo "2,3,12 ARE LOSERS; 4,5,6,8,9,10 ARE POINTS; 7,11 ARE NATURAL WINNERS." +winnings = 0 + +# play the game +while stillplaying: + echo "" + echo "INPUT THE AMOUNT OF YOUR WAGER." + wager = readline(stdin).parseInt() + echo "I WILL NOW THROW THE DICE" + rollResult = (rand 1..6) + (rand 1..6) # roll dice, then add the sum + case rollResult: + of 7, 11: + echo rollResult, "- NATURAL....A WINNER!!!!" + echo rollResult, " PAYS EVEN MONEY, YOU WIN ", wager, " DOLLARS" + winnings += wager + of 2: + echo rollResult, "- SNAKE EYES....YOU LOSE." + echo "YOU LOSE ", wager, " DOLLARS." + winnings -= wager + of 3, 12: + echo rollResult, "- CRAPS...YOU LOSE." + echo "YOU LOSE ", wager, " DOLLARS." + winnings -= wager + else: + echo rollResult, " IS THE POINT. I WILL ROLL AGAIN" + takePoint(rollResult) + if winnings < 0: echo "YOU ARE NOW UNDER $", winnings + if winnings > 0: echo "YOU ARE NOW AHEAD $", winnings + if winnings == 0: echo "YOU ARE NOW EVEN AT 0" + stillplaying = tryAgain() + +# done playing +if winnings < 0: echo "TOO BAD, YOU ARE IN THE HOLE. COME AGAIN." +if winnings > 0: echo "CONGRATULATIONS---YOU CAME OUT A WINNER. COME AGAIN!" +if winnings == 0: echo "CONGRATULATIONS---YOU CAME OUT EVEN, NOT BAD FOR AN AMATEUR" From 3f25036fdc2bed7e97ae5fa05da104fb1d9a8bde Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Sat, 5 Aug 2023 01:49:11 -0700 Subject: [PATCH 189/377] Fix random logic in Nim ports --- 00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim | 2 ++ 00_Alternate_Languages/05_Bagels/nim/bagels.nim | 2 ++ 00_Alternate_Languages/29_Craps/nim/craps.nim | 2 ++ 00_Alternate_Languages/33_Dice/nim/dice.nim | 2 ++ 00_Alternate_Languages/91_Train/nim/train.nim | 5 +++-- 5 files changed, 11 insertions(+), 2 deletions(-) diff --git a/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim b/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim index ed180de4e..a980ed5d2 100644 --- a/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim +++ b/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim @@ -4,6 +4,8 @@ var bet, cardA, cardB, cardC, stash: int retry: bool = true +randomize() # Seed the random number generator + proc printGreeting() = echo spaces(26),"ACEY DUCEY CARD GAME" echo spaces(15),"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" diff --git a/00_Alternate_Languages/05_Bagels/nim/bagels.nim b/00_Alternate_Languages/05_Bagels/nim/bagels.nim index dd260e3da..f302b375d 100644 --- a/00_Alternate_Languages/05_Bagels/nim/bagels.nim +++ b/00_Alternate_Languages/05_Bagels/nim/bagels.nim @@ -10,6 +10,8 @@ var prompt: string stillplaying: bool = true +randomize() # Seed the random number generator + # Seed 3 unique random numbers; indicate if they're all unique proc genSeed(): bool = for i in 1..3: diff --git a/00_Alternate_Languages/29_Craps/nim/craps.nim b/00_Alternate_Languages/29_Craps/nim/craps.nim index 133ee590b..770b6c0e1 100644 --- a/00_Alternate_Languages/29_Craps/nim/craps.nim +++ b/00_Alternate_Languages/29_Craps/nim/craps.nim @@ -4,6 +4,8 @@ var wager, winnings, rollResult: int stillplaying: bool = true +randomize() # Seed the random number generator + proc tryAgain(): bool = echo "WANT TO PLAY AGAIN? (YES OR NO)" var answer = readLine(stdin).normalize() diff --git a/00_Alternate_Languages/33_Dice/nim/dice.nim b/00_Alternate_Languages/33_Dice/nim/dice.nim index f19903a18..6564ae9ba 100644 --- a/00_Alternate_Languages/33_Dice/nim/dice.nim +++ b/00_Alternate_Languages/33_Dice/nim/dice.nim @@ -6,6 +6,8 @@ var z: string retry: bool = true +randomize() # Seed the random number generator + echo spaces(34), "DICE" echo spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" echo "\n" diff --git a/00_Alternate_Languages/91_Train/nim/train.nim b/00_Alternate_Languages/91_Train/nim/train.nim index 062e6dd13..aa92c1a70 100644 --- a/00_Alternate_Languages/91_Train/nim/train.nim +++ b/00_Alternate_Languages/91_Train/nim/train.nim @@ -4,10 +4,11 @@ var carSpeed, diff, err, guess, trainSpeed, carTime: int stillplaying: bool = true +randomize() # Seed the random number generator + # Return a tuple that'll be carSpeed, diff, trainSpeed proc randomNumbers(): (int,int,int) = - randomize() - result = (rand(1..25)+40 , rand(1..15)+5 , rand(1..19)+20) + result = (rand(41..65), rand(6..20), rand(21..39)) # Do we want to play again? proc tryAgain(): bool = From a9666cccc4b3270cea825f3c3a71ee8b29041ccb Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Sat, 5 Aug 2023 15:42:33 -0700 Subject: [PATCH 190/377] Acey Ducey fixes for #869 --- .../01_Acey_Ducey/nim/aceyducey.nim | 9 ++++--- 01_Acey_Ducey/python/acey_ducey.py | 25 +++++++++++-------- 01_Acey_Ducey/python/acey_ducey_oo.py | 9 +++---- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim b/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim index a980ed5d2..abc03defc 100644 --- a/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim +++ b/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim @@ -34,10 +34,10 @@ proc printCard(aCard: int) = proc drawDealerCards() = echo "HERE ARE YOUR NEXT TWO CARDS: " - cardA = rand(2..14) + cardA = rand 2..14 cardB = cardA # Copy cardA, so we can test cardB to be different while cardB == cardA: - cardB = rand(2..14) + cardB = rand 2..14 if cardA > cardB: # Make sure cardA is the smaller card swap cardA, cardB echo "" @@ -80,8 +80,9 @@ while retry: echo "YOU WIN!!!" stash += bet else: - echo "SORRY, YOU LOSE" - stash -= bet + if bet > 0: + echo "SORRY, YOU LOSE" + stash -= bet echo "SORRY, FRIEND, BUT YOU BLEW YOUR WAD." echo "" retry = tryAgain() diff --git a/01_Acey_Ducey/python/acey_ducey.py b/01_Acey_Ducey/python/acey_ducey.py index 603e01afa..8e3535695 100755 --- a/01_Acey_Ducey/python/acey_ducey.py +++ b/01_Acey_Ducey/python/acey_ducey.py @@ -7,7 +7,6 @@ import random cards = { - 1: "1", 2: "2", 3: "3", 4: "4", @@ -16,22 +15,25 @@ 7: "7", 8: "8", 9: "9", - 10: "Jack", - 11: "Queen", - 12: "King", - 13: "Ace", + 10: "10", + 11: "Jack", + 12: "Queen", + 13: "King", + 14: "Ace", } - def play_game() -> None: cash = 100 while cash > 0: print(f"You now have {cash} dollars\n") print("Here are you next two cards") - round_cards = list(cards.keys()) - random.shuffle(round_cards) - card_a, card_b, card_c = round_cards.pop(), round_cards.pop(), round_cards.pop() - if card_a > card_b: + round_cards = list(cards.keys()) # gather cards from dictionary + card_a = random.choice(round_cards) # choose a card + card_b = card_a # clone the first card, so we avoid the same number for the second card + while (card_a == card_b): # if the cards are the same, choose another card + card_b = random.choice(round_cards) + card_c = random.choice(round_cards) # choose last card + if card_a > card_b: # swap cards if card_a is greater than card_b card_a, card_b = card_b, card_a print(f" {cards[card_a]}") print(f" {cards[card_b]}\n") @@ -53,7 +55,7 @@ def play_game() -> None: print("Please enter a positive number") print(f" {cards[card_c]}") if bet > 0: - if card_a < card_c < card_b: + if card_a <= card_c <= card_b: print("You win!!!") cash += bet * 2 else: @@ -82,4 +84,5 @@ def main() -> None: if __name__ == "__main__": + random.seed() main() diff --git a/01_Acey_Ducey/python/acey_ducey_oo.py b/01_Acey_Ducey/python/acey_ducey_oo.py index 35b26d845..cd5cad76f 100644 --- a/01_Acey_Ducey/python/acey_ducey_oo.py +++ b/01_Acey_Ducey/python/acey_ducey_oo.py @@ -8,6 +8,7 @@ """ from typing import List, Literal, NamedTuple, TypeAlias, get_args +import random Suit: TypeAlias = Literal["\u2665", "\u2666", "\u2663", "\u2660"] Rank: TypeAlias = Literal[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] @@ -34,8 +35,6 @@ def build(self) -> None: self.cards.append(Card(suit, rank)) def shuffle(self) -> None: - import random - random.shuffle(self.cards) def deal(self) -> Card: @@ -72,7 +71,7 @@ def play(self) -> None: if 0 < bet <= self.money: print(f"Your deal:\t {player_card}") - if card_a.rank < player_card.rank < card_b.rank: + if card_a.rank <= player_card.rank <= card_b.rank: print("You Win!") self.money += bet else: @@ -87,9 +86,6 @@ def play(self) -> None: else: print("You would lose, so it was wise of you to chicken out!") - self.not_done = False - break - if len(self.deck.cards) <= 3: print("You ran out of cards. Game over.") self.not_done = False @@ -129,4 +125,5 @@ def main() -> None: if __name__ == "__main__": + random.seed() main() From 233592bd76f637ffec27642a09d05d3099094306 Mon Sep 17 00:00:00 2001 From: Harrison Date: Sun, 6 Aug 2023 19:55:24 -0700 Subject: [PATCH 191/377] Add an Elixir port of Acey Ducey --- 01_Acey_Ducey/elixir/acey_ducey.exs | 92 +++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 01_Acey_Ducey/elixir/acey_ducey.exs diff --git a/01_Acey_Ducey/elixir/acey_ducey.exs b/01_Acey_Ducey/elixir/acey_ducey.exs new file mode 100644 index 000000000..6642d2245 --- /dev/null +++ b/01_Acey_Ducey/elixir/acey_ducey.exs @@ -0,0 +1,92 @@ +######################################################## +# +# Acey Ducey +# +# From: BASIC Computer Games (1978) +# Edited by David Ahl +# +# "This is a simulation of the Acey Ducey card game. +# In the game, the dealer (the computer) deals two +# cards face up. You have an option to bet or not to +# bet depending on whether or not you feel the next +# card dealt will have a value between the first two. +# +# "Your initial money is set to $100. The game keeps +# going on until you lose all your money or interrupt +# the program. +# +# "The original BASIC program author was Bill Palmby +# of Prairie View, Illinois." +# +# To run this file: +# > mix run acey_ducey.exs --no-mix-exs +# +# This uses the following techniques: +# +# - The `Game` module uses a recursive `play/1` function. +# - The `Game` module stores the game state in a `%Game{}` struct. +# - The classic 52 playing card deck is set as a module attribute generated via a comprehension. +# - The deck is automatically shuffled when there are less than 3 cards remaining in the deck. +# - The initial deck defaults to an empty list which triggers a shuffle when the game begins. +# - The initial funds defaults to 100 but it can be explicitly set in the `%Game{}` struct. +# - The prompt to place a bet will automatically re-prompt when given an invalid input. +# - The bets are assumed to be the whole integers for simplicity. +# +######################################################## + +defmodule Game do + @deck for suit <- [:spades, :hearts, :clubs, :diamonds], value <- 1..13, do: {suit, value} + + defstruct funds: 100, deck: [] + + def play(), do: play(%__MODULE__{}) # for convenience + + def play(%__MODULE__{funds: funds}) when funds <= 0, do: IO.puts("~~~ game over ~~~") + def play(%__MODULE__{deck: deck} = game) when length(deck) < 3, do: play(%{game | deck: Enum.shuffle(@deck)}) + def play(%__MODULE__{deck: deck, funds: funds} = game) do + IO.gets("\n") + + [first_card, second_card, third_card | remaining_deck] = deck + + IO.puts("~~~ new round ~~~") + IO.puts("first card: #{format(first_card)}") + IO.puts("second card: #{format(second_card)}\n") + IO.puts("funds: $#{funds}") + + bet = prompt_to_place_bet(funds) + new_funds = if win?(first_card, second_card, third_card), do: funds + bet, else: funds - bet + + IO.puts("\nthird card: #{format(third_card)}") + IO.puts("funds: $#{funds} => $#{new_funds}") + IO.puts("~~~ end round ~~~\n") + + play(%{game | deck: remaining_deck, funds: new_funds}) + end + + # re-prompt if invalid integer and/or out of bounds + defp prompt_to_place_bet(funds) do + input = IO.gets("place your bet: $") + case Integer.parse(input) do + {bet, _} when bet in 0..funds -> bet + _ -> prompt_to_place_bet(funds) + end + end + + # for a stricter win condition (non-inclusive) + defp win?({_, first}, {_, second}, {_, third}) when third > first and third < second, do: true + # for a looser win condition (inclusive) + #defp win?({_, first}, {_, second}, {_, third}) when third in first..second, do: true + defp win?(_, _, _), do: false + + defp format({suit, value}) do + case value do + 1 -> "ace of #{suit}" + 11 -> "prince of #{suit}" + 12 -> "queen of #{suit}" + 13 -> "king of #{suit}" + value -> "#{value} of #{suit}" + end + end +end + +Game.play() # equivalent to Game.play(%Game{funds: 100, deck: 100}) From da85e134873ed36466982290d6271c35d53ecf7e Mon Sep 17 00:00:00 2001 From: Harrison Date: Mon, 7 Aug 2023 16:10:48 -0700 Subject: [PATCH 192/377] Fix bug in win?/3 --- 01_Acey_Ducey/elixir/acey_ducey.exs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/01_Acey_Ducey/elixir/acey_ducey.exs b/01_Acey_Ducey/elixir/acey_ducey.exs index 6642d2245..31308df78 100644 --- a/01_Acey_Ducey/elixir/acey_ducey.exs +++ b/01_Acey_Ducey/elixir/acey_ducey.exs @@ -73,10 +73,15 @@ defmodule Game do end # for a stricter win condition (non-inclusive) - defp win?({_, first}, {_, second}, {_, third}) when third > first and third < second, do: true + defp win?({_, first}, {_, second}, {_, third}) do + [floor, ceiling] = Enum.sort([first, second]) + (floor < third) && (third < ceiling) + end # for a looser win condition (inclusive) - #defp win?({_, first}, {_, second}, {_, third}) when third in first..second, do: true - defp win?(_, _, _), do: false + #defp win?({_, first}, {_, second}, {_, third}) do + #[_, middle, _] = Enum.sort([first, second, third]) + #middle == third + #end defp format({suit, value}) do case value do From 282adb3337b4997fd4dffc266bf471925e8e18d9 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 7 Aug 2023 16:55:18 -0700 Subject: [PATCH 193/377] Added MiniScript version of 39_Golf. --- .../39_Golf/MiniScript/README.md | 16 + .../39_Golf/MiniScript/golf.ms | 303 ++++++++++++++++++ 39_Golf/README.md | 4 + 3 files changed, 323 insertions(+) create mode 100644 00_Alternate_Languages/39_Golf/MiniScript/README.md create mode 100644 00_Alternate_Languages/39_Golf/MiniScript/golf.ms diff --git a/00_Alternate_Languages/39_Golf/MiniScript/README.md b/00_Alternate_Languages/39_Golf/MiniScript/README.md new file mode 100644 index 000000000..ae8f8e566 --- /dev/null +++ b/00_Alternate_Languages/39_Golf/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 golf.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 "golf" + run diff --git a/00_Alternate_Languages/39_Golf/MiniScript/golf.ms b/00_Alternate_Languages/39_Golf/MiniScript/golf.ms new file mode 100644 index 000000000..634ef0905 --- /dev/null +++ b/00_Alternate_Languages/39_Golf/MiniScript/golf.ms @@ -0,0 +1,303 @@ +print " "*34 + "Golf" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + + print "Welcome to the creative computing country club," + print "an eighteen hole championship layout located a short" + print "distance from scenic downtown Morristown. The" + print "commentator will explain the game as you play." + print "Enjoy your game; see you at the 19th hole..." + print;print + l = [0] * 11 + holesInCourse=18 + totalScore=0 + totalPar=0 + dubChance=.8 + s2=0 + curHole=1 + + +getHoleData = function(hole) + // data for all the holes: distance, par, locOnLeft, and locOnRight for each one + data = [ + 361,4,4,2,389,4,3,3,206,3,4,2,500,5,7,2, + 408,4,2,4,359,4,6,4,424,4,4,2,388,4,4,4, + 196,3,7,2,400,4,7,2,560,5,7,2,132,3,2,2, + 357,4,4,4,294,4,2,4,475,5,2,3,375,4,4,2, + 180,3,6,2,550,5,6,6] + i = (hole-1) * 4 + globals.distance = data[i] + globals.par = data[i+1] + globals.locOnRight = data[i+2] +globals.locOnLeft = data[i+3] +end function + +startHole = function(hole) + getHoleData hole + print + print "You are at the tee off hole " + hole + " distance " + distance + " yards, par " + par + globals.totalPar += par + print "On your right is ", "" + printLocation locOnRight + print "On your left is ", "" + printLocation locOnLeft +end function + +// Get player's handicap +while true + handicap = input("What is your handicap? ").val + if 0 <= handicap <= 30 then break + print "PGA handicaps range from 0 to 30." +end while + +// Get player's weak point +while true + print "Difficulties at golf include:" + print "0=hook, 1=slice, 2=poor distance, 3=trap shots, 4=putting" + weakness = input("Which one (only one) is your worst? ").val + if 0 <= weakness <= 4 then break +end while + +// End a sentence by printing the name of the given location +printLocation = function(locIdx) + if locIdx < 1 or locIdx > 6 then + print "out of bounds." + else + print ["fairway.", "rough.", "trees.", "adjacent fairway.", + "trap.", "water."][locIdx-1] + end if +end function + +// Print score for one hole (plus total), and some praise or advice. +printScore = function(hole, score, par, totalScore, totalPar) + print "Your score on hole " + hole + " was " + score + print "Total par for " + hole + " holes is " + totalPar + " Your total is " + totalScore + if hole == holesInCourse then return + if score > par+2 then + print "Keep your head down." + else if score == par then + print "A par. Nice going." + else if score == par-1 then + print "A birdie." + else if score == 1 then + print "A hole in one." + else if score == par-2 then + print "A great big eagle." + end if +end function + +// Print club advice -- but only once. +clubAdviceGiven = false +printClubAdvice = function + if clubAdviceGiven then return // (already done) + globals.clubAdviceGiven = true + print "Selection of clubs" + print "yardage desired suggested clubs" + print "200 to 280 yards 1 to 4" + print "100 to 200 yards 19 to 13" + print " 0 to 100 yards 29 to 23" +end function + +doPenalty = function + print "Penalty stroke assessed. Hit from previous location." + globals.score += 1 + globals.j += 1 + globals.curLoc = 1 + globals.distance = prevDistance +end function + +// Try to get out of a trap. Return true if succeeded, false if failed. +doTrapShot = function + if weakness == 3 then + if rnd <= dubChance then + globals.dubChance *= 0.2 + print "Shot dubbed, still in trap." + return false + end if + globals.dubChance = 0.8 + end if + globals.distToPin = 1 + (3*floor((80/(40-handicap))*rnd)) + return true +end function + +getClub = function + //print "DEBUG: getClub, with curLoc=" + curLoc + while true + club = input("What club do you choose? ").val + print + if club < 1 or club > 29 then continue + if club > 4 and club < 12 then + print "That club is not in the bag." + continue + end if + if club >= 12 then club -= 6 + if curLoc <= 5 or club == 14 or club == 23 then break + print "That club is not in the bag." + print + continue + end while + return club +end function + +getSwing = function(club) + if club <= 13 then return 1 // (full swing) + while true + print "Now gauge your distance by a percentage (1 to 100)" + swing = input("of a full swing? ").val / 100 + print + if 0 <= swing <= 1 then return swing + // Given an invalid swing input, the original BASIC code would + // print "That club is not in the bag" and go back to choosing a club. + // But that is convoluted spaghetti, and I'm not doing it. + end while +end function + +playOneHole = function + q = 0 // counts certain kinds of shots on every third hole (?) + distanceHit = 0 + offLine = 0 + + // shot loop -- take as many shots as you need for this hole + while true + if curLoc < 1 then curLoc = 1 + if curLoc > 6 then + print "Your shot went out of bounds." + doPenalty + distanceHit = 0 + else if curLoc > 5 then + print "Your shot went into the water." + doPenalty + distanceHit = 0 + end if + + if score > 0 and distanceHit then + print "Shot went " + distanceHit + " yards. It's " + distToPin + " yards from the cup." + print "Ball is " + floor(offLine) + " yards off line... in ", "" + printLocation curLoc + end if + + printClubAdvice + + club = getClub + swing = getSwing(club) + globals.score += 1 + if curLoc == 5 and not doTrapShot then continue + if club > 14 then club -= 10 + + //print "DEBUG Club:"+club + " Swing:"+swing + " Weakness:"+weakness + + if curHole % 3 == 0 then + if s2 + q + (10*(curHole-1)/18) < (curHole-1)*(72+((handicap+1)/.85))/18 then + q += 1 + if score % 2 and distance >= 95 then + globals.distance -= 75 + distanceHit = 0 + print "Ball hit tree - bounced into rough " + distance + " yards from hole." + continue + end if + end if + end if + + if club >= 4 and curLoc == 2 then + print "You dubbed it." + distanceHit = 35 + else if score > 7 and distance < 200 then + // user is really sucking, let's cut them a break + putt 1 + (3 * floor((80/(40-handicap))*rnd)) + return + else + //print "DEBUG: SWING with handicap:" + handicap + " club:" + club + distanceHit = floor(((30-handicap)*2.5+187-((30-handicap)*.25+15)*club/2)+25*rnd) + distanceHit = floor(distanceHit*swing) + if weakness == 2 then distanceHit = floor(.85*distanceHit) + end if + offLine = (rnd/.8)*(2*handicap+16)*abs(tan(distanceHit*.0035)) + distToPin = floor(sqrt(offLine^2+abs(distance-distanceHit)^2)) + //print "DEBUG distance:"+distance+"; distanceHit:"+distanceHit+"; distToPin:"+distToPin+"; offLine:"+offLine + if distanceHit > distance and distToPin >= 20 then print "Too much club. You're past the hole." + + globals.prevDistance = distance + globals.distance = distToPin + if distToPin > 27 then + if offLine < 30 or j > 0 then + curLoc = 1 + continue + end if + // hook or slice + s9 = (s2+1)/15 + if weakness == 0 then + isSlice = floor(s9) == s9 + else + isSlice = not floor(s9) == s9 + end if + if isSlice then + print "You sliced- " + curLoc = locOnRight + else + print "You hooked- " + curLoc = locOnLeft + end if + if offLine > 45 then print "badly." + + else if distToPin > 20 then + curLoc = 5 + else if distToPin > .5 then + globals.curLoc = 8 // on the green! + putt distToPin * 3 // (convert yards to feet, and putt) + return + else + curLoc = 9 + print "You holed it." + print + globals.curHole += 1 + return + end if + end while +end function + +putt = function(distToPin) + puttAttempts = 0 + while true + distToPin = abs(floor(distToPin)) + print "On green, " + distToPin + " feet from the pin." + i = input("Choose your putt potency (1 to 13): ").val + globals.score += 1 + if score+1 - par > handicap*0.072 + 2 or puttAttempts > 2 then break + puttAttempts += 1 + if weakness == 4 then + distToPin -= i*(4+1*rnd)+1 + else + distToPin -= i*(4+2*rnd)+1.5 + end if + if -2 <= distToPin <= 2 then break + if distToPin < 0 then + print "Passed by cup." + else + print "Putt short." + end if + end while + print "You holed it." + print + return +end function + +// main loop +while true + curLoc = 0 + j = 0 + s2 += 1 + if curHole > 1 then + end if + + print + + score = 0 + startHole curHole + playOneHole + + totalScore += score + printScore curHole, score, par, totalScore, totalPar + if curHole == holesInCourse then break + + curHole += 1 +end while diff --git a/39_Golf/README.md b/39_Golf/README.md index 262e7c386..f8769f99b 100644 --- a/39_Golf/README.md +++ b/39_Golf/README.md @@ -14,6 +14,10 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- The weakness numbers printed in the original BASIC program are wrong. It says 4=TRAP SHOTS, 5=PUTTING, but in the code, trap shots and putting are 3 and 4, respectively. + #### Porting Notes (please note any difficulties or challenges in porting here) From 76cefdc9dda48106a49e05c6a17c48ac5cb3a8a2 Mon Sep 17 00:00:00 2001 From: Jadi Date: Tue, 8 Aug 2023 19:48:21 +0330 Subject: [PATCH 194/377] Rust port for 25_Chief --- 25_Chief/rust/Cargo.toml | 8 +++ 25_Chief/rust/README.md | 3 + 25_Chief/rust/src/main.rs | 133 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 25_Chief/rust/Cargo.toml create mode 100644 25_Chief/rust/README.md create mode 100644 25_Chief/rust/src/main.rs diff --git a/25_Chief/rust/Cargo.toml b/25_Chief/rust/Cargo.toml new file mode 100644 index 000000000..1ec696335 --- /dev/null +++ b/25_Chief/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/25_Chief/rust/README.md b/25_Chief/rust/README.md new file mode 100644 index 000000000..8bdbf2e2b --- /dev/null +++ b/25_Chief/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) by [Jadi](https://github.com/jadijadi) \ No newline at end of file diff --git a/25_Chief/rust/src/main.rs b/25_Chief/rust/src/main.rs new file mode 100644 index 000000000..123f1a670 --- /dev/null +++ b/25_Chief/rust/src/main.rs @@ -0,0 +1,133 @@ +use std::io; + +fn print_center(text: String, width: usize) { + let pad_size: usize = if width > text.len() { + (width - text.len()) / 2 + } else { + 0 + }; + println!("{}{}", " ".repeat(pad_size), text); +} + +fn send_lightening() { + println!( + "YOU HAVE MADE ME MAD!!! +THERE MUST BE A GREAT LIGHTNING BOLT! + + X X + X X + X X + X X + X X + X X + X X + X X + X X + X XXX + X X + XX X + X X + X X + X X + X X + X X + X X + X X + X X + XX + X + * + +######################### + +I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!" + ); +} + +fn check_yes_answer() -> bool { + // reads from input and return true if it starts with Y or y + + let mut answer: String = String::new(); + io::stdin() + .read_line(&mut answer) + .expect("Error reading from stdin"); + + answer.to_uppercase().starts_with('Y') +} + +fn main() { + const PAGE_WIDTH: usize = 64; + print_center("CHIEF".to_string(), PAGE_WIDTH); + print_center( + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".to_string(), + PAGE_WIDTH, + ); + println!("\n\n\n"); + + println!("I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD."); + println!("ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR?"); + + if !check_yes_answer() { + println!("SHUT UP, PALE FACE WITH WISE TONGUE."); + } + + println!("TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND"); + println!("MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1."); + println!(" WHAT DO YOU HAVE?"); + + // read a float number + let mut answer: String = String::new(); + io::stdin() + .read_line(&mut answer) + .expect("Error reading from stdin"); + let guess: f32 = answer.trim().parse().expect("Input not a number"); + + let calculated_answer: f32 = (guess + 1.0 - 5.0) * 5.0 / 8.0 * 5.0 - 3.0; + + println!("I BET YOUR NUMBER WAS {calculated_answer}. AM I RIGHT?"); + + if check_yes_answer() { + println!("BYE!!!"); + } else { + println!("WHAT WAS YOUR ORIGINAL NUMBER?"); + + // read a float number + let mut answer: String = String::new(); + io::stdin() + .read_line(&mut answer) + .expect("Error reading from stdin"); + let claimed: f32 = answer.trim().parse().expect("Input not a number"); + + println!("SO YOU THINK YOU'RE SO SMART, EH?"); + println!("NOW WATCH."); + println!( + "{claimed} PLUS 3 EQUALS {}. THIS DIVIDED BY 5 EQUALS {};", + claimed + 3.0, + (claimed + 3.0) / 5.0 + ); + println!( + "THIS TIMES 8 EQUALS {}. IF WE DIVIDE BY 5 AND ADD 5,", + (claimed + 3.0) / 5.0 * 8.0 + ); + println!( + "WE GET {} , WHICH, MINUS 1, EQUALS {}.", + ((claimed + 3.0) / 5.0 * 8.0 / 5.0) + 5.0, + ((claimed + 3.0) / 5.0 * 8.0 / 5.0) + 4.0 + ); + println!("NOW DO YOU BELIEVE ME?"); + + if check_yes_answer() { + println!("BYE!!!"); + } else { + send_lightening(); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Porting notes: +// In floating point arithmetics in "modern" languages we might see +// unfamiliar situations such as 6.9999999 instead of 7 and such. +// resolving this needs using specific mathematical libraries which +// IMO is out of scope in these basic programs +/////////////////////////////////////////////////////////////////// From e287e311d40cf2075d9055d902ea11d8868d76b5 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 8 Aug 2023 16:50:33 -0700 Subject: [PATCH 195/377] Added MiniScript version of 40_Gomoko. (An embarrasingly poor Go Moku game.) --- .../40_Gomoko/MiniScript/README.md | 16 ++++ .../40_Gomoko/MiniScript/gomoko.ms | 94 +++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 00_Alternate_Languages/40_Gomoko/MiniScript/README.md create mode 100644 00_Alternate_Languages/40_Gomoko/MiniScript/gomoko.ms diff --git a/00_Alternate_Languages/40_Gomoko/MiniScript/README.md b/00_Alternate_Languages/40_Gomoko/MiniScript/README.md new file mode 100644 index 000000000..81f84973c --- /dev/null +++ b/00_Alternate_Languages/40_Gomoko/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 gomoko.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 "gomoko" + run diff --git a/00_Alternate_Languages/40_Gomoko/MiniScript/gomoko.ms b/00_Alternate_Languages/40_Gomoko/MiniScript/gomoko.ms new file mode 100644 index 000000000..3188e22a1 --- /dev/null +++ b/00_Alternate_Languages/40_Gomoko/MiniScript/gomoko.ms @@ -0,0 +1,94 @@ +print " "*33 + "Gomoku" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "Welcome to the Oriental game of Gomoko." +print; print "The game is played on an N by N grid of a size" +print "that you specify During your play, you may cover one grid" +print "intersection with a marker. The object of the game is to get" +print "5 adjacent markers in a row -- horizontally, vertically, or" +print "diagonally. On the board diagram, your moves are marked" +print "with a '1' and the computer moves with a '2'." +print; print "The computer does not keep track of who has won." +print "To end the game, type -1,-1 for your move."; print + +inBounds = function(x,y) + return 0 < x <= n and 0 < y <= n +end function + +empty = function(x,y) + return A[x][y] == 0 +end function + +printBoard = function + for y in range(1,n) + print A[y][1:n+1].join + end for + print +end function + +doPlayerMove = function + while true + inp = input("Your play (i,j)? ").replace(" ", "").split(",") + print + if inp.len != 2 then continue + x = inp[0].val; y = inp[1].val + if x == -1 then return false + if not inBounds(x,y) then + print "Illegal move. Try again..." + else if not empty(x,y) then + print "Square occupied. Try again..." + else + break + end if + end while + A[x][y] = 1 + globals.lastPlayerMove = [x,y] + return true +end function + +doComputerMove = function + // Computer tries a move near the player's last move + for e in range(-1,1) + for f in range(-1,1) + if e==0 and f==0 then continue + x = lastPlayerMove[0] + e; y = lastPlayerMove[1] + f + if inBounds(x,y) and empty(x,y) then + A[x][y] = 2 + return + end if + end for + end for + + // Computer tries a random move + while true + x = floor(n * rnd + 1); y = floor(n * rnd + 1) + if empty(x,y) then break + end while + A[x][y] = 2 +end function + +playGame = function + while true + globals.n = input("What is your board size (min 7/ max 19)? ").val + if 7 <= n <= 19 then break + print "I said, the minimum is 7, the maximum is 19." + end while + globals.A = [] + for i in range(0,19) + A.push [0]*20 + end for + print; print "We alternate moves. You go first..."; print + while true + if not doPlayerMove then return + doComputerMove + printBoard + end while +end function + +// Main loop +while true + playGame + print; print "Thanks for the game!!" + q = input("Play again (1 for Yes, 0 for No)? ").val + if q != 1 then break +end while \ No newline at end of file From 9b22b8cae1fbe55034952bf31b0c6ef5160eae6d Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Tue, 8 Aug 2023 19:04:03 -0700 Subject: [PATCH 196/377] Nim port of Buzzword --- .../20_Buzzword/nim/buzzword.nim | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 00_Alternate_Languages/20_Buzzword/nim/buzzword.nim diff --git a/00_Alternate_Languages/20_Buzzword/nim/buzzword.nim b/00_Alternate_Languages/20_Buzzword/nim/buzzword.nim new file mode 100644 index 000000000..dfba31c9d --- /dev/null +++ b/00_Alternate_Languages/20_Buzzword/nim/buzzword.nim @@ -0,0 +1,34 @@ +import std/[random,strutils] + +randomize() + +const + words1 = ["ABILITY","BASAL","BEHAVIORAL","CHILD-CENTERED","DIFFERENTIATED","DISCOVERY","FLEXIBLE", + "HETEROGENEOUS","HOMOGENEOUS","MANIPULATIVE","MODULAR","TAVISTOCK","INDIVIDUALIZED"] + words2 = ["LEARNING","EVALUATIVE","OBJECTIVE","COGNITIVE","ENRICHMENT","SCHEDULING","HUMANISTIC", + "INTEGRATED","NON-GRADED","TRAINING","VERTICAL AGE","MOTIVATIONAL","CREATIVE"] + words3 = ["GROUPING","MODIFICATION","ACCOUNTABILITY","PROCESS","CORE CURRICULUM","ALGORITHM", "PERFORMANCE", + "REINFORCEMENT","OPEN CLASSROOM","RESOURCE","STRUCTURE","FACILITY","ENVIRONMENT"] + +var + stillplaying: bool = true + prompt: string + +echo spaces(26), "BUZZWORD GENERATOR" +echo spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +echo "\n" +echo "THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN" +echo "'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS" +echo "AND SPEECHES. AFTER EACH PHRASE, HIT 'ENTER' FOR" +echo "ANOTHER PHRASE, OR TYPE 'N' TO QUIT." +echo "\n" +echo "HERE'S THE FIRST PHRASE..." + +while stillplaying: + echo "" + echo words1[rand(0..12)], " ", words2[rand(0..12)], " ", words3[rand(0..12)] + prompt = readLine(stdin).normalize() + if prompt.substr(0, 0) == "n": + stillplaying = false + +echo "COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!" From dd7d3c4c26c250bf34ee9d8ebb17514f332cfd08 Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Tue, 8 Aug 2023 20:57:33 -0700 Subject: [PATCH 197/377] Nim port of RockScissorsPaper Revised via Nim Discord --- .../nim/rockscissors.nim | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim b/00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim new file mode 100644 index 000000000..af2d1b1ac --- /dev/null +++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim @@ -0,0 +1,71 @@ +import std/[random,strutils] + +type + symbol = enum + PAPER = 1, SCISSORS = 2, ROCK = 3 + +var + cpuChoice, playerChoice, turns: int + cpuWins, playerWins, ties: int = 0 + +randomize() + +# Function: player makes a choice +proc choose(): int = + echo "3=ROCK...2=SCISSORS...1=PAPER...WHAT'S YOUR CHOICE?" + result = readLine(stdin).parseInt() + +# Function: determine the outcome +proc outcome(p: symbol, c: symbol): string = + if p == c: + ties += 1 + result = "TIE GAME. NO WINNER." + if p == SCISSORS and c == PAPER: + playerWins += 1 + result = "SCISSORS CUTS PAPER. YOU WIN." + if p == PAPER and c == SCISSORS: + cpuWins += 1 + result = "SCISSORS CUTS PAPER. I WIN." + if p == PAPER and c == ROCK: + playerWins += 1 + result = "PAPER COVERS ROCK. YOU WIN." + if p == ROCK and c == PAPER: + cpuWins += 1 + result = "PAPER COVERS ROCK. I WIN." + if p == ROCK and c == SCISSORS: + playerWins += 1 + result = "ROCK CRUSHES SCISSORS. YOU WIN." + if p == SCISSORS and c == ROCK: + cpuWins += 1 + result = "ROCK CRUSHES SCISSORS. I WIN." + +# Start the game +echo spaces(21), "GAME OF ROCK, SCISSORS, PAPER" +echo spaces(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +echo "\n" +echo "HOW MANY GAMES?" +turns = readLine(stdin).parseInt() +while turns > 10: + echo "SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY." + turns = readLine(stdin).parseInt() + +# Play the game +for i in 1..turns: + echo "" + echo "GAME NUMBER ", i + playerChoice = choose() + while playerChoice != 1 and playerChoice != 2 and playerChoice != 3: + echo "INVALID" + playerChoice = choose() + cpuChoice = rand(1..3) # match against range in symbol + echo "THIS IS MY CHOICE... ", symbol(cpuChoice) + echo outcome(symbol(playerChoice), symbol(cpuChoice)) + +# Results +echo "" +echo "HERE IS THE FINAL GAME SCORE:" +echo "I HAVE WON ", cpuWins," GAME(S)." +echo "YOU HAVE WON ", playerWins," GAME(S)." +echo "AND ", ties," GAME(S) ENDED IN A TIE." +echo "" +echo "THANKS FOR PLAYING!!" From aa0056624481b56e8b5dce40ad5a2f4ed0b0b8ed Mon Sep 17 00:00:00 2001 From: Michael Adams Date: Tue, 8 Aug 2023 22:09:02 -0700 Subject: [PATCH 198/377] Enhancement from Nim Discord --- .../nim/rockscissors.nim | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim b/00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim index af2d1b1ac..3c0cda0c5 100644 --- a/00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim +++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim @@ -1,4 +1,4 @@ -import std/[random,strutils] +import std/[random,strformat,strutils] type symbol = enum @@ -20,24 +20,21 @@ proc outcome(p: symbol, c: symbol): string = if p == c: ties += 1 result = "TIE GAME. NO WINNER." - if p == SCISSORS and c == PAPER: - playerWins += 1 - result = "SCISSORS CUTS PAPER. YOU WIN." - if p == PAPER and c == SCISSORS: - cpuWins += 1 - result = "SCISSORS CUTS PAPER. I WIN." - if p == PAPER and c == ROCK: - playerWins += 1 - result = "PAPER COVERS ROCK. YOU WIN." - if p == ROCK and c == PAPER: - cpuWins += 1 - result = "PAPER COVERS ROCK. I WIN." - if p == ROCK and c == SCISSORS: - playerWins += 1 - result = "ROCK CRUSHES SCISSORS. YOU WIN." - if p == SCISSORS and c == ROCK: - cpuWins += 1 - result = "ROCK CRUSHES SCISSORS. I WIN." + else: + const + winTable = [ + PAPER: (ROCK, "COVERS"), + SCISSORS: (PAPER, "CUTS"), + ROCK: (SCISSORS, "CRUSHES") + ] + let (winCond, winVerb) = winTable[p] + if winCond == c: + playerWins += 1 + result = fmt"{p} {winVerb} {c}. YOU WIN." + else: + let (_, winVerb) = winTable[c] + cpuWins += 1 + result = fmt"{c} {winVerb} {p}. I WIN." # Start the game echo spaces(21), "GAME OF ROCK, SCISSORS, PAPER" From deee3187d461305bbbf2a1e40dee90d6398db2ad Mon Sep 17 00:00:00 2001 From: Jadi Date: Wed, 9 Aug 2023 12:23:16 +0330 Subject: [PATCH 199/377] Adding the rust version for 58-Love --- 58_Love/rust/Cargo.toml | 8 ++++ 58_Love/rust/README.md | 3 ++ 58_Love/rust/src/main.rs | 92 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 58_Love/rust/Cargo.toml create mode 100644 58_Love/rust/README.md create mode 100644 58_Love/rust/src/main.rs diff --git a/58_Love/rust/Cargo.toml b/58_Love/rust/Cargo.toml new file mode 100644 index 000000000..1ec696335 --- /dev/null +++ b/58_Love/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/58_Love/rust/README.md b/58_Love/rust/README.md new file mode 100644 index 000000000..4cd904309 --- /dev/null +++ b/58_Love/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) by Jadi. diff --git a/58_Love/rust/src/main.rs b/58_Love/rust/src/main.rs new file mode 100644 index 000000000..5e8e18d72 --- /dev/null +++ b/58_Love/rust/src/main.rs @@ -0,0 +1,92 @@ +use std::io; + +fn show_intro() { + // Displays the intro text + println!("\n Love"); + println!("Creative Computing Morristown, New Jersey"); + println!("\n\n"); + println!("A tribute to the great American artist, Robert Indiana."); + println!("His great work will be reproduced with a message of"); + println!("your choice up to 60 characters. If you can't think of"); + println!("a message, simple type the word 'love'\n"); // (sic) +} + +fn main() { + enum PrintOrPass { + Print, + Pass, + } + + let data = [ + vec![60], + vec![1, 12, 26, 9, 12], + vec![3, 8, 24, 17, 8], + vec![4, 6, 23, 21, 6], + vec![4, 6, 22, 12, 5, 6, 5], + vec![4, 6, 21, 11, 8, 6, 4], + vec![4, 6, 21, 10, 10, 5, 4], + vec![4, 6, 21, 9, 11, 5, 4], + vec![4, 6, 21, 8, 11, 6, 4], + vec![4, 6, 21, 7, 11, 7, 4], + vec![4, 6, 21, 6, 11, 8, 4], + vec![4, 6, 19, 1, 1, 5, 11, 9, 4], + vec![4, 6, 19, 1, 1, 5, 10, 10, 4], + vec![4, 6, 18, 2, 1, 6, 8, 11, 4], + vec![4, 6, 17, 3, 1, 7, 5, 13, 4], + vec![4, 6, 15, 5, 2, 23, 5], + vec![1, 29, 5, 17, 8], + vec![1, 29, 9, 9, 12], + vec![1, 13, 5, 40, 1], + vec![1, 13, 5, 40, 1], + vec![4, 6, 13, 3, 10, 6, 12, 5, 1], + vec![5, 6, 11, 3, 11, 6, 14, 3, 1], + vec![5, 6, 11, 3, 11, 6, 15, 2, 1], + vec![6, 6, 9, 3, 12, 6, 16, 1, 1], + vec![6, 6, 9, 3, 12, 6, 7, 1, 10], + vec![7, 6, 7, 3, 13, 6, 6, 2, 10], + vec![7, 6, 7, 3, 13, 14, 10], + vec![8, 6, 5, 3, 14, 6, 6, 2, 10], + vec![8, 6, 5, 3, 14, 6, 7, 1, 10], + vec![9, 6, 3, 3, 15, 6, 16, 1, 1], + vec![9, 6, 3, 3, 15, 6, 15, 2, 1], + vec![10, 6, 1, 3, 16, 6, 14, 3, 1], + vec![10, 10, 16, 6, 12, 5, 1], + vec![11, 8, 13, 27, 1], + vec![11, 8, 13, 27, 1], + vec![60], + ]; + + const ROW_LEN: usize = 60; + show_intro(); + + let mut input: String = String::new(); + io::stdin().read_line(&mut input).expect("No valid input"); + let input = if input.len() == 1 { + "LOVE" + } else { + input.trim() + }; + // repeat the answer to fill the whole line, we will show chunks of this when needed + let input = input.repeat(ROW_LEN / (input.len()) + 1); + + // Now lets display the Love + print!("{}", "\n".repeat(9)); + for row in data { + let mut print_or_pass = PrintOrPass::Print; + let mut current_start = 0; + for count in row { + match print_or_pass { + PrintOrPass::Print => { + print!("{}", &input[current_start..count + current_start]); + print_or_pass = PrintOrPass::Pass; + } + PrintOrPass::Pass => { + print!("{}", " ".repeat(count)); + print_or_pass = PrintOrPass::Print; + } + } + current_start += count; + } + println!(); + } +} From 46a016decb30c91f751cc1c8271701886b6ea280 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 9 Aug 2023 08:54:34 -0700 Subject: [PATCH 200/377] Added MiniScript version of 42_Gunner. Also, clarified instructions in MiniScript README files. --- .../01_Acey_Ducey/MiniScript/README.md | 2 +- .../02_Amazing/MiniScript/README.md | 2 +- .../03_Animal/MiniScript/README.md | 2 +- .../04_Awari/MiniScript/README.md | 2 +- .../05_Bagels/MiniScript/README.md | 2 +- .../06_Banner/MiniScript/README.md | 2 +- .../07_Basketball/MiniScript/README.md | 2 +- .../08_Batnum/MiniScript/README.md | 2 +- .../09_Battle/MiniScript/README.md | 2 +- .../10_Blackjack/MiniScript/README.md | 2 +- .../11_Bombardment/MiniScript/README.md | 2 +- .../12_Bombs_Away/MiniScript/README.md | 2 +- .../13_Bounce/MiniScript/README.md | 2 +- .../14_Bowling/MiniScript/README.md | 2 +- .../15_Boxing/MiniScript/README.md | 2 +- .../16_Bug/MiniScript/README.md | 2 +- .../17_Bullfight/MiniScript/README.md | 2 +- .../18_Bullseye/MiniScript/README.md | 2 +- .../19_Bunny/MiniScript/README.md | 2 +- .../20_Buzzword/MiniScript/README.md | 2 +- .../21_Calendar/MiniScript/README.md | 2 +- .../22_Change/MiniScript/README.md | 2 +- .../23_Checkers/MiniScript/README.md | 2 +- .../24_Chemist/MiniScript/README.md | 2 +- .../25_Chief/MiniScript/README.md | 2 +- .../26_Chomp/MiniScript/README.md | 2 +- .../27_Civil_War/MiniScript/README.md | 2 +- .../28_Combat/MiniScript/README.md | 2 +- .../29_Craps/MiniScript/README.md | 2 +- .../30_Cube/MiniScript/README.md | 2 +- .../31_Depth_Charge/MiniScript/README.md | 2 +- .../32_Diamond/MiniScript/README.md | 2 +- .../33_Dice/MiniScript/README.md | 2 +- .../34_Digits/MiniScript/README.md | 2 +- .../35_Even_Wins/MiniScript/README.md | 2 +- .../36_Flip_Flop/MiniScript/README.md | 2 +- .../37_Football/MiniScript/README.md | 2 +- .../38_Fur_Trader/MiniScript/README.md | 2 +- .../39_Golf/MiniScript/README.md | 2 +- .../40_Gomoko/MiniScript/README.md | 2 +- .../41_Guess/MiniScript/README.md | 2 +- .../42_Gunner/MiniScript/README.md | 16 ++++ .../42_Gunner/MiniScript/gunner.ms | 78 +++++++++++++++++++ .../52_Kinema/MiniScript/README.md | 2 +- .../54_Letter/MiniScript/README.md | 2 +- .../64_Nicomachus/MiniScript/README.md | 2 +- .../66_Number/MiniScript/README.md | 2 +- .../78_Sine_Wave/MiniScript/README.md | 2 +- .../87_3-D_Plot/MiniScript/README.md | 2 +- .../91_Train/MiniScript/README.md | 2 +- .../92_Trap/MiniScript/README.md | 2 +- .../94_War/MiniScript/README.md | 2 +- 52 files changed, 144 insertions(+), 50 deletions(-) create mode 100644 00_Alternate_Languages/42_Gunner/MiniScript/README.md create mode 100644 00_Alternate_Languages/42_Gunner/MiniScript/gunner.ms diff --git a/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md b/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md index a15b86d99..c14b6da80 100644 --- a/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md +++ b/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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: +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 "aceyducey" run diff --git a/00_Alternate_Languages/02_Amazing/MiniScript/README.md b/00_Alternate_Languages/02_Amazing/MiniScript/README.md index a93e33d1b..301324c61 100644 --- a/00_Alternate_Languages/02_Amazing/MiniScript/README.md +++ b/00_Alternate_Languages/02_Amazing/MiniScript/README.md @@ -12,7 +12,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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: +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 "amazing" run diff --git a/00_Alternate_Languages/03_Animal/MiniScript/README.md b/00_Alternate_Languages/03_Animal/MiniScript/README.md index cb7892f60..580dd0de3 100644 --- a/00_Alternate_Languages/03_Animal/MiniScript/README.md +++ b/00_Alternate_Languages/03_Animal/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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: +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 "animal" run diff --git a/00_Alternate_Languages/04_Awari/MiniScript/README.md b/00_Alternate_Languages/04_Awari/MiniScript/README.md index 269d12154..744541123 100644 --- a/00_Alternate_Languages/04_Awari/MiniScript/README.md +++ b/00_Alternate_Languages/04_Awari/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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: +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 "awari" run diff --git a/00_Alternate_Languages/05_Bagels/MiniScript/README.md b/00_Alternate_Languages/05_Bagels/MiniScript/README.md index 91c9fda25..427482467 100644 --- a/00_Alternate_Languages/05_Bagels/MiniScript/README.md +++ b/00_Alternate_Languages/05_Bagels/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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: +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 "bagels" run diff --git a/00_Alternate_Languages/06_Banner/MiniScript/README.md b/00_Alternate_Languages/06_Banner/MiniScript/README.md index 0ec35b382..f93638530 100644 --- a/00_Alternate_Languages/06_Banner/MiniScript/README.md +++ b/00_Alternate_Languages/06_Banner/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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: +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 "banner" run diff --git a/00_Alternate_Languages/07_Basketball/MiniScript/README.md b/00_Alternate_Languages/07_Basketball/MiniScript/README.md index 408b74952..019fccb8d 100644 --- a/00_Alternate_Languages/07_Basketball/MiniScript/README.md +++ b/00_Alternate_Languages/07_Basketball/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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: +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 "basketball" run diff --git a/00_Alternate_Languages/08_Batnum/MiniScript/README.md b/00_Alternate_Languages/08_Batnum/MiniScript/README.md index 2a7ed1b45..bec1c7e03 100644 --- a/00_Alternate_Languages/08_Batnum/MiniScript/README.md +++ b/00_Alternate_Languages/08_Batnum/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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: +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 "batnum" run diff --git a/00_Alternate_Languages/09_Battle/MiniScript/README.md b/00_Alternate_Languages/09_Battle/MiniScript/README.md index 16b06b724..0e807f512 100644 --- a/00_Alternate_Languages/09_Battle/MiniScript/README.md +++ b/00_Alternate_Languages/09_Battle/MiniScript/README.md @@ -12,7 +12,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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: +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 "battle" run diff --git a/00_Alternate_Languages/10_Blackjack/MiniScript/README.md b/00_Alternate_Languages/10_Blackjack/MiniScript/README.md index 5b04b3a09..49c8818a2 100644 --- a/00_Alternate_Languages/10_Blackjack/MiniScript/README.md +++ b/00_Alternate_Languages/10_Blackjack/MiniScript/README.md @@ -12,7 +12,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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: +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 "blackjack" run diff --git a/00_Alternate_Languages/11_Bombardment/MiniScript/README.md b/00_Alternate_Languages/11_Bombardment/MiniScript/README.md index 1db2e68d2..d6e7e393c 100644 --- a/00_Alternate_Languages/11_Bombardment/MiniScript/README.md +++ b/00_Alternate_Languages/11_Bombardment/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript bombardment.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: +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 "bombardment" run diff --git a/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md b/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md index a654cb2a8..e7cb424cf 100644 --- a/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md +++ b/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript bombsaway.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: +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 "bombsaway" run diff --git a/00_Alternate_Languages/13_Bounce/MiniScript/README.md b/00_Alternate_Languages/13_Bounce/MiniScript/README.md index 22e4e41a9..d129ed9be 100644 --- a/00_Alternate_Languages/13_Bounce/MiniScript/README.md +++ b/00_Alternate_Languages/13_Bounce/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript bounce.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: +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 "bounce" run diff --git a/00_Alternate_Languages/14_Bowling/MiniScript/README.md b/00_Alternate_Languages/14_Bowling/MiniScript/README.md index 8ac592e76..e997160e2 100644 --- a/00_Alternate_Languages/14_Bowling/MiniScript/README.md +++ b/00_Alternate_Languages/14_Bowling/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript bowling.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: +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 "bowling" run diff --git a/00_Alternate_Languages/15_Boxing/MiniScript/README.md b/00_Alternate_Languages/15_Boxing/MiniScript/README.md index 0904fdae8..01454cd1d 100644 --- a/00_Alternate_Languages/15_Boxing/MiniScript/README.md +++ b/00_Alternate_Languages/15_Boxing/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript boxing.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: +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 "boxing" run diff --git a/00_Alternate_Languages/16_Bug/MiniScript/README.md b/00_Alternate_Languages/16_Bug/MiniScript/README.md index d668b53ee..aae43e942 100644 --- a/00_Alternate_Languages/16_Bug/MiniScript/README.md +++ b/00_Alternate_Languages/16_Bug/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript bug.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: +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 "bug" run diff --git a/00_Alternate_Languages/17_Bullfight/MiniScript/README.md b/00_Alternate_Languages/17_Bullfight/MiniScript/README.md index d791a463c..c3cc69c92 100644 --- a/00_Alternate_Languages/17_Bullfight/MiniScript/README.md +++ b/00_Alternate_Languages/17_Bullfight/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript bull.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: +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 "bull" run diff --git a/00_Alternate_Languages/18_Bullseye/MiniScript/README.md b/00_Alternate_Languages/18_Bullseye/MiniScript/README.md index 2c353d260..465e1c454 100644 --- a/00_Alternate_Languages/18_Bullseye/MiniScript/README.md +++ b/00_Alternate_Languages/18_Bullseye/MiniScript/README.md @@ -13,7 +13,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript bullseye.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: +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 "bullseye" run diff --git a/00_Alternate_Languages/19_Bunny/MiniScript/README.md b/00_Alternate_Languages/19_Bunny/MiniScript/README.md index 963066058..db1f76833 100644 --- a/00_Alternate_Languages/19_Bunny/MiniScript/README.md +++ b/00_Alternate_Languages/19_Bunny/MiniScript/README.md @@ -13,7 +13,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript bunny.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: +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 "bunny" run diff --git a/00_Alternate_Languages/20_Buzzword/MiniScript/README.md b/00_Alternate_Languages/20_Buzzword/MiniScript/README.md index 963066058..db1f76833 100644 --- a/00_Alternate_Languages/20_Buzzword/MiniScript/README.md +++ b/00_Alternate_Languages/20_Buzzword/MiniScript/README.md @@ -13,7 +13,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript bunny.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: +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 "bunny" run diff --git a/00_Alternate_Languages/21_Calendar/MiniScript/README.md b/00_Alternate_Languages/21_Calendar/MiniScript/README.md index 6d7f8ca58..140a5f4d0 100644 --- a/00_Alternate_Languages/21_Calendar/MiniScript/README.md +++ b/00_Alternate_Languages/21_Calendar/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript calendar.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: +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 "calendar" run diff --git a/00_Alternate_Languages/22_Change/MiniScript/README.md b/00_Alternate_Languages/22_Change/MiniScript/README.md index 5caa0d947..f43188b9c 100644 --- a/00_Alternate_Languages/22_Change/MiniScript/README.md +++ b/00_Alternate_Languages/22_Change/MiniScript/README.md @@ -13,7 +13,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript change.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: +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 "change" run diff --git a/00_Alternate_Languages/23_Checkers/MiniScript/README.md b/00_Alternate_Languages/23_Checkers/MiniScript/README.md index 51188bb1c..1c34d8cb3 100644 --- a/00_Alternate_Languages/23_Checkers/MiniScript/README.md +++ b/00_Alternate_Languages/23_Checkers/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript checkers.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: +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 "checkers" run diff --git a/00_Alternate_Languages/24_Chemist/MiniScript/README.md b/00_Alternate_Languages/24_Chemist/MiniScript/README.md index 88d26f88e..ddc32f16b 100644 --- a/00_Alternate_Languages/24_Chemist/MiniScript/README.md +++ b/00_Alternate_Languages/24_Chemist/MiniScript/README.md @@ -13,7 +13,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript chemist.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: +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 "chemist" run diff --git a/00_Alternate_Languages/25_Chief/MiniScript/README.md b/00_Alternate_Languages/25_Chief/MiniScript/README.md index f31bfa516..624f2817c 100644 --- a/00_Alternate_Languages/25_Chief/MiniScript/README.md +++ b/00_Alternate_Languages/25_Chief/MiniScript/README.md @@ -15,7 +15,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript chief.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: +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 "chief" run diff --git a/00_Alternate_Languages/26_Chomp/MiniScript/README.md b/00_Alternate_Languages/26_Chomp/MiniScript/README.md index f9800b1ed..db94c5032 100644 --- a/00_Alternate_Languages/26_Chomp/MiniScript/README.md +++ b/00_Alternate_Languages/26_Chomp/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript chomp.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: +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 "chomp" run diff --git a/00_Alternate_Languages/27_Civil_War/MiniScript/README.md b/00_Alternate_Languages/27_Civil_War/MiniScript/README.md index 205467edb..d5fd8e58d 100644 --- a/00_Alternate_Languages/27_Civil_War/MiniScript/README.md +++ b/00_Alternate_Languages/27_Civil_War/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript civilwar.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: +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 "civilwar" run diff --git a/00_Alternate_Languages/28_Combat/MiniScript/README.md b/00_Alternate_Languages/28_Combat/MiniScript/README.md index 1db41ab16..d15152479 100644 --- a/00_Alternate_Languages/28_Combat/MiniScript/README.md +++ b/00_Alternate_Languages/28_Combat/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript combat.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: +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 "combat" run diff --git a/00_Alternate_Languages/29_Craps/MiniScript/README.md b/00_Alternate_Languages/29_Craps/MiniScript/README.md index 69e82be16..2ecf089f8 100644 --- a/00_Alternate_Languages/29_Craps/MiniScript/README.md +++ b/00_Alternate_Languages/29_Craps/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript craps.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: +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 "craps" run diff --git a/00_Alternate_Languages/30_Cube/MiniScript/README.md b/00_Alternate_Languages/30_Cube/MiniScript/README.md index 56422df07..cca8d49df 100644 --- a/00_Alternate_Languages/30_Cube/MiniScript/README.md +++ b/00_Alternate_Languages/30_Cube/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript cube.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: +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 "cube" run diff --git a/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md b/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md index af1047033..d2603faed 100644 --- a/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md +++ b/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript depthcharge.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: +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 "depthcharge.ms" run diff --git a/00_Alternate_Languages/32_Diamond/MiniScript/README.md b/00_Alternate_Languages/32_Diamond/MiniScript/README.md index 552120d31..b8135184f 100644 --- a/00_Alternate_Languages/32_Diamond/MiniScript/README.md +++ b/00_Alternate_Languages/32_Diamond/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript diamond.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: +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 "diamond" run diff --git a/00_Alternate_Languages/33_Dice/MiniScript/README.md b/00_Alternate_Languages/33_Dice/MiniScript/README.md index abe65f49a..ab9361b3d 100644 --- a/00_Alternate_Languages/33_Dice/MiniScript/README.md +++ b/00_Alternate_Languages/33_Dice/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript dice.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: +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 "dice" run diff --git a/00_Alternate_Languages/34_Digits/MiniScript/README.md b/00_Alternate_Languages/34_Digits/MiniScript/README.md index 290b4b7c8..6936703d8 100644 --- a/00_Alternate_Languages/34_Digits/MiniScript/README.md +++ b/00_Alternate_Languages/34_Digits/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript digits.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: +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 "digits" run diff --git a/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md b/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md index ef01ce022..f64a21f8e 100644 --- a/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md +++ b/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md @@ -17,7 +17,7 @@ or 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: +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 "evenwins" run diff --git a/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md b/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md index 911c1441b..15b428318 100644 --- a/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md +++ b/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript flipflop.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: +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 "flipflop" run diff --git a/00_Alternate_Languages/37_Football/MiniScript/README.md b/00_Alternate_Languages/37_Football/MiniScript/README.md index ade04dd8b..c1790a56e 100644 --- a/00_Alternate_Languages/37_Football/MiniScript/README.md +++ b/00_Alternate_Languages/37_Football/MiniScript/README.md @@ -12,7 +12,7 @@ or miniscript ftball.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: +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 "football" run diff --git a/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md b/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md index 54956e39f..a714f84ba 100644 --- a/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md +++ b/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript furtrader.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: +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 "furtrader" run diff --git a/00_Alternate_Languages/39_Golf/MiniScript/README.md b/00_Alternate_Languages/39_Golf/MiniScript/README.md index ae8f8e566..33e39a949 100644 --- a/00_Alternate_Languages/39_Golf/MiniScript/README.md +++ b/00_Alternate_Languages/39_Golf/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript golf.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: +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 "golf" run diff --git a/00_Alternate_Languages/40_Gomoko/MiniScript/README.md b/00_Alternate_Languages/40_Gomoko/MiniScript/README.md index 81f84973c..bfd37db82 100644 --- a/00_Alternate_Languages/40_Gomoko/MiniScript/README.md +++ b/00_Alternate_Languages/40_Gomoko/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript gomoko.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: +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 "gomoko" run diff --git a/00_Alternate_Languages/41_Guess/MiniScript/README.md b/00_Alternate_Languages/41_Guess/MiniScript/README.md index e8c6e3d2e..903e75d72 100644 --- a/00_Alternate_Languages/41_Guess/MiniScript/README.md +++ b/00_Alternate_Languages/41_Guess/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript guess.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: +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 "guess" run diff --git a/00_Alternate_Languages/42_Gunner/MiniScript/README.md b/00_Alternate_Languages/42_Gunner/MiniScript/README.md new file mode 100644 index 000000000..6f6a59142 --- /dev/null +++ b/00_Alternate_Languages/42_Gunner/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 gunner.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 "gunner" + run diff --git a/00_Alternate_Languages/42_Gunner/MiniScript/gunner.ms b/00_Alternate_Languages/42_Gunner/MiniScript/gunner.ms new file mode 100644 index 000000000..5c52a89ea --- /dev/null +++ b/00_Alternate_Languages/42_Gunner/MiniScript/gunner.ms @@ -0,0 +1,78 @@ +print " "*30 + "Gunner" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "You are the officer-in-charge, giving orders to a gun" +print "crew, telling them the degrees of elevation you estimate" +print "will place a projectile on target. A hit within 100 yards" +print "of the target will destroy it."; print + +// Select a target and give the player up to 5 tries to hit it. +// Return the number of shots taken, or set globals.gameOver to true. +playOneTarget = function(maxRange) + globals.gameOver = false + targetDist = floor(maxRange * (.1 + .8 * rnd)) + shot = 0 + print "Distance to the target is " + targetDist + " yards." + print + while true + print + degrees = input("Elevation? ").val + if degrees > 89 then + print "Maximum elevation is 89 degrees." + continue + else if degrees < 1 then + print "Minimum elevation is one degree." + continue + end if + shot += 1 + if shot >= 6 then + globals.gameOver = true + return + end if + radiansX2 = 2 * degrees * pi/180 + throw = maxRange * sin(radiansX2) + diff = floor(targetDist - throw) + if abs(diff) < 100 then + print "*** TARGET DESTROYED *** " + shot + " rounds of ammunition expended." + return shot + end if + if diff > 0 then + print "Short of target by " + diff + " yards." + else + print "Over target by " + abs(diff) + " yards." + end if + end while +end function + +playOneGame = function + maxRange = floor(40000*rnd + 20000) + print "Maximum range of your gun is " + maxRange + " yards." + shots = 0 + for targetNum in range(1,4) + shots += playOneTarget(maxRange) + if gameOver then break + if targetNum < 4 then + print + print "The forward observer has sighted more enemy activity..." + end if + end for + if gameOver then + print; print "Boom !!!! You have just been destroyed" + print "by the enemy."; print; print; print + else + print; print; print "Total rounds expended were: " + shots + end if + if shots > 18 or gameOver then + print "Better go back to font sill for refresher training!" + else + print "Nice shooting !!" + end if +end function + +// Main loop +while true + playOneGame + print; yn = input("Try again (Y or N)? ").upper + if not yn or yn[0] != "Y" then break +end while +print; print "OK. Return to base camp." diff --git a/00_Alternate_Languages/52_Kinema/MiniScript/README.md b/00_Alternate_Languages/52_Kinema/MiniScript/README.md index 9052a1cb0..68275b3b9 100644 --- a/00_Alternate_Languages/52_Kinema/MiniScript/README.md +++ b/00_Alternate_Languages/52_Kinema/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript kinema.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: +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 "kinema" run diff --git a/00_Alternate_Languages/54_Letter/MiniScript/README.md b/00_Alternate_Languages/54_Letter/MiniScript/README.md index b64d108a6..705e34716 100644 --- a/00_Alternate_Languages/54_Letter/MiniScript/README.md +++ b/00_Alternate_Languages/54_Letter/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript letter.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: +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 "letter" run diff --git a/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md b/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md index fd2583939..803c95000 100644 --- a/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md +++ b/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript nicomachus.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: +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 "nicomachus" run diff --git a/00_Alternate_Languages/66_Number/MiniScript/README.md b/00_Alternate_Languages/66_Number/MiniScript/README.md index 230b0a4ba..769b1b46f 100644 --- a/00_Alternate_Languages/66_Number/MiniScript/README.md +++ b/00_Alternate_Languages/66_Number/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript number.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: +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 "number" run diff --git a/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md b/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md index 98d5cac98..c2f0cb5df 100644 --- a/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md +++ b/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript sinewave.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: +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 "sinewave" run diff --git a/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md b/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md index e10c4f998..817d92c03 100644 --- a/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md +++ b/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript number.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: +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 "number" run diff --git a/00_Alternate_Languages/91_Train/MiniScript/README.md b/00_Alternate_Languages/91_Train/MiniScript/README.md index bc083a8a6..6a23b537a 100644 --- a/00_Alternate_Languages/91_Train/MiniScript/README.md +++ b/00_Alternate_Languages/91_Train/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript train.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: +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 "train" run diff --git a/00_Alternate_Languages/92_Trap/MiniScript/README.md b/00_Alternate_Languages/92_Trap/MiniScript/README.md index 84dc58cd7..ab1575695 100644 --- a/00_Alternate_Languages/92_Trap/MiniScript/README.md +++ b/00_Alternate_Languages/92_Trap/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript trap.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: +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 "trap" run diff --git a/00_Alternate_Languages/94_War/MiniScript/README.md b/00_Alternate_Languages/94_War/MiniScript/README.md index d525f33ed..439064b3d 100644 --- a/00_Alternate_Languages/94_War/MiniScript/README.md +++ b/00_Alternate_Languages/94_War/MiniScript/README.md @@ -10,7 +10,7 @@ Download for your system from https://miniscript.org/cmdline/, install, and then miniscript war.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: +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 "war" run From 4efbb83d4fc918552cec7e318726d356a3d877a6 Mon Sep 17 00:00:00 2001 From: Frederic L <27208977+FreddyFunk@users.noreply.github.com> Date: Wed, 9 Aug 2023 21:36:10 +0200 Subject: [PATCH 201/377] gomoko: fix "intelligent move" coordinates --- 40_Gomoko/gomoko.bas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/40_Gomoko/gomoko.bas b/40_Gomoko/gomoko.bas index 662cca132..d57c10a1b 100644 --- a/40_Gomoko/gomoko.bas +++ b/40_Gomoko/gomoko.bas @@ -28,7 +28,7 @@ 440 A(I,J)=1 500 REM *** COMPUTER TRIES AN INTELLIGENT MOVE *** 510 FOR E=-1 TO 1: FOR F=-1 TO 1: IF E+F-E*F=0 THEN 590 -540 X=I+F: Y=J+F: GOSUB 910 +540 X=I+E: Y=J+F: GOSUB 910 570 IF L=0 THEN 590 580 IF A(X,Y)=1 THEN 710 590 NEXT F: NEXT E From 0d5de95cfa0f4d21b4f9a4a7195cf799281e6c72 Mon Sep 17 00:00:00 2001 From: steveglumify <136387213+steveglumify@users.noreply.github.com> Date: Mon, 14 Aug 2023 11:30:28 +1200 Subject: [PATCH 202/377] Update superstartrek.py Fixes issue #795- Ship class does not work correctly --- 84_Super_Star_Trek/python/superstartrek.py | 1 - 1 file changed, 1 deletion(-) diff --git a/84_Super_Star_Trek/python/superstartrek.py b/84_Super_Star_Trek/python/superstartrek.py index 2a86efba9..805c9d93a 100644 --- a/84_Super_Star_Trek/python/superstartrek.py +++ b/84_Super_Star_Trek/python/superstartrek.py @@ -335,7 +335,6 @@ def startup(self) -> None: " THE USS ENTERPRISE --- NCC-1701\n" "\n\n\n\n" ) - self.world = World() world = self.world print( "YOUR ORDERS ARE AS FOLLOWS:\n" From 238a31fcd5d348ca2c778d5ad9af36f683efa2bb Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 15 Aug 2023 16:38:40 -0700 Subject: [PATCH 203/377] Added MiniScript version of 43_Hammurabi. --- .../43_Hammurabi/MiniScript/README.md | 16 ++ .../43_Hammurabi/MiniScript/hammurabi.ms | 190 ++++++++++++++++++ .../43_Hammurabi/hammurabi.bas | 148 +++++++------- 43_Hammurabi/README.md | 3 +- 4 files changed, 281 insertions(+), 76 deletions(-) create mode 100644 00_Alternate_Languages/43_Hammurabi/MiniScript/README.md create mode 100644 00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms diff --git a/00_Alternate_Languages/43_Hammurabi/MiniScript/README.md b/00_Alternate_Languages/43_Hammurabi/MiniScript/README.md new file mode 100644 index 000000000..1d17e2b54 --- /dev/null +++ b/00_Alternate_Languages/43_Hammurabi/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 hammurabi.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 "hammurabi" + run diff --git a/00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms b/00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms new file mode 100644 index 000000000..9d06ec4d3 --- /dev/null +++ b/00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms @@ -0,0 +1,190 @@ +print " "*32 + "Hamurabi" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "Try your hand at governing ancient Sumeria" +print "for a ten-year term of office."; print + +eol = char(10) + +game = {} +game.z = 0 // year +game.p = 95 +game.s = 2800 // bushels in store +game.h = 3000 +game.e = game.h - game.s // bushels eaten by rats +game.food = 0 // bushels given to people to eat +game.y = 3 // value (in bushels) per acre +game.a = game.h / game.y // acres owned +game.i = 5 // immigration/births +game.d = 0 // how many starved this year +game.d1 = 0 // total starved over the whole game +game.p1 = 0 // average % of population starved per year +game.q = 1 // if negative, then a plague strikes + +startYear = function + print; print; print "Hamurabi: I beg to report to you," + game.z += 1 + print "In year " + game.z + ", " + + game.d + " people starved, " + + game.i + " came to the city," + game.p += game.i + if game.q < 0 then + game.p = floor(game.p / 2) + print "A horrible plague struck! Half the people died." + end if + print "Population is now " + game.p + "." + print "The city now owns " + game.a + " acres." + print "You harvested " + game.y + " bushels per acre." + print "The rats ate " + game.e + " bushels." + print "You now have " + game.s + " bushels in store."; print +end function + +exitGame = function + print; print char(7)*10 + print "So long for now."; print + exit +end function + +impeach = function + print "Due to this extreme mismanagement you have not only" + print "been impeached and thrown out of office but you have" + print "also been declared national fink!!!!" + exitGame +end function + +getNumber = function(prompt, max, maxMsg) + while true + value = input(prompt + "? ").val + if value < 0 then + print; print "Hamurabi: I cannot do what you wish." + print "Get yourself another steward!" + exitGame + end if + if value <= max then return value + print "Hamurabi: Think again. " + maxMsg + " Now then," + end while +end function + +hint = function(msg) + // This was not in the original program. But if you want to make + // the game easier, uncomment this line: + print msg +end function + +min = function(a, b, c) + m = [a, b, c] + m.sort + return m[0] +end function + +getDecisions = function + // buy/sell land + c = floor(10 * rnd); game.y = c + 17 + print "Land is trading at " + game.y + " bushels per acre." + qty = getNumber("How many acres do you wish to buy", + floor(game.s / game.y), "You have only" + eol + game.s + " bushels of grain.") + if qty > 0 then + game.a += qty + game.s -= game.y * qty + else + qty = getNumber("How many acres do you wish to sell", + game.a, "You own only" + eol + game.a + " acres.") + game.a -= qty + game.s += game.y * qty + end if + + // feed the people + hint "Your people want " + (game.p * 20) + " bushels of food." + game.food = getNumber("How many bushels do you wish to feed your people", + game.s, "You have only" + eol + game.s + " bushels of grain.") + game.s -= game.food + + // planting (a little more complicate because there are THREE limits) + hint "You can plant up to " + + min(game.a, floor(game.s * 2), floor(game.p*10-1)) + " acres." + game.d = 0 + while game.a > 0 and game.s > 2 + game.d = getNumber("How many acres do you wish to plant with seed", + game.a, "You own only " + game.a + " acres.") + // enough grain for seed? (each bushel can plant 2 acres) + if floor(game.d / 2) > game.s then + print "Hamurabi: Think again. You have only" + eol + game.s + + " bushels of grain. Now then," + continue + end if + // enough people to tend the crops? (each person can tend 10 acres) + if game.d >= game.p * 10 then + print "But you have only " + game.p + " people to tend the fields! Now then," + continue + end if + break + end while + game.s -= floor(game.d / 2) +end function + +simulateYear = function + // A bountiful harvest! + c = floor(rnd * 5) + 1 + game.y = c; game.h = game.d * game.y; game.e = 0 + c = floor(rnd * 5) + 1 + if c % 2 == 0 then + // rats are running wild!! + game.e = floor(game.s / c) + end if + game.s += game.h - game.e + + // Let's have some babies + c = floor(rnd * 5) + 1 + game.i = floor(c * (20 * game.a + game.s) / game.p / 100 + 1) + // How many people had full tummies? + c = floor(game.food / 20) + // Horros, a 15% chance of plague + game.q = floor(10 * (2 * rnd - 0.3)) + + if game.p < c then + game.d = 0 + else + // starve enough for impeachment? + game.d = game.p - c + if game.d > 0.45 * game.p then + print; print "You starved " + game.d + " people in one year!!!" + impeach + end if + game.p1 = ((game.z - 1) * game.p1 + game.d * 100 / game.p) / game.z + game.p = c + game.d1 += game.d + end if +end function + +printFinalResult = function + print "In your 10-year term of office, " + game.p1 + " percent of the" + print "population starved per year on the average, i.e., a total of" + print game.d1 + " people died!!" + acresPer = game.a / game.p + print "You started with 10 acres per person and ended with" + print acresPer + " acres per person."; print + if game.p1 > 33 or acresPer < 7 then impeach + if game.p1 > 10 or acresPer < 9 then + print "Your heavy-handed performance smacks of Nero and Ivan IV." + print "The people (remaining) find you an unpleasant ruler, and," + print "frankly, hate your guts!!" + else if game.p1 > 3 or acresPer < 10 then + print "Your performance could have been somewhat better, but" + print "really wasn't too bad at all. " + floor(game.p * 0.8 * rnd) + " people" + print "would dearly like to see you assassinated but we all have our" + print "trivial problems." + else + print "A fantastic performance!! Charlemange, Disraeli, and" + print "Jefferson combined could not have done better!" + end if +end function + +// Main loop +while true + startYear + if game.z == 11 then break + getDecisions + simulateYear +end while +printFinalResult +exitGame diff --git a/00_Alternate_Languages/43_Hammurabi/hammurabi.bas b/00_Alternate_Languages/43_Hammurabi/hammurabi.bas index e41fe4fbd..71afd1c51 100644 --- a/00_Alternate_Languages/43_Hammurabi/hammurabi.bas +++ b/00_Alternate_Languages/43_Hammurabi/hammurabi.bas @@ -1,119 +1,119 @@ -10 PRINT TAB(32);"HAMURABI" -20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" -30 PRINT:PRINT:PRINT +10 PRINT TAB(32); "HAMURABI" +20 PRINT TAB(15); "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT : PRINT : PRINT 80 PRINT "TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA" -90 PRINT "FOR A TEN-YEAR TERM OF OFFICE.":PRINT -95 D1=0: P1=0 -100 Z=0: P=95:S=2800: H=3000: E=H-S -110 Y=3: A=H/Y: I=5: Q=1 -210 D=0 -215 PRINT:PRINT:PRINT "HAMURABI: I BEG TO REPORT TO YOU,": Z=Z+1 -217 PRINT "IN YEAR";Z;",";D;"PEOPLE STARVED,";I;"CAME TO THE CITY," -218 P=P+I -227 IF Q>0 THEN 230 -228 P=INT(P/2) +90 PRINT "FOR A TEN-YEAR TERM OF OFFICE." : PRINT +95 D1 = 0 : P1 = 0 +100 Z = 0 : P = 95 : S = 2800 : H = 3000 : E = H - S +110 Y = 3 : A = H / Y : I = 5 : Q = 1 +210 D = 0 +215 PRINT : PRINT : PRINT "HAMURABI: I BEG TO REPORT TO YOU," : Z = Z + 1 +217 PRINT "IN YEAR "; Z; ","; D; " PEOPLE STARVED, "; I; " CAME TO THE CITY," +218 P = P + I +227 IF Q > 0 THEN 230 +228 P = INT(P / 2) 229 PRINT "A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED." -230 PRINT "POPULATION IS NOW";P -232 PRINT "THE CITY NOW OWNS ";A;"ACRES." -235 PRINT "YOU HARVESTED";Y;"BUSHELS PER ACRE." -250 PRINT "THE RATS ATE";E;"BUSHELS." -260 PRINT "YOU NOW HAVE ";S;"BUSHELS IN STORE.": PRINT -270 IF Z=11 THEN 860 -310 C=INT(10*RND(1)): Y=C+17 -312 PRINT "LAND IS TRADING AT";Y;"BUSHELS PER ACRE." +230 PRINT "POPULATION IS NOW "; P +232 PRINT "THE CITY NOW OWNS "; A; " ACRES." +235 PRINT "YOU HARVESTED "; Y; " BUSHELS PER ACRE." +250 PRINT "THE RATS ATE "; E; " BUSHELS." +260 PRINT "YOU NOW HAVE "; S; " BUSHELS IN STORE." : PRINT +270 IF Z = 11 THEN 860 +310 C = INT(10 * RND(1)) : Y = C + 17 +312 PRINT "LAND IS TRADING AT "; Y; " BUSHELS PER ACRE." 320 PRINT "HOW MANY ACRES DO YOU WISH TO BUY"; -321 INPUT Q: IF Q<0 THEN 850 -322 IF Y*Q<=S THEN 330 +321 INPUT Q : IF Q < 0 THEN 850 +322 IF Y * Q <= S THEN 330 323 GOSUB 710 324 GOTO 320 -330 IF Q=0 THEN 340 -331 A=A+Q: S=S-Y*Q: C=0 +330 IF Q = 0 THEN 340 +331 A = A + Q : S = S - Y * Q : C = 0 334 GOTO 400 340 PRINT "HOW MANY ACRES DO YOU WISH TO SELL"; -341 INPUT Q: IF Q<0 THEN 850 -342 IF Q
C/2 THEN 530 +522 IF INT(C / 2) <> C / 2 THEN 530 523 REM *** RATS ARE RUNNING WILD!! -525 E=INT(S/C) -530 S=S-E+H +525 E = INT(S / C) +530 S = S - E + H 531 GOSUB 800 532 REM *** LET'S HAVE SOME BABIES -533 I=INT(C*(20*A+S)/P/100+1) +533 I = INT(C *(20 * A + S) / P / 100 + 1) 539 REM *** HOW MANY PEOPLE HAD FULL TUMMIES? -540 C=INT(Q/20) +540 C = INT(Q / 20) 541 REM *** HORROS, A 15% CHANCE OF PLAGUE -542 Q=INT(10*(2*RND(1)-.3)) -550 IF P.45*P THEN 560 -553 P1=((Z-1)*P1+D*100/P)/Z -555 P=C: D1=D1+D: GOTO 215 -560 PRINT: PRINT "YOU STARVED";D;"PEOPLE IN ONE YEAR!!!" +552 D = P - C : IF D > 0.45 * P THEN 560 +553 P1 =((Z - 1) * P1 + D * 100 / P) / Z +555 P = C : D1 = D1 + D : GOTO 215 +560 PRINT : PRINT "YOU STARVED "; D; " PEOPLE IN ONE YEAR!!!" 565 PRINT "DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY" 566 PRINT "BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE" -567 PRINT "ALSO BEEN DECLARED NATIONAL FINK!!!!": GOTO 990 +567 PRINT "ALSO BEEN DECLARED NATIONAL FINK!!!!" : GOTO 990 710 PRINT "HAMURABI: THINK AGAIN. YOU HAVE ONLY" -711 PRINT S;"BUSHELS OF GRAIN. NOW THEN," -712 RETURN -720 PRINT "HAMURABI: THINK AGAIN. YOU OWN ONLY";A;"ACRES. NOW THEN," -730 RETURN -800 C=INT(RND(1)*5)+1 -801 RETURN -850 PRINT: PRINT "HAMURABI: I CANNOT DO WHAT YOU WISH." +711 PRINT S; "BUSHELS OF GRAIN. NOW THEN," +712 RETURN +720 PRINT "HAMURABI: THINK AGAIN. YOU OWN ONLY "; A; " ACRES. NOW THEN," +730 RETURN +800 C = INT(RND(1) * 5) + 1 +801 RETURN +850 PRINT : PRINT "HAMURABI: I CANNOT DO WHAT YOU WISH." 855 PRINT "GET YOURSELF ANOTHER STEWARD!!!!!" 857 GOTO 990 -860 PRINT "IN YOUR 10-YEAR TERM OF OFFICE,";P1;"PERCENT OF THE" +860 PRINT "IN YOUR 10-YEAR TERM OF OFFICE,"; P1; "PERCENT OF THE" 862 PRINT "POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF" -865 PRINT D1;"PEOPLE DIED!!": L=A/P +865 PRINT D1; "PEOPLE DIED!!" : L = A / P 870 PRINT "YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH" -875 PRINT L;"ACRES PER PERSON.": PRINT -880 IF P1>33 THEN 565 -885 IF L<7 THEN 565 -890 IF P1>10 THEN 940 -892 IF L<9 THEN 940 -895 IF P1>3 THEN 960 -896 IF L<10 THEN 960 +875 PRINT L; "ACRES PER PERSON." : PRINT +880 IF P1 > 33 THEN 565 +885 IF L < 7 THEN 565 +890 IF P1 > 10 THEN 940 +892 IF L < 9 THEN 940 +895 IF P1 > 3 THEN 960 +896 IF L < 10 THEN 960 900 PRINT "A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND" -905 PRINT "JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!":GOTO 990 +905 PRINT "JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!" : GOTO 990 940 PRINT "YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV." 945 PRINT "THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND," -950 PRINT "FRANKLY, HATE YOUR GUTS!!":GOTO 990 +950 PRINT "FRANKLY, HATE YOUR GUTS!!" : GOTO 990 960 PRINT "YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT" -965 PRINT "REALLY WASN'T TOO BAD AT ALL. ";INT(P*.8*RND(1));"PEOPLE" +965 PRINT "REALLY WASN'T TOO BAD AT ALL. "; INT(P * 0.8 * RND(1)); "PEOPLE" 970 PRINT "WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR" 975 PRINT "TRIVIAL PROBLEMS." -990 PRINT: FOR N=1 TO 10: PRINT CHR$(7);: NEXT N -995 PRINT "SO LONG FOR NOW.": PRINT -999 END +990 PRINT : FOR N = 1 TO 10 : PRINT CHR$(7); : NEXT N +995 PRINT "SO LONG FOR NOW." : PRINT +999 END \ No newline at end of file diff --git a/43_Hammurabi/README.md b/43_Hammurabi/README.md index 2e3d6397d..937044c86 100644 --- a/43_Hammurabi/README.md +++ b/43_Hammurabi/README.md @@ -23,8 +23,7 @@ http://www.vintage-basic.net/games.html #### Porting Notes -(please note any difficulties or challenges in porting here) - +- Though the file name and README both spell "Hammurabi" with two M's, the program itself consistently uses only one M. #### External Links - C: https://github.com/beyonddream/hamurabi From d8d0e93af2af0a4faaaae26edb3b290e2de4845b Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 15 Aug 2023 16:40:48 -0700 Subject: [PATCH 204/377] Hid "hint" output in MiniScript hammurabi code. --- 00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms b/00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms index 9d06ec4d3..f81a1e708 100644 --- a/00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms +++ b/00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms @@ -68,7 +68,7 @@ end function hint = function(msg) // This was not in the original program. But if you want to make // the game easier, uncomment this line: - print msg + //print msg end function min = function(a, b, c) From 4bff1aafb778273d77d9c3f58bbd7296a908d7da Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 16 Aug 2023 12:05:54 -0700 Subject: [PATCH 205/377] Added MiniScript version of 44_Hangman. --- .../44_Hangman/MiniScript/README.md | 16 +++ .../44_Hangman/MiniScript/hangman.ms | 127 ++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 00_Alternate_Languages/44_Hangman/MiniScript/README.md create mode 100644 00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms diff --git a/00_Alternate_Languages/44_Hangman/MiniScript/README.md b/00_Alternate_Languages/44_Hangman/MiniScript/README.md new file mode 100644 index 000000000..e5693849d --- /dev/null +++ b/00_Alternate_Languages/44_Hangman/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 hangman.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 "hangman" + run diff --git a/00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms b/00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms new file mode 100644 index 000000000..50c4e4466 --- /dev/null +++ b/00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms @@ -0,0 +1,127 @@ +print " "*32 + "Hangman" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +words = [] +words += ["gum","sin","for","cry","lug","bye","fly"] +words += ["ugly","each","from","work","talk","with","self"] +words += ["pizza","thing","feign","fiend","elbow","fault","dirty"] +words += ["budget","spirit","quaint","maiden","escort","pickax"] +words += ["example","tension","quinine","kidney","replica","sleeper"] +words += ["triangle","kangaroo","mahogany","sergeant","sequence"] +words += ["moustache","dangerous","scientist","different","quiescent"] +words += ["magistrate","erroneously","loudspeaker","phytotoxic"] +words += ["matrimonial","parasympathomimetic","thigmotropism"] +// Note: on Mini Micro, you could instead do: +// words = file.readLines("/sys/data/englishWords.txt") + +words.shuffle + +addToPic = function(guessCount) + if guessCount == 1 then + print "First, we draw a head" + ps[3][6]="-"; ps[3][7]="-"; ps[3][8]="-"; ps[4][5]="("; ps[4][6]="." + ps[4][8]="."; ps[4][9]=")"; ps[5][6]="-"; ps[5][7]="-"; ps[5][8]="-" + else if guessCount == 2 then + print "Now we draw a body." + for i in range(6, 9); ps[i][7]="x"; end for + else if guessCount == 3 then + print "Next we draw an arm." + for i in range(4, 7); ps[i][i-1]="\"; end for + else if guessCount == 4 then + print "This time it's the other arm." + ps[4][11]="/"; ps[5][10]="/"; ps[6][9]="/"; ps[7][8]="/" + else if guessCount == 5 then + print "Now, let's draw the right leg." + ps[10][6]="/"; ps[11][5]="/" + else if guessCount == 6 then + print "This time we draw the left leg." + ps[10][8]="\"; ps[11][9]="\" + else if guessCount == 7 then + print "Now we put up a hand." + ps[3][11]="\" + else if guessCount == 8 then + print "Next the other hand." + ps[3][3]="/" + else if guessCount == 9 then + print "Now we draw one foot" + ps[12][10]="\"; ps[12][11]="-" + else if guessCount == 10 then + print "Here's the other foot -- you're hung!!" + ps[12][3]="-"; ps[12][4]="/" + end if + for i in range(1, 12) + print ps[i].join("") + end for + print +end function + +doOneGame = function + usedLetters = [] + globals.ps = [] + for i in range(0, 12); ps.push [" "]*12; end for + for i in range(1,12); ps[i][1] = "X"; end for + for i in range(1, 7); ps[1][i] = "X"; end for; ps[2][7] = "X" + secretWord = words.pull.upper + print "(Secret word: " + secretWord + ")" + visibleWord = ["-"] * secretWord.len + wrongGuesses = 0 + while true + print "Here are the letters you used:" + print usedLetters.join(",") + print + print visibleWord.join("") + print + guess = input("What is your guess? ").upper + guess = (guess + " ")[0] + if guess < "A" or guess > "Z" then continue + if usedLetters.indexOf(guess) != null then + print "You guessed that letter before!" + continue + end if + usedLetters.push guess + for i in visibleWord.indexes + if secretWord[i] == guess then visibleWord[i] = guess + end for + if visibleWord.indexOf("-") == null then + print "You found the word!" + return true + else if secretWord.indexOf(guess) != null then + print + print visibleWord.join("") + print + guess = input("What is your guess for the word? ").upper + if guess == secretWord then + print "Right!! It took you " + usedLetters.len + " guesses!" + return true + else + print "Wrong. Try another letter." + end if + print + else + print "Sorry, that letter isn't in the word." + wrongGuesses += 1 + addToPic wrongGuesses + if wrongGuesses > 9 then + print "Sorry, you lose. The word was " + secretWord + return false + end if + end if + end while +end function + +while true + if not words then + print "You did all the words!!" + break + end if + won = doOneGame + if won then + yn = input("Want another word? ").upper + else + yn = input("You missed that one. Do you want another word? ").upper + end if + if not yn or yn[0] != "Y" then break +end while +print +print "It's been fun! Bye for now." From d46ddd68e86f7ebe9d8c3c75cb944e3211e66fe4 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 17 Aug 2023 16:05:43 -0700 Subject: [PATCH 206/377] Added MiniScript version of 45_Hello. --- .../45_Hello/MiniScript/README.md | 16 +++ .../45_Hello/MiniScript/hello.ms | 108 ++++++++++++++++++ 45_Hello/README.md | 2 +- 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/45_Hello/MiniScript/README.md create mode 100644 00_Alternate_Languages/45_Hello/MiniScript/hello.ms diff --git a/00_Alternate_Languages/45_Hello/MiniScript/README.md b/00_Alternate_Languages/45_Hello/MiniScript/README.md new file mode 100644 index 000000000..6f6a59142 --- /dev/null +++ b/00_Alternate_Languages/45_Hello/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 gunner.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 "gunner" + run diff --git a/00_Alternate_Languages/45_Hello/MiniScript/hello.ms b/00_Alternate_Languages/45_Hello/MiniScript/hello.ms new file mode 100644 index 000000000..a82344ef2 --- /dev/null +++ b/00_Alternate_Languages/45_Hello/MiniScript/hello.ms @@ -0,0 +1,108 @@ +print " "*33 + "Hello" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +print "Hello. My name is Creative Computer." +print +print +ns = input("What's your name? ") +print +print "Hi there, " + ns + ", are you enjoying yourself here?" +while true + bs = input.lower + print + if bs == "yes" then + print "I'm glad to hear that, " + ns + "." + print + break + else if bs == "no" then + print "Oh, I'm sorry to hear that, " + ns + ". Maybe we can" + print "brighten up your visit a bit." + break + else + print "Please answer 'yes' or 'no'. Do you like it here?" + end if +end while +print +print "Say, " + ns + ", I can solve all kinds of problems except" +print "those dealing with Greece. What kind of problems do" +print "you have (answer sex, health, money, or job)?" +while true + cs = input + print + if cs != "sex" and cs != "health" and cs != "money" and cs != "job" then + print "Oh, " + ns + ", your answer of " + cs + " is Greek to me." + else if cs == "job" then + print "I can sympathize with you " + ns + ". I have to work" + print "very long hours for no pay -- and some of my bosses" + print "really beat on my keyboard. My advice to you, " + ns + "," + print "is to open a retail computer store. It's great fun." + else if cs == "money" then + print "Sorry, " + ns + ", I'm broke too. Why don't you sell" + print "encyclopeadias or marry someone rich or stop eating" + print "so you won't need so much money?" + else if cs == "health" then + print "My advice to you " + ns + " is:" + print " 1. Take two asprin" + print " 2. Drink plenty of fluids (orange juice, not beer!)" + print " 3. Go to bed (alone)" + else + print "Is your problem too much or too little?" + while true + ds = input.lower + print + if ds == "too much" then + print "You call that a problem?!! I should have such problems!" + print "If it bothers you, " + ns + ", take a cold shower." + break + else if ds == "too little" then + print "Why are you here in suffern, " + ns + "? You should be" + print "in Tokyo or New York or Amsterdam or someplace with some" + print "real action." + break + else + print "Don't get all shook, " + ns + ", just answer the question" + print "with 'too much' or 'too little'. Which is it?" + end if + end while + end if + print + print "Any more problems you want solved, " + ns + "?" + es = input.lower + print + if es == "yes" then + print "What kind (sex, money, health, job)?" + else if es == "no" then + print "That will be $5.00 for the advice, " + ns + "." + print "Please leave the money on the terminal." + print + wait 2 + print + print + while true + gs = input("Did you leave the money? ").lower + print + if gs == "yes" then + print "Hey, " + ns + "??? You left no money at all!" + print "You are cheating me out of my hard-earned living." + print + print "What a rip off, " + ns + "!!!" + print + break + else if gs == "no" then + print "That's honest, " + ns + ", but how do you expect" + print "me to go on with my psychology studies if my patient" + print "don't pay their bills?" + break + else + print "Your answer of '" + gs + "' confuses me, " + ns + "." + print "Please respond with 'yes' or 'no'." + end if + end while + break + end if +end while +print +print "Take a walk, " + ns + "." +print +print diff --git a/45_Hello/README.md b/45_Hello/README.md index 87c47f65d..243efa700 100644 --- a/45_Hello/README.md +++ b/45_Hello/README.md @@ -2,7 +2,7 @@ This is a sample of one of the great number of conversational programs. In a sense, it is like a CAI program except that its responses are just good fun. Whenever a computer is exhibited at a convention or conference with people that have not used a computer before, the conversational programs seem to get the first activity. -In this particular program, the computer dispenses advice on various problems such as sex. health, money, or job. +In this particular program, the computer dispenses advice on various problems such as sex, health, money, or job. David Ahl is the author of HELLO. From af39f3df3ffaef1981b55ec77e15e9501f087401 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 17 Aug 2023 16:18:53 -0700 Subject: [PATCH 207/377] Fixed README for 45_Hello/MiniScript. --- 00_Alternate_Languages/45_Hello/MiniScript/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/00_Alternate_Languages/45_Hello/MiniScript/README.md b/00_Alternate_Languages/45_Hello/MiniScript/README.md index 6f6a59142..c35f91c5d 100644 --- a/00_Alternate_Languages/45_Hello/MiniScript/README.md +++ b/00_Alternate_Languages/45_Hello/MiniScript/README.md @@ -7,10 +7,10 @@ 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 gunner.ms + miniscript hello.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 "gunner" + load "hello" run From 5e713bc7f7bcac37e3f67f9b152a32485021810d Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 17 Aug 2023 21:27:07 -0700 Subject: [PATCH 208/377] Added MiniScript version of 46_Hexapawn. --- .../46_Hexapawn/MiniScript/README.md | 16 ++ .../46_Hexapawn/MiniScript/hexapawn.ms | 266 ++++++++++++++++++ 46_Hexapawn/README.md | 4 + 3 files changed, 286 insertions(+) create mode 100644 00_Alternate_Languages/46_Hexapawn/MiniScript/README.md create mode 100644 00_Alternate_Languages/46_Hexapawn/MiniScript/hexapawn.ms diff --git a/00_Alternate_Languages/46_Hexapawn/MiniScript/README.md b/00_Alternate_Languages/46_Hexapawn/MiniScript/README.md new file mode 100644 index 000000000..f6406c0d9 --- /dev/null +++ b/00_Alternate_Languages/46_Hexapawn/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 hexapawn.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 "hexapawn" + run diff --git a/00_Alternate_Languages/46_Hexapawn/MiniScript/hexapawn.ms b/00_Alternate_Languages/46_Hexapawn/MiniScript/hexapawn.ms new file mode 100644 index 000000000..f2505ac4e --- /dev/null +++ b/00_Alternate_Languages/46_Hexapawn/MiniScript/hexapawn.ms @@ -0,0 +1,266 @@ +print " "*32 + "Hexapawn" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +// Hexapawn: interpretation of hexapawn game as presented in +// Martin Gardner's "The Unexpected Hanging and Other Mathematic- +// al Diversions", chapter eight: A Matchbox Game-Learning Machine +// Original version for H-P timeshare system by reversed.A. Kaapke 5/5/76 +// Instructions by jeff dalton +// Conversion to MITS BASIC by Steve North +// Conversion to MiniScript by Joe Strout + +// All 19 possible board positions: +ba = [null, + [null,-1,-1,-1,1,0,0,0,1,1], + [null,-1,-1,-1,0,1,0,1,0,1], + [null,-1,0,-1,-1,1,0,0,0,1], + [null,0,-1,-1,1,-1,0,0,0,1], + [null,-1,0,-1,1,1,0,0,1,0], + [null,-1,-1,0,1,0,1,0,0,1], + [null,0,-1,-1,0,-1,1,1,0,0], + [null,0,-1,-1,-1,1,1,1,0,0], + [null,-1,0,-1,-1,0,1,0,1,0], + [null,0,-1,-1,0,1,0,0,0,1], + [null,0,-1,-1,0,1,0,1,0,0], + [null,-1,0,-1,1,0,0,0,0,1], + [null,0,0,-1,-1,-1,1,0,0,0], + [null,-1,0,0,1,1,1,0,0,0], + [null,0,-1,0,-1,1,1,0,0,0], + [null,-1,0,0,-1,-1,1,0,0,0], + [null,0,0,-1,-1,1,0,0,0,0], + [null,0,-1,0,1,-1,0,0,0,0], + [null,-1,0,0,-1,1,0,0,0,0]] + +// Possible responses for each board position (move from x to y, +// represented as x*10 + y): +ma = [null, + [null,24,25,36,0], + [null,14,15,36,0], + [null,15,35,36,47], + [null,36,58,59,0], + [null,15,35,36,0], + [null,24,25,26,0], + [null,26,57,58,0], + [null,26,35,0,0], + [null,47,48,0,0], + [null,35,36,0,0], + [null,35,36,0,0], + [null,36,0,0,0], + [null,47,58,0,0], + [null,15,0,0,0], + [null,26,47,0,0], + [null,47,58,0,0], + [null,35,36,47,0], + [null,28,58,0,0], + [null,15,47,0,0]] +s = [0]*10 +t = [0]*10 + +showBoard = function + print + for i in [1,2,3] + print " "*10, "" + for j in [1,2,3] + print "X.O"[s[(i - 1) * 3 + j] + 1], "" + end for + print + end for +end function + +mirror = function(x) + return [null, 3,2,1, 6,5,4, 9,8,7][x] +end function + +mirrorBoard = function(b) + return [null, b[3],b[2],b[1], b[6],b[5],b[4], b[9],b[8],b[7]] +end function + +intro = function + while true + s = input("Instructions (Y-N)? ").lower + if s then s = s[0] + if s == "n" then return + if s == "y" then break + end while + print + print "This program plays the game of Hexapawn." + print "Hexapawn is played with Chess pawns on a 3 by 3 board." + print "The pawns are moved as in Chess - one space forward to" + print "an empty space or one space forward and diagonally to" + print "capture an opposing man. On the board, your pawns" + print "are 'O', the computer's pawns are 'X', and empty " + print "squares are '.'. To enter a move, type the number of" + print "the square you are moving from, followed by the number" + print "of the square you will move to. The numbers must be" + print "seperated by a comma." + print + input "(Press Return.)" + print + print "The computer starts a series of games knowing only when" + print "the game is won (a draw is impossible) and how to move." + print "It has no strategy at first and just moves randomly." + print "However, it learns from each game. Thus, winning becomes" + print "more and more difficult. Also, to help offset your" + print "initial advantage, you will not be told how to win the" + print "game but must learn this by playing." + print + print "The numbering of the board is as follows:" + print " "*10 + "123" + print " "*10 + "456" + print " "*10 + "789" + print + print "For example, to move your rightmost pawn forward," + print "you would type 9,6 in response to the question" + print "'Your move?'. Since I'm a good sport, you'll always" + print "go first." + print +end function + +getMove = function + while true + inp = input("Your move? ").replace(",", " ").split + if inp.len > 1 then + m1 = inp[0].val + m2 = inp[-1].val + if 0 < m1 < 10 and 0 < m2 < 10 then + if s[m1] != 1 or s[m2] == 1 or + (m2 - m1 != -3 and s[m2] != -1) or + (m2 > m1) or (m2 - m1 == -3 and s[m2] != 0) or + (m2 - m1 < -4) or (m1 == 7 and m2 == 3) then + print "Illegal move." + continue + end if + return [m1, m2] + end if + end if + print "Illegal co-ordinates." + end while +end function + +// Find the current board number (1-19) and whether it is mirrored. +findBoardNum = function + idx = ba.indexOf(s) + if idx != null then return [idx, false] + idx = ba.indexOf(mirrorBoard(s)) + if idx != null then return [idx, true] + return null +end function + +// Main program +intro +wins = 0 +losses = 0 +while true + s = [null, -1,-1,-1, 0,0,0, 1,1,1] + computerWins = false + showBoard + while true + // Input player's move + userMove = getMove + m1 = userMove[0]; m2 = userMove[1] + + // Move player's pawn + s[m1] = 0 + s[m2] = 1 + showBoard + + // If no computer pawns, or player reached top, then computer loses + if s.indexOf(-1) == null or s[1] == 1 or s[2] == 1 or s[3] == 1 then + break + end if + // Ensure at least one computer pawn with valid move. + // (Note: original BASIC code for this had several bugs; the code + // below should be more correct.) + anyValidMove = false + for i in range(1, 6) // (no sense checking position 7-9) + if s[i] != -1 then continue + // check for a straight-ahead move + if s[i + 3] == 0 then anyValidMove = true + // check for a capture + if i == 2 or i == 5 then + if s[i+2] == 1 or s[i+4] == 1 then anyValidMove = true + else if i == 1 or i == 4 then + if s[i+4] == 1 then anyValidMove = true + else + if s[i+2] == 1 then anyValidMove = true + end if + end for + if not anyValidMove then break + + boardAndReversed = findBoardNum + if boardAndReversed == null then + print "Illegal board pattern" // (should never happen in normal play) + break + end if + x = boardAndReversed[0]; reversed = boardAndReversed[1] + + // Select a random move for board X, as permitted by our memory + possibilities = [] + for i in range(1, 4) + if ma[x][i] != 0 then possibilities.push i + end for + + // For more insight into how the computer learns, uncomment this line: + //print "Considering for board " + x + ": " + possibilities + " (reversed=" + reversed + ")" + if not possibilities then + print "I resign." + break + end if + possibilities.shuffle + y = possibilities[0] + + m1 = floor(ma[x][y] / 10) + m2 = ma[x][y] % 10 + if reversed then + m1 = mirror(m1) + m2 = mirror(m2) + end if + + // Announce move + print "I move from " + m1 + " to " + m2 + s[m1] = 0 + s[m2] = -1 + showBoard + + // Finish if computer reaches bottom, or no player pawns are left + if s[7] == -1 or s[8] == -1 or s[9] == -1 or s.indexOf(1) == null then + computerWins = true + break + end if + + // Finish if player cannot move + playerCanMove = false + for i in range(1, 9) + if s[i] != 1 then continue + if i > 3 and s[i - 3] == 0 then playerCanMove = true + if mirror(i) != i then + if i >= 7 then + if s[5] == -1 then playerCanMove = true + else + if s[2] == -1 then playerCanMove = true + end if + else + if s[i - 2] == -1 or s[i - 4] == -1 then playerCanMove = true + end if + end for + if not playerCanMove then + print "You can't move, so ", "" + computerWins = true + break + end if + end while + if computerWins then + print "I win." + wins += 1 + else + print "You win" + // Because we lost, clear out the last response used, so that we don't + // make the same mistake again. This is how the computer learns! + ma[x][y] = 0 + losses += 1 + end if + print "I have won " + wins + " and you " + losses + " out of " + (losses + wins) + " games." + print + wait 2 +end while \ No newline at end of file diff --git a/46_Hexapawn/README.md b/46_Hexapawn/README.md index bbcf0ad67..6376c0367 100644 --- a/46_Hexapawn/README.md +++ b/46_Hexapawn/README.md @@ -15,6 +15,10 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- There are valid board positions that will cause the program to print "ILLEGAL BOARD PATTERN" and break. For example: human 8,5; computer 1,5; human 9,5; computer 3,5; human 7,5. This is a valid game-over pattern, but it is not detected as such because of incorrect logic in lines 240-320 (intended to detect whether the computer has any legal moves). + #### Porting Notes (please note any difficulties or challenges in porting here) From a0d77610224729fc14a4f1d1dcd147eddb4f477d Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Fri, 18 Aug 2023 07:38:02 -0700 Subject: [PATCH 209/377] Added MiniScript version of 47_Hi-Lo. --- .../47_Hi-Lo/MiniScript/README.md | 19 +++++++++ .../47_Hi-Lo/MiniScript/hi-lo.ms | 41 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md create mode 100644 00_Alternate_Languages/47_Hi-Lo/MiniScript/hi-lo.ms diff --git a/00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md b/00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md new file mode 100644 index 000000000..21af327dc --- /dev/null +++ b/00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of hi-lo.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 hi-lo.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 "hi-lo" + run diff --git a/00_Alternate_Languages/47_Hi-Lo/MiniScript/hi-lo.ms b/00_Alternate_Languages/47_Hi-Lo/MiniScript/hi-lo.ms new file mode 100644 index 000000000..bd0801eed --- /dev/null +++ b/00_Alternate_Languages/47_Hi-Lo/MiniScript/hi-lo.ms @@ -0,0 +1,41 @@ +print " "*34 + "Hi Lo" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "This is the game of hi lo."; print +print "You will have 6 tries to guess the amount of money in the" +print "hi lo jackpot, which is between 1 and 100 dollars. If you" +print "guess the amount, you win all the money in the jackpot!" +print "Then you get another chance to win more money. However," +print "if you do not guess the amount, the game ends."; print +total = 0 +while true + guesses=0 + print + number=floor(100*rnd) + while true + guess = input("Your guess? ").val + guesses += 1 + if guess < number then + print "Your guess is too low." + else if guess > number then + print "Your guess is too high." + else + print "Got it!!!!!!!!!! You win " + number + " dollars." + total += number + print "Your total winnings are now " + total + " dollars." + break + end if + if guesses >= 6 then + print "You blew it...too bad...the number was " + number + total = 0 + break + end if + end while + + print + yn = input("Play again (yes or no)?").lower + if not yn or yn[0] != "y" then break +end while + +print +print "So long. Hope you enjoyed yourself!!!" From d8cb591dea7212f8614b3ba49f108e26e00ae6e6 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Fri, 18 Aug 2023 08:51:39 -0700 Subject: [PATCH 210/377] Added MiniScript version of 48_High_IQ. --- .../48_High_IQ/MiniScript/README.md | 16 ++ .../48_High_IQ/MiniScript/highiq.ms | 163 ++++++++++++++++++ 2 files changed, 179 insertions(+) create mode 100644 00_Alternate_Languages/48_High_IQ/MiniScript/README.md create mode 100644 00_Alternate_Languages/48_High_IQ/MiniScript/highiq.ms diff --git a/00_Alternate_Languages/48_High_IQ/MiniScript/README.md b/00_Alternate_Languages/48_High_IQ/MiniScript/README.md new file mode 100644 index 000000000..27d7baf8e --- /dev/null +++ b/00_Alternate_Languages/48_High_IQ/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 highiq.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 "highiq" + run diff --git a/00_Alternate_Languages/48_High_IQ/MiniScript/highiq.ms b/00_Alternate_Languages/48_High_IQ/MiniScript/highiq.ms new file mode 100644 index 000000000..5d2ab966f --- /dev/null +++ b/00_Alternate_Languages/48_High_IQ/MiniScript/highiq.ms @@ -0,0 +1,163 @@ +print " "*33 + "H-I-Q" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "Here is the board:"; print + +print " ! ! !" +print " 13 14 15"; print +print " ! ! !" +print " 22 23 24"; print +print "! ! ! ! ! ! !" +print "29 30 31 32 33 34 35"; print +print "! ! ! ! ! ! !" +print "38 39 40 41 42 43 44"; print +print "! ! ! ! ! ! !" +print "47 48 49 50 51 52 53"; print +print " ! ! !" +print " 58 59 60"; print +print " ! ! !" +print " 67 68 69"; print +print "To save typing time, a compressed version of the game board" +print "will be used during play. Refer to the above one for peg" +input "numbers. Press Return to begin." +print + +// Prepare the board (t): a 9x9 2D array, with 5 for pins, +// -5 for invalid (no hole) positions, and 0 for empty holes. +// Also prepare the pinToPos map, which maps pin numbers to +// [row, column] positions. +setupBoard = function + globals.t = [[-5]*10] + globals.pinToPos = {} + pinNums = [13,14,15,22,23,24,29,30,31,32,33,34,35,38,39,40,41, + 42,43,44,47,48,49,50,51,52,53,58,59,60,67,68,69] + for row in range(1,9) + t.push [-5]*10 + for col in range(1,9) + if row < 2 or row > 8 or col < 2 or col > 8 or + ((row < 4 or row > 6) and (col < 4 or col > 6)) then + t[row][col] = -5 + else + t[row][col] = 5 + pinToPos[pinNums.pull] = [row,col] + end if + end for + end for + t[5][5] = 0 +end function + +printBoard = function + for x in range(1,9) + s = "" + for y in range(1,9) + if t[x][y] < 0 then + s += " " + else if t[x][y] == 0 then + s += " o" + else + s += " !" + end if + end for + print s + end for +end function + +isPin = function(pinNum) + if not pinToPos.hasIndex(pinNum) then return false + pos = pinToPos[pinNum] + return t[pos[0]][pos[1]] == 5 +end function + +isHole = function(pinNum) + if not pinToPos.hasIndex(pinNum) then return false + pos = pinToPos[pinNum] + return t[pos[0]][pos[1]] == 0 +end function + +isValidJump = function(pinFrom, pinTo) + if not pinToPos.hasIndex(pinFrom) then return false + posFrom = pinToPos[pinFrom] + if not isHole(pinTo) then return false + posTo = pinToPos[pinTo] + // check that the Manhattan distance is exactly 2 + dist = abs(posFrom[0] - posTo[0]) + abs(posFrom[1] - posTo[1]) + if dist != 2 then return false + // and check that the intervening position contains a pin + if t[(posFrom[0]+posTo[0])/2][(posFrom[1]+posTo[1])/2] != 5 then return false + return true +end function + +// Check if the game is over (player has no legal moves). +// Return true if over, false if there are legal moves yet. +checkGameOver = function + for row in range(2,8) + for col in range(2,8) + fromPin = pinToPos.indexOf([row,col]) + if fromPin == null or not isPin(fromPin) then continue + for r2 in [row-2, row+2] + toPin = pinToPos.indexOf([r2,col]) + if toPin == null then continue + if isValidJump(fromPin, toPin) then return false + end for + for c2 in [col-2, col+2] + toPin = pinToPos.indexOf([row,c2]) + if toPin == null then continue + if isValidJump(fromPin, toPin) then return false + end for + end for + end for + return true // no legal moves found, so game over +end function + +// Get the user's move, returning [[fromRow,fromCol], [toRow,toCol]]. +// (Check legality and return only legal moves.) +getMove = function + print + while true + fromNum = input("Move which piece? ").val + if isPin(fromNum) then toNum = input("To where? ").val else toNum = 0 + if isHole(toNum) and isValidJump(fromNum, toNum) then break + print "Illegal move, try again..." + end while + return [pinToPos[fromNum], pinToPos[toNum]] +end function + +// Get the user's move, and update the board accordingly. +doOneMove = function + move = getMove + fromRow = move[0][0]; fromCol = move[0][1] + toRow = move[1][0]; toCol = move[1][1] + t[fromRow][fromCol] = 0 + t[toRow][toCol] = 5 + t[(fromRow+toRow)/2][(fromCol+toCol)/2] = 0 +end function + +// Main program +while true + setupBoard + printBoard + while true + doOneMove + print + printBoard + if checkGameOver then break + end while + print; print "The game is over." + pinsLeft = 0 + for a in t + for b in a + if b == 5 then pinsLeft += 1 + end for + end for + print "You had " + pinsLeft + " pieces remaining." + if pinsLeft == 1 then + print "Bravo! You made a perfect score!" + print "Save this paper as a record of your accomplishment!" + end if + print + yn = input("Play again (yes or no)? ").lower + if yn and yn[0] == "n" then break +end while +print; print "So long for now."; print + + \ No newline at end of file From 15970619e3866a1aee7afba4aec7da6d765b052c Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 22 Aug 2023 07:50:57 -0700 Subject: [PATCH 211/377] Added MiniScript version of 49_Hockey. --- .../49_Hockey/MiniScript/README.md | 16 + .../49_Hockey/MiniScript/hockey.ms | 396 ++++++++++++++++++ 49_Hockey/README.md | 5 + 3 files changed, 417 insertions(+) create mode 100644 00_Alternate_Languages/49_Hockey/MiniScript/README.md create mode 100644 00_Alternate_Languages/49_Hockey/MiniScript/hockey.ms diff --git a/00_Alternate_Languages/49_Hockey/MiniScript/README.md b/00_Alternate_Languages/49_Hockey/MiniScript/README.md new file mode 100644 index 000000000..d350aca2a --- /dev/null +++ b/00_Alternate_Languages/49_Hockey/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 hockey.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 "hockey" + run diff --git a/00_Alternate_Languages/49_Hockey/MiniScript/hockey.ms b/00_Alternate_Languages/49_Hockey/MiniScript/hockey.ms new file mode 100644 index 000000000..450736f70 --- /dev/null +++ b/00_Alternate_Languages/49_Hockey/MiniScript/hockey.ms @@ -0,0 +1,396 @@ +print " "*33 + "Hockey" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +// ROBERT PUOPOLO ALG. 1 140 MCCOWAN 6/7/73 HOCKEY + +getYesNo = function(prompt) + while true + yn = input(prompt + "? ").lower + if yn and yn[0] == "y" then return "yes" + if yn and yn[0] == "n" then return "no" + print "Answer yes or no!!" + end while +end function + +getTwoStrings = function(prompt) + s = input(prompt + "? ").replace(", ", ",").split(",") + answer1 = s[0] + if s.len < 2 then + answer2 = input("?? ") + else + answer2 = s[1] + end if + return [answer1, answer2] +end function + +getNumber = function(prompt, minVal = 1, maxVal = 999) + while true + num = input(prompt + "? ").val + if minVal <= num <= maxVal then return num + end while +end function + +printWithTab = function(s) + print s.replace("\t", char(9)) +end function + +ha = [0] * 21 +ta = [0] * 6 +t1 = [0] * 6 +t2 = [0] * 6 +t3 = [0] * 6 +aNames = [""] * 8 // Team 1 player names and team name +bNames = [""] * 8 // Team 2 player names and team name +x = 1 +print; print; print +if getYesNo("Would you like the instructions") == "yes" then + print + print "This is a simulated hockey game." + print "Question Response" + print "pass Type in the number of passes you would" + print " like to make, from 0 to 3." + print "shot Type the number corresponding to the shot" + print " you want to make. Enter:" + print " 1 for a slapshot" + print " 2 for a wristshot" + print " 3 for a backhand" + print " 4 for a snap shot" + print "area Type in the number corresponding to" + print " the area you are aiming at. Enter:" + print " 1 for upper left hand corner" + print " 2 for upper right hand corner" + print " 3 for lower left hand corner" + print " 4 for lower right hand corner" + print + print "At the start of the game, you will be asked for the names" + print "of your players. They are entered in the order: " + print "left wing, center, right wing, left defense," + print "right defense, goalkeeper. Any other input required will" + print "have explanatory instructions." +end if + +setup = function + teamNames = getTwoStrings("Enter the two teams") + aNames[7] = teamNames[0] + bNames[7] = teamNames[1] + print + globals.roundsInGame = getNumber("Enter the number of minutes in a game") + print + print "Would the " + aNames[7] + " coach enter his team" + print + for i in range(1, 6) + aNames[i] = input("Player " + i + "? ") + end for + print + print "Would the " + bNames[7] + " coach do the same" + print + for t in range(1, 6) + bNames[t] = input("Player " + t + "? ") + end for + print + rs = input("Input the referee for this game? ") + print + print " "*10 + aNames[7] + " starting lineup" + for t in range(1, 6) + print aNames[t] + end for + print + print " "*10 + bNames[7] + " starting lineup" + for t in range(1, 6) + print bNames[t] + end for + print + print "We're ready for tonights opening face-off." + print rs + " will drop the puck between " + aNames[2] + " and " + bNames[2] +end function + +shootAndScore = function(shootingTeam, shooter, asst1, asst2, z) + while true + ha[20] = floor(100 * rnd) + 1 + if ha[20] % z != 0 then break + a2 = floor(100 * rnd) + 1 + if a2 % 4 == 0 then + if shootingTeam == 1 then + print "Save " + bNames[6] + " -= 1 rebound" + else + print "Save " + aNames[6] + " -= 1 follow up" + end if + continue + end if + end while + + if shootingTeam == 1 then + print "Goal " + aNames[7] + ha[9] += 1 + else + print "Score " + bNames[7] + ha[8] += 1 + end if + print char(7) * 25 + print "Score: " + if ha[8] <= ha[9] then + printWithTab aNames[7] + ": " + ha[9] + "\t" + bNames[7] + ": " + ha[8] + else + printWithTab bNames[7] + ": " + ha[8] + "\t" + aNames[7] + ": " + ha[9] + end if + if shootingTeam == 1 then + print "Goal scored by: " + aNames[shooter] + if asst1 then + if asst2 then + print " assisted by: " + aNames[asst1] + " and " + aNames[asst2] + else + print " assisted by: " + aNames[asst1] + end if + else + print " unassisted." + end if + ta[shooter] += 1 + t1[asst1] += 1 + t1[asst2] += 1 + else + print "Goal scored by: " + bNames[shooter] + if asst1 then + if asst2 then + print " assisted by: " + bNames[asst1] + " and " + bNames[asst2] + else + print " assisted by: " + bNames[asst1] + end if + else + print " unassisted." + end if + t2[shooter] += 1 + t3[asst1] += 1 + t3[asst2] += 1 + end if +end function + +shootBlocked = function(shootingTeam, shooter) + s1 = floor(6 * rnd) + 1 + if shootingTeam == 1 then + if s1 == 1 then + print "Kick save and a beauty by " + bNames[6] + print "cleared out by " + bNames[3] + return false + else if s1 == 2 then + print "what a spectacular glove save by " + bNames[6] + print "and " + bNames[6] + " golfs it into the crowd" + else if s1 == 3 then + print "skate save on a low steamer by " + bNames[6] + return false + else if s1 == 4 then + print "pad save by " + bNames[6] + " off the stick" + print "of " + aNames[shooter] + " and " + bNames[6] + " covers up" + else if s1 == 5 then + print "whistles one over the head of " + bNames[6] + return false + else if s1 == 6 then + print bNames[6] + " makes a face save!! and he is hurt" + print "the defenseman " + bNames[5] + " covers up for him" + end if + else + if s1 == 1 then + print "stick save by " + aNames[6] +"" + print "and cleared out by " + aNames[4] + return false + else if s1 == 2 then + print "Oh my god!! " + bNames[shooter] + " rattles one off the post" + print "to the right of " + aNames[6] + " and " + aNames[6] + " covers " + print "on the loose puck!" + else if s1 == 3 then + print "Skate save by " + aNames[6] + print aNames[6] + " whacks the loose puck into the stands" + else if s1 == 4 then + print "Stick save by " + aNames[6] + " and he clears it out himself" + return false + else if s1 == 5 then + print "Kicked out by " + aNames[6] + print "and it rebounds all the way to center ice" + return false + else if s1 == 6 then + print "Glove save " + aNames[6] + " and he hangs on" + end if + end if +end function + +doOneRound = function + control = floor(2 * rnd) + 1 + if control == 1 then + print aNames[7] + " has control of the puck" + else + print bNames[7] + " has control." + end if + p = getNumber("Pass", 0, 3) + for n in range(1, 3) + ha[n] = 0 + end for + while true + for j in range(1, p + 2) + ha[j] = floor(5 * rnd) + 1 + end for + if not (ha[j - 1] == ha[j - 2] or (p + 2 >= 3 and (ha[j - 1] == ha[j - 3] or ha[j - 2] == ha[j - 3]))) then break + end while + + if p == 0 then + s = getNumber("Shot", 1, 4) + if control == 1 then + print aNames[ha[j - 1]], "" + g = ha[j - 1] + g1 = 0 + g2 = 0 + else + print bNames[ha[j - 1]], "" + g2 = 0 + g2 = 0 + g = ha[j - 1] + end if + if s == 1 then + print " lets a boomer go from the red line!!" + z = 10 + else if s == 2 then + print " flips a wristshot down the ice" + // BUG: missing line 430 in the original caused it to fall through + // to the s == 3 case. We'll instead just do: + z = 2 + else if s == 3 then + print " backhands one in on the goaltender" + z = 25 + else + print " snaps a long flip shot" + z = 17 + end if + else + if control == 1 then + if p == 1 then + print aNames[ha[j - 2]] + " leads " + aNames[ha[j - 1]] + " with a perfect pass." + print aNames[ha[j - 1]] + " cutting in!!!" + g = ha[j - 1] + g1 = ha[j - 2] + g2 = 0 + z1 = 3 + else if p == 2 then + print aNames[ha[j - 2]] + " gives to a streaking " + aNames[ha[j - 1]] + print aNames[ha[j - 3]] + " comes down on " + bNames[5] + " and " + bNames[4] + g = ha[j - 3] + g1 = ha[j - 1] + g2 = ha[j - 2] + z1 = 2 + else if p == 3 then + print "oh my god!! a ' 4 on 2 ' situation" + print aNames[ha[j - 3]] + " leads " + aNames[ha[j - 2]] + print aNames[ha[j - 2]] + " is wheeling through center." + print aNames[ha[j - 2]] + " gives and goest with " + aNames[ha[j - 1]] + print "pretty passing!" + print aNames[ha[j - 1]] + " drops it to " + aNames[ha[j - 4]] + g = ha[j - 4] + g1 = ha[j - 1] + g2 = ha[j - 2] + z1 = 1 + end if + else + if p == 1 then + print bNames[ha[j - 1]] + " hits " + bNames[ha[j - 2]] + " flying down the left side" + g = ha[j - 2] + g1 = ha[j - 1] + g2 = 0 + z1 = 3 + else if p == 2 then + print "it's a ' 3 on 2 '!" + print "only " + aNames[4] + " and " + aNames[5] + " are back." + print bNames[ha[j - 2]] + " gives off to " + bNames[ha[j - 1]] + print bNames[ha[j - 1]] + " drops to " + bNames[ha[j - 3]] + g = ha[j - 3] + g1 = ha[j - 1] + g2 = ha[j - 2] + z1 = 2 + else if p == 3 then + print " a '3 on 2 ' with a ' trailer '!" + print bNames[ha[j - 4]] + " gives to " + bNames[ha[j - 2]] + " who shuffles it off to" + print bNames[ha[j - 1]] + " who fires a wing to wing pass to " + print bNames[ha[j - 3]] + " aNames he cuts in alone!!" + g = ha[j - 3] + g1 = ha[j - 1] + g2 = ha[j - 2] + z1 = 1 + end if + end if + s = getNumber("Shot", 1, 4) + if control == 1 then + print aNames[g], "" + else + print bNames[g], "" + end if + if s == 1 then + print " lets a big slap shot go!!" + z = 4 + z += z1 + else if s == 2 then + print " rips a wrist shot off" + z = 2 + z += z1 + else if s == 3 then + print " gets a backhand off" + z = 3 + z += z1 + else + print " snaps off a snap shot" + z = 2 + z += z1 + end if + end if + + a = getNumber("Area", 1, 4) // area shot in + a1 = floor(4 * rnd) + 1 // area vulnerable + + if control == 1 then + globals.teamAShotsOnNet += 1 + else + globals.teamBShotsOnNet += 1 + end if + if a == a1 then + shootAndScore control, g, g1, g2 + else + shootBlocked control, g + end if + return true +end function + +// Main program +setup +teamAShotsOnNet = 0 +teamBShotsOnNet = 0 +for l in range(1, roundsInGame) + while not doOneRound; end while // (repeat until it returns true) + if l < roundsInGame then print "And we're ready for the face-off" +end for + + + +print char(7)*30 +print "That's the Siren" +print +print " "*15 + "Final Score:" +if ha[8] <= ha[9] then + printWithTab aNames[7] + ": " + ha[9] + "\t" + bNames[7] + ": " + ha[8] +else + printWithTab bNames[7] + ": " + ha[8] + "\t" + aNames[7] + ": " + ha[9] +end if +print +print " "*10 + "Scoring Summary" +print +print " "*25 + aNames[7] +printWithTab "\tName\tGoals\tAssists" +printWithTab "\t -= 1 -= 1\t -= 1 -= 1-\t -= 1 -= 1 -= 1-" +for i in range(1, 5) + printWithTab "\t" + aNames[i] + "\t" + ta[i] + "\t" + t1[i] +end for +print +print " "*25 + bNames[7] +printWithTab "\tName\tGoals\tAssists" +printWithTab "\t -= 1 -= 1\t -= 1 -= 1-\t -= 1 -= 1 -= 1-" +for t in range(1, 5) + printWithTab "\t" + bNames[t] + "\t" + t2[t] + "\t" + t3[t] +end for +print +print "Shots on net" +print aNames[7] + ": " + teamAShotsOnNet +print bNames[7] + ": " + teamBShotsOnNet diff --git a/49_Hockey/README.md b/49_Hockey/README.md index 3decfe1b1..98db22d58 100644 --- a/49_Hockey/README.md +++ b/49_Hockey/README.md @@ -15,6 +15,11 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- An apparent missing line 430 causes the code to fall through from the "FLIPS A WRISTSHOT" case directly to the "BACKHANDS ONE" case. +- The author consistently misspells the verb "lets" (writing it like the contraction "let's"), while having no trouble with "leads", "gets", "hits", etc. + #### Porting Notes (please note any difficulties or challenges in porting here) From 41ef1ba818397e1703a4a93dc79c8ff6aeb9d3dd Mon Sep 17 00:00:00 2001 From: Lyndon Stolton Date: Sun, 27 Aug 2023 17:40:30 +0100 Subject: [PATCH 212/377] Added Rust version of 43_Hammurabi --- 43_Hammurabi/rust/Cargo.toml | 9 ++ 43_Hammurabi/rust/README.md | 3 + 43_Hammurabi/rust/src/main.rs | 258 ++++++++++++++++++++++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 43_Hammurabi/rust/Cargo.toml create mode 100644 43_Hammurabi/rust/README.md create mode 100644 43_Hammurabi/rust/src/main.rs diff --git a/43_Hammurabi/rust/Cargo.toml b/43_Hammurabi/rust/Cargo.toml new file mode 100644 index 000000000..3b1d02f52 --- /dev/null +++ b/43_Hammurabi/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" diff --git a/43_Hammurabi/rust/README.md b/43_Hammurabi/rust/README.md new file mode 100644 index 000000000..fc6468b9f --- /dev/null +++ b/43_Hammurabi/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) diff --git a/43_Hammurabi/rust/src/main.rs b/43_Hammurabi/rust/src/main.rs new file mode 100644 index 000000000..bba412472 --- /dev/null +++ b/43_Hammurabi/rust/src/main.rs @@ -0,0 +1,258 @@ +use std::io; +use rand::Rng; + +fn run() { + let mut year = 0; + let mut population = 95; + let mut immigrants = 5; + let mut starved = 0; + let mut total_starved = 0; + let mut plague = false; + let mut grain = 2800; + let mut bushels_fed; + let mut harvest; + let mut planted; + let mut yield_acre = 3; + let mut eaten_rats = 200; + let mut acres = 1000; + let mut land_price; + let mut bought_land; + let mut perc_starved = 0.0; + let mut game_failed = false; + + 'main: loop { + year += 1; + if year > 11 { + break; + } + println!("\n\n\nHAMURABI: I BEG TO REPORT TO YOU,"); + println!("IN YEAR {year}, {starved} PEOPLE STARVED, {immigrants} CAME TO THE CITY,"); + population = population + immigrants; + if plague{ + population = population / 2; + plague = false; + println!("A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED."); + } + println!("POPULATION IS NOW {population}"); + println!("THE CITY NOW OWNS {acres} ACRES."); + println!("YOU HARVESTED {yield_acre} BUSHELS PER ACRE."); + println!("THE RATS ATE {eaten_rats} BUSHELS."); + println!("YOU NOW HAVE {grain} BUSHELS IN STORE.\n"); + let r = rand::thread_rng().gen_range(1..10); + land_price = r + 17; + println!("LAND IS TRADING AT {land_price} BUSHELS PER ACRE."); + + loop { + println!("HOW MANY ACRES DO YOU WISH TO BUY? "); + if let Some(qty) = get_input() { + if qty < 0 { + impossible_task(); + game_failed = true; + break 'main; + } + if qty == 0 { + bought_land = false; + break; + } + if land_price * qty as u32 > grain { + insufficient_grain(grain); + continue; + } + if land_price * qty as u32 <= grain { + acres += qty as u32; + grain -= land_price * qty as u32; + bought_land = true; + break; + } + } + } + + if bought_land == false { + loop { + println!("HOW MANY ACRES DO YOU WISH TO SELL? "); + if let Some(qty) = get_input() { + if qty < 0 { + impossible_task(); + game_failed = true; + break 'main; + } + if qty as u32 <= acres { + acres -= qty as u32; + grain += land_price * qty as u32; + break; + } + insufficient_land(acres); + } + } + } + + loop { + println!("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? "); + if let Some(qty) = get_input() { + if qty < 0 { + impossible_task(); + game_failed = true; + break 'main; + } + // Trying to use more grain than is in silos? + if qty as u32 > grain { + insufficient_grain(grain); + continue; + } + bushels_fed = qty as u32; + grain -= bushels_fed; + break; + } + } + + loop { + println!("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? "); + if let Some(qty) = get_input() { + if qty < 0 { + impossible_task(); + game_failed = true; + break 'main; + } + // Trying to plant more acres than you own? + if qty as u32 > acres { + insufficient_land(acres); + continue; + } + // Enough grain for seed? + if qty as u32 / 2 > grain { + insufficient_grain(grain); + continue; + } + // Enough people to tend the crops? + if qty as u32 > (10 * population) { + insufficient_people(population); + continue; + } + planted = qty as u32; + grain = grain - (planted / 2); + break; + } + } + + // A bountiful harvest! + yield_acre = gen_random(); + harvest = planted * yield_acre; + eaten_rats = 0; + + // Determine if any grain was eaten by rats + let mut c = gen_random(); + if c % 2 == 0 { // If c is even... + // Rats are running wild! + eaten_rats = grain / c; + } + // Update the amount of grain held + grain = grain - eaten_rats + harvest; + + // Let's have some babies + c = gen_random(); + immigrants = c * (20 * acres + grain) / population / 100 + 1; + + // How many people had full tummies? + c = bushels_fed / 20; + // Horrors, a 15% chance of plague + let rf: f32 = rand::thread_rng().gen(); + let plague_chance = (10. * ((2. * rf) - 0.3)) as i32; + if plague_chance == 0 { + plague = true; + } + if population >= c { + // Starve enough for impeachment? + starved = population - c; + if starved > (0.45 * population as f32) as u32 { + println!("YOU STARVED {starved} PEOPLE IN ONE YEAR!!!"); + national_fink(); + game_failed = true; + break; + } + // Calculate percentages here + perc_starved = ((year - 1) as f32 * perc_starved + starved as f32 * 100. / population as f32) / year as f32; + population = c; + total_starved = total_starved + starved; + } + } + + if game_failed == false { + println!("IN YOUR 10-YEAR TERM OF OFFICE {perc_starved} PERCENT OF THE"); + println!("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF"); + println!("{total_starved} PEOPLE DIED!!"); + let acres_head = acres / population; + println!("YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH"); + println!("{acres_head} ACRES PER PERSON.\n"); + if perc_starved > 33. || acres_head < 7 { + national_fink(); + } + else if perc_starved > 10. || acres_head < 9 { + println!("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV."); + println!("THE PEOPLE (REMAINING) FIND YOU AND UNPLEASANT RULER, AND,"); + println!("FRANKLY, HATE YOUR GUTS!!"); + } + else if perc_starved > 3. || acres_head < 10 { + let haters = (population as f32 * 0.8 * gen_random() as f32) as u32; + println!("YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT"); + println!("REALLY WASN'T TOO BAD AT ALL. {haters} PEOPLE"); + println!("WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR"); + println!("TRIVIAL PROBLEMS."); + } else { + println!("A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND"); + println!("JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\n"); + } + for _ in 1..10 { + print!("\n"); + } + } + + println!("\nSO LONG FOR NOW.\n"); +} + +fn get_input() -> Option { + let mut input = String::new(); + io::stdin().read_line(&mut input).expect("Failed read_line"); + match input.trim().parse() { + Ok(num) => Some(num), + Err(_) => None, + } +} + +fn gen_random() -> u32 { + let r: f32 = rand::thread_rng().gen(); + (r * 5.0 + 1.0) as u32 +} + +fn impossible_task() { + println!("HAMURABI: I CANNOT DO WHAT YOU WISH."); + println!("GET YOURSELF ANOTHER STEWARD!!!!!"); +} + +fn insufficient_grain(grain: u32) { + println!("HAMURABI: THINK AGAIN. YOU HAVE ONLY"); + println!("{grain} BUSHELS OF GRAIN. NOW THEN,"); +} + +fn insufficient_land(acres: u32) { + println!("HAMURABI: THINK AGAIN. YOU OWN ONLY {acres} ACRES. NOW THEN,"); +} + +fn insufficient_people(population: u32) { + println!("BUT YOU HAVE ONLY {population} PEOPLE TO TEND THE FIELDS! NOW THEN,"); +} + +fn national_fink() { + println!("DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY"); + println!("BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE"); + println!("ALSO BEEN DECLARED NATIONAL FINK!!!!"); +} + +fn main() { + println!(" HAMURABI"); + println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + print!("\n\n\n\n"); + println!("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA"); + println!("FOR A TEN-YEAR TERM OF OFFICE.\n"); + + run(); +} From 6555d1cf2d0e6895bc26206519c55b4107b0b11f Mon Sep 17 00:00:00 2001 From: Lyndon Stolton Date: Sun, 27 Aug 2023 21:13:26 +0100 Subject: [PATCH 213/377] Minor changes to 43_Hammurabi/rust - Minor changes to make code more idiomatic (clippy no longer has any issues), no functional changes - Added some additional comments to make code easier to follow --- 43_Hammurabi/rust/src/main.rs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/43_Hammurabi/rust/src/main.rs b/43_Hammurabi/rust/src/main.rs index bba412472..061d502e2 100644 --- a/43_Hammurabi/rust/src/main.rs +++ b/43_Hammurabi/rust/src/main.rs @@ -2,6 +2,7 @@ use std::io; use rand::Rng; fn run() { + // Set up variables let mut year = 0; let mut population = 95; let mut immigrants = 5; @@ -27,9 +28,9 @@ fn run() { } println!("\n\n\nHAMURABI: I BEG TO REPORT TO YOU,"); println!("IN YEAR {year}, {starved} PEOPLE STARVED, {immigrants} CAME TO THE CITY,"); - population = population + immigrants; + population += immigrants; if plague{ - population = population / 2; + population /= 2; plague = false; println!("A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED."); } @@ -45,19 +46,22 @@ fn run() { loop { println!("HOW MANY ACRES DO YOU WISH TO BUY? "); if let Some(qty) = get_input() { - if qty < 0 { + if qty < 0 { // A negative amount is impossible impossible_task(); game_failed = true; break 'main; } + // Player decides not to buy any land if qty == 0 { bought_land = false; break; } + // Trying to buy more land than you can afford? if land_price * qty as u32 > grain { insufficient_grain(grain); continue; } + // Everything checks out OK if land_price * qty as u32 <= grain { acres += qty as u32; grain -= land_price * qty as u32; @@ -67,20 +71,22 @@ fn run() { } } - if bought_land == false { + if !bought_land { loop { println!("HOW MANY ACRES DO YOU WISH TO SELL? "); if let Some(qty) = get_input() { - if qty < 0 { + if qty < 0 { // A negative amount is impossible impossible_task(); game_failed = true; break 'main; } + // Everything checks out OK if qty as u32 <= acres { acres -= qty as u32; grain += land_price * qty as u32; break; } + // Trying to sell more land that you own insufficient_land(acres); } } @@ -89,7 +95,7 @@ fn run() { loop { println!("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? "); if let Some(qty) = get_input() { - if qty < 0 { + if qty < 0 { // A negative amount is impossible impossible_task(); game_failed = true; break 'main; @@ -99,6 +105,7 @@ fn run() { insufficient_grain(grain); continue; } + // Everything checks out OK bushels_fed = qty as u32; grain -= bushels_fed; break; @@ -108,7 +115,7 @@ fn run() { loop { println!("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? "); if let Some(qty) = get_input() { - if qty < 0 { + if qty < 0 { // A negative amount is impossible impossible_task(); game_failed = true; break 'main; @@ -128,8 +135,9 @@ fn run() { insufficient_people(population); continue; } + // Everything checks out OK planted = qty as u32; - grain = grain - (planted / 2); + grain -= planted / 2; break; } } @@ -169,14 +177,14 @@ fn run() { game_failed = true; break; } - // Calculate percentages here + // Calculate percentage of people that starved per year on average perc_starved = ((year - 1) as f32 * perc_starved + starved as f32 * 100. / population as f32) / year as f32; population = c; - total_starved = total_starved + starved; + total_starved += starved; } } - if game_failed == false { + if !game_failed { println!("IN YOUR 10-YEAR TERM OF OFFICE {perc_starved} PERCENT OF THE"); println!("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF"); println!("{total_starved} PEOPLE DIED!!"); @@ -202,7 +210,7 @@ fn run() { println!("JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\n"); } for _ in 1..10 { - print!("\n"); + println!(); } } From adba99e76784676491847cbbe827025560525113 Mon Sep 17 00:00:00 2001 From: Guido Knips Date: Mon, 28 Aug 2023 20:29:46 +0200 Subject: [PATCH 214/377] Add documentation for tourist trade bug in King - really bad pollution can get positive money from tourists - fix issue in python implementation, other implementations still lack it --- 53_King/README.md | 15 +++++++++++++++ 53_King/python/king.py | 6 ++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/53_King/README.md b/53_King/README.md index 14a66fe9a..83fb61c33 100644 --- a/53_King/README.md +++ b/53_King/README.md @@ -78,3 +78,18 @@ On basic line 1310 we see this: but it should probably be: 1310 IF J=0 THEN 1324 + +### Bug 5 + +On basic line 1390 the income from tourism is calculated: + +``` +1390 A=INT(A+Q) +1400 V1=INT(((B-P1)*22)+(RND(1)*500)) +1405 V2=INT((2000-D)*15) +1410 PRINT " YOU MADE";ABS(INT(V1-V2));"RALLODS FROM TOURIST TRADE." +``` + +It is very easily possible that `V2` is larger than `V1` e.g. if all of the land has been sold. In the original game this does not make a difference because of Bug 1 (see above). + +However, judging by how `V1` and `V2` are handled in the code, it looks like `V1` is the basic income from tourism and `V2` is a deduction for pollution. When `ABS(INT(V1-V2))` is used as earnings from tourism, the player actually _gets_ money for a large enough pollution. So a better solution would be to let `V1 - V2` cap out at 0, so once the pollution is large enough, there is no income from tourists anymore. diff --git a/53_King/python/king.py b/53_King/python/king.py index 9c8d075c0..a4d9b7696 100644 --- a/53_King/python/king.py +++ b/53_King/python/king.py @@ -61,7 +61,7 @@ def settled_people(self) -> int: return self.countrymen - self.population_change def sell_land(self, amount: int) -> None: - assert amount < self.farmland + assert amount <= self.farmland self.land -= amount self.rallods += self.land_buy_price * amount @@ -126,7 +126,9 @@ def handle_deaths( def handle_tourist_trade(self) -> None: V1 = int(self.settled_people * 22 + random() * 500) V2 = int((INITIAL_LAND - self.land) * 15) - tourist_trade_earnings = int(V1 - V2) + tourist_trade_earnings = 0 + if V1 > V2: + tourist_trade_earnings = V1 - V2 print(f" YOU MADE {tourist_trade_earnings} RALLODS FROM TOURIST TRADE.") if V2 != 0 and not (V1 - V2 >= self.tourism_earnings): print(" DECREASE BECAUSE ") From be75ea138641daee992ed00ed1584b5b6b5685b9 Mon Sep 17 00:00:00 2001 From: Guido Knips Date: Mon, 28 Aug 2023 20:41:55 +0200 Subject: [PATCH 215/377] Fix pick of pollution reason in python King - was intended to pick only one random reason each time - picked up to five reasons - also removed bad line break --- 53_King/python/king.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/53_King/python/king.py b/53_King/python/king.py index a4d9b7696..4bca76fac 100644 --- a/53_King/python/king.py +++ b/53_King/python/king.py @@ -131,17 +131,17 @@ def handle_tourist_trade(self) -> None: tourist_trade_earnings = V1 - V2 print(f" YOU MADE {tourist_trade_earnings} RALLODS FROM TOURIST TRADE.") if V2 != 0 and not (V1 - V2 >= self.tourism_earnings): - print(" DECREASE BECAUSE ") + print(" DECREASE BECAUSE ", end="") reason = randint(0, 10) if reason <= 2: print("FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.") - if reason <= 4: + elif reason <= 4: print("AIR POLLUTION IS KILLING GAME BIRD POPULATION.") - if reason <= 6: + elif reason <= 6: print("MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.") - if reason <= 8: + elif reason <= 8: print("UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.") - if reason <= 10: + else: print("HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.") # NOTE: The following two lines had a bug in the original game: From fa4f6888ddabea2b3d1fe86d2d5393b2b66b0cb6 Mon Sep 17 00:00:00 2001 From: Guido Knips Date: Mon, 28 Aug 2023 20:57:27 +0200 Subject: [PATCH 216/377] Fix flake8 issues in acey ducey - came seemingly out of nowhere and broke my totally unrelated PR --- 01_Acey_Ducey/python/acey_ducey.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/01_Acey_Ducey/python/acey_ducey.py b/01_Acey_Ducey/python/acey_ducey.py index 8e3535695..75a1eac27 100755 --- a/01_Acey_Ducey/python/acey_ducey.py +++ b/01_Acey_Ducey/python/acey_ducey.py @@ -6,6 +6,7 @@ import random + cards = { 2: "2", 3: "3", @@ -22,18 +23,19 @@ 14: "Ace", } + def play_game() -> None: cash = 100 while cash > 0: print(f"You now have {cash} dollars\n") print("Here are you next two cards") - round_cards = list(cards.keys()) # gather cards from dictionary - card_a = random.choice(round_cards) # choose a card - card_b = card_a # clone the first card, so we avoid the same number for the second card - while (card_a == card_b): # if the cards are the same, choose another card + round_cards = list(cards.keys()) # gather cards from dictionary + card_a = random.choice(round_cards) # choose a card + card_b = card_a # clone the first card, so we avoid the same number for the second card + while (card_a == card_b): # if the cards are the same, choose another card card_b = random.choice(round_cards) - card_c = random.choice(round_cards) # choose last card - if card_a > card_b: # swap cards if card_a is greater than card_b + card_c = random.choice(round_cards) # choose last card + if card_a > card_b: # swap cards if card_a is greater than card_b card_a, card_b = card_b, card_a print(f" {cards[card_a]}") print(f" {cards[card_b]}\n") From 7a62098e94aa5278f9e1b038966862f72b8d4353 Mon Sep 17 00:00:00 2001 From: Guido Knips Date: Mon, 28 Aug 2023 21:06:35 +0200 Subject: [PATCH 217/377] Un-ignore Cargo.lock Official cargo documentation says Cargo.lock should be under version control for binaries (but not for libraries) see https://doc.rust-lang.org/cargo/faq.html#why-do-binaries-have-cargolock-in-version-control-but-not-libraries --- .gitignore | 1 - 01_Acey_Ducey/rust/Cargo.lock | 75 +++++++++++ 02_Amazing/rust/Cargo.lock | 75 +++++++++++ 03_Animal/rust/Cargo.lock | 7 + 04_Awari/rust/Cargo.lock | 75 +++++++++++ 05_Bagels/rust/Cargo.lock | 75 +++++++++++ 10_Blackjack/rust/Cargo.lock | 75 +++++++++++ 11_Bombardment/rust/Cargo.lock | 82 ++++++++++++ 18_Bullseye/rust/Cargo.lock | 75 +++++++++++ 20_Buzzword/rust/Cargo.lock | 75 +++++++++++ 21_Calendar/rust/Cargo.lock | 7 + 22_Change/rust/Cargo.lock | 7 + 24_Chemist/rust/Cargo.lock | 75 +++++++++++ 25_Chief/rust/Cargo.lock | 7 + 29_Craps/rust/Cargo.lock | 75 +++++++++++ 30_Cube/rust/Cargo.lock | 75 +++++++++++ 32_Diamond/rust/Cargo.lock | 7 + 33_Dice/rust/Cargo.lock | 75 +++++++++++ 35_Even_Wins/rust/Cargo.lock | 7 + 36_Flip_Flop/rust/Cargo.lock | 82 ++++++++++++ 41_Guess/rust/Cargo.lock | 75 +++++++++++ 43_Hammurabi/rust/Cargo.lock | 75 +++++++++++ 47_Hi-Lo/rust/Cargo.lock | 75 +++++++++++ 50_Horserace/rust/Cargo.lock | 75 +++++++++++ 51_Hurkle/rust/Cargo.lock | 75 +++++++++++ 54_Letter/rust/Cargo.lock | 75 +++++++++++ 55_Life/rust/Cargo.lock | 7 + 57_Literature_Quiz/rust/Cargo.lock | 7 + 58_Love/rust/Cargo.lock | 7 + 61_Math_Dice/rust/Cargo.lock | 75 +++++++++++ 62_Mugwump/rust/Cargo.lock | 75 +++++++++++ 64_Nicomachus/rust/Cargo.lock | 7 + 65_Nim/rust/Cargo.lock | 23 ++++ 66_Number/rust/Cargo.lock | 75 +++++++++++ 68_Orbit/rust/Cargo.lock | 75 +++++++++++ 72_Queen/rust/Cargo.lock | 75 +++++++++++ 74_Rock_Scissors_Paper/rust/Cargo.lock | 91 +++++++++++++ 75_Roulette/rust/Cargo.lock | 82 ++++++++++++ 76_Russian_Roulette/rust/Cargo.lock | 75 +++++++++++ 78_Sine_Wave/rust/Cargo.lock | 7 + 81_Splat/rust/Cargo.lock | 75 +++++++++++ 82_Stars/rust/Cargo.lock | 75 +++++++++++ 84_Super_Star_Trek/rust/Cargo.lock | 169 +++++++++++++++++++++++++ 85_Synonym/rust/Cargo.lock | 75 +++++++++++ 89_Tic-Tac-Toe/rust/Cargo.lock | 7 + 90_Tower/rust/Cargo.lock | 7 + 91_Train/rust/Cargo.lock | 75 +++++++++++ 92_Trap/rust/Cargo.lock | 75 +++++++++++ 94_War/rust/Cargo.lock | 75 +++++++++++ 95_Weekday/rust/Cargo.lock | 7 + 96_Word/rust/Cargo.lock | 75 +++++++++++ 51 files changed, 2877 insertions(+), 1 deletion(-) create mode 100644 01_Acey_Ducey/rust/Cargo.lock create mode 100644 02_Amazing/rust/Cargo.lock create mode 100644 03_Animal/rust/Cargo.lock create mode 100644 04_Awari/rust/Cargo.lock create mode 100644 05_Bagels/rust/Cargo.lock create mode 100644 10_Blackjack/rust/Cargo.lock create mode 100644 11_Bombardment/rust/Cargo.lock create mode 100644 18_Bullseye/rust/Cargo.lock create mode 100644 20_Buzzword/rust/Cargo.lock create mode 100644 21_Calendar/rust/Cargo.lock create mode 100644 22_Change/rust/Cargo.lock create mode 100644 24_Chemist/rust/Cargo.lock create mode 100644 25_Chief/rust/Cargo.lock create mode 100644 29_Craps/rust/Cargo.lock create mode 100644 30_Cube/rust/Cargo.lock create mode 100644 32_Diamond/rust/Cargo.lock create mode 100644 33_Dice/rust/Cargo.lock create mode 100644 35_Even_Wins/rust/Cargo.lock create mode 100644 36_Flip_Flop/rust/Cargo.lock create mode 100644 41_Guess/rust/Cargo.lock create mode 100644 43_Hammurabi/rust/Cargo.lock create mode 100644 47_Hi-Lo/rust/Cargo.lock create mode 100644 50_Horserace/rust/Cargo.lock create mode 100644 51_Hurkle/rust/Cargo.lock create mode 100644 54_Letter/rust/Cargo.lock create mode 100644 55_Life/rust/Cargo.lock create mode 100644 57_Literature_Quiz/rust/Cargo.lock create mode 100644 58_Love/rust/Cargo.lock create mode 100644 61_Math_Dice/rust/Cargo.lock create mode 100644 62_Mugwump/rust/Cargo.lock create mode 100644 64_Nicomachus/rust/Cargo.lock create mode 100644 65_Nim/rust/Cargo.lock create mode 100644 66_Number/rust/Cargo.lock create mode 100644 68_Orbit/rust/Cargo.lock create mode 100644 72_Queen/rust/Cargo.lock create mode 100644 74_Rock_Scissors_Paper/rust/Cargo.lock create mode 100644 75_Roulette/rust/Cargo.lock create mode 100644 76_Russian_Roulette/rust/Cargo.lock create mode 100644 78_Sine_Wave/rust/Cargo.lock create mode 100644 81_Splat/rust/Cargo.lock create mode 100644 82_Stars/rust/Cargo.lock create mode 100644 84_Super_Star_Trek/rust/Cargo.lock create mode 100644 85_Synonym/rust/Cargo.lock create mode 100644 89_Tic-Tac-Toe/rust/Cargo.lock create mode 100644 90_Tower/rust/Cargo.lock create mode 100644 91_Train/rust/Cargo.lock create mode 100644 92_Trap/rust/Cargo.lock create mode 100644 94_War/rust/Cargo.lock create mode 100644 95_Weekday/rust/Cargo.lock create mode 100644 96_Word/rust/Cargo.lock diff --git a/.gitignore b/.gitignore index 2243de053..e28f8fe09 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,6 @@ venv/ .DS_Store .vs/ **/target/ -Cargo.lock **/*.rs.bk /target todo.md diff --git a/01_Acey_Ducey/rust/Cargo.lock b/01_Acey_Ducey/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/01_Acey_Ducey/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/02_Amazing/rust/Cargo.lock b/02_Amazing/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/02_Amazing/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/03_Animal/rust/Cargo.lock b/03_Animal/rust/Cargo.lock new file mode 100644 index 000000000..9c4ba014c --- /dev/null +++ b/03_Animal/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "animal" +version = "0.1.0" diff --git a/04_Awari/rust/Cargo.lock b/04_Awari/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/04_Awari/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/05_Bagels/rust/Cargo.lock b/05_Bagels/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/05_Bagels/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/10_Blackjack/rust/Cargo.lock b/10_Blackjack/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/10_Blackjack/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/11_Bombardment/rust/Cargo.lock b/11_Bombardment/rust/Cargo.lock new file mode 100644 index 000000000..81365033b --- /dev/null +++ b/11_Bombardment/rust/Cargo.lock @@ -0,0 +1,82 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "morristown" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83b191fd96370b91c2925125774011a7a0f69b4db9e2045815e4fd20af725f6" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "morristown", + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/18_Bullseye/rust/Cargo.lock b/18_Bullseye/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/18_Bullseye/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/20_Buzzword/rust/Cargo.lock b/20_Buzzword/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/20_Buzzword/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/21_Calendar/rust/Cargo.lock b/21_Calendar/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/21_Calendar/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/22_Change/rust/Cargo.lock b/22_Change/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/22_Change/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/24_Chemist/rust/Cargo.lock b/24_Chemist/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/24_Chemist/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/25_Chief/rust/Cargo.lock b/25_Chief/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/25_Chief/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/29_Craps/rust/Cargo.lock b/29_Craps/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/29_Craps/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/30_Cube/rust/Cargo.lock b/30_Cube/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/30_Cube/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/32_Diamond/rust/Cargo.lock b/32_Diamond/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/32_Diamond/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/33_Dice/rust/Cargo.lock b/33_Dice/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/33_Dice/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/35_Even_Wins/rust/Cargo.lock b/35_Even_Wins/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/35_Even_Wins/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/36_Flip_Flop/rust/Cargo.lock b/36_Flip_Flop/rust/Cargo.lock new file mode 100644 index 000000000..81365033b --- /dev/null +++ b/36_Flip_Flop/rust/Cargo.lock @@ -0,0 +1,82 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "morristown" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83b191fd96370b91c2925125774011a7a0f69b4db9e2045815e4fd20af725f6" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "morristown", + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/41_Guess/rust/Cargo.lock b/41_Guess/rust/Cargo.lock new file mode 100644 index 000000000..5329dedd1 --- /dev/null +++ b/41_Guess/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "guess" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/43_Hammurabi/rust/Cargo.lock b/43_Hammurabi/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/43_Hammurabi/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/47_Hi-Lo/rust/Cargo.lock b/47_Hi-Lo/rust/Cargo.lock new file mode 100644 index 000000000..937c07c63 --- /dev/null +++ b/47_Hi-Lo/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "guessing_game" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/50_Horserace/rust/Cargo.lock b/50_Horserace/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/50_Horserace/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/51_Hurkle/rust/Cargo.lock b/51_Hurkle/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/51_Hurkle/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/54_Letter/rust/Cargo.lock b/54_Letter/rust/Cargo.lock new file mode 100644 index 000000000..6a34e6ec8 --- /dev/null +++ b/54_Letter/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "letter" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/55_Life/rust/Cargo.lock b/55_Life/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/55_Life/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/57_Literature_Quiz/rust/Cargo.lock b/57_Literature_Quiz/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/57_Literature_Quiz/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/58_Love/rust/Cargo.lock b/58_Love/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/58_Love/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/61_Math_Dice/rust/Cargo.lock b/61_Math_Dice/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/61_Math_Dice/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/62_Mugwump/rust/Cargo.lock b/62_Mugwump/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/62_Mugwump/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/64_Nicomachus/rust/Cargo.lock b/64_Nicomachus/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/64_Nicomachus/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/65_Nim/rust/Cargo.lock b/65_Nim/rust/Cargo.lock new file mode 100644 index 000000000..fc74a49e2 --- /dev/null +++ b/65_Nim/rust/Cargo.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "nanorand" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729eb334247daa1803e0a094d0a5c55711b85571179f5ec6e53eccfdf7008958" + +[[package]] +name = "nim" +version = "1.0.0" +dependencies = [ + "nanorand", + "text_io", +] + +[[package]] +name = "text_io" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f0c8eb2ad70c12a6a69508f499b3051c924f4b1cfeae85bfad96e6bc5bba46" diff --git a/66_Number/rust/Cargo.lock b/66_Number/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/66_Number/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/68_Orbit/rust/Cargo.lock b/68_Orbit/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/68_Orbit/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/72_Queen/rust/Cargo.lock b/72_Queen/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/72_Queen/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/74_Rock_Scissors_Paper/rust/Cargo.lock b/74_Rock_Scissors_Paper/rust/Cargo.lock new file mode 100644 index 000000000..81a95200e --- /dev/null +++ b/74_Rock_Scissors_Paper/rust/Cargo.lock @@ -0,0 +1,91 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "nanorand" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "729eb334247daa1803e0a094d0a5c55711b85571179f5ec6e53eccfdf7008958" + +[[package]] +name = "proc-macro2" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rock_scissors_paper" +version = "1.0.0" +dependencies = [ + "nanorand", + "strum", + "strum_macros", + "text_io", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "text_io" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f0c8eb2ad70c12a6a69508f499b3051c924f4b1cfeae85bfad96e6bc5bba46" + +[[package]] +name = "unicode-ident" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" diff --git a/75_Roulette/rust/Cargo.lock b/75_Roulette/rust/Cargo.lock new file mode 100644 index 000000000..81365033b --- /dev/null +++ b/75_Roulette/rust/Cargo.lock @@ -0,0 +1,82 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "morristown" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83b191fd96370b91c2925125774011a7a0f69b4db9e2045815e4fd20af725f6" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "morristown", + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/76_Russian_Roulette/rust/Cargo.lock b/76_Russian_Roulette/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/76_Russian_Roulette/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/78_Sine_Wave/rust/Cargo.lock b/78_Sine_Wave/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/78_Sine_Wave/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/81_Splat/rust/Cargo.lock b/81_Splat/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/81_Splat/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/82_Stars/rust/Cargo.lock b/82_Stars/rust/Cargo.lock new file mode 100644 index 000000000..b13b873bb --- /dev/null +++ b/82_Stars/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "stars" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/84_Super_Star_Trek/rust/Cargo.lock b/84_Super_Star_Trek/rust/Cargo.lock new file mode 100644 index 000000000..71bbf0c8c --- /dev/null +++ b/84_Super_Star_Trek/rust/Cargo.lock @@ -0,0 +1,169 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "ctrlc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a011bbe2c35ce9c1f143b7af6f94f29a167beb4cd1d29e6740ce836f723120e" +dependencies = [ + "nix", + "windows-sys", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "nix" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abbbc55ad7b13aac85f9401c796dcda1b864e07fcad40ad47792eaa8932ea502" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "ctrlc", + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/85_Synonym/rust/Cargo.lock b/85_Synonym/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/85_Synonym/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/89_Tic-Tac-Toe/rust/Cargo.lock b/89_Tic-Tac-Toe/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/89_Tic-Tac-Toe/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/90_Tower/rust/Cargo.lock b/90_Tower/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/90_Tower/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/91_Train/rust/Cargo.lock b/91_Train/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/91_Train/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/92_Trap/rust/Cargo.lock b/92_Trap/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/92_Trap/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/94_War/rust/Cargo.lock b/94_War/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/94_War/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/95_Weekday/rust/Cargo.lock b/95_Weekday/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/95_Weekday/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/96_Word/rust/Cargo.lock b/96_Word/rust/Cargo.lock new file mode 100644 index 000000000..4fe2abbea --- /dev/null +++ b/96_Word/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" From 4f70fa315b4b30222066e70488570f36c7936a39 Mon Sep 17 00:00:00 2001 From: Guido Knips Date: Sun, 13 Aug 2023 18:50:44 +0200 Subject: [PATCH 218/377] Implement King in rust --- 53_King/rust/Cargo.lock | 16 ++ 53_King/rust/Cargo.toml | 9 + 53_King/rust/src/main.rs | 577 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 602 insertions(+) create mode 100644 53_King/rust/Cargo.lock create mode 100644 53_King/rust/Cargo.toml create mode 100644 53_King/rust/src/main.rs diff --git a/53_King/rust/Cargo.lock b/53_King/rust/Cargo.lock new file mode 100644 index 000000000..db44c2e7a --- /dev/null +++ b/53_King/rust/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + +[[package]] +name = "king" +version = "0.1.0" +dependencies = [ + "fastrand", +] diff --git a/53_King/rust/Cargo.toml b/53_King/rust/Cargo.toml new file mode 100644 index 000000000..c4f9c9132 --- /dev/null +++ b/53_King/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "king" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +fastrand = "^2.0.0" diff --git a/53_King/rust/src/main.rs b/53_King/rust/src/main.rs new file mode 100644 index 000000000..90b2aac67 --- /dev/null +++ b/53_King/rust/src/main.rs @@ -0,0 +1,577 @@ +#![forbid(unsafe_code)] + +use fastrand::Rng; +use std::io; +use std::io::{stdin, stdout, BufRead, Write}; + +// global variable `N5` in the original game +const TERM_LENGTH: u32 = 8; + +fn main() { + let mut rng = Rng::new(); + let mut input = stdin().lock(); + let mut state = intro(&mut input, &mut rng).expect("input error"); + + loop { + let land_price = 95 + rng.u32(0..10); + let plant_price = 10 + rng.u32(0..5); + print_state(&state, land_price, plant_price); + state = match next_round(&mut input, &mut rng, &state, land_price, plant_price) + .expect("input error") + { + RoundEnd::Next(s) => s, + RoundEnd::GameOver(msg) => { + println!("{}", msg); + return; + } + } + } +} + +// The game is round based (one round per in-game year). +// This struct represents the state before each round +#[derive(Clone, PartialEq, Eq, Debug)] +struct State { + // global variable `A` in the original game (currency: "rallods") + money: u32, + // global variable `B` in the original game + countrymen: u32, + // global variable `C` in the original game + foreign_workers: u32, + // global variable `D` in the original game + land: u32, + // global variable `X5` in original game + year_in_office: u32, + // global variable `X` in original game + show_land_hint: bool, + // global variable `V3` in original game + previous_tourist_trade: u32, +} + +#[derive(Clone, PartialEq, Eq, Debug)] +enum RoundEnd { + GameOver(String), + Next(State), +} + +fn init_state(rng: &mut Rng) -> State { + State { + // the original formula for random values used floating point numbers. + // e.g. `INT(60000+(1000*RND(1))-(1000*RND(1)))` + // I want to avoid floats unless necessary. These values generated here should be close + // enough to the original distribution + money: 60000 + rng.u32(0..1000) - rng.u32(0..1000), + countrymen: 500 + rng.u32(0..10) - rng.u32(0..10), + foreign_workers: 0, + land: 2000, + year_in_office: 0, + show_land_hint: true, + previous_tourist_trade: 0, + } +} + +fn print_state(state: &State, land_price: u32, plant_price: u32) { + print!( + r" +YOU NOW HAVE {} RALLODS IN THE TREASURY. + {} COUNTRYMEN, ", + state.money, state.countrymen + ); + if state.foreign_workers > 0 { + print!("{} FOREIGN WORKERS, ", state.foreign_workers) + } + println!( + r"AND {} SQ. MILES OF LAND. +THIS YEAR INDUSTRY WILL BUY LAND FOR {} RALLODS PER SQUARE MILE. +LAND CURRENTLY COSTS {} RALLODS PER SQUARE MILE TO PLANT. +", + state.land, land_price, plant_price + ); +} + +// print the intro, optional instructions or a previous savegame +fn intro(mut input: R, rng: &mut Rng) -> io::Result { + println!("⚠️ This game includes references to suicide or self-harm."); + println!(" KING"); + println!(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"); + print!("DO YOU WANT INSTRUCTIONS?? "); + // In the original game, all inputs were made in the same line as the previous output. + // I try to replicate this behaviour here, but if I do not print a line break, the stdout buffer + // will not be flushed and the user may not see the input prompt before the input. + // this means in these cases I have to explicitly flush stdout. + stdout().flush()?; + let mut buf = String::with_capacity(16); + input.read_line(&mut buf)?; + buf.make_ascii_lowercase(); + match buf.trim() { + "n" => Ok(init_state(rng)), + "again" => { + let year_in_office = read_and_verify_int( + &mut input, + &mut buf, + "HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED?? ", + |v| { + if v < 8 { + Ok(v) + } else { + Err(format!( + " COME ON, YOUR TERM IN OFFICE IS ONLY {} YEARS.", + TERM_LENGTH + )) + } + }, + )?; + // The original game exits here when you enter a negative number for any of + // the following values. This looks like intentional behaviour. However, to replicate that + // I would have to change everything to signed number which I do not want right now. + print!("HOW MUCH DID YOU HAVE IN THE TREASURY?? "); + stdout().flush()?; + let money = read_int(&mut input, &mut buf)?; + print!("HOW MANY COUNTRYMEN?? "); + stdout().flush()?; + let countrymen = read_int(&mut input, &mut buf)?; + print!("HOW MANY WORKERS?? "); + stdout().flush()?; + let foreign_workers = read_int(&mut input, &mut buf)?; + let land = read_and_verify_int( + &mut input, + &mut buf, + "HOW MANY SQUARE MILES OF LAND?? ", + |v| { + if !(1000..=2000).contains(&v) { + // Note: the original says "10,000 SQ. MILES OF FOREST LAND", but this is + // inconsistent and listed as Bug 3 in the README.md + Err(" COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\n AND 1000 SQ. MILES OF FOREST LAND.".to_owned()) + } else { + Ok(v) + } + }, + )?; + Ok(State { + money, + countrymen, + foreign_workers, + land, + year_in_office, + show_land_hint: true, + previous_tourist_trade: 0, + }) + } + _ => { + println!( + r" +CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS +DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR +JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE +MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY. +THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100 +RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES +FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT +FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND +WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD +TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT +THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER +SQUARE MILE TO PLANT. +YOUR GOAL IS TO COMPLETE YOUR {} YEAR TERM OF OFFICE. +GOOD LUCK! +", + TERM_LENGTH + ); + Ok(init_state(rng)) + } + } +} + +static POLLUTION: &[&str] = &[ + "FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.", + "AIR POLLUTION IS KILLING GAME BIRD POPULATION.", + "MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.", + "UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.", + "HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.", +]; + +fn next_round( + mut input: R, + rng: &mut Rng, + state: &State, + land_price: u32, + plant_price: u32, +) -> io::Result { + let mut buf = String::with_capacity(16); + let mut show_land_hint = state.show_land_hint; + // global variable `H` in the original game + let land_sold = read_and_verify_int( + &mut input, + &mut buf, + "HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY?? ", + |v| { + if v + 1000 <= state.land { + Ok(v) + } else if show_land_hint { + show_land_hint = false; + Err(format!( + r"*** THINK AGAIN. YOU ONLY HAVE {} SQUARE MILES OF FARM LAND. +(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE +FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES, +THICKER TOP SOIL, ETC.)", + state.land - 1000 + )) + } else { + Err(format!( + r"*** THINK AGAIN. YOU ONLY HAVE {} SQUARE MILES OF FARM LAND.\n", + state.land - 1000 + )) + } + }, + )?; + + let land = state.land - land_sold; + let money = state.money + land_sold * land_price; + + // global variable `I` in the original game + let money_distributed = read_and_verify_int( + &mut input, + &mut buf, + "HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN?? ", + |v| { + if v <= money { + Ok(v) + } else { + Err(format!( + " THINK AGAIN. YOU'VE ONLY {} RALLODS IN THE TREASURY", + money + )) + } + }, + )?; + let money = money - money_distributed; + + // global variable `J` in the original game + let land_planted = if money > 0 { + read_and_verify_int( + &mut input, + &mut buf, + "HOW MANY SQUARE MILES DO YOU WISH TO PLANT?? ", + |v| { + if v > 2 * state.countrymen { + Err(" SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.".to_owned()) + } else if v + 1000 > land { + Err(format!( + " SORRY, BUT YOU'VE ONLY {} SQ. MILES OF FARM LAND.", + land - 1000 + )) + } else if v * plant_price > money { + Err(format!( + " THINK AGAIN. YOU'VE ONLY {} RALLODS LEFT IN THE TREASURY.", + money + )) + } else { + Ok(v) + } + }, + )? + } else { + 0 + }; + let money = money - land_planted * plant_price; + + // global variable `K` in the original game + let pollution_control = if money > 0 { + read_and_verify_int( + &mut input, + &mut buf, + "HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL?? ", + |v| { + if v <= money { + Ok(v) + } else { + Err(format!( + " THINK AGAIN. YOU ONLY HAVE {} RALLODS REMAINING.", + money + )) + } + }, + )? + } else { + 0 + }; + let money = money - pollution_control; + + if land_sold == 0 && money_distributed == 0 && land_planted == 0 && pollution_control == 0 { + return Ok(RoundEnd::GameOver( + r" +GOODBYE. +(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER +'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START +OF THE GAME)." + .to_owned(), + )); + } + + println!("\n\n"); + + let money_after_expenses = money; + + let starvation_deaths = state.countrymen.saturating_sub(money_distributed / 100); + if starvation_deaths > 0 { + println!("{starvation_deaths} COUNTRYMEN DIED OF STARVATION"); + } + + // the original was using `RND(1)` as factor, but I do not want to deal with floats. + // this solution should do the same in the range of numbers we expect + let pollution = ((2000 - land) * rng.u32(0..=2000)) / 2000; + let pollution_deaths = if pollution_control >= 25 { + pollution / (pollution_control / 25) + } else { + pollution + }; + + if pollution_deaths > 0 { + println!( + "{} COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION", + pollution_deaths + ); + } + + let (money, land) = if pollution_deaths + starvation_deaths > 0 { + let funeral_costs = (pollution_deaths + starvation_deaths) * 9; + println!(" YOU WERE FORCED TO SPEND {funeral_costs} RALLODS ON FUNERAL EXPENSES"); + if funeral_costs > money { + println!(" INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD"); + ( + 0, + // I only handle integers here, but I think the basic code implicitly turns integers + // to floats on division. So in order to round up to the next full land unit, I have + // to do this weird modulo stuff here + land - funeral_costs / land_price + + if funeral_costs % land_price == 0 { + 0 + } else { + 1 + }, + ) + } else { + (money - funeral_costs, land) + } + } else { + (money, land) + }; + + let mut countrymen = state + .countrymen + .saturating_sub(starvation_deaths) + .saturating_sub(pollution_deaths); + + let tourist_trade_positive = countrymen * 22 + rng.u32(0..500); + let tourist_trade_negative = (2000 - land) * 15; + + let new_foreign_workers: i32 = if land_sold > 0 { + land_sold as i32 + rng.i32(0..10) - rng.i32(0..20) + + if state.foreign_workers == 0 { 20 } else { 0 } + } else { + 0 + }; + // In theory, we could come up with negative foreign workers here (and in the original game) + // This does not seem to be right, so let's cap them at 0 + let foreign_workers = if new_foreign_workers < 0 { + state + .foreign_workers + .saturating_sub(new_foreign_workers.unsigned_abs()) + } else { + state.foreign_workers + new_foreign_workers as u32 + }; + print!(" {new_foreign_workers} WORKERS CAME TO THE COUNTRY AND "); + + let countryman_migration = (money_distributed as i32 / 100 - countrymen as i32) / 10 + + pollution_control as i32 / 25 + - (2000 - land as i32) / 50 + - pollution_deaths as i32 / 2; + + if countryman_migration < 0 { + println!("{} COUNTRYMEN LEFT THE ISLAND", countryman_migration.abs()); + countrymen = countrymen.saturating_sub(countryman_migration.unsigned_abs()) + } else { + println!("{countryman_migration} COUNTRYMEN CAME TO THE ISLAND"); + countrymen += countryman_migration as u32 + } + + let harvest_lost = ((2000 - land) * (rng.u32(0..2000) + 3000)) / 4000; + // in the original game, this checked for foreign_workers == 0 instead of land_planted == 0 + // this is documented as Bug 4 in the README.md + if land_planted == 0 { + print!("OF {land_planted} SQ. MILES PLANTED,"); + } + println!( + " YOU HARVESTED {} SQ. MILES OF CROPS.", + land_planted.saturating_sub(harvest_lost) + ); + + if harvest_lost > 0 { + // There was a bug here in the original code (Bug 2 in README.md). + // Based on the variable `V1`, the word `INCREASED` was inserted. + // However, no value was ever assigned to `V1`. Since the pollution comes from land that has + // been sold, I used the land difference to check whether the pollution increased. + if state.land < land { + println!(" (DUE TO INCREASED AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)"); + } else { + println!(" (DUE TO AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)"); + } + } + + let crop_winnings = land_planted.saturating_sub(harvest_lost) * land_price / 2; + println!("MAKING {crop_winnings} RALLODS."); + let money = money + crop_winnings; + + // In the original game, there are two bugs here (documented as Bug 1 and Bug 5 in the README.md) + // The first one made the game ignore the income from tourists and duplicated the money that was + // left at this point (the "DECREASE BECAUSE"-message would never have been shown). + // The second bug made the tourist trade profitable again is the pollution was too high (i.e. + // if `tourist_trade_positive` was less than `tourist_trade_negative` + let tourist_trade = tourist_trade_positive.saturating_sub(tourist_trade_negative); + println!(" YOU MADE {tourist_trade} RALLODS FROM TOURIST TRADE."); + if tourist_trade < state.previous_tourist_trade { + println!( + " DECREASE BECAUSE {}", + POLLUTION[rng.usize(0..POLLUTION.len())] + ); + } + let money = money + tourist_trade; + + if starvation_deaths + pollution_deaths > 200 { + let reason = rng.u8(0..10); + return Ok(RoundEnd::GameOver(format!( + r" + + {} COUNTRYMEN DIED IN ONE YEAR!!!!! +DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY +BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU +{} +", + starvation_deaths + pollution_deaths, + // The reasons are not equally probable in the original game. + // I wonder if this was intentional. + if reason <= 3 { + "ALSO HAD YOUR LEFT EYE GOUGED OUT!" + } else if reason <= 6 { + "HAVE ALSO GAINED A VERY BAD REPUTATION." + } else { + "HAVE ALSO BEEN DECLARED NATIONAL FINK." + } + ))); + } + if countrymen < 343 { + // This is not entirely fair, it is possible that some of them just left, not died. + // Also: the initial number of countrymen varies a bit, but this boundary is fix, so it is + // not always a third + return Ok(RoundEnd::GameOver(format!( + r" + +OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU +WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING) +HATE YOUR GUTS. +{} +", + departure_flavour(rng) + ))); + } + if money_after_expenses / 100 > 5 && starvation_deaths >= 2 { + return Ok(RoundEnd::GameOver( + r" +MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID +NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED +OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE +BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE. +THE CHOICE IS YOURS. +IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER +BEFORE PROCEEDING. +" + .to_owned(), + )); + } + if foreign_workers > countrymen { + return Ok(RoundEnd::GameOver(format!( + r" + +THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER +OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND +TAKEN OVER THE COUNTRY. +{} +", + departure_flavour(rng) + ))); + } + if state.year_in_office + 1 >= TERM_LENGTH { + return Ok(RoundEnd::GameOver(format!( + r" + +CONGRATULATIONS!!!!!!!!!!!!!!!!!! +YOU HAVE SUCCESFULLY COMPLETED YOUR {} YEAR TERM +OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT +NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD +LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT +PLAYS THIS GAME. +", + TERM_LENGTH + ))); + } + + Ok(RoundEnd::Next(State { + money, + countrymen, + foreign_workers, + land, + year_in_office: state.year_in_office + 1, + show_land_hint, + previous_tourist_trade: tourist_trade, + })) +} + +fn departure_flavour(rng: &mut Rng) -> &'static str { + if rng.bool() { + "YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\nRESIDING IN PRISON.\n" + } else { + "YOU HAVE BEEN ASSASSINATED.\n" + } +} + +fn read_int(mut input: R, buf: &mut String) -> io::Result { + loop { + buf.clear(); + input.read_line(buf)?; + let line = buf.trim(); + // This is implicit behaviour in the original code: empty input is equal to 0 + if line.is_empty() { + return Ok(0); + } + if let Ok(n) = line.parse::() { + return Ok(n); + } else { + print!("??REENTER\n?? "); + stdout().flush()?; + } + } +} + +fn read_and_verify_int( + mut input: R, + buf: &mut String, + prompt: &str, + mut verify: Verify, +) -> io::Result +where + Verify: FnMut(u32) -> Result, +{ + loop { + print!("{}", prompt); + stdout().flush()?; + let v = read_int(&mut input, buf)?; + match verify(v) { + Ok(v) => { + return Ok(v); + } + Err(msg) => { + println!("{}", msg); + } + } + } +} From 3742b8fede129171d6e1bad1fe0db1afca2189d3 Mon Sep 17 00:00:00 2001 From: Guido Knips Date: Tue, 29 Aug 2023 21:00:15 +0200 Subject: [PATCH 219/377] Add README.md for rust King --- 53_King/rust/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 53_King/rust/README.md diff --git a/53_King/rust/README.md b/53_King/rust/README.md new file mode 100644 index 000000000..529da33b7 --- /dev/null +++ b/53_King/rust/README.md @@ -0,0 +1,28 @@ +King +==== + +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [rust](https://www.rust-lang.org/). + +Porting Notes +------------- + +### Floats + +The original code implicitly uses floating point numbers in many places which are explicitly cast to integers. In this port, I avoided using floats and tried to replicate the behaviour using just integers. It is possible that I missed some places where rounding a value would have made a difference. If you find such a bug, please notify me or make implement a fix yourself. + +### Signed Numbers + +I used unsigned integers for most of the program because it was easier than to check for negative values all the time. Unfortunately, that made the code a bit whacky in one or two places. + +Since I only allow input of positive numbers, it is not possible to exit the game when entering the stats to resume a game, which would be possible by entering negative numbers in the original game. + +### Bugs + +I tried to fix all bugs listed in the [main README for King](../README.md). I have tested this implementation a bit but not extensively, so there may be some portation bugs. If you find them, you are free to fix them. + +Future Development +------------------ + +I plan to add some tests and tidy up the code a bit, but this version should be feature-complete. From 0e8619802d15ef6c2f53d008895416cdc2eebffb Mon Sep 17 00:00:00 2001 From: Guido Knips Date: Tue, 29 Aug 2023 21:11:38 +0200 Subject: [PATCH 220/377] Add rust version of King to progress table --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b4532cf8b..0544ea2e0 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 50_Horserace | x | | x | | | | | | x | x | | 51_Hurkle | x | x | x | | | x | x | x | x | x | | 52_Kinema | x | x | x | | | x | x | x | | x | -| 53_King | x | | x | | | | x | | | x | +| 53_King | x | | x | | | | x | | x | x | | 54_Letter | x | x | x | | | x | x | x | x | x | | 55_Life | x | x | x | | | x | x | x | x | x | | 56_Life_for_Two | x | x | x | | | x | x | | | x | From a358e441cee622f018d852c6055cedead39d52b9 Mon Sep 17 00:00:00 2001 From: Guido Knips Date: Wed, 30 Aug 2023 21:51:03 +0200 Subject: [PATCH 221/377] Add rust implementation for 23 Matches --- 93_23_Matches/README.md | 2 +- 93_23_Matches/rust/Cargo.lock | 16 +++++ 93_23_Matches/rust/Cargo.toml | 9 +++ 93_23_Matches/rust/README.md | 3 + 93_23_Matches/rust/src/main.rs | 108 +++++++++++++++++++++++++++++++++ 5 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 93_23_Matches/rust/Cargo.lock create mode 100644 93_23_Matches/rust/Cargo.toml create mode 100644 93_23_Matches/rust/README.md create mode 100644 93_23_Matches/rust/src/main.rs diff --git a/93_23_Matches/README.md b/93_23_Matches/README.md index 8ef8d6f8a..e4ece5fd5 100644 --- a/93_23_Matches/README.md +++ b/93_23_Matches/README.md @@ -19,4 +19,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -(please note any difficulties or challenges in porting here) +There is an oddity (you can call it a bug, but it is no big deal) in the original code. If there are only two or three matches left at the player's turn and the player picks all of them (or more), the game would still register that as a win for the player. diff --git a/93_23_Matches/rust/Cargo.lock b/93_23_Matches/rust/Cargo.lock new file mode 100644 index 000000000..96e2f79ef --- /dev/null +++ b/93_23_Matches/rust/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + +[[package]] +name = "twenty-three-matches" +version = "0.1.0" +dependencies = [ + "fastrand", +] diff --git a/93_23_Matches/rust/Cargo.toml b/93_23_Matches/rust/Cargo.toml new file mode 100644 index 000000000..a4227bbd4 --- /dev/null +++ b/93_23_Matches/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "twenty-three-matches" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +fastrand = "^2.0.0" diff --git a/93_23_Matches/rust/README.md b/93_23_Matches/rust/README.md new file mode 100644 index 000000000..6249450a1 --- /dev/null +++ b/93_23_Matches/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [rust](https://www.rust-lang.org/) diff --git a/93_23_Matches/rust/src/main.rs b/93_23_Matches/rust/src/main.rs new file mode 100644 index 000000000..a14c39f58 --- /dev/null +++ b/93_23_Matches/rust/src/main.rs @@ -0,0 +1,108 @@ +use std::io; +use std::io::{stdin, stdout, BufRead, Write}; + +fn main() -> io::Result<()> { + intro(); + let mut input = stdin().lock(); + let mut buf = String::with_capacity(16); + // variable `N` in the original game + let mut matches: u8 = 23; + if fastrand::bool() { + println!("TAILS! YOU GO FIRST. \n"); + } else { + println!("HEADS! I WIN! HA! HA!\nPREPARE TO LOSE, MEATBALL-NOSE!!\n\nI TAKE 2 MATCHES"); + matches -= 2; + println!("THE NUMBER OF MATCHES IS NOW {matches}\n"); + println!("YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES."); + } + loop { + // variable `K` in the original game + let human_picked = read_matches(&mut input, &mut buf)?; + matches = matches.saturating_sub(human_picked); + if matches == 0 { + // this can only happen if the player could win with the next turn but they take too + // many matches (e.g. if there are three matches left and the player takes three instead of + // two). In the original game, this would count as a win for the player. + println!("\nYOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\nHA ! HA ! I BEAT YOU !!!\n\nGOOD BYE LOSER!"); + return Ok(()); + } + + println!("THERE ARE NOW {matches} MATCHES REMAINING."); + + if matches <= 1 { + println!("YOU WON, FLOPPY EARS !\nTHINK YOU'RE PRETTY SMART !\nLETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!"); + return Ok(()); + } + + // variable `Z` in the original game + let ai_picked = ai_pick(matches, human_picked); + println!("MY TURN ! I REMOVE {ai_picked} MATCHES"); + matches = matches.saturating_sub(ai_picked); + // The AI will never pick the last match except for the case where only one match is left (which is handled above) + if matches == 1 { + println!("\nYOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\nHA ! HA ! I BEAT YOU !!!\n\nGOOD BYE LOSER!"); + return Ok(()); + } + println!("THE NUMBER OF MATCHES IS NOW {matches}\n"); + println!("YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES."); + } +} + +fn intro() { + println!( + r" 23 MATCHES + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + + THIS IS A GAME CALLED '23 MATCHES'. + +WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE +MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE +THE LAST MATCH. + +LET'S FLIP A COIN TO SEE WHO GOES FIRST. +IF IT COMES UP HEADS, I WILL WIN THE TOSS. +" + ); +} + +fn read_matches(mut input: R, buf: &mut String) -> io::Result { + print!("HOW MANY DO YOU WISH TO REMOVE ?? "); + stdout().flush()?; + loop { + let input = read_int(&mut input, buf)?; + if input <= 0 || input > 3 { + print!("VERY FUNNY! DUMMY!\nDO YOU WANT TO PLAY OR GOOF AROUND?\nNOW, HOW MANY MATCHES DO YOU WANT ?? "); + stdout().flush()?; + } else { + return Ok(input as u8); + } + } +} + +fn read_int(mut input: R, buf: &mut String) -> io::Result { + loop { + buf.clear(); + input.read_line(buf)?; + let line = buf.trim(); + // This is implicit behaviour in the original code: empty input is equal to 0 + if line.is_empty() { + return Ok(0); + } + if let Ok(n) = line.parse::() { + return Ok(n); + } else { + print!("??REENTER\n?? "); + stdout().flush()?; + } + } +} + +fn ai_pick(matches: u8, human_picked: u8) -> u8 { + if matches < 4 { + matches - 1 + } else { + 4 - human_picked + } +} From b11b45e7906637c94d4c45c75712bc021ecf0781 Mon Sep 17 00:00:00 2001 From: Guido Knips Date: Wed, 30 Aug 2023 22:09:30 +0200 Subject: [PATCH 222/377] List 23 Matches as implemented for rust --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0544ea2e0..0ddd2748f 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 90_Tower | x | x | x | | | x | x | | x | x | | 91_Train | x | x | x | | | x | x | x | x | x | | 92_Trap | x | x | x | | | x | x | x | x | x | -| 93_23_Matches | x | x | x | | | x | x | x | | x | +| 93_23_Matches | x | x | x | | | x | x | x | x | x | | 94_War | x | x | x | x | | x | x | x | x | x | | 95_Weekday | x | x | x | | | x | x | | x | x | | 96_Word | x | x | x | | | x | x | x | x | x | From 7dff2a67e797db298c36cef128fdee555efae202 Mon Sep 17 00:00:00 2001 From: lmstolton Date: Mon, 4 Sep 2023 19:29:18 +0100 Subject: [PATCH 223/377] Changed get_input() to return Option --- 43_Hammurabi/rust/src/main.rs | 64 ++++++++++++++++------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/43_Hammurabi/rust/src/main.rs b/43_Hammurabi/rust/src/main.rs index 061d502e2..529a61451 100644 --- a/43_Hammurabi/rust/src/main.rs +++ b/43_Hammurabi/rust/src/main.rs @@ -46,28 +46,27 @@ fn run() { loop { println!("HOW MANY ACRES DO YOU WISH TO BUY? "); if let Some(qty) = get_input() { - if qty < 0 { // A negative amount is impossible - impossible_task(); - game_failed = true; - break 'main; - } // Player decides not to buy any land if qty == 0 { bought_land = false; break; } // Trying to buy more land than you can afford? - if land_price * qty as u32 > grain { + if land_price * qty > grain { insufficient_grain(grain); continue; } // Everything checks out OK - if land_price * qty as u32 <= grain { - acres += qty as u32; - grain -= land_price * qty as u32; + if land_price * qty <= grain { + acres += qty ; + grain -= land_price * qty ; bought_land = true; break; } + } else { + impossible_task(); + game_failed = true; + break 'main; } } @@ -75,19 +74,18 @@ fn run() { loop { println!("HOW MANY ACRES DO YOU WISH TO SELL? "); if let Some(qty) = get_input() { - if qty < 0 { // A negative amount is impossible - impossible_task(); - game_failed = true; - break 'main; - } // Everything checks out OK - if qty as u32 <= acres { - acres -= qty as u32; - grain += land_price * qty as u32; + if qty <= acres { + acres -= qty; + grain += land_price * qty; break; } // Trying to sell more land that you own insufficient_land(acres); + } else { + impossible_task(); + game_failed = true; + break 'main; } } } @@ -95,50 +93,48 @@ fn run() { loop { println!("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? "); if let Some(qty) = get_input() { - if qty < 0 { // A negative amount is impossible - impossible_task(); - game_failed = true; - break 'main; - } // Trying to use more grain than is in silos? - if qty as u32 > grain { + if qty > grain { insufficient_grain(grain); continue; } // Everything checks out OK - bushels_fed = qty as u32; + bushels_fed = qty; grain -= bushels_fed; break; + } else { + impossible_task(); + game_failed = true; + break 'main; } } loop { println!("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? "); if let Some(qty) = get_input() { - if qty < 0 { // A negative amount is impossible - impossible_task(); - game_failed = true; - break 'main; - } // Trying to plant more acres than you own? - if qty as u32 > acres { + if qty > acres { insufficient_land(acres); continue; } // Enough grain for seed? - if qty as u32 / 2 > grain { + if qty / 2 > grain { insufficient_grain(grain); continue; } // Enough people to tend the crops? - if qty as u32 > (10 * population) { + if qty > (10 * population) { insufficient_people(population); continue; } // Everything checks out OK - planted = qty as u32; + planted = qty; grain -= planted / 2; break; + } else { + impossible_task(); + game_failed = true; + break 'main; } } @@ -217,7 +213,7 @@ fn run() { println!("\nSO LONG FOR NOW.\n"); } -fn get_input() -> Option { +fn get_input() -> Option { let mut input = String::new(); io::stdin().read_line(&mut input).expect("Failed read_line"); match input.trim().parse() { From 39b1a89fcb3e935c1bacae29bfea62b78c9bfd34 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Tue, 12 Sep 2023 12:03:07 -0700 Subject: [PATCH 224/377] Create word.ms --- .../96_Word/MiniScrip/word.ms | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 00_Alternate_Languages/96_Word/MiniScrip/word.ms diff --git a/00_Alternate_Languages/96_Word/MiniScrip/word.ms b/00_Alternate_Languages/96_Word/MiniScrip/word.ms new file mode 100644 index 000000000..190ad6117 --- /dev/null +++ b/00_Alternate_Languages/96_Word/MiniScrip/word.ms @@ -0,0 +1,63 @@ +words = ["dinky", "smoke", "water", "grass", "train", "might", + "first", "candy", "champ", "would", "clump", "dopey"] + +playGame = function + secret = words[rnd * words.len] + guesses = 0 + exact = ["-"]*5 + + print "You are starting a new game..." + while true + guess = "" + while guess == "" + print + guess = input("Guess a five letter word. ").lower + if guess == "?" then break + if guess.len != 5 then + guess = "" + print "You must guess a five letter word. Try again." + end if + end while + guesses += 1 + + if guess == "?" then + print "The secret word is " + secret + break + else + common = "" + for i in range(0, 4) + if secret.indexOf(guess[i]) != null then + common += guess[i] + if secret[i] == guess[i] then + exact[i] = guess[i] + end if + end if + end for + print "There were " + common.len + " matches and the common letters were..." + common + print "From the exact letter matches, you know"+"."*16 + exact.join("") + + if secret == guess or secret == exact.join("") then + print "You have guessed the word. It took " + guesses + " guesses!" + break + else if common.len < 2 then + print + print "If you give up, type '?' for your next guess." + end if + end if + end while +end function + +print " " * 33 + "WORD" +print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print +print "I am thinking of a word -- you guess it. I will give you" +print "clues to help you get it. Good luck!" +print + +playing = "y" +while playing == "y" + playGame + print + playing = input("Want to play again? ") + " " + playing = playing[0].lower +end while From 26ce0214abc5d2d16e1a77ce33c5d45684baebbb Mon Sep 17 00:00:00 2001 From: chinhouse Date: Tue, 12 Sep 2023 12:03:55 -0700 Subject: [PATCH 225/377] Delete 00_Alternate_Languages/96_Word/MiniScrip directory --- .../96_Word/MiniScrip/word.ms | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 00_Alternate_Languages/96_Word/MiniScrip/word.ms diff --git a/00_Alternate_Languages/96_Word/MiniScrip/word.ms b/00_Alternate_Languages/96_Word/MiniScrip/word.ms deleted file mode 100644 index 190ad6117..000000000 --- a/00_Alternate_Languages/96_Word/MiniScrip/word.ms +++ /dev/null @@ -1,63 +0,0 @@ -words = ["dinky", "smoke", "water", "grass", "train", "might", - "first", "candy", "champ", "would", "clump", "dopey"] - -playGame = function - secret = words[rnd * words.len] - guesses = 0 - exact = ["-"]*5 - - print "You are starting a new game..." - while true - guess = "" - while guess == "" - print - guess = input("Guess a five letter word. ").lower - if guess == "?" then break - if guess.len != 5 then - guess = "" - print "You must guess a five letter word. Try again." - end if - end while - guesses += 1 - - if guess == "?" then - print "The secret word is " + secret - break - else - common = "" - for i in range(0, 4) - if secret.indexOf(guess[i]) != null then - common += guess[i] - if secret[i] == guess[i] then - exact[i] = guess[i] - end if - end if - end for - print "There were " + common.len + " matches and the common letters were..." + common - print "From the exact letter matches, you know"+"."*16 + exact.join("") - - if secret == guess or secret == exact.join("") then - print "You have guessed the word. It took " + guesses + " guesses!" - break - else if common.len < 2 then - print - print "If you give up, type '?' for your next guess." - end if - end if - end while -end function - -print " " * 33 + "WORD" -print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" -print -print "I am thinking of a word -- you guess it. I will give you" -print "clues to help you get it. Good luck!" -print - -playing = "y" -while playing == "y" - playGame - print - playing = input("Want to play again? ") + " " - playing = playing[0].lower -end while From b94bef19064f9bcaf659992bf9a226eb7c2d0f48 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Tue, 12 Sep 2023 12:04:24 -0700 Subject: [PATCH 226/377] Create word.ms --- .../96_Word/MiniScript/word.ms | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 00_Alternate_Languages/96_Word/MiniScript/word.ms diff --git a/00_Alternate_Languages/96_Word/MiniScript/word.ms b/00_Alternate_Languages/96_Word/MiniScript/word.ms new file mode 100644 index 000000000..190ad6117 --- /dev/null +++ b/00_Alternate_Languages/96_Word/MiniScript/word.ms @@ -0,0 +1,63 @@ +words = ["dinky", "smoke", "water", "grass", "train", "might", + "first", "candy", "champ", "would", "clump", "dopey"] + +playGame = function + secret = words[rnd * words.len] + guesses = 0 + exact = ["-"]*5 + + print "You are starting a new game..." + while true + guess = "" + while guess == "" + print + guess = input("Guess a five letter word. ").lower + if guess == "?" then break + if guess.len != 5 then + guess = "" + print "You must guess a five letter word. Try again." + end if + end while + guesses += 1 + + if guess == "?" then + print "The secret word is " + secret + break + else + common = "" + for i in range(0, 4) + if secret.indexOf(guess[i]) != null then + common += guess[i] + if secret[i] == guess[i] then + exact[i] = guess[i] + end if + end if + end for + print "There were " + common.len + " matches and the common letters were..." + common + print "From the exact letter matches, you know"+"."*16 + exact.join("") + + if secret == guess or secret == exact.join("") then + print "You have guessed the word. It took " + guesses + " guesses!" + break + else if common.len < 2 then + print + print "If you give up, type '?' for your next guess." + end if + end if + end while +end function + +print " " * 33 + "WORD" +print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print +print "I am thinking of a word -- you guess it. I will give you" +print "clues to help you get it. Good luck!" +print + +playing = "y" +while playing == "y" + playGame + print + playing = input("Want to play again? ") + " " + playing = playing[0].lower +end while From b71f5232b5fa3c4b3dabaafde145902e5d47176d Mon Sep 17 00:00:00 2001 From: chinhouse Date: Tue, 12 Sep 2023 12:07:09 -0700 Subject: [PATCH 227/377] Create README.md --- .../96_Word/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/96_Word/MiniScript/README.md diff --git a/00_Alternate_Languages/96_Word/MiniScript/README.md b/00_Alternate_Languages/96_Word/MiniScript/README.md new file mode 100644 index 000000000..5e60340ab --- /dev/null +++ b/00_Alternate_Languages/96_Word/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 word.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 "word" + run From 4ae8c5502f48300eebe251b0e0e74c7102954cfd Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 24 Aug 2023 14:31:34 -0700 Subject: [PATCH 228/377] Added MiniScript versions of 50_Horserace and 51_Hurkle. --- .../50_Horserace/MiniScript/README.md | 23 +++ .../50_Horserace/MiniScript/horserace.ms | 149 ++++++++++++++++++ .../51_Hurkle/MiniScript/README.md | 19 +++ .../51_Hurkle/MiniScript/hurkle.ms | 56 +++++++ 4 files changed, 247 insertions(+) create mode 100644 00_Alternate_Languages/50_Horserace/MiniScript/README.md create mode 100644 00_Alternate_Languages/50_Horserace/MiniScript/horserace.ms create mode 100644 00_Alternate_Languages/51_Hurkle/MiniScript/README.md create mode 100644 00_Alternate_Languages/51_Hurkle/MiniScript/hurkle.ms diff --git a/00_Alternate_Languages/50_Horserace/MiniScript/README.md b/00_Alternate_Languages/50_Horserace/MiniScript/README.md new file mode 100644 index 000000000..c9a5cd1fd --- /dev/null +++ b/00_Alternate_Languages/50_Horserace/MiniScript/README.md @@ -0,0 +1,23 @@ +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 horserace.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 "horserace" + run + + +## Porting Notes + +- The original program, designed to be played directly on a printer, drew a track 27 rows long. To fit better on modern screens, I've shortened the track to 23 rows. This is adjustable via the "trackLen" value assigned on line 72. + +- Also because we're playing on a screen instead of a printer, I'm clearing the screen and pausing briefly before each new update of the track. This is done via the `clear` API when running in Mini Micro, or by using a VT100 escape sequence in other contexts. diff --git a/00_Alternate_Languages/50_Horserace/MiniScript/horserace.ms b/00_Alternate_Languages/50_Horserace/MiniScript/horserace.ms new file mode 100644 index 000000000..a8750f5ed --- /dev/null +++ b/00_Alternate_Languages/50_Horserace/MiniScript/horserace.ms @@ -0,0 +1,149 @@ +print " "*31 + "Horserace" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +print "Welcome to South Portland High Racetrack" +print " ...owned by Laurie Chevalier" + +// show directions, if wanted +x = input("Do you want directions? ").lower +if not x or x[0] != "n" then + print "Up to 10 may play. A table of odds will be printed. You" + print "may bet any + amount under 100000 on one horse." + print "During the race, a horse will be shown by its" + print "number. The horses race down the paper!" + print +end if + +// get player names +qtyPlayers = input("How many want to bet? ").val +if qtyPlayers < 1 then exit +print "When ? appears, type name" +playerNames = [null] +for i in range(1, qtyPlayers) + playerNames.push input("?") +end for +print +pick = [null] + [0]*qtyPlayers +bet = [null] + [0]*qtyPlayers + +d = [0] * 9 // odds denominator +r = 0 // odds numerator + +printInColumns = function(col0, col1, col2) + print (col0+" "*16)[16] + (col1+" "*10)[:10] + (col2+" "*10)[:10] +end function + +setup = function + // initialize the horses + globals.names = [null] + + "Joe Maw,L.B.J.,Mr.Washburn,Miss Karen,Jolly,Horse,Jelly Do Not,Midnight".split(",") + for i in range(1,8) + d[i] = floor(10*rnd+1) + end for + globals.r = d.sum + + // print odds table + printInColumns "Horse", "Number", "Odds" + for i in range(1,8) + printInColumns names[i], i, round(r/d[i],2) + ":1" + end for + + // get the players' bets + print "--------------------------------------------------" + print "Place your bets...Horse # then Amount" + for j in range(1, qtyPlayers) + while true + s = input(playerNames[j] + "? ").replace(",", " ").split + if s.len < 2 then s.push -1 + pick[j] = s[0].val + bet[j] = s[-1].val + if pick[j] < 1 or pick[j] > 8 or bet[j] < 1 or bet[j] >=100000 then + print "You can't do that!" + else + break + end if + end while + end for +end function + +// Draw a racetrack, with each horse the given number +// of lines down from START to FINISH. +trackLen = 23 +drawTrack = function(horsePositions) + print + if version.hostName == "Mini Micro" then clear else print char(27)+"c" + if horsePositions[1] == 0 then print "1 2 3 4 5 6 7 8" else print + print "XXXXSTARTXXXX" + for row in range(1, trackLen) + for h in range(1,8) + p = horsePositions[h] + if p > trackLen then p = trackLen + if p == row then print h, " " + end for + print + end for + print "XXXXFINISHXXXX", "" + if version.hostName != "Mini Micro" then print +end function + +runRace = function + pos = [0]*9 + maxPos = 0 + while true + drawTrack pos + wait 1 + if maxPos >= trackLen then break + for i in range(1,8) + q = floor(100*rnd+1) + x = floor(r/d[i]+0.5) + if q < 10 then + speed = 1 + else if q < x+17 then + speed = 2 + else if q < x+37 then + speed = 3 + else if q < x+57 then + speed = 4 + else if q < x+77 then + speed = 5 + else if q < x+92 then + speed = 6 + else + speed = 7 + end if + pos[i] += speed + if pos[i] > maxPos then maxPos = pos[i] + end for + end while + + print + print "---------------------------------------------" + print + print "The race results are:" + results = [] + for i in range(1,8) + results.push {"num":i, "pos":pos[i]} + end for + results.sort "pos", false + for place in range(1, 8) + h = results[place-1].num + print " " + place + " Place Horse No. " + h + " at " + round(r/d[h],2) + ":1" + print + end for + for p in range(1, qtyPlayers) + if pick[p] == results[0].num then + print playerNames[p] + " wins $" + round((r/d[pick[p]])*bet[p], 2) + end if + end for +end function + +// Main loop +while true + setup + runRace + print "Do you want to bet on the next race ?" + yn = input("Yes or no? ").lower + if not yn or yn[0] != "y" then break +end while + diff --git a/00_Alternate_Languages/51_Hurkle/MiniScript/README.md b/00_Alternate_Languages/51_Hurkle/MiniScript/README.md new file mode 100644 index 000000000..0f4ff6a61 --- /dev/null +++ b/00_Alternate_Languages/51_Hurkle/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of hurkle.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 hurkle.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 "hurkle" + run diff --git a/00_Alternate_Languages/51_Hurkle/MiniScript/hurkle.ms b/00_Alternate_Languages/51_Hurkle/MiniScript/hurkle.ms new file mode 100644 index 000000000..a1b228222 --- /dev/null +++ b/00_Alternate_Languages/51_Hurkle/MiniScript/hurkle.ms @@ -0,0 +1,56 @@ +print " "*33 + "Hurcle" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +n = 5 // number of guesses allowed +g = 10 // grid size +print +print "A hurkle is hiding on a " + g + " by " + g + " grid. Homebase" +print "on the grid is point 0,0 in the southwest corner," +print "and any point on the grid is designated by a" +print "pair of whole numbers seperated by a comma. The first" +print "number is the horizontal position and the second number" +print "is the vertical position. You must try to" +print "guess the hurkle's gridpoint. You get " + n + "tries." +print "After each try, I will tell you the approximate" +print "direction to go to look for the hurkle." +print + +playOneGame = function + a = floor(g*rnd) + b = floor(g*rnd) + for k in range(1, n) + s = input("Guess #" + k + "? ").replace(",", " ").split + x = s[0].val + y = s[-1].val + if x == a and y == b then + print + print "You found him in " + k + " guesses!" + return + end if + if y == b then + if x == a then + print + print "You found him in " + k + " guesses!" + return + else if x < a then + dir = "east" + else + dir = "west" + end if + else if y < b then + dir = "north" + else + dir = "south" + end if + print "Go " + dir + end for + print "Sorry, that's " + n + " guesses." + print "The hurkle is at " + a + "," + b +end function + +while true + playOneGame + print + print "Let's play again, hurkle is hiding." + print +end while From 06caa5085beeb56d04f0cd721953c40c54698249 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Fri, 25 Aug 2023 10:29:48 -0700 Subject: [PATCH 229/377] Added code markup around MiniScript commands in the README files, for clarity --- .../01_Acey_Ducey/MiniScript/README.md | 5 ++++- .../02_Amazing/MiniScript/README.md | 5 ++++- .../03_Animal/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/04_Awari/MiniScript/README.md | 5 ++++- .../05_Bagels/MiniScript/README.md | 5 ++++- .../06_Banner/MiniScript/README.md | 5 ++++- .../07_Basketball/MiniScript/README.md | 5 ++++- .../08_Batnum/MiniScript/README.md | 5 ++++- .../09_Battle/MiniScript/README.md | 5 ++++- .../10_Blackjack/MiniScript/README.md | 5 ++++- .../11_Bombardment/MiniScript/README.md | 5 ++++- .../12_Bombs_Away/MiniScript/README.md | 5 ++++- .../13_Bounce/MiniScript/README.md | 5 ++++- .../14_Bowling/MiniScript/README.md | 5 ++++- .../15_Boxing/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/16_Bug/MiniScript/README.md | 5 ++++- .../17_Bullfight/MiniScript/README.md | 5 ++++- .../18_Bullseye/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/19_Bunny/MiniScript/README.md | 5 ++++- .../20_Buzzword/MiniScript/README.md | 5 ++++- .../21_Calendar/MiniScript/README.md | 5 ++++- .../22_Change/MiniScript/README.md | 5 ++++- .../23_Checkers/MiniScript/README.md | 5 ++++- .../24_Chemist/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/25_Chief/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/26_Chomp/MiniScript/README.md | 5 ++++- .../27_Civil_War/MiniScript/README.md | 5 ++++- .../28_Combat/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/29_Craps/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/30_Cube/MiniScript/README.md | 5 ++++- .../31_Depth_Charge/MiniScript/README.md | 5 ++++- .../32_Diamond/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/33_Dice/MiniScript/README.md | 6 ++++-- .../34_Digits/MiniScript/README.md | 5 ++++- .../35_Even_Wins/MiniScript/README.md | 11 ++++++++--- .../36_Flip_Flop/MiniScript/README.md | 5 ++++- .../37_Football/MiniScript/README.md | 12 ++++++++---- .../38_Fur_Trader/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/39_Golf/MiniScript/README.md | 5 ++++- .../40_Gomoko/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/41_Guess/MiniScript/README.md | 6 ++++-- .../42_Gunner/MiniScript/README.md | 5 ++++- .../43_Hammurabi/MiniScript/README.md | 5 ++++- .../44_Hangman/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/45_Hello/MiniScript/README.md | 5 ++++- .../46_Hexapawn/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md | 5 ++++- .../48_High_IQ/MiniScript/README.md | 5 ++++- .../49_Hockey/MiniScript/README.md | 5 ++++- .../50_Horserace/MiniScript/README.md | 6 ++++-- .../51_Hurkle/MiniScript/README.md | 5 ++++- .../52_Kinema/MiniScript/README.md | 6 ++++-- .../54_Letter/MiniScript/README.md | 6 ++++-- .../64_Nicomachus/MiniScript/README.md | 6 ++++-- .../66_Number/MiniScript/README.md | 6 ++++-- .../78_Sine_Wave/MiniScript/README.md | 5 ++++- .../87_3-D_Plot/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/91_Train/MiniScript/README.md | 6 ++++-- 00_Alternate_Languages/92_Trap/MiniScript/README.md | 5 ++++- 00_Alternate_Languages/94_War/MiniScript/README.md | 5 ++++- 60 files changed, 248 insertions(+), 73 deletions(-) diff --git a/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md b/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md index c14b6da80..06640e03b 100644 --- a/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md +++ b/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md @@ -7,10 +7,13 @@ 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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` load "aceyducey" run +``` \ 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 index 301324c61..35d818ef5 100644 --- a/00_Alternate_Languages/02_Amazing/MiniScript/README.md +++ b/00_Alternate_Languages/02_Amazing/MiniScript/README.md @@ -7,12 +7,15 @@ 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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` load "amazing" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/03_Animal/MiniScript/README.md b/00_Alternate_Languages/03_Animal/MiniScript/README.md index 580dd0de3..1e48ea49c 100644 --- a/00_Alternate_Languages/03_Animal/MiniScript/README.md +++ b/00_Alternate_Languages/03_Animal/MiniScript/README.md @@ -7,10 +7,13 @@ 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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` load "animal" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/04_Awari/MiniScript/README.md b/00_Alternate_Languages/04_Awari/MiniScript/README.md index 744541123..f2b6dfe50 100644 --- a/00_Alternate_Languages/04_Awari/MiniScript/README.md +++ b/00_Alternate_Languages/04_Awari/MiniScript/README.md @@ -7,10 +7,13 @@ 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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` load "awari" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/05_Bagels/MiniScript/README.md b/00_Alternate_Languages/05_Bagels/MiniScript/README.md index 427482467..743d5160b 100644 --- a/00_Alternate_Languages/05_Bagels/MiniScript/README.md +++ b/00_Alternate_Languages/05_Bagels/MiniScript/README.md @@ -7,10 +7,13 @@ 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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` load "bagels" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/06_Banner/MiniScript/README.md b/00_Alternate_Languages/06_Banner/MiniScript/README.md index f93638530..25a241af9 100644 --- a/00_Alternate_Languages/06_Banner/MiniScript/README.md +++ b/00_Alternate_Languages/06_Banner/MiniScript/README.md @@ -7,10 +7,13 @@ 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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` load "banner" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/07_Basketball/MiniScript/README.md b/00_Alternate_Languages/07_Basketball/MiniScript/README.md index 019fccb8d..5958590e2 100644 --- a/00_Alternate_Languages/07_Basketball/MiniScript/README.md +++ b/00_Alternate_Languages/07_Basketball/MiniScript/README.md @@ -7,10 +7,13 @@ 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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` load "basketball" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/08_Batnum/MiniScript/README.md b/00_Alternate_Languages/08_Batnum/MiniScript/README.md index bec1c7e03..b33a3f84d 100644 --- a/00_Alternate_Languages/08_Batnum/MiniScript/README.md +++ b/00_Alternate_Languages/08_Batnum/MiniScript/README.md @@ -7,10 +7,13 @@ 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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` load "batnum" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/09_Battle/MiniScript/README.md b/00_Alternate_Languages/09_Battle/MiniScript/README.md index 0e807f512..07cd98272 100644 --- a/00_Alternate_Languages/09_Battle/MiniScript/README.md +++ b/00_Alternate_Languages/09_Battle/MiniScript/README.md @@ -9,10 +9,13 @@ 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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` load "battle" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/10_Blackjack/MiniScript/README.md b/00_Alternate_Languages/10_Blackjack/MiniScript/README.md index 49c8818a2..2f68bb794 100644 --- a/00_Alternate_Languages/10_Blackjack/MiniScript/README.md +++ b/00_Alternate_Languages/10_Blackjack/MiniScript/README.md @@ -7,12 +7,15 @@ 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 - +``` 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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: +``` load "blackjack" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/11_Bombardment/MiniScript/README.md b/00_Alternate_Languages/11_Bombardment/MiniScript/README.md index d6e7e393c..4a399a7bd 100644 --- a/00_Alternate_Languages/11_Bombardment/MiniScript/README.md +++ b/00_Alternate_Languages/11_Bombardment/MiniScript/README.md @@ -7,10 +7,13 @@ 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 bombardment.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 "bombardment" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md b/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md index e7cb424cf..22bcc0b1a 100644 --- a/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md +++ b/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md @@ -7,10 +7,13 @@ 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 bombsaway.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 "bombsaway" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/13_Bounce/MiniScript/README.md b/00_Alternate_Languages/13_Bounce/MiniScript/README.md index d129ed9be..e7e8f23a7 100644 --- a/00_Alternate_Languages/13_Bounce/MiniScript/README.md +++ b/00_Alternate_Languages/13_Bounce/MiniScript/README.md @@ -7,10 +7,13 @@ 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 bounce.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 "bounce" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/14_Bowling/MiniScript/README.md b/00_Alternate_Languages/14_Bowling/MiniScript/README.md index e997160e2..bfb33e6b5 100644 --- a/00_Alternate_Languages/14_Bowling/MiniScript/README.md +++ b/00_Alternate_Languages/14_Bowling/MiniScript/README.md @@ -7,10 +7,13 @@ 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 bowling.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 "bowling" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/15_Boxing/MiniScript/README.md b/00_Alternate_Languages/15_Boxing/MiniScript/README.md index 01454cd1d..9c0ae8fc2 100644 --- a/00_Alternate_Languages/15_Boxing/MiniScript/README.md +++ b/00_Alternate_Languages/15_Boxing/MiniScript/README.md @@ -7,10 +7,13 @@ 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 boxing.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 "boxing" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/16_Bug/MiniScript/README.md b/00_Alternate_Languages/16_Bug/MiniScript/README.md index aae43e942..554d5e529 100644 --- a/00_Alternate_Languages/16_Bug/MiniScript/README.md +++ b/00_Alternate_Languages/16_Bug/MiniScript/README.md @@ -7,10 +7,13 @@ 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 bug.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 "bug" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/17_Bullfight/MiniScript/README.md b/00_Alternate_Languages/17_Bullfight/MiniScript/README.md index c3cc69c92..2290e6e12 100644 --- a/00_Alternate_Languages/17_Bullfight/MiniScript/README.md +++ b/00_Alternate_Languages/17_Bullfight/MiniScript/README.md @@ -7,10 +7,13 @@ 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 bull.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 "bull" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/18_Bullseye/MiniScript/README.md b/00_Alternate_Languages/18_Bullseye/MiniScript/README.md index 465e1c454..73a1c749a 100644 --- a/00_Alternate_Languages/18_Bullseye/MiniScript/README.md +++ b/00_Alternate_Languages/18_Bullseye/MiniScript/README.md @@ -10,10 +10,13 @@ Go to https://miniscript.org/tryit/, clear the sample code from the code editor, 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 bullseye.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 "bullseye" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/19_Bunny/MiniScript/README.md b/00_Alternate_Languages/19_Bunny/MiniScript/README.md index db1f76833..90a054330 100644 --- a/00_Alternate_Languages/19_Bunny/MiniScript/README.md +++ b/00_Alternate_Languages/19_Bunny/MiniScript/README.md @@ -10,10 +10,13 @@ Go to https://miniscript.org/tryit/, clear the sample code from the code editor, 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 bunny.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 "bunny" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/20_Buzzword/MiniScript/README.md b/00_Alternate_Languages/20_Buzzword/MiniScript/README.md index db1f76833..90a054330 100644 --- a/00_Alternate_Languages/20_Buzzword/MiniScript/README.md +++ b/00_Alternate_Languages/20_Buzzword/MiniScript/README.md @@ -10,10 +10,13 @@ Go to https://miniscript.org/tryit/, clear the sample code from the code editor, 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 bunny.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 "bunny" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/21_Calendar/MiniScript/README.md b/00_Alternate_Languages/21_Calendar/MiniScript/README.md index 140a5f4d0..fea2264e6 100644 --- a/00_Alternate_Languages/21_Calendar/MiniScript/README.md +++ b/00_Alternate_Languages/21_Calendar/MiniScript/README.md @@ -7,10 +7,13 @@ 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 calendar.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 "calendar" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/22_Change/MiniScript/README.md b/00_Alternate_Languages/22_Change/MiniScript/README.md index f43188b9c..5708156d8 100644 --- a/00_Alternate_Languages/22_Change/MiniScript/README.md +++ b/00_Alternate_Languages/22_Change/MiniScript/README.md @@ -10,10 +10,13 @@ Go to https://miniscript.org/tryit/, clear the sample code from the code editor, 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 change.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 "change" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/23_Checkers/MiniScript/README.md b/00_Alternate_Languages/23_Checkers/MiniScript/README.md index 1c34d8cb3..9cb5fd6ee 100644 --- a/00_Alternate_Languages/23_Checkers/MiniScript/README.md +++ b/00_Alternate_Languages/23_Checkers/MiniScript/README.md @@ -7,10 +7,13 @@ 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 checkers.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 "checkers" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/24_Chemist/MiniScript/README.md b/00_Alternate_Languages/24_Chemist/MiniScript/README.md index ddc32f16b..82983edc2 100644 --- a/00_Alternate_Languages/24_Chemist/MiniScript/README.md +++ b/00_Alternate_Languages/24_Chemist/MiniScript/README.md @@ -10,10 +10,13 @@ Go to https://miniscript.org/tryit/, clear the sample code from the code editor, 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 chemist.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 "chemist" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/25_Chief/MiniScript/README.md b/00_Alternate_Languages/25_Chief/MiniScript/README.md index 624f2817c..fa28aa67b 100644 --- a/00_Alternate_Languages/25_Chief/MiniScript/README.md +++ b/00_Alternate_Languages/25_Chief/MiniScript/README.md @@ -12,10 +12,13 @@ Go to https://miniscript.org/tryit/, clear the sample code from the code editor, 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 chief.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 "chief" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/26_Chomp/MiniScript/README.md b/00_Alternate_Languages/26_Chomp/MiniScript/README.md index db94c5032..2fce3ec72 100644 --- a/00_Alternate_Languages/26_Chomp/MiniScript/README.md +++ b/00_Alternate_Languages/26_Chomp/MiniScript/README.md @@ -7,10 +7,13 @@ 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 chomp.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 "chomp" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/27_Civil_War/MiniScript/README.md b/00_Alternate_Languages/27_Civil_War/MiniScript/README.md index d5fd8e58d..ad8e06ed8 100644 --- a/00_Alternate_Languages/27_Civil_War/MiniScript/README.md +++ b/00_Alternate_Languages/27_Civil_War/MiniScript/README.md @@ -7,10 +7,13 @@ 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 civilwar.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 "civilwar" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/28_Combat/MiniScript/README.md b/00_Alternate_Languages/28_Combat/MiniScript/README.md index d15152479..0963185f3 100644 --- a/00_Alternate_Languages/28_Combat/MiniScript/README.md +++ b/00_Alternate_Languages/28_Combat/MiniScript/README.md @@ -7,10 +7,13 @@ 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 combat.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 "combat" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/29_Craps/MiniScript/README.md b/00_Alternate_Languages/29_Craps/MiniScript/README.md index 2ecf089f8..e500f4c36 100644 --- a/00_Alternate_Languages/29_Craps/MiniScript/README.md +++ b/00_Alternate_Languages/29_Craps/MiniScript/README.md @@ -7,10 +7,13 @@ 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 craps.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 "craps" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/30_Cube/MiniScript/README.md b/00_Alternate_Languages/30_Cube/MiniScript/README.md index cca8d49df..17eeb20b7 100644 --- a/00_Alternate_Languages/30_Cube/MiniScript/README.md +++ b/00_Alternate_Languages/30_Cube/MiniScript/README.md @@ -7,10 +7,13 @@ 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 cube.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 "cube" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md b/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md index d2603faed..0c20ea36f 100644 --- a/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md +++ b/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md @@ -7,10 +7,13 @@ 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 depthcharge.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 "depthcharge.ms" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/32_Diamond/MiniScript/README.md b/00_Alternate_Languages/32_Diamond/MiniScript/README.md index b8135184f..3a8249a0d 100644 --- a/00_Alternate_Languages/32_Diamond/MiniScript/README.md +++ b/00_Alternate_Languages/32_Diamond/MiniScript/README.md @@ -7,10 +7,13 @@ 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 diamond.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 "diamond" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/33_Dice/MiniScript/README.md b/00_Alternate_Languages/33_Dice/MiniScript/README.md index ab9361b3d..b670e30da 100644 --- a/00_Alternate_Languages/33_Dice/MiniScript/README.md +++ b/00_Alternate_Languages/33_Dice/MiniScript/README.md @@ -7,13 +7,15 @@ 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 dice.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 "dice" run - +``` 3. "Try-It!" page on the web: Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of dice.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/34_Digits/MiniScript/README.md b/00_Alternate_Languages/34_Digits/MiniScript/README.md index 6936703d8..280be246e 100644 --- a/00_Alternate_Languages/34_Digits/MiniScript/README.md +++ b/00_Alternate_Languages/34_Digits/MiniScript/README.md @@ -7,10 +7,13 @@ 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 digits.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 "digits" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md b/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md index f64a21f8e..d52819302 100644 --- a/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md +++ b/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md @@ -9,20 +9,25 @@ 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 evenwins.ms - +``` or +``` miniscript gameofevenwins.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 "evenwins" run - +``` or +``` load "gameofevenwins" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md b/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md index 15b428318..e012477dd 100644 --- a/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md +++ b/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md @@ -7,10 +7,13 @@ 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 flipflop.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 "flipflop" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/37_Football/MiniScript/README.md b/00_Alternate_Languages/37_Football/MiniScript/README.md index c1790a56e..4d8c33066 100644 --- a/00_Alternate_Languages/37_Football/MiniScript/README.md +++ b/00_Alternate_Languages/37_Football/MiniScript/README.md @@ -7,19 +7,23 @@ 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 football.ms -or +```or +``` miniscript ftball.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 "football" run -or +```or +``` load "ftball" run - +``` #### Apology from the Translator diff --git a/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md b/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md index a714f84ba..3b15b9926 100644 --- a/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md +++ b/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md @@ -7,10 +7,13 @@ 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 furtrader.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 "furtrader" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/39_Golf/MiniScript/README.md b/00_Alternate_Languages/39_Golf/MiniScript/README.md index 33e39a949..8a7e5325d 100644 --- a/00_Alternate_Languages/39_Golf/MiniScript/README.md +++ b/00_Alternate_Languages/39_Golf/MiniScript/README.md @@ -7,10 +7,13 @@ 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 golf.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 "golf" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/40_Gomoko/MiniScript/README.md b/00_Alternate_Languages/40_Gomoko/MiniScript/README.md index bfd37db82..5613d133a 100644 --- a/00_Alternate_Languages/40_Gomoko/MiniScript/README.md +++ b/00_Alternate_Languages/40_Gomoko/MiniScript/README.md @@ -7,10 +7,13 @@ 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 gomoko.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 "gomoko" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/41_Guess/MiniScript/README.md b/00_Alternate_Languages/41_Guess/MiniScript/README.md index 903e75d72..bf19c7599 100644 --- a/00_Alternate_Languages/41_Guess/MiniScript/README.md +++ b/00_Alternate_Languages/41_Guess/MiniScript/README.md @@ -7,13 +7,15 @@ 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 guess.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 "guess" run - +``` 3. "Try-It!" page on the web: Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of guess.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/42_Gunner/MiniScript/README.md b/00_Alternate_Languages/42_Gunner/MiniScript/README.md index 6f6a59142..323499176 100644 --- a/00_Alternate_Languages/42_Gunner/MiniScript/README.md +++ b/00_Alternate_Languages/42_Gunner/MiniScript/README.md @@ -7,10 +7,13 @@ 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 gunner.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 "gunner" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/43_Hammurabi/MiniScript/README.md b/00_Alternate_Languages/43_Hammurabi/MiniScript/README.md index 1d17e2b54..bb4411bbf 100644 --- a/00_Alternate_Languages/43_Hammurabi/MiniScript/README.md +++ b/00_Alternate_Languages/43_Hammurabi/MiniScript/README.md @@ -7,10 +7,13 @@ 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 hammurabi.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 "hammurabi" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/44_Hangman/MiniScript/README.md b/00_Alternate_Languages/44_Hangman/MiniScript/README.md index e5693849d..cf8b20021 100644 --- a/00_Alternate_Languages/44_Hangman/MiniScript/README.md +++ b/00_Alternate_Languages/44_Hangman/MiniScript/README.md @@ -7,10 +7,13 @@ 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 hangman.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 "hangman" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/45_Hello/MiniScript/README.md b/00_Alternate_Languages/45_Hello/MiniScript/README.md index c35f91c5d..c3e534cbf 100644 --- a/00_Alternate_Languages/45_Hello/MiniScript/README.md +++ b/00_Alternate_Languages/45_Hello/MiniScript/README.md @@ -7,10 +7,13 @@ 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 hello.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 "hello" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/46_Hexapawn/MiniScript/README.md b/00_Alternate_Languages/46_Hexapawn/MiniScript/README.md index f6406c0d9..e2cd714ad 100644 --- a/00_Alternate_Languages/46_Hexapawn/MiniScript/README.md +++ b/00_Alternate_Languages/46_Hexapawn/MiniScript/README.md @@ -7,10 +7,13 @@ 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 hexapawn.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 "hexapawn" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md b/00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md index 21af327dc..dc20e7c83 100644 --- a/00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md +++ b/00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md @@ -10,10 +10,13 @@ Go to https://miniscript.org/tryit/, clear the sample code from the code editor, 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 hi-lo.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 "hi-lo" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/48_High_IQ/MiniScript/README.md b/00_Alternate_Languages/48_High_IQ/MiniScript/README.md index 27d7baf8e..794d1c57f 100644 --- a/00_Alternate_Languages/48_High_IQ/MiniScript/README.md +++ b/00_Alternate_Languages/48_High_IQ/MiniScript/README.md @@ -7,10 +7,13 @@ 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 highiq.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 "highiq" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/49_Hockey/MiniScript/README.md b/00_Alternate_Languages/49_Hockey/MiniScript/README.md index d350aca2a..8c92997dc 100644 --- a/00_Alternate_Languages/49_Hockey/MiniScript/README.md +++ b/00_Alternate_Languages/49_Hockey/MiniScript/README.md @@ -7,10 +7,13 @@ 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 hockey.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 "hockey" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/50_Horserace/MiniScript/README.md b/00_Alternate_Languages/50_Horserace/MiniScript/README.md index c9a5cd1fd..8f5703a2c 100644 --- a/00_Alternate_Languages/50_Horserace/MiniScript/README.md +++ b/00_Alternate_Languages/50_Horserace/MiniScript/README.md @@ -7,14 +7,16 @@ 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 horserace.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 "horserace" run - +``` ## Porting Notes diff --git a/00_Alternate_Languages/51_Hurkle/MiniScript/README.md b/00_Alternate_Languages/51_Hurkle/MiniScript/README.md index 0f4ff6a61..2f774e452 100644 --- a/00_Alternate_Languages/51_Hurkle/MiniScript/README.md +++ b/00_Alternate_Languages/51_Hurkle/MiniScript/README.md @@ -10,10 +10,13 @@ Go to https://miniscript.org/tryit/, clear the sample code from the code editor, 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 hurkle.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 "hurkle" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/52_Kinema/MiniScript/README.md b/00_Alternate_Languages/52_Kinema/MiniScript/README.md index 68275b3b9..173e59ad5 100644 --- a/00_Alternate_Languages/52_Kinema/MiniScript/README.md +++ b/00_Alternate_Languages/52_Kinema/MiniScript/README.md @@ -7,13 +7,15 @@ 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 kinema.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 "kinema" run - +``` 3. "Try-It!" page on the web: Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of kinema.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/54_Letter/MiniScript/README.md b/00_Alternate_Languages/54_Letter/MiniScript/README.md index 705e34716..dfc5cf386 100644 --- a/00_Alternate_Languages/54_Letter/MiniScript/README.md +++ b/00_Alternate_Languages/54_Letter/MiniScript/README.md @@ -7,13 +7,15 @@ 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 letter.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 "letter" run - +``` 3. "Try-It!" page on the web: Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of letter.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md b/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md index 803c95000..5ea2cf130 100644 --- a/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md +++ b/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md @@ -7,13 +7,15 @@ 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 nicomachus.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 "nicomachus" run - +``` 3. "Try-It!" page on the web: Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of nicomachus.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/66_Number/MiniScript/README.md b/00_Alternate_Languages/66_Number/MiniScript/README.md index 769b1b46f..e3c8143ac 100644 --- a/00_Alternate_Languages/66_Number/MiniScript/README.md +++ b/00_Alternate_Languages/66_Number/MiniScript/README.md @@ -7,13 +7,15 @@ 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 number.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 "number" run - +``` 3. "Try-It!" page on the web: Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of number.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md b/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md index c2f0cb5df..a17e5cf14 100644 --- a/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md +++ b/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md @@ -7,10 +7,13 @@ 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 sinewave.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 "sinewave" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md b/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md index 817d92c03..2bcec68c8 100644 --- a/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md +++ b/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md @@ -7,10 +7,13 @@ 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 number.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 "number" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/91_Train/MiniScript/README.md b/00_Alternate_Languages/91_Train/MiniScript/README.md index 6a23b537a..a19701581 100644 --- a/00_Alternate_Languages/91_Train/MiniScript/README.md +++ b/00_Alternate_Languages/91_Train/MiniScript/README.md @@ -7,13 +7,15 @@ 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 train.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 "train" run - +``` 3. "Try-It!" page on the web: Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of train.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/92_Trap/MiniScript/README.md b/00_Alternate_Languages/92_Trap/MiniScript/README.md index ab1575695..521d3aff7 100644 --- a/00_Alternate_Languages/92_Trap/MiniScript/README.md +++ b/00_Alternate_Languages/92_Trap/MiniScript/README.md @@ -7,10 +7,13 @@ 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 trap.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 "trap" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/94_War/MiniScript/README.md b/00_Alternate_Languages/94_War/MiniScript/README.md index 439064b3d..0d964946f 100644 --- a/00_Alternate_Languages/94_War/MiniScript/README.md +++ b/00_Alternate_Languages/94_War/MiniScript/README.md @@ -7,10 +7,13 @@ 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 war.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 "war" run +``` \ No newline at end of file From e8688935bbe8ab7777484a08749e1eda1fcd2bbd Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 7 Sep 2023 12:49:54 -0700 Subject: [PATCH 230/377] Added MiniScript version of 53_King. Also updated the king_variable_update.bas with some additional variable tweaks for clarity. --- .../53_King/MiniScript/README.md | 19 + .../53_King/MiniScript/king.ms | 390 ++++++++++++++++++ .../53_King/king_variable_update.bas | 12 +- 53_King/king_variable_update.bas | 7 +- 4 files changed, 419 insertions(+), 9 deletions(-) create mode 100644 00_Alternate_Languages/53_King/MiniScript/README.md create mode 100644 00_Alternate_Languages/53_King/MiniScript/king.ms diff --git a/00_Alternate_Languages/53_King/MiniScript/README.md b/00_Alternate_Languages/53_King/MiniScript/README.md new file mode 100644 index 000000000..34818a09c --- /dev/null +++ b/00_Alternate_Languages/53_King/MiniScript/README.md @@ -0,0 +1,19 @@ +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 king.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 "king" + run +``` diff --git a/00_Alternate_Languages/53_King/MiniScript/king.ms b/00_Alternate_Languages/53_King/MiniScript/king.ms new file mode 100644 index 000000000..a4ba8f3d1 --- /dev/null +++ b/00_Alternate_Languages/53_King/MiniScript/king.ms @@ -0,0 +1,390 @@ +print " "*34 + "KING" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +yearsRequired = 8 + +zs = input("Do you want instructions? ").lower +if zs == "again" then + // ToDo: load previous state +else if not zs or zs[0] != "n" then + print; print; print + print "Congratulations! You've just been elected premier of Setats" + print "Detinu, a small communist island 30 by 70 miles long. Your" + print "job is to decide upon the contry's budget and distribute" + print "money to your countrymen from the communal treasury." + print "The money system is rallods, and each person needs 100" + print "rallods per year to survive. Your country's income comes" + print "from farm produce and tourists visiting your magnificent" + print "forests, hunting, fishing, etc. Half your land is farm land" + print "which also has an excellent mineral content and may be sold" + print "to foreign industry (strip mining) who import and support" + print "their own workers. Crops cost between 10 and 15 rallods per" + print "square mile to plant." + print "Your goal is to complete your " + yearsRequired + " year term of office." + print "Good luck!" +end if + +print + +rallods = floor(60000+(1000*rnd)-(1000*rnd)) +countrymen = floor(500+(10*rnd)-(10*rnd)) +landArea = 2000 +foreignWorkers = 0 +sellableLandExplained = false +tourism = 0 +year = 0 + +// Bonus little feature when running in Mini Micro: display a status bar with +// key game stats at the top of the screen. +updateStatusBar = function + if version.hostName != "Mini Micro" then return + display(2).mode = displayMode.text; td = display(2) + s = " Rallods: " + (rallods + " "*8)[:8] + s += " Land: " + (landArea + " "*6)[:6] + s += " Countrymen: " + (countrymen + " "*6)[:6] + s += " Foreigners: " + (foreignWorkers + " "*5)[:5] + td.color = color.black; td.backColor = text.color + td.row = 25; td.column = 0; td.print s +end function + +min0 = function(x) + if x < 0 then return 0 else return x +end function +floorMin0 = function(x) + return min0(floor(x)) +end function +stop = function + updateStatusBar + print; print; exit +end function + +while true + landPrice = floor(10*rnd+95) + plantingArea = 0 + pollutionControl = 0 + deaths = 0 + + print + print "You now have " + rallods + " rallods in the treasury." + print floor(countrymen) + " countrymen, ", "" + costToPlant = floor(((rnd/2)*10+10)) + if foreignWorkers != 0 then + print floor(foreignWorkers) + " foreign workers, ", "" + end if + print "and " + floor(landArea) + " sq. miles of land." + print "This year industry will buy land for " + landPrice, "" + print " rallods per square mile." + print "Land currently costs " + costToPlant + " rallods per square mile to plant." + print + + updateStatusBar + while true + sellToIndustry = input("How many square miles do you wish to sell to industry? ").val + if sellToIndustry < 0 then continue + if sellToIndustry <= landArea-1000 then break + print "*** Think again. You only have " + (landArea-1000) + " square miles of farm land." + if not sellableLandExplained then + print;print "(Foreign industry will only buy farm land because" + print "forest land is uneconomical to strip mine due to trees," + print "thicker top soil, etc.)" + sellableLandExplained = true + end if + end while + landArea = floor(landArea-sellToIndustry) + rallods = floor(rallods+(sellToIndustry*landPrice)) + + updateStatusBar + while true + welfare = input("How many rallods will you distribute among your countrymen? ").val + if welfare < 0 then continue + if welfare <= rallods then break + print " Think again. You've only " + rallods + " rallods in the treasury" + end while + rallods = floor(rallods-welfare) + + updateStatusBar + while rallods > 0 + plantingArea = input("How many square miles do you wish to plant? ").val + if plantingArea < 0 then continue + if plantingArea > countrymen*2 then + print " Sorry, but each countryman can only plant 2 sq. miles." + continue + end if + if plantingArea > landArea-1000 then + print " Sorry, but you've only " + (landArea-1000) + " sq. miles of farm land." + continue + end if + plantingCost = floor(plantingArea * costToPlant) + if plantingCost <= rallods then break + print " Think again. You've only " + rallods + " rallods left in the treasury." + end while + rallods -= plantingCost + + updateStatusBar + while rallods > 0 + pollutionControl = input("How many rallods do you wish to spend on pollution control? ").val + if pollutionControl < 0 then continue + if pollutionControl <= rallods then break + print " Think again. You only have " + rallods + " rallods remaining." + end while + + if sellToIndustry == 0 and welfare == 0 and plantingArea == 0 and pollutionControl == 0 then + print + print "Goodbye." + print "(If you wish to continue this game at a later date, answer" + print "'again' when asked if you want instructions at the start" + print "of the game.)" + exit + end if + + print + print + + rallods = floor(rallods-pollutionControl) + updateStatusBar + + original_rallods = rallods + + starvationDeaths = floorMin0(countrymen - welfare/100) + if starvationDeaths then + if welfare/100 < 50 then + print + print + print "Over one third of the popultation has died since you" + print "were elected to office. The people (remaining)" + print "hate your guts." + if rnd > .5 then + print "You have been thrown out of office and are now" + print "residing in prison." + else + print "You have been assassinated." + end if + countrymen -= starvationDeaths + stop + end if + print starvationDeaths + " countrymen died of starvation" + end if + + pollutionDeaths = floorMin0(rnd*(2000-landArea)) + if pollutionControl >= 25 then + pollutionDeaths = floor(pollutionDeaths/(pollutionControl/25)) + end if + if pollutionDeaths > 0 then + print pollutionDeaths + " countrymen died of carbon-monoxide and dust inhalation" + end if + + deaths = starvationDeaths + pollutionDeaths + if deaths then + print " You were forced to spend " + floor(deaths*9), "" + print " rallods on funeral expenses" + rallods -= deaths * 9 + end if + + if rallods < 0 then + print " Insufficient reserves to cover cost - land was sold" + landArea = floorMin0(landArea+(rallods/landPrice)) + rallods = 0 + end if + + countrymen = min0(countrymen - deaths) + + if sellToIndustry then + newForeigners = floor(sellToIndustry+(rnd*10)-(rnd*20)) + if foreignWorkers == 0 then newForeigners += 20 + foreignWorkers += newForeigners + print newForeigners + " workers came to the country and ", "" + end if + + immigration = floor(((welfare/100-countrymen)/10)+(pollutionControl/25)-((2000-landArea)/50)-(pollutionDeaths/2)) + print abs(immigration) + " countrymen ", "" + if immigration < 0 then print "came to", "" else print "left", "" + print " the island." + countrymen = floorMin0(countrymen + immigration) + + cropLoss = floor(((2000-landArea)*((rnd+1.5)/2))) + if cropLoss > plantingArea then cropLoss = plantingArea + if foreignWorkers > 0 then print "Of " + floor(plantingArea) + " sq. miles planted,", "" + print " you harvested " + floor(plantingArea-cropLoss) + " sq. miles of crops." + if cropLoss then + print " (Due to air and water pollution from foreign industry.)" + end if + agriculturalIncome = floor((plantingArea-cropLoss)*(landPrice/2)) + print "Making " + agriculturalIncome + " rallods." + rallods += agriculturalIncome + + v1 = floor(((countrymen-immigration)*22)+(rnd*500)) + v2 = floor((2000-landArea)*15) + prevTourism = tourism + tourism = abs(floor(v1-v2)) + print " You made " + tourism + " rallods from tourist trade." + if v2 > 2 and tourism < prevTourism then + print " Decrease because ", "" + g1 = 10*rnd + if g1 <= 2 then + print "fish population has dwindled due to water pollution." + else if g1 <= 4 then + print "air pollution is killing game bird population." + else if g1 <= 6 then + print "mineral baths are being ruined by water pollution." + else if g1 <= 8 then + print "unpleasant smog is discouraging sun bathers." + else + print "hotels are looking shabby due to smog grit." + end if + end if + rallods += tourism + updateStatusBar + + if deaths > 200 then + print + print + print deaths + "countrymen died in one year!!!!!" + print "due to this extreme mismanagement, you have not only" + print "been impeached and thrown out of office, but you" + m6 = floor(rnd*10) + if m6 <= 3 then 1670 + if m6 <= 6 then 1680 + if m6 <= 10 then 1690 + print "also had your left eye gouged out!" + goto 1590 + print "have also gained a very bad reputation." + goto 1590 + print "have also been declared national fink." + stop + else if countrymen < 343 then + print + print + print "Over one third of the popultation has died since you" + print "were elected to office. The people (remaining)" + print "hate your guts." + if rnd > .5 then + print "You have been thrown out of office and are now" + print "residing in prison." + else + print "You have been assassinated." + end if + stop + else if (original_rallods/100) > 5 and deaths - pollutionDeaths >= 2 then + print + print "Money was left over in the treasury which you did" + print "not spend. As a result, some of your countrymen died" + print "of starvation. The public is enraged and you have" + print "been forced to either resign or commit suicide." + print "The choice is yours." + print "If you choose the latter, please turn off your computer" + print "before proceeding." + stop + else if foreignWorkers > countrymen then + print + print + print "The number of foreign workers has exceeded the number" + print "of countrymen. As a minority, they have revolted and" + print "taken over the country." + if rnd > .5 then + print "You have been thrown out of office and are now" + print "residing in prison." + else + print "You have been assassinated." + end if + stop + else if year == yearsRequired-1 then + print + print + print "Congratulations!!!!!!!!!!!!!!!!!!" + print "You have succesfully completed your " + yearsRequired + " year term" + print "of office. You were, of course, extremely lucky, but" + print "nevertheless, it's quite an achievement. Goodbye and good" + print "luck - you'll probably need it if you're the type that" + print "plays this game." + stop + end if + + updateStatusBar + wait + year += 1 +end while + +//print +//print +//print "the number of foreign workers has exceeded the number" +//print "of countrymen. as a minority, they have revolted and" +//print "taken over the country." +//if rnd<=.5 then 1580 +//print "you have been thrown out of office and are now" +//print "residing in prison." +//goto 1590 +//print "you have been assassinated." +//print +//print +//exit +//print +//print +//print deaths + "countrymen died in one year!!!!!" +//print "due to this extreme mismanagement, you have not only" +//print "been impeached and thrown out of office, but you" +//m6 = floor(rnd*10) +//if m6 <= 3 then 1670 +//if m6 <= 6 then 1680 +//if m6 <= 10 then 1690 +//print "also had your left eye gouged out!" +//goto 1590 +//print "have also gained a very bad reputation." +//goto 1590 +//print "have also been declared national fink." +//goto 1590 +// +//print +//print +//print "over one third of the popultation has died since you" +//print "were elected to office. the people (remaining)" +//print "hate your guts." +//goto 1570 +//if deaths-pollutionDeaths < 2 then 1515 +//print +//print "money was left over in the treasury which you did" +//print "not spend. as a result, some of your countrymen died" +//print "of starvation. the public is enraged and you have" +//print "been forced to either resign or commit suicide." +//print "the choice is yours." +//print "if you choose the latter, please turn off your computer" +//print "before proceeding." +//goto 1590 +//print +//print +//print "congratulations!!!!!!!!!!!!!!!!!!" +//print "you have succesfully completed your" + yearsRequired + "year term" +//print "of office. you were, of course, extremely lucky, but" +//print "nevertheless, it's quite an achievement. goodbye and good" +//print "luck - you'll probably need it if you're the type that" +//print "plays this game." +//goto 1590 +// +//print "how many years had you been in office when interrupted"; +//input year +//if year < 0 then 1590 +//if year < 8 then 1969 +//print " come on, your term in office is only" + yearsRequired + "years." +//goto 1960 +//print "how much did you have in the treasury"; +//input rallods +//if rallods < 0 then 1590 +//print "how many countrymen"; +//input countrymen +//if countrymen < 0 then 1590 +//print "how many workers"; +//input foreignWorkers +//if foreignWorkers < 0 then 1590 +//print "how many square miles of land"; +//input landArea +//if landArea < 0 then 1590 +//if landArea > 2000 then 1996 +//if landArea > 1000 then 100 +//print " come on, you started with 1000 sq. miles of farm land" +//print " and 10,000 sq. miles of forest land." +//goto 1990 +// +//year = year+1 +//deaths = 0 +//goto 100 +//end diff --git a/00_Alternate_Languages/53_King/king_variable_update.bas b/00_Alternate_Languages/53_King/king_variable_update.bas index 7f88e1014..86c3828c3 100644 --- a/00_Alternate_Languages/53_King/king_variable_update.bas +++ b/00_Alternate_Languages/53_King/king_variable_update.bas @@ -8,7 +8,7 @@ 11 IF Z$="AGAIN" THEN 1960 12 PRINT:PRINT:PRINT 20 PRINT "CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS" - 22 PRINT "DETINU, RALLODS SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR" + 22 PRINT "DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR" 24 PRINT "JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE" 26 PRINT "MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY." 28 PRINT "THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100" @@ -219,7 +219,7 @@ REM I think tourism calculations are actually wrong in the original code! 1505 IF COUNTRYMEN<343 THEN 1700 1510 IF (ORIGINAL_RALLODS/100)>5 THEN 1800 1515 IF FOREIGN_WORKERS>COUNTRYMEN THEN 1550 -1520 IF YEARS_REQUIRED-1=X5 THEN 1900 +1520 IF YEARS_REQUIRED-1=YEAR THEN 1900 1545 GOTO 2000 1550 PRINT 1552 PRINT @@ -277,9 +277,9 @@ REM I think tourism calculations are actually wrong in the original code! 1950 GOTO 1590 1960 PRINT "HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED"; -1961 INPUT X5 -1962 IF X5<0 THEN 1590 -1963 IF X5<8 THEN 1969 +1961 INPUT YEAR +1962 IF YEAR<0 THEN 1590 +1963 IF YEAR<8 THEN 1969 1965 PRINT " COME ON, YOUR TERM IN OFFICE IS ONLY";YEARS_REQUIRED;"YEARS." 1967 GOTO 1960 1969 PRINT "HOW MUCH DID YOU HAVE IN THE TREASURY"; @@ -300,7 +300,7 @@ REM I think tourism calculations are actually wrong in the original code! 1997 PRINT " AND 10,000 SQ. MILES OF FOREST LAND." 1998 GOTO 1990 -2000 X5=X5+1 +2000 YEAR=YEAR+1 2020 DEATHS=0 2040 GOTO 100 2046 END diff --git a/53_King/king_variable_update.bas b/53_King/king_variable_update.bas index 7f88e1014..0ae19de45 100644 --- a/53_King/king_variable_update.bas +++ b/53_King/king_variable_update.bas @@ -8,7 +8,7 @@ 11 IF Z$="AGAIN" THEN 1960 12 PRINT:PRINT:PRINT 20 PRINT "CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS" - 22 PRINT "DETINU, RALLODS SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR" + 22 PRINT "DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR" 24 PRINT "JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE" 26 PRINT "MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY." 28 PRINT "THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100" @@ -66,7 +66,8 @@ 380 PLANTING_AREA=0 390 MONEY_SPENT_ON_POLLUTION_CONTROL=0 395 RALLODS=0 -399 GOTO 1000 +399 GOTO 600 + 400 RALLODS=INT(RALLODS-WELFARE) 410 PRINT "HOW MANY SQUARE MILES DO YOU WISH TO PLANT"; @@ -88,7 +89,7 @@ 490 MONEY_SPENT_ON_POLLUTION_CONTROL=0 495 RALLODS=0 -499 GOTO 1000 +499 GOTO 600 500 RALLODS=RALLODS-MONEY_SPENT_ON_PLANTING From d16e1fd213a4e8820d94c19ae9c026a23c0bb61d Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 7 Sep 2023 13:05:03 -0700 Subject: [PATCH 231/377] Finished 53_King program with "resume game" feature. --- .../53_King/MiniScript/king.ms | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/00_Alternate_Languages/53_King/MiniScript/king.ms b/00_Alternate_Languages/53_King/MiniScript/king.ms index a4ba8f3d1..8d4f106c9 100644 --- a/00_Alternate_Languages/53_King/MiniScript/king.ms +++ b/00_Alternate_Languages/53_King/MiniScript/king.ms @@ -3,10 +3,30 @@ print " "*15 + "Creative Computing Morristown, New Jersey" print; print; print yearsRequired = 8 +rallods = floor(60000+(1000*rnd)-(1000*rnd)) +countrymen = floor(500+(10*rnd)-(10*rnd)) +landArea = 2000 +foreignWorkers = 0 +sellableLandExplained = false +tourism = 0 +year = 0 zs = input("Do you want instructions? ").lower if zs == "again" then - // ToDo: load previous state + while true + year = input("How many years had you been in office when interrupted? ").val + if 0 <= year < yearsRequired then break + print " Come on, your term in office is only " + yearsRequired + " years." + end while + rallods = input("How much did you have in the treasury? ").val + countrymen = input("How many countrymen? ").val + foreignWorkers = input("How many foreign workers? ").val + while true + landArea = input("How many square miles of land? ").val + if 1000 <= landArea <= 2000 then break + print " Come on, you started with 1000 sq. miles of farm land" + print " and 1000 sq. miles of forest land." + end while else if not zs or zs[0] != "n" then print; print; print print "Congratulations! You've just been elected premier of Setats" @@ -27,13 +47,6 @@ end if print -rallods = floor(60000+(1000*rnd)-(1000*rnd)) -countrymen = floor(500+(10*rnd)-(10*rnd)) -landArea = 2000 -foreignWorkers = 0 -sellableLandExplained = false -tourism = 0 -year = 0 // Bonus little feature when running in Mini Micro: display a status bar with // key game stats at the top of the screen. From 8fe02cc22ddce4b9ba8f4f68035ddbbb2b0a0d0c Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Fri, 8 Sep 2023 08:12:57 -0700 Subject: [PATCH 232/377] Added MiniScript version of 55_Life. --- 55_Life/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/55_Life/README.md b/55_Life/README.md index 1834c1e68..195bd7956 100644 --- a/55_Life/README.md +++ b/55_Life/README.md @@ -37,4 +37,11 @@ http://www.vintage-basic.net/games.html #### Porting Notes +- To make sense of the code, it's important to understand what the values in the A(X,Y) array mean: + - 0: dead cell + - 1: live cell + - 2: currently live, but dead next cycle + - 3: currently dead, but alive next cycle + + (please note any difficulties or challenges in porting here) From 7753f6bf132c9b855cc7be17824e47ebef1f1e0c Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sun, 10 Sep 2023 15:33:30 -0700 Subject: [PATCH 233/377] Added MiniScript versions of 55_Life and 56_Life_for_Two. --- .../55_Life/MiniScript/README.md | 19 +++ .../55_Life/MiniScript/life.ms | 132 ++++++++++++++++++ .../56_Life_for_Two/MiniScript/README.md | 19 +++ .../56_Life_for_Two/MiniScript/lifefortwo.ms | 129 +++++++++++++++++ 56_Life_for_Two/README.md | 3 +- 5 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/55_Life/MiniScript/README.md create mode 100644 00_Alternate_Languages/55_Life/MiniScript/life.ms create mode 100644 00_Alternate_Languages/56_Life_for_Two/MiniScript/README.md create mode 100644 00_Alternate_Languages/56_Life_for_Two/MiniScript/lifefortwo.ms diff --git a/00_Alternate_Languages/55_Life/MiniScript/README.md b/00_Alternate_Languages/55_Life/MiniScript/README.md new file mode 100644 index 000000000..4cfd557b0 --- /dev/null +++ b/00_Alternate_Languages/55_Life/MiniScript/README.md @@ -0,0 +1,19 @@ +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 life.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 "life" + run +``` diff --git a/00_Alternate_Languages/55_Life/MiniScript/life.ms b/00_Alternate_Languages/55_Life/MiniScript/life.ms new file mode 100644 index 000000000..69f3bafc1 --- /dev/null +++ b/00_Alternate_Languages/55_Life/MiniScript/life.ms @@ -0,0 +1,132 @@ +print " "*34 + "LIFE" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +import "listUtil" // (needed for list.init2d) + +maxx = 66 // (size adjusted for Mini Micro display) +maxy = 23 +A = list.init2d(maxx+1, maxy+1, 0) + +// Stuff the given pattern into the center of the cell array. +// Return the number of live cells. +stuffIntoCenter = function(pattern) + maxLen = 0 + for p in pattern + if p.len > maxLen then maxLen = p.len + end for + + population = 0 + y = floor(maxy/2 - pattern.len/2) + for row in pattern + x = floor(maxx/2 - maxLen/2) + for c in row + if c != " " then + A[x][y] = 1 + population += 1 + end if + x += 1 + end for + y += 1 + end for + return population +end function + +// Get the initial pattern from the user +initToUserPattern = function + print "Enter your pattern (enter DONE when done):" + userPattern = [] + while true + p = input("?") + if p.upper == "DONE" then break + if p and p[0] == "." then p = " " + p[1:] + userPattern.push p + end while + return stuffIntoCenter(userPattern) +end function + +// For testing purposes, skip asking the user and just use a hard-coded pattern. +initToStandardPattern = function + pattern = [ + " **", + " * *", + " *"] + return stuffIntoCenter(pattern) +end function + +// Or, just for fun, initialize to a random pattern of junk in the center. +initRandom = function + for x in range(ceil(maxx*0.3), floor(maxx*0.7)) + for y in range(ceil(maxy*0.3), floor(maxy*0.7)) + A[x][y] = rnd > 0.5 + end for + end for +end function + +// Define a function to draw the current game state. +// This also changes 2 (dying) to 0 (dead), and 3 (being born) to 1 (alive). +drawGameState = function(generation=0, population=0, invalid=false) + if version.hostName == "Mini Micro" then text.row = 26 else print + print "Generation: " + generation + " Population: " + population + + " " + "INVALID!" * invalid + for y in range(0, maxy) + s = "" + for x in range(0, maxx) + if A[x][y] == 2 then + A[x][y] = 0 + else if A[x][y] == 3 then + A[x][y] = 1 + end if + if A[x][y] then s += "*" else s += " " + end for + print s + end for +end function + +// Update the game state, setting cells that should be born to 3 and +// cells that should die to 2. Return the number of cells that will +// be alive after this update. Also, set globals.invalid if any live +// cells are found on the edge of the map. +updateGameState = function + population = 0 + for x in range(0, maxx) + for y in range(0, maxy) + c = A[x][y] == 1 or A[x][y] == 2 // center state + n = -c // number of neighbors + for nx in range(x-1, x+1) + if nx < 0 or nx > maxx then continue + for ny in range(y-1, y+1) + if ny < 0 or ny > maxy then continue + n += A[nx][ny] == 1 or A[nx][ny] == 2 + end for + end for + if c and n != 2 and n != 3 then // live cell with < 2 or > 3 neighbors... + A[x][y] = 2 // dies + else if not c and n == 3 then // dead cell with 3 neighbors... + A[x][y] = 3 // comes to life + if x == 0 or x == maxx or y == 0 or y == maxy then + globals.invalid = true + end if + end if + population += (A[x][y] == 1 or A[x][y] == 3) + end for + end for + return population +end function + + +// Initialize the game state (uncomment one of the following three lines) +population = initToUserPattern +//population = initToStandardPattern +//population = initRandom + +// Main loop +if version.hostName == "Mini Micro" then clear +invalid = false +generation = 0 +while population > 0 + drawGameState generation, population, invalid + population = updateGameState + generation += 1 + //key.get // <-- Uncomment this to single-step with each keypress! +end while +drawGameState generation, population, invalid diff --git a/00_Alternate_Languages/56_Life_for_Two/MiniScript/README.md b/00_Alternate_Languages/56_Life_for_Two/MiniScript/README.md new file mode 100644 index 000000000..93b25b999 --- /dev/null +++ b/00_Alternate_Languages/56_Life_for_Two/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). The only liberty I took with the original design is that, when prompting each player for their turn, I include a reminder of what symbol (* or #) represents their pieces on the board. + +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 lifefortwo.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 "lifefortwo" + run +``` diff --git a/00_Alternate_Languages/56_Life_for_Two/MiniScript/lifefortwo.ms b/00_Alternate_Languages/56_Life_for_Two/MiniScript/lifefortwo.ms new file mode 100644 index 000000000..49ac531ed --- /dev/null +++ b/00_Alternate_Languages/56_Life_for_Two/MiniScript/lifefortwo.ms @@ -0,0 +1,129 @@ +print " "*33 + "LIFE2" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print " "*10 + "U.B. LIFE GAME" + +// N: counts neighbors and game state, as follows: +// 1's digit: player 1 neighbors +// 10's digit: player 2 neighbors +// 100's digit: player 1 current live cell +// 1000's digit: player 2 current live cell +N = [] +for i in range(0,6); N.push [0]*7; end for + +// K: encodes the rule for what cells come to life, based on +// the value in N. The first 9 entries mean new life for Player 1; +// the second 9 entries mean new life for Player 2. +K = [3,102,103,120,130,121,112,111,12, + 21,30,1020,1030,1011,1021,1003,1002,1012] + +// population: how many live cells each player (1-2) has +population = [null, 0, 0] + +// Function to get input coordinates from the player, for any empty space. +// Where possible, hide the input so the other player can't see it. +getCoords = function + while true + print "X,Y" + inp = input.replace(",", " ").replace(" "," ") + if version.hostName == "Mini Micro" then + text.row = text.row + 1; print " "*60 + end if + parts = inp.split + if parts.len == 2 then + x = parts[0].val + y = parts[1].val + if 0 < x <= 5 and 0 < y <= 5 and N[x][y] == 0 then break + end if + print "Illegal coords. Retype" + end while + return [x, y] +end function + +// Function to print the board. At the same time, it replaces +// any player 1 value (as judged by list K) with 100, and any +// player 2 value with 1000. Also update population[] with the +// number of pieces of each player. +printBoard = function + population[1] = 0 + population[2] = 0 + for y in range(0, 6) + if y == 0 or y == 6 then + print " 0 1 2 3 4 5 0" + else + print " " + y, " " + for x in range(1, 5) + kIndex = K.indexOf(N[x][y]) + if kIndex == null then + print " ", " " + N[x][y] = 0 + else if kIndex < 9 then + print "*", " " + N[x][y] = 100 + population[1] += 1 + else + print "#", " " + N[x][y] = 1000 + population[2] += 1 + end if + end for + print y + end if + end for + print +end function + +// Function to update the board (N). +updateBoard = function + for j in range(1,5) + for k in range(1,5) + if N[j][k] < 100 then continue // not a live cell + if N[j][k] > 999 then value = 10 else value = 1 + for x in range(j-1, j+1) + for y in range(k-1, k+1) + if x == j and y == k then continue + N[x][y] += value + //if [x,y] == [2,1] then print "adding " + value + " from " + j+","+k + " to " + x+","+y + ", --> " + N[x][y] + end for + end for + end for + end for +end function + + +// Get initial player positions. +for player in [1,2] + print; print "Player " + player + " - 3 live pieces." + if player == 2 then value = 30 else value = 3 + for k in range(1,3) + pos = getCoords + N[pos[0]][pos[1]] = value + end for +end for + +printBoard +while true + updateBoard + printBoard + if population[1] == 0 and population[2] == 0 then + print "A DRAW" + break + else if population[1] == 0 then + print "PLAYER 2 IS THE WINNER" + break + else if population[2] == 0 then + print "PLAYER 1 IS THE WINNER" + break + end if + + print; print "Player 1 (*)" + p1pos = getCoords + print; print "Player 2 (#)" + p2pos = getCoords + if p1pos == p2pos then + print "Same coord. Set to 0" + else + N[p1pos[0]][p1pos[1]] = 100 + N[p2pos[0]][p2pos[1]] = 1000 + end if +end while \ No newline at end of file diff --git a/56_Life_for_Two/README.md b/56_Life_for_Two/README.md index e68c8d64a..5ce081d37 100644 --- a/56_Life_for_Two/README.md +++ b/56_Life_for_Two/README.md @@ -26,7 +26,7 @@ A new cell will be generated at (3,3) which will be a `#` since there are two `# | 4 | | | | | | | 5 | | | | | | ``` -On the first most each player positions 3 pieces of life on the board by typing in the co-ordinates of the pieces. (In the event of the same cell being chosen by both players that cell is left empty.) +On the first move each player positions 3 pieces of life on the board by typing in the co-ordinates of the pieces. (In the event of the same cell being chosen by both players that cell is left empty.) The board is then adjusted to the next generation and printed out. @@ -45,6 +45,7 @@ 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) From f62b9864bcfe37d0aa7288cd048100d5c60ee191 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sun, 10 Sep 2023 15:45:05 -0700 Subject: [PATCH 234/377] Added MiniScript version of 57_Literature_Quiz. --- .../57_Literature_Quiz/MiniScript/README.md | 22 +++++++ .../57_Literature_Quiz/MiniScript/litquiz.ms | 66 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 00_Alternate_Languages/57_Literature_Quiz/MiniScript/README.md create mode 100644 00_Alternate_Languages/57_Literature_Quiz/MiniScript/litquiz.ms diff --git a/00_Alternate_Languages/57_Literature_Quiz/MiniScript/README.md b/00_Alternate_Languages/57_Literature_Quiz/MiniScript/README.md new file mode 100644 index 000000000..e3f12eb47 --- /dev/null +++ b/00_Alternate_Languages/57_Literature_Quiz/MiniScript/README.md @@ -0,0 +1,22 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of litquiz.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 litquiz.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 "litquiz" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/57_Literature_Quiz/MiniScript/litquiz.ms b/00_Alternate_Languages/57_Literature_Quiz/MiniScript/litquiz.ms new file mode 100644 index 000000000..e465cc6bb --- /dev/null +++ b/00_Alternate_Languages/57_Literature_Quiz/MiniScript/litquiz.ms @@ -0,0 +1,66 @@ +print " "*24 + "Literature Quiz" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +r=0 +print "Test your knowledge of children's literature." +print; print "This is a multiple-choice quiz." +print "Type a 1, 2, 3, or 4 after the question mark." +print; print "Good luck!"; + +print; print +print "In pinocchio, what was the name of the cat?" +print "1)Tigger, 2)Cicero, 3)Figaro, 4)Fuipetto"; +a = input("?").val +if a!=3 then + print "Sorry...Figaro was his name." +else + print "Very good! Here's another." + r += 1 +end if + +print; print +print "From whose garden did Bugs Bunny steal the carrots?" +print "1)Mr. Nixon's, 2)Elmer Fudd's, 3)Clem Judd's, 4)Stromboli's"; +a = input("?").val +if a != 2 then + print "Too bad...it was elmer fudd's garden." +else + print "Pretty good!" + r += 1 +end if + +print; print +print "In the Wizard of Oz, Dorothy's dog was named" +print "1)Cicero, 2)Trixia, 3)King, 4)Toto"; +a = input("?").val +if a != 4 then + print "Back to the books,...Toto was his name." +else + print "Yea! You're a real literature giant." + r += 1 +end if + +print;print +print "Who was the fair maiden who ate the poison apple?" +print "1)Sleeping Beauty, 2)Cinderella, 3)Snow White, 4)Wendy"; +a = input("?").val +if a != 3 then + print "Oh, come on now...it was Snow White." +else + print "Good memory!" + r += 1 +end if + +print;print +if r == 4 then + print "Wow! That's super! You really know your nursery" + print "Your next quiz will be on 2nd century Chinese" + print "literature (ha, ha, ha)" +else if r<2 then + print "Ugh. That was definitely not too swift. Back to" + print "nursery school for you, my friend." +else + print "Not bad, but you might spend a little more time" + print "reading the nursery greats." +end if From 81ed4f3f1e9f8e069a39bbbef9909e269beeeb93 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sun, 10 Sep 2023 16:05:13 -0700 Subject: [PATCH 235/377] Added MiniScript version of 58_Love. --- .../58_Love/MiniScript/README.md | 22 ++++++++++ .../58_Love/MiniScript/love.ms | 41 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 00_Alternate_Languages/58_Love/MiniScript/README.md create mode 100644 00_Alternate_Languages/58_Love/MiniScript/love.ms diff --git a/00_Alternate_Languages/58_Love/MiniScript/README.md b/00_Alternate_Languages/58_Love/MiniScript/README.md new file mode 100644 index 000000000..1186963df --- /dev/null +++ b/00_Alternate_Languages/58_Love/MiniScript/README.md @@ -0,0 +1,22 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of love.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 love.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 "love" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/58_Love/MiniScript/love.ms b/00_Alternate_Languages/58_Love/MiniScript/love.ms new file mode 100644 index 000000000..64693f127 --- /dev/null +++ b/00_Alternate_Languages/58_Love/MiniScript/love.ms @@ -0,0 +1,41 @@ +print " "*33 + "LOVE" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +print "A tribute to the great american artist, Robert Indiana." +print "His greatest work will be reproduced with a message of" +print "your choice up to 60 characters. If you can't think of" +print "a message, simple type the word 'LOVE'"; print +msg = input("Your message, please? ") +for i in range(1, 10); print; end for + +repeatedMsg = msg * ceil(60 / msg.len) + +data = [] +data += [60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5] +data += [4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4] +data += [4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4] +data += [4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4] +data += [4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8] +data += [1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1] +data += [5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1] +data += [6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10] +data += [7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10] +data += [8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1] +data += [9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1] +data += [11,8,13,27,1,11,8,13,27,1,60] + +for row in range(0, 35) + s = [] + a1 = 0; p = true + while a1 < 60 + a = data.pull + a1 += a + for i in range(a1-a, a1-1) + s.push repeatedMsg[i] * p + " " * (not p) + end for + p = not p + end while + print s.join("") + wait 0.1 // OPTIONAL; slows printing down so you can see it all +end for From ae81f67e2d5330128be207053bff1e6811dae0e4 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 11 Sep 2023 09:32:32 -0700 Subject: [PATCH 236/377] Added MiniScript version of 59_Lunar_LEM_Rocket, "lem" program. (Still need to do the other two in this folder.) --- .../59_Lunar_LEM_Rocket/MiniScript/README.md | 19 + .../59_Lunar_LEM_Rocket/MiniScript/lem.ms | 324 ++++++++++++++++++ 59_Lunar_LEM_Rocket/README.md | 9 + 3 files changed, 352 insertions(+) create mode 100644 00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/README.md create mode 100644 00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lem.ms diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/README.md new file mode 100644 index 000000000..6ba18136c --- /dev/null +++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/README.md @@ -0,0 +1,19 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). Note that there are three different programs in this folder, all variations on the "land the LEM on the Moon" idea. + +Ways to play: + +1. Command-Line MiniScript: +Download for your system from https://miniscript.org/cmdline/, install, and then run the desired program with a command such as: + +``` + miniscript lem.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 "lem" // (or "lunar" or "rocket") + run +``` diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lem.ms b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lem.ms new file mode 100644 index 000000000..92a263e26 --- /dev/null +++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lem.ms @@ -0,0 +1,324 @@ +print " "*34 + "LEM" +print " "*15 + "Creative Computing Morristown, New Jersey" +// rockt2 is an interactive game that simulates a lunar +// landing is similar to that of the apollo program. +// There is absolutely no chance involved + + +printIntro = function + print + print " You are on a lunar landing mission. as the pilot of" + print "the lunar excursion module, you will be expected to" + print "give certain commands to the module navigation system." + print "The on-board computer will give a running account" + print "of information needed to navigate the ship." + print + input "(Press Return.)" + print + print "The attitude angle called for is described as follows." + print "+ or -180 degrees is directly away from the moon" + print "-90 degrees is on a tangent in the direction of orbit" + print "+90 degrees is on a tangent from the direction of orbit" + print "0 (zero) degrees is directly toward the moon" + print + print " "*30 + "-180|+180" + print " "*34 + "^" + print " "*27 + "-90 < -+- > +90" + print " "*34 + "!" + print " "*34 + "0" + print " "*21 + "<<<< direction of orbit <<<<" + print + print " "*20 + "------ surface of moon ------" + print + input + print + print "All angles between -180 and +180 degrees are accepted." + print + print "1 fuel unit = 1 sec. at max thrust" + print "Any discrepancies are accounted for in the use of fuel" + print "for an attitude change." + print "Available engine power: 0 (zero) and any value between" + print "10 and 100 percent." + print + print "Negative thrust or time is prohibited." + print + input +end function + +printInOutInfo = function(withExample = true) + print + print "Input: time interval in seconds ------ (T)" + print " percentage of thrust ---------- (P)" + print " attitude angle in degrees ----- (A)" + print + if withExample then + print "For example:" + print "T,P,A? 10,65,-60" + print "To abort the mission at any time, enter 0,0,0" + print + end if + print "Output: total time in elapsed seconds" + print " height in " + ms + print " distance from landing site in " + ms + print " vertical velocity in " + ms + "/second" + print " horizontal velocity in " + ms + "/second" + print " fuel units remaining" + print +end function + +initState = function + globals.m = 17.95 + globals.f1 = 5.25 + globals.n = 7.5 + globals.r0 = 926 + globals.v0 = 1.29 + globals.t = 0 + globals.h0 = 60 + globals.r = r0+h0 + globals.a = -3.425 + globals.r1 = 0 + globals.a1 = 8.84361e-04 + globals.r3 = 0 + globals.a3 = 0 + globals.m1 = 7.45 + globals.m0 = m1 + globals.b = 750 + globals.t1 = 0 + globals.f = 0 + globals.p = 0 + globals.n = 1 + globals.m2 = 0 + globals.s = 0 + globals.c = 0 +end function + +getUnits = function(moreHelp=true) + print + while true + print "Input measurement option number? ", "" + if moreHelp then + print + print "Which system of measurement do you prefer?" + print " 1 = metric 0 = english" + print "Enter the appropriate number? ", "" + end if + k = input.val + if k == 0 then + globals.z = 6080 + globals.ms = "feet" + globals.g3 = .592 + globals.ns = "n.miles" + globals.g5 = z + break + else if k == 1 then + globals.z = 1852.8 + globals.ms="meters" + globals.g3 = 3.6 + globals.ns=" kilometers" + globals.g5 = 1000 + break + end if + moreHelp = true + end while +end function + +startFirstGame = function + initState + print + print "Lunar Landing Simulation" + print + print "Have you flown an Apollo/LEM mission before", "" + while true + qs = input(" (yes or no)? ").lower + if qs and (qs[0] == "y" or qs[0] == "n") then break + print "Just answer the question, please, ", "" + end while + getUnits (qs[0] == "n") + if qs[0] == "n" then printIntro + printInOutInfo +end function + +startSubsequentGame = function + initState + print + print "OK, do you want the complete instructions or the input -" + print "output statements?" + while true + print "1 = complete instructions" + print "2 = input-output statements" + print "3 = neither" + b1 = input.val + if 1 <= b1 <= 3 then break + end while + if b1 == 1 then printIntro + if b1 < 3 then printInOutInfo +end function + +getTurnInputs = function + while true + print + inp = input("T,P,A? ").replace(",", " ").replace(" ", " ").split + if inp.len != 3 then continue + globals.t1 = inp[0].val // NOTE: though we prompt for T, P, A, + globals.f = inp[1].val // internally these are t1, f, and p respectively. + globals.p = inp[2].val + globals.f = f/100 + if t1 < 0 then + print + print "This spacecraft is not able to violate the space-"; + print "time continuum." + continue + else if t1 == 0 then + return // abort mission + end if + if f < 0 or f > 1.05 or abs(f-.05) < .05 then + print + print "Impossible thrust value: ", "" + if f < 0 then + print "negative" + else if f < 0.5 then + print "too small" + else + print "too large" + end if + continue + end if + if abs(p) > 180 then + print + print "If you want to spin around, go outside the module" + print "for an E.V.A." + continue + end if + return + end while +end function + +pad = function(num, width=10) + anum = abs(num) + if anum >= 10000 then + s = round(num) + else if anum >= 10000 then + s = round(num, 1) + else if anum > 100 then + s = round(num, 2) + else + s = round(num, 3) + end if + return (s + " " * width)[:width] +end function + +integrate = function + n = 20 + if t1 >= 400 then n = t1/20 + globals.t1 = t1/n + globals.p = p*3.14159/180 + s = sin(p) + c = cos(p) + globals.m2 = m0*t1*f/b + globals.r3 = -.5*r0*((v0/r)^2)+r*a1*a1 + globals.a3 = -2*r1*a1/r + + for i in range(1, n) + if m1 != 0 then + globals.m1 = m1-m2 + if m1<=0 then + globals.f = f*(1+m1/m2) + globals.m2 = m1+m2 + print "You are out of fuel." + globals.m1 = 0 + end if + else + globals.f = 0 + globals.m2 = 0 + end if + globals.m = m-.5*m2 + globals.r4 = r3 + globals.r3 = -.5*r0*((v0/r)^2)+r*a1*a1 + globals.r2 = (3*r3-r4)/2+.00526*f1*f*c/m + globals.a4 = a3 + globals.a3 = -2*r1*a1/r + globals.a2 = (3*a3-a4)/2+.0056*f1*f*s/(m*r) + globals.x = r1*t1+.5*r2*t1*t1 + globals.r = r+x + globals.h0 = h0+x + globals.r1 = r1+r2*t1 + globals.a = a+a1*t1+.5*a2*t1*t1 + globals.a1 = a1+a2*t1 + globals.m = m-.5*m2 + globals.t = t+t1 + if h0<3.287828e-04 then break + end for + + globals.h = h0*z + globals.h1 = r1*z + globals.d = r0*a*z + globals.d1 = r*a1*z + globals.t2 = m1*b/m0 + + print " " + [pad(t, 10), pad(h, 10), pad(d, 10), pad(h1, 10), pad(d1, 10), pad(t2, 10)].join +end function + +// Do one turn of the game. Return true if game still in progress, +// or false when game is over (aborted, crashed, or landed). +doOneTurn = function + if m1 == 0 then + // out of fuel! + globals.t1 = 20 + globals.f = 0 + globals.p = 0 + else + getTurnInputs + end if + if t1 == 0 then + print "Mission abended" + return false + end if + integrate + + if h0 < 3.287828e-04 then + if r1 < -8.21957e-04 or abs(r*a1) > 4.93174e-04 or h0 < -3.287828e-04 then + print + print "Crash !!!!!!!!!!!!!!!!" + print "Your impact created a crater " + abs(h) + " " + ms + " deep." + x1 = sqr(d1*d1+h1*h1)*g3 + print "At contact you were traveling " + x1 + " " + ns + "/hr" + else if abs(d)>10*z then + print "You are down safely - " + print + print "But missed the landing site by" + abs(d/g5) + " " + ns + "." + else + print + print "Tranquility Base here -- the Eagle has landed." + print "Congratulations -- there was no spacecraft damage." + print "You may now proceed with surface exploration." + end if + return false + end if + + if r0*a>164.474 then + print + print "You have been lost in space with no hope of recovery." + return false + end if + return true +end function + +startFirstGame +while true + t1 = 0; f = 0; p = 0 + integrate + while doOneTurn + end while + print + while true + qs = input("Do you want to try it again (yes/no)? ").lower + if qs and (qs[0] == "y" or qs[0] == "n") then break + end while + if qs[0] == "n" then + print + print "Too bad, the space program hates to lose experienced" + print "astronauts." + break + end if + startSubsequentGame +end while diff --git a/59_Lunar_LEM_Rocket/README.md b/59_Lunar_LEM_Rocket/README.md index 91fe1cd63..c0ec8df01 100644 --- a/59_Lunar_LEM_Rocket/README.md +++ b/59_Lunar_LEM_Rocket/README.md @@ -23,6 +23,15 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +### lem.bas + +- The input validation on the thrust value (displayed as P, stored internally as F) appears to be incorrect. It allows negative values up up to -95, but at -96 or more balks and calls it negative. I suspect the intent was to disallow any value less than 0 (in keeping with the instructions), *or* nonzero values less than 10. + +- The physics calculations seem very sus. If you enter "1000,0,0" (i.e. no thrust at all, integrating 1000 seconds at a time) four times in a row, you first fall, but then mysteriously gain vertical speed, and end up being lost in space. This makes no sense. A similar result happened when just periodically applying 10% thrust in an attempt to hover. + + #### Porting Notes (please note any difficulties or challenges in porting here) From bc8156f7dadcb652946b100384c3370cffbf0d68 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 12 Sep 2023 15:01:56 -0700 Subject: [PATCH 237/377] Added MiniScript implementation of lunar.bas. --- .../59_Lunar_LEM_Rocket/MiniScript/lunar.ms | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lunar.ms diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lunar.ms b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lunar.ms new file mode 100644 index 000000000..e8da8d72c --- /dev/null +++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lunar.ms @@ -0,0 +1,114 @@ +print " "*33 + "Lunar" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "This is a computer simulation of an Apollo lunar" +print "landing capsule."; print; print +print "The on-board computer has failed (it was made by" +print "Xerox) so you have to land the capsule manually." + +printCols = function(fields, delimiter=null) + if delimiter == null then delimiter = text.delimiter + line = "" + for s in fields + line += (s + " "*12)[:12] + end for + print line, delimiter +end function + +doOneGame = function + print; print "Set burn rate of retro rockets to any value between" + print "0 (free fall) and 200 (maximum burn) pounds per second." + print "Set new burn rate every 10 seconds."; print + print "Capsule weight 32,500 lbs; fuel weight 16,500 lbs." + print; print; print; print "Good luck" + l = 0 + + print + printCols ["sec","mi + ft","mph","lb fuel","burn rate"] + print + a=120; v = 1; m=33000; n=16500; g=1e-03; z = 1.8 + + formulaSet1 = function // (subroutine 330) + outer.l += s + outer.t -= s + outer.m -= s * k + outer.a = i + outer.v = j + end function + + formulaSet2 = function // (subroutine 420) + outer.q = s * k / m + outer.j = v + g*s + z*(-q-q*q/2-q^3/3-q^4/4-q^5/5) + outer.i = a - g*s*s/2 - v*s+z*s*(q/2+q^2/6+q^3/12+q^4/20+q^5/30) + end function + + formulaSet3 = function // (loop 340-360) + while s >= 5e-3 + outer.d = v + sqrt(v * v + 2 * a * (g - z * k / m)) + outer.s = 2 * a / d + formulaSet2 + formulaSet1 + end while + end function + + while true + printCols [l, floor(a) + " " + floor(5280*(a-floor(a))), 3600*v, m-n], "" + k = input.val + t=10 + shouldExit = false + + while true + if m-n < 1e-03 then break + if t < 1e-03 then break + s = t; if m < n+s*k then s = (m-n)/k + formulaSet2 + if i <= 0 then + formulaSet3 + shouldExit = true + break + end if + if v > 0 and j < 0 then + while v > 0 and j <= 0 + w = (1 - m*g/(z*k))/2 + s = m*v / (z*k*(w + sqrt(w*w + v/z))) + 0.05 + formulaSet2 + if i <= 0 then + formulaSet3 + shouldExit = true + break + end if + formulaSet1 + end while + if shouldExit then break + continue + end if + formulaSet1 + end while + if shouldExit then break + if m-n < 1e-03 then + print "Fuel out at " + round(l) + " seconds" + s = (-v+sqrt(v*v+2*a*g))/g + v = v+g*s; l = l+s + break + end if + end while + + w = 3600*v + print "On moon at " + l + " seconds - impact velocity " + round(w,1) + " mph" + if w <= 1.2 then + print "Perfect landing!" + else if w <= 10 then + print "Good landing (could be better)" + else if w <= 60 then + print "Craft damage... you're stranded here until a rescue" + print "party arrives. Hope you have enough oxygen!" + else + print "Sorry there were no survivors. You blew it!" + print "In fact, you blasted a new lunar crater " + round(w*.227,1) + " feet deep!" + end if +end function + +while true + doOneGame + print; print; print; print "Try again??" +end while From bbac41f6bdd011f1ab5a0c29a75519795c99310d Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 12 Sep 2023 15:47:24 -0700 Subject: [PATCH 238/377] Added MiniScript version of rocket.bas. --- .../59_Lunar_LEM_Rocket/MiniScript/rocket.ms | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms new file mode 100644 index 000000000..3bb4957fc --- /dev/null +++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms @@ -0,0 +1,101 @@ +if version.hostName == "Mini Micro" then clear +print " "*30 + "Rocket" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "Lunar Landing Simulation" +print "----- ------- ----------"; print +yn = input("Do you want instructions (yes or no)? ").lower +if not yn or yn[0] != "n" then + print + print "You are landing on the moon and and have taken over manual" + print "control 1000 feet above a good landing spot. You have a down-" + print "ward velocity of 50 feet/sec. 150 units of fuel remain." + print + print "Here are the rules that govern your Apollo space-craft" + print "(Press Return after each one):"; print + print "(1) After each second the height, velocity, and remaining fuel" + print " will be reported via Digby your on-board computer." + input + print "(2) After the report a '?' will appear. Enter the number" + print " of units of fuel you wish to burn during the next" + print " second. Each unit of fuel will slow your descent by" + print " 1 foot/sec." + input + print "(3) The maximum thrust of your engine is 30 feet/sec/sec" + print " or 30 units of fuel per second." + input + print "(4) When you contact the lunar surface, your descent engine" + print " will automatically shut down and you will be given a" + print " report of your landing speed and remaining fuel." + input + print "(5) If you run out of fuel the '?' will no longer appear" + print " but your second by second report will continue until" + print " you contact the lunar surface."; print + input +end if + +pad = function(s, width=10) + return (s + " "*width)[:width] +end function + +// Bonus little feature when running in Mini Micro: display a header bar +// always at the top of the screen. +drawHeaders = function + display(2).mode = displayMode.text; td = display(2) + td.color = text.color; td.backColor = color.black + td.row = 25; td.column = 0 + td.print "sec feet speed fuel plot of distance" + " "*21 +end function + +while true + print "Beginning landing procedure.........."; print + print "G O O D L U C K ! ! !" + print; print + print "sec feet speed fuel plot of distance" + drawHeaders + print + t=0; h=1000; v=50; fuel=150 + while true + print pad(t,5) + pad(h,7) + pad(v, 10) + pad(fuel,8) + "|" + " "*floor(h/30) + "*" + if fuel <= 0 then + burn = 0 + wait 0.5 // (slight pause for drama and legibility) + else + burn = input("?").val + if burn < 0 then burn = 0 + if burn > 30 then burn=30 + if burn > fuel then + burn = fuel + print "**** out of fuel ****" + end if + end if + v1 = v - burn + 5 + fuel -= burn + h -= .5*(v+v1) + if h <= 0 then break + t += 1 + v = v1 + end while + print "***** CONTACT *****" + h = h+ .5*(v1+v) + if burn == 5 then + d = h/v + else + d = (-v+sqrt(v*v+h*(10-2*burn)))/(5-burn) + end if + v1 = v + (5-burn)*d + print "Touchdown at " + (t+d) + " seconds." + print "Landing velocity = " + round(v1,1) + " feet/sec." + print fuel + " units of fuel remaining." + if v1 == 0 then + print "Congratulations! a perfect landing!!" + print "Your license will be renewed.......later." + else if abs(v1) >= 2 then + print "***** Sorry, but you blew it!!!!" + print "Appropriate condolences will be sent to your next of kin." + end if + print; print; print + yn = input("Another mission? ").lower + if not yn or yn[0] != "y" then break +end while +print; print "Control out."; print From 5a3b282faacd31562bc8ca900b520fdc55d69e0d Mon Sep 17 00:00:00 2001 From: chinhouse Date: Tue, 12 Sep 2023 20:13:41 -0700 Subject: [PATCH 239/377] Update README.md From 4a5686322a3e963d1b63a7044d827a88eea26bdb Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 13 Sep 2023 09:44:56 -0700 Subject: [PATCH 240/377] Added MiniScript version of 60_Mastermind. --- .../60_Mastermind/MiniScript/README.md | 17 ++ .../60_Mastermind/MiniScript/mastermind.ms | 260 ++++++++++++++++++ 60_Mastermind/README.md | 10 +- 3 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 00_Alternate_Languages/60_Mastermind/MiniScript/README.md create mode 100644 00_Alternate_Languages/60_Mastermind/MiniScript/mastermind.ms diff --git a/00_Alternate_Languages/60_Mastermind/MiniScript/README.md b/00_Alternate_Languages/60_Mastermind/MiniScript/README.md new file mode 100644 index 000000000..088a33011 --- /dev/null +++ b/00_Alternate_Languages/60_Mastermind/MiniScript/README.md @@ -0,0 +1,17 @@ +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 mastermind.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 "mastermind" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/60_Mastermind/MiniScript/mastermind.ms b/00_Alternate_Languages/60_Mastermind/MiniScript/mastermind.ms new file mode 100644 index 000000000..93ea30820 --- /dev/null +++ b/00_Alternate_Languages/60_Mastermind/MiniScript/mastermind.ms @@ -0,0 +1,260 @@ +// +// MASTERMIND II +// STEVE NORTH +// CREATIVE COMPUTING +// PO BOX 789-M MORRISTOWN NEW JERSEY 07960 +// +// Converted to MiniScript by Joe Strout (Sep 2023) + +// Advance the given combination to the next possible combination. +// Note that (unlike the BASIC program) our values are 0-based, not 1-based. +incrementCombo = function(combo) + idx = 0 + while true + combo[idx] += 1 + if combo[idx] < colorCount then return + combo[idx] = 0 + idx += 1 + end while +end function + +// Convert a numeric combination like [2, 0, 1] into a color string like "RBW". +comboToColorString = function(combo) + result = "" + for q in combo + result += colorCodes[q] + end for + return result +end function + +// Get a random color code like "RBW". +getRandomCode = function + // We do this by starting with a numeric combo of all 0's (first color), + // and then stepping through subsequent combos a random number of times. + combo = [0] * posCount + steps = floor(possibilities * rnd) + while steps + incrementCombo combo + steps -= 1 + end while + return comboToColorString(combo) +end function + +// Return [blackPins, whitePins] for the given guess and actual code. +// blackPins is how many guess entries are the correct color AND position; +// whitePins is how many guess entries have the right color, but wrong position. +// This works with either color strings or numeric combos. +calcResult = function(guess, actual) + if guess isa string then guess = guess.split("") else guess = guess[:] + if actual isa string then actual = actual.split("") else actual = actual[:] + black = 0; white = 0 + for i in guess.indexes + if guess[i] == actual[i] then + black += 1 + actual[i] = null + else + for j in actual.indexes + if guess[i] == actual[j] and guess[j] != actual[j] then + white += 1 + actual[j] = null + break + end if + end for + end if + guess[i] = null + end for + return [black, white] +end function + +// Pad a string with spaces, to the given width. +pad = function(s, width=12) + return (s + " "*width)[:width] +end function + +// Print the history of guesses and results. +printBoard = function + print + print "BOARD" + print "Move Guess Black White" + for i in guessHistory.indexes + print pad(i+1, 9) + pad(guessHistory[i], 15) + + pad(guessResult[i][0], 10) + guessResult[i][1] + end for + print +end function + +// Quit the game (after reporting the computer's secret code). +quit = function(computerCode) + print "Quitter! My combination was: " + computerCode + print + print "Good bye" + exit +end function + +// Prompt the user for a guess (e.g. "RBW"). +// Also handle "BOARD" and "QUIT" commands. +inputGuess = function(guessNum, secretCode) + while true + guess = input("Move #" + guessNum + " Guess? ").upper + if guess == "BOARD" then + printBoard + else if guess == "QUIT" then + quit secretCode + else if guess.len != posCount then + print "Bad number of positions." + else + ok = true + for c in guess + if colorCodes.indexOf(c) == null then + print "'" + c + "' is unrecognized." + ok = false + break + end if + end for + if ok then return guess + end if + end while +end function + +// Play one half-round where the computer picks a code, +// and the human tries to guess it. +doHumanGuesses = function + print "Guess my combination." + print + secretCode = getRandomCode + //print "My secret combo is: " + secretCode // (for debugging purposes) + + globals.guessHistory = [] // list of guesses, e.g. "RBW" + globals.guessResult = [] // result of each guess, as [BlackPins, WhitePins] + + for guessNum in range(1, 10) + guess = inputGuess(guessNum, secretCode) + result = calcResult(guess, secretCode) + if result[0] == posCount then + print "You guessed it in " + guessNum + " moves!" + break + end if + // Tell human results + print "You have " + result[0] + " blacks and " + result[1] + " whites." + // Save all this stuff for board printout later + guessHistory.push guess + guessResult.push result + end for + if guess != secretCode then + print "You ran out of moves! That's all you get!" + print "The actual combination was: " + secretCode + end if + globals.humanScore += guessNum +end function + +// Play one half-round where the human picks a code, +// and the computer tries to guess it. +// Return true if this goes OK, and false if we need a do-over. +doComputerGuesses = function + print "Now I guess. Think of a combination." + input "Hit Return when ready:" + + // Make a list of possible combination *numbers*, from 0 to possibilities-1. + // We'll remove entries from this list as we eliminate them with our guesses. + possible = range(0, possibilities-1) + + gotIt = false + for guessNum in range(1, 10) + if not possible then + print "You have given me inconsistent information." + print "Try again, and this time please be more careful." + return false + end if + guessIdx = possible[rnd * possible.len] + guessCombo = [0] * posCount + if guessIdx > 0 then + for x in range(0, guessIdx-1) + incrementCombo guessCombo + end for + end if + + print "My guess is: " + comboToColorString(guessCombo) + + while true + s = input(" Blacks, Whites? ").replace(",", " ").replace(" ", " ").split + if s.len == 2 then break + end while + actualResult = [s[0].val, s[1].val] + + if actualResult[0] == posCount then + print "I got it in " + guessNum + " moves!" + gotIt = true + break + end if + + // Now zip through all possibilities, and if it's still in our + // possible list but doesn't match the given result, remove it. + combo = [0] * posCount + for x in range(0, possibilities-1) + if x > 0 then incrementCombo combo + idx = possible.indexOf(x) + if idx == null then continue // (already eliminated) + result = calcResult(combo, guessCombo) + if result != actualResult then + //print "Eliminating #" + x + ", " + comboToColorString(combo) + possible.remove idx + end if + end for + end for + + if not gotIt then + print "I used up all my moves!" + print "I guess my CPU is just having an off day." + end if + globals.computerScore += guessNum + return true +end function + +// Show the score (with the given header). +showScore = function(header="Score") + print header + ":" + print " COMPUTER " + computerScore + print " HUMAN " + humanScore + print +end function + +// Initialization of global variables +colorCodes = "BWRGOYPT" +colorNames = "Black,White,Red,Green,Orange,Yellow,Purple,Tan".split(",") +computerScore = 0 +humanScore = 0 + +// Main program +print " "*30 + "Mastermind" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +while true + colorCount = input("Number of colors? ").val + if 0 < colorCount <= 8 then break + print "No more than 8, please!" +end while +posCount = input("Number of positions? ").val +roundCount = input("Number of rounds? ").val +possibilities = colorCount ^ posCount +print "Total possibilities = " + possibilities + +print; print +print "Color Letter" +print "===== ======" +for x in range(0, colorCount-1) + print pad(colorNames[x], 9) + colorCodes[x] +end for +print + +for round in range(1, roundCount) + print + print "Round number " + round + " ----" + print + doHumanGuesses + showScore + while not doComputerGuesses; end while + showScore +end for + +print "GAME OVER" +showScore "Final score" diff --git a/60_Mastermind/README.md b/60_Mastermind/README.md index 7820eed7b..05383f106 100644 --- a/60_Mastermind/README.md +++ b/60_Mastermind/README.md @@ -86,7 +86,7 @@ solutions reporting their black and white pegs against `RBW`. | BRW | 1 | 2 | | WRW | 1 | 1 | | RRW | 2 | 0 | | BRR | 0 | 2 | | WRR | 0 | 2 | | RRR | 1 | 0 | -Now we are going to eliminate every solution that **DOESN'T** matches 0 black and 2 white. +Now we are going to eliminate every solution that **DOESN'T** match 0 black and 2 white. | Guess | Black | White | | Guess | Black | White | | Guess | Black | White | |----------|-------|-------|-----|----------|-------|-------|-----|----------|-------|-------| @@ -130,7 +130,7 @@ report 1 black and 0 whites. | ~~~WWB~~ | 0 | 1 | | ~~~WRR~~ | 2 | 0 | -Only one solution matches and its our secret code! The computer will guess this +Only one solution matches and it's our secret code! The computer will guess this one next as it's the only choice left, for a total of three moves. Coincidentally, I believe the expected maximum number of moves the computer will make is the number of positions plus one for the initial guess with no information. @@ -150,4 +150,8 @@ WB first, the most you can logically deduce if you get 1 black and 1 white is that it is either WW, or BB which could bring your total guesses up to three which is the number of positions plus one. So if your computer's turn is taking longer than the number of positions plus one to find the answer then something -is wrong with your code. \ No newline at end of file +is wrong with your code. + +#### Known Bugs + +- Line 622 is unreachable, as the previous line ends in a GOTO and that line number is not referenced anywhere. It appears that the intent was to tell the user the correct combination after they fail to guess it in 10 tries, which would be a very nice feature, but does not actually work. (In the MiniScript port, I have made this feature work.) From c347d6a1ef6c47cb0f7575bfbe31c2e6bc39bc92 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 13 Sep 2023 15:56:08 -0700 Subject: [PATCH 241/377] Added MiniScript version of 61_Math_Dice. --- .../61_Math_Dice/MiniScript/README.md | 21 +++++++ .../61_Math_Dice/MiniScript/mathdice.ms | 58 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 00_Alternate_Languages/61_Math_Dice/MiniScript/README.md create mode 100644 00_Alternate_Languages/61_Math_Dice/MiniScript/mathdice.ms diff --git a/00_Alternate_Languages/61_Math_Dice/MiniScript/README.md b/00_Alternate_Languages/61_Math_Dice/MiniScript/README.md new file mode 100644 index 000000000..ac7b913c2 --- /dev/null +++ b/00_Alternate_Languages/61_Math_Dice/MiniScript/README.md @@ -0,0 +1,21 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of mathdice.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 mathdice.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 "mathdice" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/61_Math_Dice/MiniScript/mathdice.ms b/00_Alternate_Languages/61_Math_Dice/MiniScript/mathdice.ms new file mode 100644 index 000000000..74ed63496 --- /dev/null +++ b/00_Alternate_Languages/61_Math_Dice/MiniScript/mathdice.ms @@ -0,0 +1,58 @@ +print " "*31 + "Math Dice" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "This program generates successive pictures of two dice." +print "When two dice and an equal sign followed by a question" +print "mark have been printed, type your answer and the return key." +print "To conclude the lesson, type Control-C as your answer." +print + +printDie = function(d) + print + print " -----" + if d == 1 then + print "| |" + else if d == 2 or d == 3 then + print "| * |" + else + print "| * * |" + end if + if d == 2 or d == 4 then + print "| |" + else if d == 6 then + print "| * * |" + else + print "| * |" + end if + if d == 1 then + print "| |" + else if d == 2 or d == 3 then + print "| * |" + else + print "| * * |" + end if + print " -----" + print +end function + +while true + d1 = floor(6 * rnd + 1) + printDie d1 + print " +" + d2 = floor(6 * rnd + 1) + printDie d2 + total = d1 + d2 + answer = input(" =? ").val + if answer != total then + print "No, count the spots and give another answer." + answer = input(" =? ").val + end if + if answer == total then + print "Right!" + else + print "No, the answer is " + total + end if + print + print "The dice roll again..." +end while + From 9b9db040fe61b7bf800ef582c0e805160cc82355 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 13 Sep 2023 16:14:26 -0700 Subject: [PATCH 242/377] Added MiniScript version of 62_Mugwump. --- .../62_Mugwump/MiniScript/README.md | 21 ++++++ .../62_Mugwump/MiniScript/mugwump.ms | 65 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 00_Alternate_Languages/62_Mugwump/MiniScript/README.md create mode 100644 00_Alternate_Languages/62_Mugwump/MiniScript/mugwump.ms diff --git a/00_Alternate_Languages/62_Mugwump/MiniScript/README.md b/00_Alternate_Languages/62_Mugwump/MiniScript/README.md new file mode 100644 index 000000000..ac7b913c2 --- /dev/null +++ b/00_Alternate_Languages/62_Mugwump/MiniScript/README.md @@ -0,0 +1,21 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of mathdice.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 mathdice.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 "mathdice" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/62_Mugwump/MiniScript/mugwump.ms b/00_Alternate_Languages/62_Mugwump/MiniScript/mugwump.ms new file mode 100644 index 000000000..8ba5f7fb2 --- /dev/null +++ b/00_Alternate_Languages/62_Mugwump/MiniScript/mugwump.ms @@ -0,0 +1,65 @@ +print " "*33 + "Mugwump" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +// Courtesy People's Computer Company +print "The object of this game is to find four mugwumps" +print "hidden on a 10 by 10 grid. Homebase is position 0,0." +print "Any guess you make must be two numbers with each" +print "number between 0 and 9, inclusive. First number" +print "is distance to right of homebase and second number" +print "is distance above homebase." +print +print "You get 10 tries. After each try, I will tell" +print "you how far you are from each mugwump." +print + +playOneGame = function + mugwump = {} // key: number 1-4; value: [x,y] position + for i in range(1, 4) + mugwump[i] = [floor(10*rnd), floor(10*rnd)] + end for + + found = 0 + for turn in range(1, 10) + print + print + while true + inp = input("Turn no. " + turn + " -- what is your guess? ") + inp = inp.replace(",", " ").replace(" ", " ").split + if inp.len == 2 then break + end while + x = inp[0].val; y = inp[1].val + for i in range(1, 4) + pos = mugwump[i] + if pos == null then continue // (already found) + if pos == [x,y] then + print "You have found mugwump " + i + mugwump[i] = null + found += 1 + else + d = sqrt( (pos[0] - x)^2 + (pos[1] - y)^2 ) + print "You are " + round(d, 1) + " units from mugwump " + i + end if + end for + if found == 4 then + print + print "You got them all in " + turn + " turns!" + return + end if + end for + print + print "Sorry, that's 10 tries. Here is where they're hiding:" + for i in range(1, 4) + pos = mugwump[i] + if pos == null then continue + print "Mugwump " + i + " is at (" + pos[0] + "," + pos[1] + ")" + end for +end function + +// Main loop +while true + playOneGame + print + print "That was fun! Let's play again......." + print "Four more mugwumps are now in hiding." +end while From 9c7698461d6a141d3e7603fce2b49e401023b92c Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 13 Sep 2023 16:24:22 -0700 Subject: [PATCH 243/377] Added MiniScript version of 63_Name. --- .../63_Name/MiniScript/README.md | 21 ++++++++++++++++ .../63_Name/MiniScript/name.ms | 25 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 00_Alternate_Languages/63_Name/MiniScript/README.md create mode 100644 00_Alternate_Languages/63_Name/MiniScript/name.ms diff --git a/00_Alternate_Languages/63_Name/MiniScript/README.md b/00_Alternate_Languages/63_Name/MiniScript/README.md new file mode 100644 index 000000000..819ecf501 --- /dev/null +++ b/00_Alternate_Languages/63_Name/MiniScript/README.md @@ -0,0 +1,21 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of name.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 name.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 "name" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/63_Name/MiniScript/name.ms b/00_Alternate_Languages/63_Name/MiniScript/name.ms new file mode 100644 index 000000000..bb3d2da23 --- /dev/null +++ b/00_Alternate_Languages/63_Name/MiniScript/name.ms @@ -0,0 +1,25 @@ +print " "*34 + "Name" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "Hello."; print "My name is Creative Computer." +name = input("What's your name (first and last)? ") + +s = "" +for i in range(name.len - 1) + s += name[i] +end for +print; print "Thank you, " + s + "." +print "Oops! I guess I got it backwards. A smart" +print "computer like me shouldn't make a mistake like that!"; print +print "But i just noticed your letters are out of order." +s = name.split("").sort.join("") +print "Let's put them in order like this: " + s +yn = input("Don't you like that better? ").lower +print +if yn and yn[0] == "y" then + print "I knew you'd agree!!" +else + print "I'm sorry you don't like it that way." +end if +print; print "I really enjoyed meeting you " + name + "." +print "Have a nice day!" From ed2c1d37e34ef962e23ec4a4152616447a09cf61 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Wed, 13 Sep 2023 16:43:31 -0700 Subject: [PATCH 244/377] Create weekday.ms --- .../95_Weekday/MiniScript/weekday.ms | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms diff --git a/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms b/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms new file mode 100644 index 000000000..d32790017 --- /dev/null +++ b/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms @@ -0,0 +1,177 @@ +TAB = char(9) +CR = char(13) + +Age = {"m": 0, "d": 0, "y": 0} +Age.init = function(m,d,y) + noob = new Age + noob.m = m;noob.d = d;noob.y = y + return noob +end function + +Age.sub = function(a) + m1 = self.m; d1 = self.d; y1 = self.y + d1 = d1 - a.d + if d1 < 0 then + d1 = d1 + 30 + m1 = m1 - 1 + end if + m1 = m1 - a.m + if m1 < 0then + m1 = m1 + 12 + y1 = y1 - 1 + end if + y1 = y1 - a.y + return Age.init(m1,d1,y1) +end function + +Age.multiply = function(multiplier) + ageInDays = self.y *365 + self.m * 30 + self.d + floor(self.m / 2) + newAge = ageInDays * multiplier + years = floor(newAge/ 365) + leftover = newAge % 365 + months = floor(leftover / 30) + days = floor(leftover % 30) + return Age.init(months, days, years) +end function + +Date = {"m": null, "d": null, "y": null} + +// the number of days between the 1st of one month to the next +Date.daysPerMonth = [0,31,28,31,30,31,30, 31,31,30,31,30] +Date.dayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", +"Thursday", "Friday", "Saturday"] + +Date.init = function(dt) + d = dt.split(",") + if d.len != 3 then return + noob = new Date + noob.m = d[0].val + noob.d = d[1].val + noob.y = d[2].val + return noob +end function + +Date.diff = function(mdy) + dday = self.d - mdy.d + dmonth = self.m - mdy.m + if dday < 0 then + dmonth -= 1 + dday += 30 + end if + + dyear = self.y - mdy.y + if dmonth <0 then + dyear -= 1 + dmonth += 12 + end if + return Age.init(dmonth, dday, dyear) +end function + +Date._isLeapYear = function + return (self.y % 4 == 0 and self.y % 100 != 0) or self.y % 400 == 0 +end function + +Date.value = function + //Not accepting dates Jan 1st 1583 this because the + //transistion to Gregorian calendar occurred in 1582. + + //calculating days since the end of 1582 + years = self.y - 1583 + days = years * 365 + self._leapYears + Date.daysPerMonth[:self.m].sum + self.d + return days // returns 1 for 1,1,1583 +end function + +Date.dayOfWeek = function + // 1,1,1583 is a Saturday + // Date.value calculates a value of 1 for that date + return (self.value + 5) % 7 +end function + +Date.weekday = function + return Date.dayNames[self.dayOfWeek] +end function + +// get # of lear yeaps since the change to Gregorian +Date._leapYears = function + ly = floor((self.y - 1580) / 4) + + //exclude centuries + centuries = floor((self.y - 1500) / 100) + + //unless centuries divisible by 400 + centuries400 = floor((self.y - 1200) / 400) + ly = ly - centuries + centuries400 + + if self._isLeapYear and self.m < 3 then ly -= 1 + return ly +end function + +print " "*32 + "WEEKDAY" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"+CR+CR+CR + +print "WEEKDAY is a computer demonstration that" +print "gives facts about a date of interest to you."+CR + +mdy = input("Enter today's date in the form: 3,24,1979?"+CR) +today = Date.init(mdy) + +mdy = input("Enter day of birth (or other day of interest)"+CR) +dob = Date.init(mdy) + +print +if dob.y < 1583 then + print "Not prepared to give day of the week prior to 1583" + exit +end if + +verb = " was a " +if today.value < dob.value then verb= " will be a " +if today.value == dob.value then verb = " is a " + +if dob.d == 13 and dob.weekday == "Friday" then + endMsg = " The Thirteenth--Beware!" +else + endMsg = "." +end if +print dob.m + "/" + dob.d + "/" + dob.y + verb + dob.weekday + endMsg + +age = today.diff(dob) + +totalAge = Age.init(age.m,age.d,age.y) +if verb == " was a " then + lines= [["", "YEARS", "MONTHS", "DAYS"]] + lines.push(["", "-----", "------", "----"]) + lines.push(["Your age (if birthdate)", age.y,age.m, age.d]) + + spent = age.multiply(.35) + lines.push(["You have slept", spent.y,spent.m, spent.d]) + totalAge = totalAge.sub(spent) + + spent = age.multiply(.17) + lines.push(["You have eaten", spent.y,spent.m, spent.d]) + totalAge = totalAge.sub(spent) + + if totalAge.y <= 3 then + phrase = "You have played" + else if totalAge.y <= 9 then + phrase = "You have played/studied" + else + phrase = "You have worked/played" + end if + + spent = age.multiply(.23) + lines.push([phrase, spent.y,spent.m, spent.d]) + totalAge = totalAge.sub(spent) + + relaxed = totalAge + lines.push(["You have relaxed", relaxed.y, relaxed.m, relaxed.d]) + for line in lines + col0 = (" " * 25 + line[0])[-25:] + col1 = (line[1] + " " * 6)[:6] + col2 = (line[2] + " " * 7)[:7] + col3 = (line[3] + " " * 5)[:5] + print (col0+" " + col1+col2+col3) + end for +end if + +print CR+"Yoy may retire in " + (dob.y + 65) From e1151d4e04e81e304305ba09f7ecc251b2c73e9a Mon Sep 17 00:00:00 2001 From: chinhouse Date: Wed, 13 Sep 2023 16:45:08 -0700 Subject: [PATCH 245/377] Create README.md --- .../95_Weekday/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/95_Weekday/MiniScript/README.md diff --git a/00_Alternate_Languages/95_Weekday/MiniScript/README.md b/00_Alternate_Languages/95_Weekday/MiniScript/README.md new file mode 100644 index 000000000..c6bd62672 --- /dev/null +++ b/00_Alternate_Languages/95_Weekday/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 weekday.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 "weekday" + run From 3d78654ba15c568f8e81a6ac095cfa7abd439dcb Mon Sep 17 00:00:00 2001 From: chinhouse Date: Wed, 13 Sep 2023 17:18:17 -0700 Subject: [PATCH 246/377] Create 23matches.ms --- .../93_23_Matches/MiniScript./23matches.ms | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms b/00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms new file mode 100644 index 000000000..c906eaaeb --- /dev/null +++ b/00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms @@ -0,0 +1,67 @@ +CR = char(13) + +print " "*32 + "WEEKDAY" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"+CR+CR+CR + +print "This is a game called '23 Matches'." +print +print "When it is your turn, you may take one, two, or three" +print "matches. The object of the game is not to have to take" +print "the last match." +print +print "Let's flip a coin to see who goes first." +print "If it comes up heads, I will win the toss." +print +matches = 23 +humanTurn = floor(rnd * 2) + +if humanTurn then + print "Tails! You go first." + prompt = "How many do you wish to remove? " +else + print "Heads! I win! Ha! Ha!" + print "Prepare to lose, meatball-nose!!" +end if + +choice = 2 +while matches > 0 + if humanTurn then + choice = 0 + if matches == 1 then choice = 1 + while choice == 0 + choice = input(prompt).val + if choice <1 or choice > 3 or choice > matches then + choice = 0 + print "Very funny! Dummy!" + print "Do you want to play or goof around?" + prompt = "Now, how many matches do you want? " + end if + end while + matches = matches - choice + if matches == 0 then + print "You poor boob! You took the last match! I gotcha!!" + print "Ha! Ha! I beat you !!" + print "Good bye loser!" + else + print "There are now " + matches + " matches remaining." + CR + end if + else + choice_comp = 4 - choice + if matches == 1 then + choice_comp = 1 + else if 1 < matches and matches < 4 then + choice_comp = matches - 1 + end if + matches = matches - choice_comp + if matches == 0 then + print "You won, floppy ears!" + print "Think you're pretty smart!" + print "Let's play again and I'll blow your shoes off!!" + else + print "My turn! I remove " + choice_comp + " matches" + print "The number of matches is now " + matches + CR + end if + end if + humanTurn = not humanTurn + prompt = "Your turn -- you may take 1, 2 or 3 matches." + CR + "How many do you wish to remove? " +end while From d5afb0d56dc5d9c911ad42c752cc0360fcce603c Mon Sep 17 00:00:00 2001 From: chinhouse Date: Wed, 13 Sep 2023 17:20:15 -0700 Subject: [PATCH 247/377] Create README.md --- .../93_23_Matches/MiniScript./README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/93_23_Matches/MiniScript./README.md diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript./README.md b/00_Alternate_Languages/93_23_Matches/MiniScript./README.md new file mode 100644 index 000000000..c14b6da80 --- /dev/null +++ b/00_Alternate_Languages/93_23_Matches/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 MiniScript program and this README file. Then, at the Mini Micro command prompt, enter: + + load "aceyducey" + run From 4d7bda317dbce80072b882216e0f434fb9df28c9 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Wed, 13 Sep 2023 17:20:53 -0700 Subject: [PATCH 248/377] Update README.md --- 00_Alternate_Languages/93_23_Matches/MiniScript./README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript./README.md b/00_Alternate_Languages/93_23_Matches/MiniScript./README.md index c14b6da80..5fe9b2c48 100644 --- a/00_Alternate_Languages/93_23_Matches/MiniScript./README.md +++ b/00_Alternate_Languages/93_23_Matches/MiniScript./README.md @@ -7,10 +7,10 @@ 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 + miniscript 23matches.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 "aceyducey" + load "23matches" run From ed15a884933d218f823c09c05b22068b4209cd27 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Wed, 13 Sep 2023 17:21:05 -0700 Subject: [PATCH 249/377] Update README.md --- 00_Alternate_Languages/93_23_Matches/MiniScript./README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript./README.md b/00_Alternate_Languages/93_23_Matches/MiniScript./README.md index 5fe9b2c48..105b221f0 100644 --- a/00_Alternate_Languages/93_23_Matches/MiniScript./README.md +++ b/00_Alternate_Languages/93_23_Matches/MiniScript./README.md @@ -13,4 +13,5 @@ Download for your system from https://miniscript.org/cmdline/, install, and then 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 "23matches" + run From b79951a628d3befce6bee6f8b4ee7850fb2c56da Mon Sep 17 00:00:00 2001 From: chinhouse Date: Wed, 13 Sep 2023 17:44:15 -0700 Subject: [PATCH 250/377] Update 23matches.ms --- 00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms b/00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms index c906eaaeb..853e387d3 100644 --- a/00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms +++ b/00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms @@ -1,6 +1,6 @@ CR = char(13) -print " "*32 + "WEEKDAY" +print " "*31 + "23 MATCHES" print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"+CR+CR+CR print "This is a game called '23 Matches'." From 8fb06a78ba0a8713c808eaa5be9215eca496223e Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Thu, 14 Sep 2023 13:09:44 -0700 Subject: [PATCH 251/377] Added MiniScript version of 65_Nim. --- .../65_Nim/MiniScript/README.md | 21 ++ .../65_Nim/MiniScript/nim.ms | 194 ++++++++++++++++++ 65_Nim/README.md | 4 + 3 files changed, 219 insertions(+) create mode 100644 00_Alternate_Languages/65_Nim/MiniScript/README.md create mode 100644 00_Alternate_Languages/65_Nim/MiniScript/nim.ms diff --git a/00_Alternate_Languages/65_Nim/MiniScript/README.md b/00_Alternate_Languages/65_Nim/MiniScript/README.md new file mode 100644 index 000000000..d92876559 --- /dev/null +++ b/00_Alternate_Languages/65_Nim/MiniScript/README.md @@ -0,0 +1,21 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of nim.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 nim.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 "nim" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/65_Nim/MiniScript/nim.ms b/00_Alternate_Languages/65_Nim/MiniScript/nim.ms new file mode 100644 index 000000000..f241c6964 --- /dev/null +++ b/00_Alternate_Languages/65_Nim/MiniScript/nim.ms @@ -0,0 +1,194 @@ +print " "*33 + "Nim" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +askYesNo = function(prompt) + while true + answer = input(prompt + "? ").lower + if answer and answer[0] == "y" then return "yes" + if answer and answer[0] == "n" then return "no" + print "Please answer yes or no." + end while +end function + +print "This is the game of Nim." +if askYesNo("Do you want instructions") == "yes" then + print "The game is played with a number of piles of objects." + print "Any number of objects are removed from one pile by you and" + print "the machine alternately. On your turn, you may take" + print "all the objects that remain in any pile, but you must" + print "take at least one object, and you may take objects from" + print "only one pile on a single turn. You must specify whether" + print "winning is defined as taking or not taking the last object," + print "the number of piles in the game, and how many objects are" + print "originally in each pile. Each pile may contain a" + print "different number of objects." + print "The machine will show its move by listing each pile and the" + print "number of objects remaining in the piles after each of its" + print "moves." +end if + +allEmpty = function(piles) + for i in range(1, piles.len-1) + if piles[i] then return false + end for + return true +end function + +// Do the computer's turn; return true if game over, false otherwise. +doComputerTurn = function(pile, winCondition) + n = pile.len - 1 + d = [0,0,0] + b = [null] + for i in range(1, n) + b.push [0]*11 + end for + + if winCondition == 2 then + c = 0 + broke = false + for i in range(1, n) + if pile[i] == 0 then continue + c += 1 + if c == 3 then; broke = true; break; end if + d[c] = i + end for + if not broke then + if c == 2 and (pile[d[1]] == 1 or pile[d[2]] == 1) then + print "Machine wins" + return true + end if + if pile[d[1]] > 1 then + print "Machine wins" + return true + end if + print "Machine loses" + return true + end if + c = 0 + broke = false + for i in range(1, n) + if pile[i] > 1 then; broke = true; break; end if + if pile[i] == 0 then continue + c += 1 + end for + if not broke and c/2 != floor(c/2) then + print "Machine loses" + return true + end if + end if + + for i in range(1, n) + e = pile[i] + for j in range(0, 10) + f = e/2 + b[i][j] = 2*(f-floor(f)) + e = floor(f) + end for + end for + broke = false + for j in range(10, 0) + c = 0 + h = 0 + for i in range(1, n) + if b[i][j] == 0 then continue + c += 1 + if pile[i] <= h then continue + h = pile[i] + g = i + end for + if c/2 != floor(c/2) then; broke = true; break; end if + end for + if not broke then + while true + e = floor(n*rnd+1) + if pile[e] != 0 then break + end while + f = floor(pile[e]*rnd+1) + pile[e] -= f + else + pile[g] = 0 + for j in range(0, 10) + b[g][j] = 0 + c=0 + for i in range(1,n) + if b[i][j] == 0 then continue + c += 1 + end for + pile[g] += 2*(c/2-floor(c/2))*2^j + end for + if winCondition != 1 then + c = 0 + broke = false + for i in range(1, n) + if pile[i]>1 then; broke = true; break; end if + if pile[i] == 0 then continue + c += 1 + end for + if not broke and c/2 == floor(c/2) then pile[g]= 1 - pile[g] + end if + end if + + print "Pile Size" + for i in range(1, n) + print i + " " + pile[i] + end for + if winCondition == 1 and allEmpty(pile) then + print "Machine wins" + return true + end if + return false +end function + +// Do the human player's turn; return true if game over, false otherwise. +doPlayerTurn = function(pile, winCondition) + n = pile.len - 1 + while true + inp = input("Your move - pile, number to be removed? ") + inp = inp.replace(",", " ").replace(" ", " ").split + if inp.len != 2 then continue + x = inp[0].val; y = inp[1].val + if x == floor(x) and y == floor(y) and 1 <= x <= n and 1 <= y <= pile[x] then break + end while + + pile[x] -= y + if allEmpty(pile) then + if winCondition == 1 then print "Machine loses" else print "Machine wins" + return true + end if + return false +end function + +playOneGame = function + print + while true + w = input("Enter win option - 1 to take last, 2 to avoid last? ").val + if w == 1 or w == 2 then break + end while + while true + n = input("Enter number of piles? ").val + if n == floor(n) and 1 <= n <= 100 then break + end while + + print "Enter pile sizes" + pile = [null] + [0]*n // (null at element 0 to make our array 1-based) + for i in range(1, n) + while true + pile[i] = input(i + "? ").val + if pile[i] == floor(pile[i]) and 1 <= pile[i] <= 2000 then break + end while + end for + + if askYesNo("Do you want to move first") == "yes" then + if doPlayerTurn(pile, w) then return + end if + while true + if doComputerTurn(pile, w) then return + if doPlayerTurn(pile, w) then return + end while +end function + +while true + playOneGame + if askYesNo("Do you want to play another game") == "no" then break +end while diff --git a/65_Nim/README.md b/65_Nim/README.md index 11243f0fc..fae886395 100644 --- a/65_Nim/README.md +++ b/65_Nim/README.md @@ -28,3 +28,7 @@ http://www.vintage-basic.net/games.html #### Porting Notes This can be a real challenge to port because of all the `GOTO`s going out of loops down to code. You may need breaks and continues, or other techniques. + +#### Known Bugs + +- If, after the player moves, all piles are gone, the code prints "MACHINE LOSES" regardless of the win condition (when line 1550 jumps to line 800). This should instead jump to line 800 ("machine loses") if W=1, but jump to 820 ("machine wins") if W=2. From b9abbcbef6819f8b5317a07d9a40cb3a652f0cbd Mon Sep 17 00:00:00 2001 From: chinhouse Date: Thu, 14 Sep 2023 13:50:05 -0700 Subject: [PATCH 252/377] Create tower.ms --- .../90_Tower/MiniScript/tower.ms | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 00_Alternate_Languages/90_Tower/MiniScript/tower.ms diff --git a/00_Alternate_Languages/90_Tower/MiniScript/tower.ms b/00_Alternate_Languages/90_Tower/MiniScript/tower.ms new file mode 100644 index 000000000..c800314c2 --- /dev/null +++ b/00_Alternate_Languages/90_Tower/MiniScript/tower.ms @@ -0,0 +1,202 @@ +kInvalidDisk = 100 +kNotTopDisk = 200 +kNotTower = 300 +kGameOver = 300 + +Tower = {"disks": []} +Tower.init = function + noob = new Tower + noob.disks = [] + return noob +end function + +Tower.height = function + return self.disks.len +end function + +Tower.top = function + if self.height == 0 then return 100 + return self.disks[-1] +end function + +Game = {} +Game["towers"] = [] +Game["numOfDisks"] = 0 +Game["rangeOfDisks"] = [] +Game["selectedDisk"] = 0 +Game["selectedDiskOn"] = 0 +Game["selectedTower"] = 0 +Game["inputErrors"] = 0 +Game["turns"] = 0 + +Game.display = function + print + for r in range(7,1,-1) + rowstr = "" + for tower in self.towers + if r > tower.height then + rowstr += " " * 12 + "#" + " " * 7 + else + spaces = (15 - tower.disks[r-1])/2 + disks = " " * 4 + tower.disks[r-1] + rowstr += disks[-5:] + " " * spaces + rowstr += "#" * tower.disks[r-1] + rowstr += " " * spaces + end if + rowstr += " " + end for + print rowstr + end for + rowstr = (" " * 5 + "=" * 15 + " ") * 3 + print rowstr + print +end function + +Game.init = function(num) + if num < 1 or num > 7 then + self.inputErrors += 1 + return false + end if + Game.towers = [] + for i in range(0,2) + Game.towers.push(Tower.init) + end for + + first = self.towers[0] + first.disks = range(15, 17 - num * 2, -2) + self.numOfDisks = num + self.rangeOfDisks = range(17 -num * 2, 15, 2) + + // This game doesn't like to be bothered + // and keeps track of how many incorrect inputs + // are made before it stops the game + self.inputErrors = 0 + self.turns = 0 + return true +end function + +Game.diskStatus = function + n = self.selectedDisk + if self.rangeOfDisks.indexOf(n) == null then + self.inputErrors +=1 + return kInvalidDisk + end if + self.inputErrors = 0 + for i in range(0, self.towers.len - 1) + if self.towers[i].top == n then + self.selectedDiskOn = i + self.inputErrors = 0 + return i + end if + end for + return kNotTopDisk +end function + +Game.pickDisk = function + self.selectedDisk = input("Which disk would you like to move? ").val + return self.diskStatus +end function + +Game.pickTower = function + self.selectedTower = input("Place disk on which needle? ").val - 1 + if not(0<= self.selectedTower and self.selectedTower <= 2) then + self.inputErrors += 1 + return kNotTower + end if + return self.selectedTower +end function + +Game.doneWithYou = function + return self.inputErrors >= 2 +end function + +Game.isFinish = function + return self.towers[0].disks.len == 0 and self.towers[1].disks.len == 0 +end function + +Game.move = function + print "Take turn # " + (self.turns + 1) + status = -1 + self.inputErrors = 0 + while 1 + status = self.pickDisk + if 0 <= status and status <= 2 then break + if status == kInvalidDisk and self.doneWithYou then + print "Stop wasting my time. Go bother someone else." + exit + else if status == kInvalidDisk then + msg = "Illegal entry ... you may only type " + msg += self.rangeOfDisks[0:-1].join(",") + " " + if self.rangeOfDisks.len > 1 then + msg += "or " + end if + msg += "15" + print msg + else if status == kNotTopDisk then + print "That disk is below another. Make another choice." + end if + end while + + self.inputErrors = 0 + while 1 + status = self.pickTower + if 0 <= status and status <= 2 then break + if status == kNotTower and self.doneWithYou then + print "I tried to warn you. But you wouldn't listen." + print "By bye, big shot." + exit + else if status == kNotTower then + print "I'll assume you hit the wrong ket this time. But watch it" + print "I only allow one mistake." + end if + end while + + if self.selectedDisk > self.towers[self.selectedTower].top then + print "You can't place a larger disk on a top of a smaller one," + print "it may crush it!" + else + n=self.towers[self.selectedDiskOn].disks.pop + self.towers[self.selectedTower].disks.push(n) + self.turns += 1 + self.inputErrors = 0 + end if +end function + + +print " " * 33 + "TOWERS" +print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print;print +print "You must transfer the disks from the left to the right" +print "tower, one at a time, never putting a larger disk on a" +print "smaller disk." +print + +ans = "Y" +while ans[0].upper == "Y" + while 1 + disks = input ("How many disks do you want to move (7 is MAX)? ").val + status = Game.init(disks) + if status == false and Game.doneWithYou then + print "All right, wise guy, if you can't play the game right, I'll" + print "take my puzzle and go home. So long." + exit + else if not status then + print "Sorry, but I can't do that job for you" + else + break + end if + end while + + while not Game.isFinish + Game.display + + Game.move + end while + Game.display + print "Congratulations!" + print "You performed the task in " + Game.turns + " moves." + print + ans = input("Play again (Yes or No)? ") +end while +print +print "Thanks for the game!" From 0d40d03a7cafea5fe8a4020d3038dca68c325cd9 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Thu, 14 Sep 2023 13:52:25 -0700 Subject: [PATCH 253/377] Add files via upload --- .../90_Tower/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/90_Tower/MiniScript/README.md diff --git a/00_Alternate_Languages/90_Tower/MiniScript/README.md b/00_Alternate_Languages/90_Tower/MiniScript/README.md new file mode 100644 index 000000000..d8c97a891 --- /dev/null +++ b/00_Alternate_Languages/90_Tower/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 tower.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 "tower" + run \ No newline at end of file From a5e3c64c9d132a1e1ae948e210ec0c38bd976a1a Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Fri, 15 Sep 2023 07:52:38 -0700 Subject: [PATCH 254/377] Added MiniScript version of 67_One_Check. --- .../65_Nim/MiniScript/README.md | 3 - .../67_One_Check/MiniScript/README.md | 18 ++++ .../67_One_Check/MiniScript/onecheck.ms | 99 +++++++++++++++++++ 3 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 00_Alternate_Languages/67_One_Check/MiniScript/README.md create mode 100644 00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms diff --git a/00_Alternate_Languages/65_Nim/MiniScript/README.md b/00_Alternate_Languages/65_Nim/MiniScript/README.md index d92876559..0265ff51f 100644 --- a/00_Alternate_Languages/65_Nim/MiniScript/README.md +++ b/00_Alternate_Languages/65_Nim/MiniScript/README.md @@ -4,9 +4,6 @@ Conversion to [MiniScript](https://miniscript.org). Ways to play: -0. Try-It! Page: -Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of nim.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. - 1. Command-Line MiniScript: Download for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as: ``` diff --git a/00_Alternate_Languages/67_One_Check/MiniScript/README.md b/00_Alternate_Languages/67_One_Check/MiniScript/README.md new file mode 100644 index 000000000..d79b401fb --- /dev/null +++ b/00_Alternate_Languages/67_One_Check/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 onecheck.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 "onecheck" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms b/00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms new file mode 100644 index 000000000..b4bfb952a --- /dev/null +++ b/00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms @@ -0,0 +1,99 @@ +print "Solitaire Checker Puzzle by david ahl" +print +print "48 checkers are placed on the 2 outside spaces of a" +print "standard 64-square checkerboard. The object is to" +print "remove as many checkers as possible by diagonal jumps" +print "(as in standard checkers). Use the numbered board to" +print "indicate the square you wish to jump from and to. On" +print "the board printed out on each turn '1' indicates a" +print "checker and '0' an empty square. When you have no" +print "possible jumps remaining, input a '0' in response to" +print "question 'Jump from?'" +print + +pad4 = function(n) + return (" " + n)[-4:] +end function + +printBoard = function + // Idea: This program could be greatly improved by printing the board + // as the index numbers (1-64), indicating which of those positions + // contain checkers via color or punctuation, e.g. "(42)" vs " 42 ". + // This would make it much easier for the user to figure out what + // numbers correspond to the positions they have in mind. + print + for j in range(1, 57, 8) + print " " + board[j:j+8].join(" ") + end for +end function + +initBoard = function + globals.board = [null] + [1] * 64 // treat this as 1-based array + for j in range(19, 43, 8) + for i in range(j, j+3) + board[i] = 0 + end for + end for +end function + +isLegal = function(from, to) + if board[from] == 0 then return false + if board[to] == 1 then return false + if board[(to+from)/2] == 0 then return false + fromRow = floor((from-1) / 8) // row in range 0-7 + fromCol = from - fromRow*8 // column in range 1-8 + toRow = floor((to-1) / 8) + toCol = to - toRow*8 + if fromRow > 7 or toRow > 7 or fromCol > 8 or toCol > 8 then return false + if abs(fromRow-toRow) != 2 or abs(fromCol-toCol) != 2 then return false + return true +end function + +askYesNo = function(prompt) + while true + answer = input(prompt + "? ").lower + if answer and answer[0] == "y" then return "yes" + if answer and answer[0] == "n" then return "no" + print "Please answer 'yes' or 'no'." + end while +end function + +print "Here is the numerical board:" +print +for j in range(1, 57, 8) + print pad4(j) + pad4(j+1) + pad4(j+2) + pad4(j+3) + + pad4(j+4) + pad4(j+5) + pad4(j+6) + pad4(j+7) +end for + +while true + initBoard + print + print "And here is the opening position of the checkers." + printBoard + jumps = 0 + while true + fromPos = input("Jump from? ").val + if fromPos == 0 then break + toPos = input("To? ").val + print + if not isLegal(fromPos, toPos) then + print "Illegal move. Try again..." + continue + end if + board[fromPos] = 0 + board[toPos] = 1 + board[(toPos+fromPos)/2] = 0 + jumps += 1 + printBoard + end while + // End game summary + sum = board[1:].sum + print "You made " + jumps + " jumps and had " + sum + " pieces" + print "remaining on the board." + print + if askYesNo("Try again") == "no" then break +end while +print +print "O.K. Hope you had fun!!" + + \ No newline at end of file From 5192e78d9d8ac3d3616c0084628a91eaad165aef Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Fri, 15 Sep 2023 07:54:13 -0700 Subject: [PATCH 255/377] A couple tweaks to onecheck.ms. --- 00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms b/00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms index b4bfb952a..fee41c8c4 100644 --- a/00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms +++ b/00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms @@ -1,4 +1,4 @@ -print "Solitaire Checker Puzzle by david ahl" +print "Solitaire Checker Puzzle by David Ahl" print print "48 checkers are placed on the 2 outside spaces of a" print "standard 64-square checkerboard. The object is to" @@ -10,6 +10,8 @@ print "checker and '0' an empty square. When you have no" print "possible jumps remaining, input a '0' in response to" print "question 'Jump from?'" print +input "(Press Return.)" +print pad4 = function(n) return (" " + n)[-4:] From 1f76bac78eb4bd4cbb970bfece70cc2f40a7c7e2 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 15:42:23 -0700 Subject: [PATCH 256/377] Delete 00_Alternate_Languages/93_23_Matches/MiniScript. directory --- .../93_23_Matches/MiniScript./23matches.ms | 67 ------------------- .../93_23_Matches/MiniScript./README.md | 17 ----- 2 files changed, 84 deletions(-) delete mode 100644 00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms delete mode 100644 00_Alternate_Languages/93_23_Matches/MiniScript./README.md diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms b/00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms deleted file mode 100644 index 853e387d3..000000000 --- a/00_Alternate_Languages/93_23_Matches/MiniScript./23matches.ms +++ /dev/null @@ -1,67 +0,0 @@ -CR = char(13) - -print " "*31 + "23 MATCHES" -print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"+CR+CR+CR - -print "This is a game called '23 Matches'." -print -print "When it is your turn, you may take one, two, or three" -print "matches. The object of the game is not to have to take" -print "the last match." -print -print "Let's flip a coin to see who goes first." -print "If it comes up heads, I will win the toss." -print -matches = 23 -humanTurn = floor(rnd * 2) - -if humanTurn then - print "Tails! You go first." - prompt = "How many do you wish to remove? " -else - print "Heads! I win! Ha! Ha!" - print "Prepare to lose, meatball-nose!!" -end if - -choice = 2 -while matches > 0 - if humanTurn then - choice = 0 - if matches == 1 then choice = 1 - while choice == 0 - choice = input(prompt).val - if choice <1 or choice > 3 or choice > matches then - choice = 0 - print "Very funny! Dummy!" - print "Do you want to play or goof around?" - prompt = "Now, how many matches do you want? " - end if - end while - matches = matches - choice - if matches == 0 then - print "You poor boob! You took the last match! I gotcha!!" - print "Ha! Ha! I beat you !!" - print "Good bye loser!" - else - print "There are now " + matches + " matches remaining." + CR - end if - else - choice_comp = 4 - choice - if matches == 1 then - choice_comp = 1 - else if 1 < matches and matches < 4 then - choice_comp = matches - 1 - end if - matches = matches - choice_comp - if matches == 0 then - print "You won, floppy ears!" - print "Think you're pretty smart!" - print "Let's play again and I'll blow your shoes off!!" - else - print "My turn! I remove " + choice_comp + " matches" - print "The number of matches is now " + matches + CR - end if - end if - humanTurn = not humanTurn - prompt = "Your turn -- you may take 1, 2 or 3 matches." + CR + "How many do you wish to remove? " -end while diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript./README.md b/00_Alternate_Languages/93_23_Matches/MiniScript./README.md deleted file mode 100644 index 105b221f0..000000000 --- a/00_Alternate_Languages/93_23_Matches/MiniScript./README.md +++ /dev/null @@ -1,17 +0,0 @@ -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 23matches.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 "23matches" - - run From 2d7ba534b8ecf5a25a07cc8bc883ac00d328d868 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 15:43:24 -0700 Subject: [PATCH 257/377] Create 23matches.ms --- .../93_23_Matches/MiniScript/23matches.ms | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 00_Alternate_Languages/93_23_Matches/MiniScript/23matches.ms diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript/23matches.ms b/00_Alternate_Languages/93_23_Matches/MiniScript/23matches.ms new file mode 100644 index 000000000..c906eaaeb --- /dev/null +++ b/00_Alternate_Languages/93_23_Matches/MiniScript/23matches.ms @@ -0,0 +1,67 @@ +CR = char(13) + +print " "*32 + "WEEKDAY" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"+CR+CR+CR + +print "This is a game called '23 Matches'." +print +print "When it is your turn, you may take one, two, or three" +print "matches. The object of the game is not to have to take" +print "the last match." +print +print "Let's flip a coin to see who goes first." +print "If it comes up heads, I will win the toss." +print +matches = 23 +humanTurn = floor(rnd * 2) + +if humanTurn then + print "Tails! You go first." + prompt = "How many do you wish to remove? " +else + print "Heads! I win! Ha! Ha!" + print "Prepare to lose, meatball-nose!!" +end if + +choice = 2 +while matches > 0 + if humanTurn then + choice = 0 + if matches == 1 then choice = 1 + while choice == 0 + choice = input(prompt).val + if choice <1 or choice > 3 or choice > matches then + choice = 0 + print "Very funny! Dummy!" + print "Do you want to play or goof around?" + prompt = "Now, how many matches do you want? " + end if + end while + matches = matches - choice + if matches == 0 then + print "You poor boob! You took the last match! I gotcha!!" + print "Ha! Ha! I beat you !!" + print "Good bye loser!" + else + print "There are now " + matches + " matches remaining." + CR + end if + else + choice_comp = 4 - choice + if matches == 1 then + choice_comp = 1 + else if 1 < matches and matches < 4 then + choice_comp = matches - 1 + end if + matches = matches - choice_comp + if matches == 0 then + print "You won, floppy ears!" + print "Think you're pretty smart!" + print "Let's play again and I'll blow your shoes off!!" + else + print "My turn! I remove " + choice_comp + " matches" + print "The number of matches is now " + matches + CR + end if + end if + humanTurn = not humanTurn + prompt = "Your turn -- you may take 1, 2 or 3 matches." + CR + "How many do you wish to remove? " +end while From 39a170bdf1a99f4976ea414091ece5728ea0fefd Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 15:44:14 -0700 Subject: [PATCH 258/377] Add files via upload --- .../93_23_Matches/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/93_23_Matches/MiniScript/README.md diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript/README.md b/00_Alternate_Languages/93_23_Matches/MiniScript/README.md new file mode 100644 index 000000000..9156a730e --- /dev/null +++ b/00_Alternate_Languages/93_23_Matches/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 23matches.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 "23matches" + run \ No newline at end of file From ca2fc14df508501861d21f530736a7f73354676f Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 15:45:26 -0700 Subject: [PATCH 259/377] Create target.ms --- .../86_Target/MiniScript/target.ms | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 00_Alternate_Languages/86_Target/MiniScript/target.ms diff --git a/00_Alternate_Languages/86_Target/MiniScript/target.ms b/00_Alternate_Languages/86_Target/MiniScript/target.ms new file mode 100644 index 000000000..5f0c4fe43 --- /dev/null +++ b/00_Alternate_Languages/86_Target/MiniScript/target.ms @@ -0,0 +1,113 @@ +degToRad = function(n) + return n * pi / 180 +end function + +radToDeg = function(n) + return n * 180 / pi +end function + +roundDown = function(n, r) + return floor(n / r) * r +end function + +getCoord = function(distance, radX, radZ) + xc = sin(radZ)*cos(radX)*distance + yc = sin(radZ)*sin(radX)*distance + zc = cos(radZ)*distance + return [xc,yc,zc] +end function + +distanceBetween = function (d1,d2) + return ((d1[0]-d2[0])^2 + (d1[1]-d2[1])^2 + (d1[2]-d2[2])^2)^.5 +end function + +print " " * 33 + "TARGET" +print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print + +print "You are the weapons officer on the Starship Enterprise" +print "and this is a test to see how accurae a shot you" +print "are in a 3-dimensional range. You will be told" +print "the radian offset for the X and Z axes, the location" +print "of the target in 3-dimensional rectangular coordinates," +print "the approximate number of degrees from the X and Z" +print "axes, and the approximate distance to the target." +print "You will then proceed to shoot at the target until it is" +print "destroyed!" +print; print +print "Good luck!" +roundToList = [20,10,2,1] +ready = true +while ready + turns = -1 + radX = rnd * 2 * pi + radZ = rnd * 2 * pi + print "Radians from X axis = " + radX + " from Z axis = " + radZ + + distance = 100000 * rnd * rnd + coords = getCoord(distance, radX, radZ) + + print "Target sighted: Approx Coordinates (X,Y,Z) = ("+coords.join(",")+")" + + gameRunning = true + while gameRunning + turns += 1 + if turns >=4 then + estDistance = distance + else + estDistance = roundDown(distance, roundToList[turns]) + end if + + print " Estimated Distance: " + estDistance + print + tx = input ("Input angle deviation from X in degrees: ").val + tz = input ("Input angle deviation from Z in degrees: ").val + tdist = input ("Input distance: ").val + print + if tdist < 20 then + print "You blew yourself up!!" + gameRunning = false + else + tx = degToRad(tx) + tz = degToRad(tz) + + print "Radians from X-axis = " + tx + " from Z-axis = " + tz + targeted = getCoord(tdist, tx,tz) + distBet = distanceBetween(coords, targeted) + if distBet > 20 then + dx = targeted[0] - coords[0] + dy = targeted[1] - coords[1] + dz = targeted[2] - coords[2] + xMsg = {false: "Shot in front of target ", true: "Shot behind target "} + print xMsg[dx<0] + dx + " kilometers." + yMsg = {false: "Shot to left of target ", true: "Shot to right of target "} + print yMsg[dy<0] + dy + " kilometers." + zMsg = {false: "Shot above target ", true: "Shot below target "} + print zMsg[dz<0] + dz + " kilometers." + + print "Approx position of explosion + (" + targeted.join(",") + ")" + print " Distance from target = " + distBet + print + print + + else + print + print " * * * HIT * * * Target is non-functional" + print + print "Distance of explosion from target was " + distBet + "kilometers." + print + print "Mission accomplished in " + (turns+1) + " shots." + print + gameRunning = false + end if + end if + end while + print + ans = input("Ready for next target? ").lower + if ans == "" then + ready == false + else + ready = ans[0].lower == "y" + end if + print +end while From a5adab61e05c7b024e191d14736e68773962da0c Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 15:46:02 -0700 Subject: [PATCH 260/377] Add files via upload --- .../86_Target/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/86_Target/MiniScript/README.md diff --git a/00_Alternate_Languages/86_Target/MiniScript/README.md b/00_Alternate_Languages/86_Target/MiniScript/README.md new file mode 100644 index 000000000..5c4fcf0b2 --- /dev/null +++ b/00_Alternate_Languages/86_Target/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 target.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 "target" + run \ No newline at end of file From e309ec4d8ef038ef495486d0f1869f3c393b7772 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 17:04:39 -0700 Subject: [PATCH 261/377] Create synonym.ms --- .../85_Synonym/MiniScript/synonym.ms | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms diff --git a/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms b/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms new file mode 100644 index 000000000..663e55125 --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms @@ -0,0 +1,47 @@ +words = [["first", "start", "beginning", "onset", "initial"], +["similar", "alike", "same", "like", "resembling"], +["model", "pattern", "prototype", "standard", "criterion"], +["small", "insignificant", "little", "tiny", "minute"], +["stop", "halt", "stay", "arrest", "check", "standstill"], +["house", "dwelling", "residence", "domicile", "lodging", "habitation"], +["pit", "hole", "hollow", "well", "gulf", "chasm", "abyss"], +["push", "shove", "thrust", "prod","poke","butt", "press"], +["red", "rouge", "scarlet", "crimson", "flame", "ruby"], +["pain", "suffering", "hurt", "misery", "distress", "ache", "discomfort"]] + +words.shuffle + +responses = ["Right","Correct","Fine","Good!","Check"] + +print " " * 33 + "SYNONYM" +print " " * 5 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print +print "A synonym of a word means another word in the English" +print "language which has the same or very nearly the same meaning." +print "I choose a word -- you type a synonym." +print "If you can't think a synonym, type the word 'HELP'" +print "and I will tell you a synonym." +print + +for synonyms in words + word = synonyms[0] + synonyms = synonyms[1:] + responses.shuffle + + print + while 1 + guess = input(" What is a synonym of " + word + "? ").lower + if guess == "help" then + synonyms.shuffle + print "**** A synonym of " + word + " is " + synonyms[0] + "." + print + else if guess == word or synonyms.indexOf(guess) == null then + print " Try again." + else + print responses[0] + break + end if + end while +end for +print +print "Synonym drill completed." From ec8c7172c955db34f910690518282118011a2ff1 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 17:05:39 -0700 Subject: [PATCH 262/377] Add files via upload --- .../85_Synonym/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/85_Synonym/MiniScript/README.md diff --git a/00_Alternate_Languages/85_Synonym/MiniScript/README.md b/00_Alternate_Languages/85_Synonym/MiniScript/README.md new file mode 100644 index 000000000..ab7dd376a --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/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 synonym.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 "synonym" + run \ No newline at end of file From e9aed8fbe83e5f443c1daf8e8fc56085b004745f Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 17:56:22 -0700 Subject: [PATCH 263/377] Create stars.ms --- .../82_Stars/MiniScript/stars.ms | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 00_Alternate_Languages/82_Stars/MiniScript/stars.ms diff --git a/00_Alternate_Languages/82_Stars/MiniScript/stars.ms b/00_Alternate_Languages/82_Stars/MiniScript/stars.ms new file mode 100644 index 000000000..b42346220 --- /dev/null +++ b/00_Alternate_Languages/82_Stars/MiniScript/stars.ms @@ -0,0 +1,48 @@ +kMaxNum = 100 +kTries = 7 + +instructions = function + print "I am thinking of a whole number from 1 to " + kMaxNum + print "Try to guess my number. After you guess, I" + print "will output one or more stars (*). The more" + print "stars I type, the closer you are to my number." + print "One star (*) means far away, seven stars (*******)" + print "means really close! You get " + kTries + " guesses." + print +end function + +print " " * 34 + "STARS" +print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print + +ans = input("Do you want instructions? ").lower +if ans[0] == "y" then + instructions +end if + +while 1 + print + print "OK, I am thinking of a number, start guessing." + starNum = floor(rnd * kMaxNum) + 1 + try = 0 + while try < kTries + print + guess = input("Your guess: ").val + + if guess == starNum then + break + else + d = abs(guess - starNum) + print "*" * (7 - floor(log(d,2))) + end if + try += 1 + end while + + if try < kTries then + print "*" * 59 + print "You got it in " + (try + 1) + " guesses! Let's play again." + else + print "Sorry, that's " + try + " guesses. The number was " + starNum + end if + print +end while From 2249e4aed74372001068a345e0a572afbd72ef88 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 17:57:05 -0700 Subject: [PATCH 264/377] Add files via upload --- .../82_Stars/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/82_Stars/MiniScript/README.md diff --git a/00_Alternate_Languages/82_Stars/MiniScript/README.md b/00_Alternate_Languages/82_Stars/MiniScript/README.md new file mode 100644 index 000000000..bcbbd39a6 --- /dev/null +++ b/00_Alternate_Languages/82_Stars/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 stars.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 "stars" + run \ No newline at end of file From 4c0148e94fbb03467838bf6d85558272341aa4d7 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 19:01:52 -0700 Subject: [PATCH 265/377] Update synonym.ms --- 00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms b/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms index 663e55125..684482d25 100644 --- a/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms +++ b/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms @@ -14,7 +14,7 @@ words.shuffle responses = ["Right","Correct","Fine","Good!","Check"] print " " * 33 + "SYNONYM" -print " " * 5 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" print; print; print print "A synonym of a word means another word in the English" print "language which has the same or very nearly the same meaning." From da28a784ded77591865c2db9319e6e5c753eec5d Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 21:09:40 -0700 Subject: [PATCH 266/377] Create README.md --- .../73_Reverse/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/73_Reverse/MiniScript/README.md diff --git a/00_Alternate_Languages/73_Reverse/MiniScript/README.md b/00_Alternate_Languages/73_Reverse/MiniScript/README.md new file mode 100644 index 000000000..18812f302 --- /dev/null +++ b/00_Alternate_Languages/73_Reverse/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 reverse.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 "reverse" + run From 2899eebe54a7d659428d78e3bffa548a8ff242cd Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 15 Sep 2023 21:10:00 -0700 Subject: [PATCH 267/377] Add files via upload --- .../73_Reverse/MiniScript/reverse.ms | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms diff --git a/00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms b/00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms new file mode 100644 index 000000000..a83d6b107 --- /dev/null +++ b/00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms @@ -0,0 +1,71 @@ +num = 9 + +reverse = function(i) + if i == null then return i + ret = [] + for item in i + ret.insert(0,item) + end for + return ret +end function + +showRules = function + print + print "This is the game of 'Reverse'. To win, all you have" + print "to do is arrange a list of numbers (1 through " + num + ")" + print "in numerical order from left to right. To move, you" + print "tell me how many numbers (counting from the left) to" + print "reverse. For example, if the current list is:" + print; print "2 3 4 5 1 6 7 8 9" + print; print "and you reverse 4, the result will be:" + print; print "5 4 3 2 1 6 7 8 9" + print; print "Now if reverse 5, you win!" + print; print "1 2 3 4 5 6 7 8 9" + print + print "No doubt you will like this game, but" + print "if you want to quit, reverse 0 (zero)." + print + return +end function + +printState = function + print;print digits.join(" "); print +end function + +print " " * 32 + "REVERSE" +print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print +print "Reverse -- a game of skill" +print + +ans = input("Do you want the rules? ") +if ans != null and ans[0].lower == "y" then showRules + +while 1 + turns = 0 + digits = range(1, num) + digits.shuffle + print;print "Here we go ... the list is:" + while 1 + printState + amt = input("How many shall I reverse? ").val + if amt == null or amt == 0 then break + + if amt > num then + print "OOPS! Too many! I can reverse at most " + num + else + turns += 1 + digits = reverse(digits[:amt]) + digits[amt:] + end if + if digits == range(1,num) then + printState + print "You won it in " + turns + " moves!!" + break + end if + end while + print + ans = input("Try again (YES or NO)? ") + print + if ans == null or ans[0].lower == "n" then break +end while +print "O.K. Hope you had fun!!" \ No newline at end of file From 212c0445fee3dfad890493b8a2b3dd683a46f6ce Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 16 Sep 2023 13:52:40 -0700 Subject: [PATCH 268/377] Fixed some minor issues with weekday.ms. --- .../95_Weekday/MiniScript/README.md | 7 ++++--- .../95_Weekday/MiniScript/weekday.ms | 17 +++++++++++------ .../96_Word/MiniScript/README.md | 7 ++++--- 68_Orbit/README.md | 2 +- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/00_Alternate_Languages/95_Weekday/MiniScript/README.md b/00_Alternate_Languages/95_Weekday/MiniScript/README.md index c6bd62672..218cb4cc9 100644 --- a/00_Alternate_Languages/95_Weekday/MiniScript/README.md +++ b/00_Alternate_Languages/95_Weekday/MiniScript/README.md @@ -6,11 +6,12 @@ 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 weekday.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 "weekday" run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms b/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms index d32790017..fafa1bc63 100644 --- a/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms +++ b/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms @@ -1,5 +1,4 @@ TAB = char(9) -CR = char(13) Age = {"m": 0, "d": 0, "y": 0} Age.init = function(m,d,y) @@ -107,15 +106,18 @@ Date._leapYears = function end function print " "*32 + "WEEKDAY" -print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"+CR+CR+CR +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print print "WEEKDAY is a computer demonstration that" -print "gives facts about a date of interest to you."+CR +print "gives facts about a date of interest to you." +print -mdy = input("Enter today's date in the form: 3,24,1979?"+CR) +mdy = input("Enter today's date in the form: 3,24,1979? ") today = Date.init(mdy) -mdy = input("Enter day of birth (or other day of interest)"+CR) + +mdy = input("Enter day of birth (or other day of interest)? ") dob = Date.init(mdy) print @@ -139,6 +141,8 @@ age = today.diff(dob) totalAge = Age.init(age.m,age.d,age.y) if verb == " was a " then + if dob.d == today.d and dob.m == today.m then print "***HAPPY BIRTHDAY***" + lines= [["", "YEARS", "MONTHS", "DAYS"]] lines.push(["", "-----", "------", "----"]) lines.push(["Your age (if birthdate)", age.y,age.m, age.d]) @@ -174,4 +178,5 @@ if verb == " was a " then end for end if -print CR+"Yoy may retire in " + (dob.y + 65) +print +print " "*16 + "*** Yoy may retire in " + (dob.y + 65) + " ***" diff --git a/00_Alternate_Languages/96_Word/MiniScript/README.md b/00_Alternate_Languages/96_Word/MiniScript/README.md index 5e60340ab..567a84baf 100644 --- a/00_Alternate_Languages/96_Word/MiniScript/README.md +++ b/00_Alternate_Languages/96_Word/MiniScript/README.md @@ -6,11 +6,12 @@ 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 word.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 "word" run +``` \ No newline at end of file diff --git a/68_Orbit/README.md b/68_Orbit/README.md index 9e4e9afdf..be765b557 100644 --- a/68_Orbit/README.md +++ b/68_Orbit/README.md @@ -20,7 +20,7 @@ of orbit < ^ ship ``` -The distance of the bomb from the ship is computed using the law of consines. The law of cosines states: +The distance of the bomb from the ship is computed using the law of cosines. The law of cosines states: ``` D = SQUAREROOT( R**2 + D1**2 - 2*R*D1*COS(A-A1) ) From adb6ad5c948f145c4b30cc6d9cab140d940e7792 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 16 Sep 2023 14:07:10 -0700 Subject: [PATCH 269/377] Minor tweaks to 23matches.ms and weekday.ms. --- .../93_23_Matches/MiniScript/23matches.ms | 21 +++++++++++-------- .../95_Weekday/MiniScript/weekday.ms | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript/23matches.ms b/00_Alternate_Languages/93_23_Matches/MiniScript/23matches.ms index c906eaaeb..645082acf 100644 --- a/00_Alternate_Languages/93_23_Matches/MiniScript/23matches.ms +++ b/00_Alternate_Languages/93_23_Matches/MiniScript/23matches.ms @@ -1,7 +1,6 @@ -CR = char(13) - -print " "*32 + "WEEKDAY" -print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"+CR+CR+CR +print " "*31 + "23 MATCHES" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print print "This is a game called '23 Matches'." print @@ -26,11 +25,13 @@ end if choice = 2 while matches > 0 if humanTurn then + if matches < 23 then print "Your turn -- you may take 1, 2 or 3 matches." + prompt = "How many do you wish to remove? " choice = 0 if matches == 1 then choice = 1 while choice == 0 choice = input(prompt).val - if choice <1 or choice > 3 or choice > matches then + if choice < 1 or choice > 3 or choice > matches then choice = 0 print "Very funny! Dummy!" print "Do you want to play or goof around?" @@ -40,10 +41,12 @@ while matches > 0 matches = matches - choice if matches == 0 then print "You poor boob! You took the last match! I gotcha!!" - print "Ha! Ha! I beat you !!" + print "Ha ! Ha ! I beat you !!" + print print "Good bye loser!" else - print "There are now " + matches + " matches remaining." + CR + print "There are now " + matches + " matches remaining." + print end if else choice_comp = 4 - choice @@ -59,9 +62,9 @@ while matches > 0 print "Let's play again and I'll blow your shoes off!!" else print "My turn! I remove " + choice_comp + " matches" - print "The number of matches is now " + matches + CR + print "The number of matches is now " + matches + print end if end if humanTurn = not humanTurn - prompt = "Your turn -- you may take 1, 2 or 3 matches." + CR + "How many do you wish to remove? " end while diff --git a/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms b/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms index fafa1bc63..65641ebc3 100644 --- a/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms +++ b/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms @@ -179,4 +179,4 @@ if verb == " was a " then end if print -print " "*16 + "*** Yoy may retire in " + (dob.y + 65) + " ***" +print " "*16 + "*** You may retire in " + (dob.y + 65) + " ***" From 6d477470289432f0e93223aafdfe0e683e5fa0e8 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 16 Sep 2023 14:15:34 -0700 Subject: [PATCH 270/377] Tweaks to tower.ms. --- .../90_Tower/MiniScript/tower.ms | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/00_Alternate_Languages/90_Tower/MiniScript/tower.ms b/00_Alternate_Languages/90_Tower/MiniScript/tower.ms index c800314c2..a1846545a 100644 --- a/00_Alternate_Languages/90_Tower/MiniScript/tower.ms +++ b/00_Alternate_Languages/90_Tower/MiniScript/tower.ms @@ -20,18 +20,18 @@ Tower.top = function end function Game = {} -Game["towers"] = [] -Game["numOfDisks"] = 0 -Game["rangeOfDisks"] = [] -Game["selectedDisk"] = 0 -Game["selectedDiskOn"] = 0 -Game["selectedTower"] = 0 -Game["inputErrors"] = 0 -Game["turns"] = 0 +Game.towers = [] +Game.numOfDisks = 0 +Game.rangeOfDisks = [] +Game.selectedDisk = 0 +Game.selectedDiskOn = 0 +Game.selectedTower = 0 +Game.inputErrors = 0 +Game.turns = 0 Game.display = function print - for r in range(7,1,-1) + for r in range(7,1) rowstr = "" for tower in self.towers if r > tower.height then @@ -143,10 +143,10 @@ Game.move = function if 0 <= status and status <= 2 then break if status == kNotTower and self.doneWithYou then print "I tried to warn you. But you wouldn't listen." - print "By bye, big shot." + print "Bye bye, big shot." exit else if status == kNotTower then - print "I'll assume you hit the wrong ket this time. But watch it" + print "I'll assume you hit the wrong key this time. But watch it," print "I only allow one mistake." end if end while @@ -164,8 +164,8 @@ end function print " " * 33 + "TOWERS" -print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" -print;print +print " " * 15 + "Creative Computing Morristown, New Jersey" +print; print print "You must transfer the disks from the left to the right" print "tower, one at a time, never putting a larger disk on a" print "smaller disk." @@ -174,7 +174,7 @@ print ans = "Y" while ans[0].upper == "Y" while 1 - disks = input ("How many disks do you want to move (7 is MAX)? ").val + disks = input("How many disks do you want to move (7 is MAX)? ").val status = Game.init(disks) if status == false and Game.doneWithYou then print "All right, wise guy, if you can't play the game right, I'll" @@ -196,7 +196,7 @@ while ans[0].upper == "Y" print "Congratulations!" print "You performed the task in " + Game.turns + " moves." print - ans = input("Play again (Yes or No)? ") + ans = input("Play again (Yes or No)? ") + " " end while print print "Thanks for the game!" From 8e8bbfb08e226b925379feefd1ec6596a979871d Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 16 Sep 2023 14:27:21 -0700 Subject: [PATCH 271/377] Tweaks to target.ms. --- .../86_Target/MiniScript/target.ms | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/00_Alternate_Languages/86_Target/MiniScript/target.ms b/00_Alternate_Languages/86_Target/MiniScript/target.ms index 5f0c4fe43..711aa4f6e 100644 --- a/00_Alternate_Languages/86_Target/MiniScript/target.ms +++ b/00_Alternate_Languages/86_Target/MiniScript/target.ms @@ -21,8 +21,13 @@ distanceBetween = function (d1,d2) return ((d1[0]-d2[0])^2 + (d1[1]-d2[1])^2 + (d1[2]-d2[2])^2)^.5 end function +coordStr = function(coords) + return "X = " + round(coords[0]) + + " Y = " + round(coords[1]) + " Z = " + round(coords[2]) +end function + print " " * 33 + "TARGET" -print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print " " * 15 + "Creative Computing Morristown, New Jersey" print; print; print print "You are the weapons officer on the Starship Enterprise" @@ -47,7 +52,7 @@ while ready distance = 100000 * rnd * rnd coords = getCoord(distance, radX, radZ) - print "Target sighted: Approx Coordinates (X,Y,Z) = ("+coords.join(",")+")" + print "Target sighted: Approx Coordinates: " + coordStr(coords) gameRunning = true while gameRunning @@ -85,7 +90,7 @@ while ready zMsg = {false: "Shot above target ", true: "Shot below target "} print zMsg[dz<0] + dz + " kilometers." - print "Approx position of explosion + (" + targeted.join(",") + ")" + print "Approx position of explosion: " + coordStr(targeted) print " Distance from target = " + distBet print print @@ -104,10 +109,6 @@ while ready end while print ans = input("Ready for next target? ").lower - if ans == "" then - ready == false - else - ready = ans[0].lower == "y" - end if + ready = ans and ans[0].lower == "y" print end while From 60d43edb9f891d327059af8f79d36b0a280e376a Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 16 Sep 2023 14:33:11 -0700 Subject: [PATCH 272/377] Minor tweaks to target.ms and README's. --- 00_Alternate_Languages/85_Synonym/MiniScript/README.md | 9 +++++---- 00_Alternate_Languages/86_Target/MiniScript/README.md | 9 +++++---- 00_Alternate_Languages/86_Target/MiniScript/target.ms | 6 +++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/00_Alternate_Languages/85_Synonym/MiniScript/README.md b/00_Alternate_Languages/85_Synonym/MiniScript/README.md index ab7dd376a..f887013c7 100644 --- a/00_Alternate_Languages/85_Synonym/MiniScript/README.md +++ b/00_Alternate_Languages/85_Synonym/MiniScript/README.md @@ -6,11 +6,12 @@ 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 synonym.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 "synonym" - run \ No newline at end of file + run +``` diff --git a/00_Alternate_Languages/86_Target/MiniScript/README.md b/00_Alternate_Languages/86_Target/MiniScript/README.md index 5c4fcf0b2..c06194764 100644 --- a/00_Alternate_Languages/86_Target/MiniScript/README.md +++ b/00_Alternate_Languages/86_Target/MiniScript/README.md @@ -6,11 +6,12 @@ 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 target.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 "target" - run \ No newline at end of file + run +``` diff --git a/00_Alternate_Languages/86_Target/MiniScript/target.ms b/00_Alternate_Languages/86_Target/MiniScript/target.ms index 711aa4f6e..125fe2ff5 100644 --- a/00_Alternate_Languages/86_Target/MiniScript/target.ms +++ b/00_Alternate_Languages/86_Target/MiniScript/target.ms @@ -65,9 +65,9 @@ while ready print " Estimated Distance: " + estDistance print - tx = input ("Input angle deviation from X in degrees: ").val - tz = input ("Input angle deviation from Z in degrees: ").val - tdist = input ("Input distance: ").val + tx = input("Input angle deviation from X in degrees: ").val + tz = input("Input angle deviation from Z in degrees: ").val + tdist = input("Input distance: ").val print if tdist < 20 then print "You blew yourself up!!" From 3bb0d10930732b1de14b1ff56b32f368d00aab17 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 16 Sep 2023 14:49:17 -0700 Subject: [PATCH 273/377] Added MiniScript version of 68_Orbit. --- .../68_Orbit/MiniScript/README.md | 18 ++++ .../68_Orbit/MiniScript/orbit.ms | 95 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 00_Alternate_Languages/68_Orbit/MiniScript/README.md create mode 100644 00_Alternate_Languages/68_Orbit/MiniScript/orbit.ms diff --git a/00_Alternate_Languages/68_Orbit/MiniScript/README.md b/00_Alternate_Languages/68_Orbit/MiniScript/README.md new file mode 100644 index 000000000..cc0c29669 --- /dev/null +++ b/00_Alternate_Languages/68_Orbit/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 orbit.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 "orbit" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/68_Orbit/MiniScript/orbit.ms b/00_Alternate_Languages/68_Orbit/MiniScript/orbit.ms new file mode 100644 index 000000000..5c624c42b --- /dev/null +++ b/00_Alternate_Languages/68_Orbit/MiniScript/orbit.ms @@ -0,0 +1,95 @@ +print " "*33 + "Orbit" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "Somewhere above your planet is a Romulan ship." +print +print "The ship is in a constant polar orbit. Its" +print "distance from the center of your planet is from" +print "10,000 to 30,000 miles and at its present velocity can" +print "circle your planet once every 12 to 36 hours." +print +print "Unfortunately, they are using a cloaking device so" +print "you are unable to see them, but with a special" +print "instrument you can tell how near their ship your" +print "photon bomb exploded. You have seven hours until they" +print "have built up sufficient power in order to escape" +print "your planet's gravity." +print +print "Your planet has enough power to fire one bomb an hour." +print +print "At the beginning of each hour you will be asked to give an" +print "angle (between 0 and 360) and a distance in units of" +print "100 miles (between 100 and 300), after which your bomb's" +print "distance from the enemy ship will be given." +print +print "An explosion within 5,000 miles of the romulan ship" +print "will destroy it." +print; input "(Press Return.)" +print +print "Below is a diagram to help you visualize your plight." +print +print +print " 90" +print " 0000000000000" +print " 0000000000000000000" +print " 000000 000000" +print " 00000 00000" +print " 00000 xxxxxxxxxxx 00000" +print " 00000 xxxxxxxxxxxxx 00000" +print " 0000 xxxxxxxxxxxxxxx 0000" +print " 0000 xxxxxxxxxxxxxxxxx 0000" +print " 0000 xxxxxxxxxxxxxxxxxxx 0000" +print "180<== 00000 xxxxxxxxxxxxxxxxxxx 00000 ==>0" +print " 0000 xxxxxxxxxxxxxxxxxxx 0000" +print " 0000 xxxxxxxxxxxxxxxxx 0000" +print " 0000 xxxxxxxxxxxxxxx 0000" +print " 00000 xxxxxxxxxxxxx 00000" +print " 00000 xxxxxxxxxxx 00000" +print " 00000 00000" +print " 000000 000000" +print " 0000000000000000000" +print " 0000000000000" +print " 270" +print +print "x - your planet" +print "o - the orbit of the romulan ship" +print; input "(Press Return.)" +print +print "On the above diagram, the romulan ship is circling" +print "counterclockwise around your planet. Don't forget that" +print "without sufficient power the romulan ship's altitude" +print "and orbital rate will remain constant." +print +print "Good luck. The federation is counting on you." + +while true + a=floor(360*rnd) + d=floor(200*rnd + 200) + r=floor(20*rnd + 10) + for h in range(1,7) + print + print + print "This is hour " + h + ", at what angle do you wish to send" + a1 = input("your photon bomb? ").val + d1 = input("How far out do you wish to detonate it? ").val + print + print + a += r + if a >= 360 then a -= 360 + t = abs(a-a1) + if t >= 180 then t = 360 - t + c = sqrt(d*d + d1*d1 - 2*d*d1*cos(t*pi/180)) + print "Your photon bomb exploded " + round(c) + " * 10^2 miles from the" + print "Romulan ship." + if c<=50 then break + end for + if c <= 50 then + print "You have succesfully completed your mission." + else + print "You have allowed the Romulans to escape." + end if + print "Another romulan ship has gone into orbit." + yn = input("Do you wish to try to destroy it? ").lower + " " + if yn[0] != "y" then break +end while +print "good bye." From 7ce6ba6f98eeb06604e237bd280cb6ad7254699a Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 16 Sep 2023 16:56:56 -0700 Subject: [PATCH 274/377] Added MiniScript version of 69_Pizza. --- 69_Pizza/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/69_Pizza/README.md b/69_Pizza/README.md index 56548b645..7f9e3fcf2 100644 --- a/69_Pizza/README.md +++ b/69_Pizza/README.md @@ -15,6 +15,10 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- The program does no validation of its input, and crashes if you enter coordinates outside the valid range. (Ports may choose to improve on this, for example by repeating the prompt until valid coordinates are given.) + #### Porting Notes (please note any difficulties or challenges in porting here) From 1fc6618ee9e24cbc8161405a2b9539946404d6de Mon Sep 17 00:00:00 2001 From: chinhouse Date: Sat, 16 Sep 2023 19:01:14 -0700 Subject: [PATCH 275/377] Create tictactoe.ms --- .../89_Tic-Tac-Toe/MiniScript/tictactoe.ms | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe.ms diff --git a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe.ms b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe.ms new file mode 100644 index 000000000..8d472a7bb --- /dev/null +++ b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe.ms @@ -0,0 +1,90 @@ +// This program plays Tic Tac Toe +// The machine goes first and the way this is set up +// there's no way the human player can win. At best +// it will be a draw. +computerNext = function(x) + return x - 8 * floor((x - 1) / 8) +end function + +print " " * 30 + "TIC TAC TOE" +print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print + +print "The game board is numbered:" +print +print "1 2 3" +print "8 9 4" +print "7 6 5" +print + +while true + computer = 9 + gameOver = false + // MOVE ONE line 240 in original + // Computer always moves first and takes the center + print "Computer moves " + computer + player = input("Your move? ").val + playerFirstMove = player + + // MOVE TWO line 280 + // Computer's 2nd move - always the next space clockwise + // from the player's + computer = computerNext(player + 1) + canWinAt = computerNext(computer+4) + print "Computer moves " + computer + player = input("Your move? ").val + + // MOVE THREE line 300 + // Computer has two consecutive cells. This includes the + // middle so, to complete this 3-in-a-row, get the opposite + // value of comp's last move - which is four cells clockwise away. + + if player != canWinAt then + computer = canWinAt + print "Computer moves " + computer + print "... and wins ********" + gameOver = true + else + // Blocked - so two cells away from comp's last move + // line 360 + computer = computerNext(computer + 2) + print "Computer moves " + computer + end if + + if gameOver == false then + canWinAt = computerNext(computer+4) + player = input("Your move? ").val + + // MOVE FOUR - line 400 + if player != canWinAt then + computer = canWinAt + print "Computer moves " + computer + print "... and wins ********" + gameOver = true + else + // Foiled again! - line 450 + if playerFirstMove % 2 == 0 then + computer = computerNext(computer + 7) + print "Computer moves " + computer + print "... and wins ********" + gameOver = true + else // line 500 + computer = computerNext(computer + 3) + print "Computer moves " + computer + end if + end if + end if + + if gameOver == false then + // line 520 + player = input("Your move? ").val + if player != computerNext(computer + 4) then + computer = computerNext(computer + 4) + else + computer = computerNext(computer + 6) + end if + print "Computer moves " + computer + print "The game is a draw." + end if + print +end while From 01e2d0c9e3a585efedad7a0598bf16fb38e8706c Mon Sep 17 00:00:00 2001 From: chinhouse Date: Sat, 16 Sep 2023 19:02:13 -0700 Subject: [PATCH 276/377] Add files via upload --- .../89_Tic-Tac-Toe/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md diff --git a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md new file mode 100644 index 000000000..6774c0d95 --- /dev/null +++ b/00_Alternate_Languages/89_Tic-Tac-Toe/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 tictactoe.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 "tictactoe" + run \ No newline at end of file From 8a5763893a22c9de68624eab87b6079954acc8ef Mon Sep 17 00:00:00 2001 From: chinhouse Date: Sat, 16 Sep 2023 19:05:13 -0700 Subject: [PATCH 277/377] Update stars.ms --- 00_Alternate_Languages/82_Stars/MiniScript/stars.ms | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/00_Alternate_Languages/82_Stars/MiniScript/stars.ms b/00_Alternate_Languages/82_Stars/MiniScript/stars.ms index b42346220..d83d75b74 100644 --- a/00_Alternate_Languages/82_Stars/MiniScript/stars.ms +++ b/00_Alternate_Languages/82_Stars/MiniScript/stars.ms @@ -11,16 +11,16 @@ instructions = function print end function -print " " * 34 + "STARS" -print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print " " * 34 + "Stars" +print " " * 15 + "Creative Computing Morristown, New Jersey" print; print; print -ans = input("Do you want instructions? ").lower +ans = input("Do you want instructions? ").lower + " " if ans[0] == "y" then instructions end if -while 1 +while true print print "OK, I am thinking of a number, start guessing." starNum = floor(rnd * kMaxNum) + 1 From 45b18718a2664cc81e13372280368f392f5aae03 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Sat, 16 Sep 2023 19:07:52 -0700 Subject: [PATCH 278/377] Update reverse.ms --- .../73_Reverse/MiniScript/reverse.ms | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms b/00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms index a83d6b107..9d7396cf3 100644 --- a/00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms +++ b/00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms @@ -32,21 +32,21 @@ printState = function print;print digits.join(" "); print end function -print " " * 32 + "REVERSE" -print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print " " * 32 + "Reverse" +print " " * 15 + "Creative Computing Morristown, New Jersey" print; print; print print "Reverse -- a game of skill" print -ans = input("Do you want the rules? ") +ans = input("Do you want the rules? ") + " " if ans != null and ans[0].lower == "y" then showRules -while 1 +while true turns = 0 digits = range(1, num) digits.shuffle print;print "Here we go ... the list is:" - while 1 + while true printState amt = input("How many shall I reverse? ").val if amt == null or amt == 0 then break @@ -64,8 +64,8 @@ while 1 end if end while print - ans = input("Try again (YES or NO)? ") + ans = input("Try again (YES or NO)? ") + " " print - if ans == null or ans[0].lower == "n" then break + if ans == null or ans[0].lower != "y" then break end while -print "O.K. Hope you had fun!!" \ No newline at end of file +print "O.K. Hope you had fun!!" From 95e9d8b2c4c41c23ff842468d6ce055a1ab9b8a9 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 18 Sep 2023 07:58:50 -0700 Subject: [PATCH 279/377] A couple of minor tweaks to already-ported-to-MiniScript projects. --- .../59_Lunar_LEM_Rocket/MiniScript/rocket.ms | 1 + 00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms | 2 +- 70_Poetry/README.md | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms index 3bb4957fc..4131290b5 100644 --- a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms +++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms @@ -41,6 +41,7 @@ end function // Bonus little feature when running in Mini Micro: display a header bar // always at the top of the screen. drawHeaders = function + if version.hostName != "Mini Micro" then return display(2).mode = displayMode.text; td = display(2) td.color = text.color; td.backColor = color.black td.row = 25; td.column = 0 diff --git a/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms b/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms index 684482d25..c64c4f52e 100644 --- a/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms +++ b/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms @@ -14,7 +14,7 @@ words.shuffle responses = ["Right","Correct","Fine","Good!","Check"] print " " * 33 + "SYNONYM" -print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print " " * 15 + "Creative Computing Morristown, New Jersey" print; print; print print "A synonym of a word means another word in the English" print "language which has the same or very nearly the same meaning." diff --git a/70_Poetry/README.md b/70_Poetry/README.md index 7684ebecc..be21f8bee 100644 --- a/70_Poetry/README.md +++ b/70_Poetry/README.md @@ -30,4 +30,6 @@ http://www.vintage-basic.net/games.html #### Porting Notes -(please note any difficulties or challenges in porting here) +- The program begins by switching on `I`, which has not been initialized. We should probably initialize this to 0, though this means the output always begins with the phrase "midnight dreary". + +- Though the program contains an END statement (line 999), it is unreachable. The program continues to generate output until it is forcibly interrupted. From 70743baaef9c679819397ea9d7035f71667deb6e Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 18 Sep 2023 09:48:48 -0700 Subject: [PATCH 280/377] Added MiniScript implementations of 69_Pizza and 70_Poetry. --- .../69_Pizza/MiniScript/README.md | 18 ++++ .../69_Pizza/MiniScript/pizza.ms | 98 +++++++++++++++++++ .../70_Poetry/MiniScript/README.md | 18 ++++ .../70_Poetry/MiniScript/poetry.ms | 51 ++++++++++ 4 files changed, 185 insertions(+) create mode 100644 00_Alternate_Languages/69_Pizza/MiniScript/README.md create mode 100644 00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms create mode 100644 00_Alternate_Languages/70_Poetry/MiniScript/README.md create mode 100644 00_Alternate_Languages/70_Poetry/MiniScript/poetry.ms diff --git a/00_Alternate_Languages/69_Pizza/MiniScript/README.md b/00_Alternate_Languages/69_Pizza/MiniScript/README.md new file mode 100644 index 000000000..993c4056c --- /dev/null +++ b/00_Alternate_Languages/69_Pizza/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 pizza.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 "pizza" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms b/00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms new file mode 100644 index 000000000..5d52fbb77 --- /dev/null +++ b/00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms @@ -0,0 +1,98 @@ +print " "*33 + "Pizza" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "Pizza Delivery Game"; print +name = input("What is your first name? "); print +print "Hi, " + name + ". In this game you are to take orders" +print "for pizzas. Then you are to tell a delivery boy" +print "where to deliver the ordered pizzas."; print; print + +// Convert a house name like "G" into coordinates like [3,2]. +nameToCoords = function(name) + idx = name.code - "A".code + row = floor(idx / 4) + col = idx % 4 + return [col+1, row+1] +end function + +// Convert house coordinates like [3,2] into a house name like "G". +coordsToName = function(coords) + idx = (coords[1]-1)*4 + (coords[0]-1) + return char("A".code + idx) +end function + +askYesNo = function(prompt) + while true + yn = input(prompt + "? ").lower + " " + if yn[0] == "y" then return "yes" + if yn[0] == "n" then return "no" + print "'Yes' or 'no' please, now then," + end while +end function + +input "(Press Return.)"; print + +print "Map of the city of Hyattsville"; print +print " -----1-----2-----3-----4-----" +for row in range(4, 1) + print "-"; print "-"; print "-" + s = row + " " + for col in range(1, 4) + s += coordsToName([col, row]) + " " + end for + s += row + print s +end for +print "-"; print "-"; print "-" +print " -----1-----2-----3-----4-----" + +input +print "The output is a map of the homes where" +print "you are to send pizzas."; print +print "Your job is to give a truck driver" +print "the location or coordinates of the" +print "home ordering the pizza."; print +if askYesNo("Do you need more directions") == "yes" then + print; print "Somebody will ask for a pizza to be" + print "delivered. Then a delivery boy will" + print "ask you for the location."; + print " Example:" + print "This is J. Please send a pizza." + print "Driver to " + name + ". Where does j live?" + print "Your answer would be 2,3"; print + if askYesNo("Understand") == "no" then + print "This job is definitely too difficult for you. Thanks anyway" + exit + end if + print "Good. you are now ready to start taking orders."; print + print "Good luck!!"; print +end if + +while true + for turn in range(1,5) + coords = [floor(rnd*4+1), floor(rnd*4+1)] + buyer = coordsToName(coords) + print "Hello " + name + "'s Pizza. This is " + buyer + + ". Please send a pizza." + while true + while true + inp = input(" Driver to " + name + ": Where does " + buyer + " live? ") + inp = inp.replace(",", " ").replace(" ", " ") + inp = inp.split + [0,0] + guess = [inp[0].val, inp[1].val] + if 1 <= guess[0] <= 4 and 1 <= guess[1] <= 4 then break + end while + if guess == coords then + print "Hello " + name + ". This is " + buyer + ", thanks for the pizza." + break + else + print "This is " + coordsToName(guess) + ". I did not order a pizza." + print "I live at " + guess.join(",") + end if + end while + print + end for + if askYesNo("Do you want to deliver more pizzas") == "no" then break +end while + +print; print "O.K. " + name + ", see you later!"; print diff --git a/00_Alternate_Languages/70_Poetry/MiniScript/README.md b/00_Alternate_Languages/70_Poetry/MiniScript/README.md new file mode 100644 index 000000000..52effbcc2 --- /dev/null +++ b/00_Alternate_Languages/70_Poetry/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 poetry.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 "poetry" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/70_Poetry/MiniScript/poetry.ms b/00_Alternate_Languages/70_Poetry/MiniScript/poetry.ms new file mode 100644 index 000000000..7c136bbb6 --- /dev/null +++ b/00_Alternate_Languages/70_Poetry/MiniScript/poetry.ms @@ -0,0 +1,51 @@ +print ""*30 + "POETRY" +print ""*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print; print; print + +I = 0; J = 0; K = 0; U = 0 + +// Note: infinite loop. Press control-C to break. +while true + if J == 1 then + print ["MIDNIGHT DREARY", "FIERY EYES", + "BIRD OR FIEND", "THING OF EVIL", "PROPHET"][I-1], "" + else if J == 2 then + if I == 1 or I == 4 then U = 2 + if I == 3 then U = 0 + print ["BEGUILING ME", "THRILLED ME", + "STILL SITTING....", "NEVER FLITTING", "BURNED"][I-1], "" + else if J == 3 then + if U != 0 or I < 5 then + print ["AND MY SOUL", "DARKNESS THERE", + "SHALL BE LIFTED", "QUOTH THE RAVEN", "SIGN OF PARTING"][I-1], "" + end if + else if J == 4 then + print ["NOTHING MORE", "YET AGAIN", + "SLOWLY CREEPING", "...EVERMORE", "NEVERMORE"][I-1], "" + end if + if U != 0 and rnd <= 0.19 then + print ",", "" + U = 2 + end if + if rnd <= 0.65 then + print " ", "" + U += 1 + else + print + U = 0 + end if + while true + I =floor(floor(10*rnd)/2)+1 + J += 1 + K += 1 + if U == 0 and floor(J/2) == J/2 then print " ", "" + if J <= 5 then break + J = 0 + print + if K <= 20 then continue + print + U = 0 + K = 0 + break + end while +end while From 1b40ef39e174f6fd3dd9add75d11ab3c2d114106 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Tue, 19 Sep 2023 16:07:39 -0700 Subject: [PATCH 281/377] Create slots.ms --- .../80_Slots/MiniScript/slots.ms | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 00_Alternate_Languages/80_Slots/MiniScript/slots.ms diff --git a/00_Alternate_Languages/80_Slots/MiniScript/slots.ms b/00_Alternate_Languages/80_Slots/MiniScript/slots.ms new file mode 100644 index 000000000..40748e574 --- /dev/null +++ b/00_Alternate_Languages/80_Slots/MiniScript/slots.ms @@ -0,0 +1,125 @@ +center = function(s,n) + h = floor((n - s.len)/2) + s = " " * h + s + " " * n + return s[:n] +end function + +Machine = {"symbols": ["Bar", "Bell", "Orange", "Lemon", "Plum ", "Cherry"]} +Machine.money = 0 +Machine.bet = 0 +Machine.playing = true +Machine.reels = [0,0,0] +Machine.results = null + +Machine.reelsSpin = function(n, msg, row) + env = [1,.95,.9,.85,.25,.2,.15,.1,.05,0] + bell = new Sound + bell.init .1, 800, env, Sound.sineWave + for i in range(1,2) + s1 = new Sound + s1.init .2, i * 800 + 800, env, Sound.sineWave + bell.mix(s1, 1 / (2 ^ i)) + end for + for i in range(1,n) + bell.play + ix = 0 + while bell.isPlaying + text.row = row + ix = (ix + 1) % self.symbols.len + print msg + center(self.symbols[ix],8) + end while + end for +end function + +Machine.makeBet = function() + while true + bet = floor(input("Your bet? ").val) + if bet > 100 then + print "House limits are $100" + else if bet < 1 then + print "Minimum bet is $1" + else + break + end if + end while + Machine.bet = bet +end function + +Machine.pullHandle = function + if text.row < 3 then + print; print + text.row = text.row + 2 + end if + row = text.row + msg = "" + for i in range(0,2) + self.reelsSpin(5 + 5 * (i==0), msg, row) + wait .1 + symIx = floor(rnd * self.symbols.len) + msg += center(self.symbols[symIx],9) + self.reels[i] = symIx + text.row = row + print msg + end for +end function + +Machine.winnings = function + bet = Machine.bet + barIdx = self.symbols.indexOf("Bar") + numBars = 0 + multiples = 0 + for i in range(0,2) + numBars += (self.reels[i] == barIdx) + multiples += (self.reels[i] == self.reels[(i + 1) % 3]) + end for + + if numBars == 3 then return {"won": bet * 101, "msg": "***Jackpot***"} + if numBars == 2 then return {"won": bet * 6, "msg": "*Double Bar*"} + if multiples == 3 then return {"won": bet * 11, "msg": "**Top Dollar**"} + if multiples == 1 then return {"won": bet * 3, "msg": "Double!!"} + return {"won": -bet, "msg": "You lost."} +end function + +Machine.results = function + result = Machine.winnings + self.money += result.won + print result.msg + if result.won > 0 then + print "You Won!!" + end if + print "Your standings are $" + self.money + return +end function + +Machine.playAgain = function + ans = input("Again? ") + " " + self.playing = (ans[0].lower == "y") + if self.playing then return + print + if self.money < 0 then + print "Pay up! Please leave your money on the terminal." + else if self.money == 0 then + print "Hey, you broke even." + else + print "Collect your winnings from the H&M cashier." + end if +end function + +clear +print " " * 30 + "Slots" +print " " * 15 + "Creative Computing Morristown, New Jersey" +print;print;print +print "You are in the H&M Casino, in front of one of our" +print "one-arm bandits. Bet from $1 to $100." +print "to pull the arm, punch the return key after making your bet." + +print +while Machine.playing + Machine.makeBet + print + Machine.pullHandle + print + Machine.results + Machine.playAgain + print +end while From b9031ce637929db39dfcff4d9d5243ba5012299d Mon Sep 17 00:00:00 2001 From: chinhouse Date: Tue, 19 Sep 2023 16:08:09 -0700 Subject: [PATCH 282/377] Add files via upload --- .../80_Slots/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/80_Slots/MiniScript/README.md diff --git a/00_Alternate_Languages/80_Slots/MiniScript/README.md b/00_Alternate_Languages/80_Slots/MiniScript/README.md new file mode 100644 index 000000000..e8cc201ec --- /dev/null +++ b/00_Alternate_Languages/80_Slots/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 slots.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 "slots" + run \ No newline at end of file From 5f707c06274a59c10fdd495ce8ee50d1cd179bf6 Mon Sep 17 00:00:00 2001 From: amjadkofahi Date: Wed, 20 Sep 2023 14:54:04 +0300 Subject: [PATCH 283/377] Update HOW_TO_RUN_THE_GAMES.md --- HOW_TO_RUN_THE_GAMES.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md index 36061f161..06b0256c8 100644 --- a/HOW_TO_RUN_THE_GAMES.md +++ b/HOW_TO_RUN_THE_GAMES.md @@ -29,7 +29,9 @@ To run from the command line, you will need a Java SDK (eg. [Oracle JDK](https:/ 1. Navigate to the corresponding directory. 1. Compile the program with `javac`: - * eg. `javac AceyDuceyGame.java` + * eg. `**```python + javac + ```** AceyDuceyGame.java` 1. Run the compiled program with `java`: * eg. `java AceyDuceyGame` @@ -68,7 +70,7 @@ In addition to the java runtime you will need the `kotlinc` compiler, which can The pascal examples can be run using [Free Pascal](https://www.freepascal.org/). Additionally, `.lsi` project files can be opened with the [Lazarus Project IDE](https://www.lazarus-ide.org/). -The pascal examples include both *simple* (single-file) and *object-oriented* (in the `/object-pascal`directories) examples. +The pascal examples include both ___simple_ (single-file) and_o**bject-oriented_ (in the `/object-pascal`directories) examples. 1. You can compile the program from the command line with the `fpc` command. * eg. `fpc amazing.pas` @@ -92,7 +94,9 @@ The python translations can be run from the command line by using the `py` inter * eg. `python aceyducey.py` **Note** - +{ + "MD013": false +} Some translations include multiple versions for python, such as `acey ducey` which features versions for Python 2 (`aceyducey.py`) and Python 3 (`acey_ducey.py`) as well as an extra object-oriented version (`acey_ducey_oo.py`). You can manage and use different versions of python with [pip](https://pypi.org/project/pip/). From fce9a32450945fd0c467c3a638d4532e5f3b3a7a Mon Sep 17 00:00:00 2001 From: amjadkofahi Date: Wed, 20 Sep 2023 15:03:09 +0300 Subject: [PATCH 284/377] Update HOW_TO_RUN_THE_GAMES.md --- HOW_TO_RUN_THE_GAMES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md index 06b0256c8..1d25fe417 100644 --- a/HOW_TO_RUN_THE_GAMES.md +++ b/HOW_TO_RUN_THE_GAMES.md @@ -23,7 +23,7 @@ Alternatively, for non-dotnet compatible translations, you will need [Visual Stu ## java -The Java translations can be run via the command line or from an IDE such as [Eclipse](https://www.eclipse.org/downloads/packages/release/kepler/sr1/eclipse-ide-java-developers) or [IntelliJ](https://www.jetbrains.com/idea/) +The Java translations can be run via the command line or from an IDE such as [Eclipse](https://www.eclipse.org/downloads/packages/release/kepler/sr1/eclipse-ide-java-developers) or [IntelJ][def] To run from the command line, you will need a Java SDK (eg. [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) or [Open JDK](https://openjdk.java.net/)). @@ -120,3 +120,5 @@ If you don't already have Rust on your computer, you can follow the instruction 1. From the command-line, navigate to the corresponding directory. 2. Run the following command. * `cargo run` + +[def]: https://www.jetbrains.com/idea/ From 68eb34c466f7c8c88c336e363c2e339c0373640d Mon Sep 17 00:00:00 2001 From: amjadkofahi Date: Wed, 20 Sep 2023 16:20:57 +0300 Subject: [PATCH 285/377] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2243de053..62fdc5be6 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,5 @@ Cargo.lock **/*.rs.bk /target todo.md + +.fake \ No newline at end of file From 7c1e336f14f2237b36f6c1cc7eb3f40384993df9 Mon Sep 17 00:00:00 2001 From: amjadkofahi Date: Wed, 20 Sep 2023 20:42:48 +0300 Subject: [PATCH 286/377] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8efd6d4aa..878190440 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,5 @@ venv/ /target todo.md +.fake .fake \ No newline at end of file From 7db163b2f302ea70d8c518851b7224b805f6a228 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Thu, 21 Sep 2023 22:28:27 -0700 Subject: [PATCH 287/377] Create README.md --- .../81_Splat/MiniScript/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 00_Alternate_Languages/81_Splat/MiniScript/README.md diff --git a/00_Alternate_Languages/81_Splat/MiniScript/README.md b/00_Alternate_Languages/81_Splat/MiniScript/README.md new file mode 100644 index 000000000..f7d3b016b --- /dev/null +++ b/00_Alternate_Languages/81_Splat/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 splat.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 "splat" + run From 5126e835982c61d6adfe12c975f4442e13f31574 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Thu, 21 Sep 2023 22:28:49 -0700 Subject: [PATCH 288/377] Add files via upload --- .../81_Splat/MiniScript/splat.ms | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 00_Alternate_Languages/81_Splat/MiniScript/splat.ms diff --git a/00_Alternate_Languages/81_Splat/MiniScript/splat.ms b/00_Alternate_Languages/81_Splat/MiniScript/splat.ms new file mode 100644 index 000000000..befff4319 --- /dev/null +++ b/00_Alternate_Languages/81_Splat/MiniScript/splat.ms @@ -0,0 +1,133 @@ +within5pct = function(n) + return n * (1 + rnd / 20 - rnd / 20) +end function + +splatMsg = ["Requiescat in pace.", "May the Angel of Heaven lead you into Paradise.", + "Rest in piece.", "Son-Of-A-Gun.", "#$%&&%!$", + "A kick in the pants is a boost if you're headed right.", + "Hmm. Should have picked a shorter time.", "Mutter. Mutter. Mutter.", + "Pushing up daisies.", "Easy come, easy go."] + +history = [] +clear +print " " * 33 + "Splat" +print " " * 15 + "Creative Computing Morristown, New Jersey" +print;print;print +print "Welcome to 'Splat' -- the game that simulates a parachute" +print "jump. Try to open your chute at the last possible" +print "moment without going splat." +ans = "y" +while ans == "y" + print;print + + distance = floor(9001 * rnd) + 1000 + + ans = input("Select your own terminal velocity (Yes or No)? ") + " " + if ans[0].lower == "y" then + terminalVel = input("What terminal velocity (mi/hr)? ").val + else + terminalVel = floor(1000 * rnd) + print "Ok. Terminal velocity = " + terminalVel + "mi/hr" + end if + + terminalVel = terminalVel * 5280/3600 + velocity = within5pct(terminalVel) + + ans = input("Want to select acceleration due to gravity (Yes or No)? ") + " " + if ans[0].lower == "y" then + acceleration = input("What acceleration (ft/sec/sec)? ").val + acceleration = within5pct(acceleration) + else + bodies = ["Mercury", "Venus", "Earth", "the moon", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "the Sun"] + gravity = [12.2, 28.3,32.16,5.15,12.5,85.2,37.6,33.8,39.6,896] + + initialStmt = ["Fine. You're on ", "All right. You're on ", "Then you're on "] + + i = floor(rnd * 10) + acceleration = gravity[i] + stmt = initialStmt[i%3] + bodies[i] + ". Acceleration=" + acceleration + " ft/sec/sec." + print stmt + end if + + actAccel = within5pct(acceleration) + print + print " Altitude = " + distance + " ft" + print " Term. Velocity = " + terminalVel + " ft/sec +/-5%" + print " Acceleration = " + acceleration + " ft/sec/sec +/-5%" + print "Set the timer for your freefall." + sec = input("How many seconds? ").val + + print "Here we go."; print + + print "Time (sec)" + char(9) + "Dist to Fall (ft)" + print "==========" + char(9) + "=================" + termVelHit = false + for i in range(0, sec, sec/8) + sec = velocity/actAccel + if i <= sec and termVelHit == false then + dist = distance - ((actAccel/2)*i^2) + else if termVelHit == false then + termVelHit = true + print "Terminal velocity reached a T plus " + velocity/actAccel + " seconds." + end if + if termVelHit then + dist = distance - ((velocity^2/(2*actAccel))+(velocity*(i-sec))) + end if + + if dist <= 0 then break + print (" " + i + " " * 9)[:9] + char(9) + " " + dist + end for + + if dist > 0 then + print "Chute open" + history.push(dist) + numJumps = history.len + numLowerJumps = 0 + for d in history + numLowerJumps += (dist <= d) + end for + + jumpDiff = numJumps - numLowerJumps + if numJumps < 4 then + ordinal = ["1st", "2nd", "3rd"] + print "Amazing!! Not bad for your " + ordinal[numJumps-1] + " successful jump!!!" + else if jumpDiff <= numJumps * 0.10 then + print "Wow! That's some jumping. Of the " + numJumps + " successful jumps" + print "before yours, only " + jumpDiff + " opened their chutes lower than" + print "you did." + else if jumpDiff <= numJumps * 0.25 then + print "Pretty good! " + numJumps + " successful jumps preceded yours and only" + print jumpDiff + " of them got lower than you did before their chute" + print "opened." + else if jumpDiff <= numJumps * 0.50 then + print "Not bad. There have been " + numJumps + " successful jumps before yours." + print "You were beaten out by " + jumpDiff + " of them." + else if jumpDiff <= numJumps * 0.75 then + print "Conservative, aren't you? You ranked only " + jumpDiff + " in the" + print numJumps + " successful jumps before yours." + else if jumpDiff <= numJumps * 0.90 then + print "Humph! Don't you have any sporting blood? There were" + print numJumps + " successful jumps before yours and you came in " + numLowerJumps + " jumps" + print "better than the worst. Shape up!!!" + else + print "Hey! You pulled the rip code much too soon. " + numJumps + " successful" + print "jumps before yours and you came in number " + jumpDiff + "! Get with it." + end if + else if dist <= 0 and not termVelHit then + print (2 * distance / actAccel) ^ .5 + " " * 5 + "Splat" + else if dist <= 0 and termVelHit then + print velocity/actAccel + ((distance - (velocity^2/(2*actAccel)))/velocity) + " " *5 + "Splat" + end if + + if dist <=0 then + splatMsg.shuffle + print splatMsg[0] + print "I'll give you another chance." + end if + + ans = input("Do you want to play again? ") + " " + ans = ans[0].lower +end while + +print "S" * 10 +print \ No newline at end of file From 7e3fe0279e93142398a020077390584ba3ed9784 Mon Sep 17 00:00:00 2001 From: chinhouse Date: Fri, 22 Sep 2023 22:34:39 -0700 Subject: [PATCH 289/377] Add tictactoe2.ms --- .../89_Tic-Tac-Toe/MiniScript/tictactoe2.ms | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe2.ms diff --git a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe2.ms b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe2.ms new file mode 100644 index 000000000..20981ab08 --- /dev/null +++ b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe2.ms @@ -0,0 +1,155 @@ +solutions = [[0,1,2],[3,4,5],[6,7,8]] +solutions += [[0,3,6],[1,4,7],[2,5,8]] +solutions += [[0,4,8],[2,4,6]] + +TicTacToe = {} +TicTacToe.grid = (" " * 9).split("") +TicTacToe.markers = {true: "X",false:"O"} +TicTacToe.AI = "X" +TicTacToe.human = "O" +TicTacToe.next = "X" +TicTacToe.lastMove = -1 + +TicTacToe.show = function + print " " + self.grid[0:3].join(" ! ") + print "---+---+---" + print " " + self.grid[3:6].join(" ! ") + print "---+---+---" + print " " + self.grid[6:].join(" ! ") + print + print +end function + +TicTacToe.set = function(player, pos) + if self.grid[pos] != " " then + return false + end if + self.grid[pos] = player + self.lastMove = pos + return true +end function + +TicTacToe.setMarkers = function(mark) + self.human = self.markers[mark == "X"] + self.AI = self.markers[mark == "O"] +end function + +TicTacToe.getWinner = function + for mark in self.markers.values + for solution in solutions + cnt = 0 + for i in solution + cnt += (self.grid[i] == mark) + end for + if cnt == 3 then return mark + end for + end for + return null +end function + +TicTacToe.potentialWins = function + potential = {"X": [], "O": []} + for mark in self.markers.values + for solution in solutions + cnt = 0 + emptyCells = [] + for i in solution + cnt += (self.grid[i] == mark) + if self.grid[i] == " " then emptyCells.push(i) + end for + if cnt == 2 and emptyCells.len == 1 then potential[mark].push(emptyCells[0]) + end for + end for + return potential +end function + +TicTacToe.moveAvailable = function + return self.grid.indexOf(" ") != null +end function + +TicTacToe.selectAI = function + if self.grid[4] == " " then return 4 + + potential = self.potentialWins + + AIWins = potential[self.AI] + if AIWins.len >0 then return AIWins[0] + + HumanWins = potential[self.human] + + if HumanWins.len > 0 then return HumanWins[0] + + if [1,3,5,7].indexOf(self.lastMove) != null then + for corner in [8,6,2,0] + if self.grid[corner] == " " then + self.grid[corner] = self.AI + potential = self.potentialWins + self.grid[corner] = " " + AIWins = potential[self.AI] + if AIWins.len > 0 then return corner + end if + end for + else + for side in [1,3,5,7] + if self.grid[side] == " " then + self.grid[side] = self.AI + potential = self.potentialWins + self.grid[side] = " " + AIWins = potential[self.AI] + if AIWins.len > 0 then return side + end if + end for + end if + for ix in range(0,8) + if self.grid[ix] == " " then return ix + end for + + return null +end function + +print " " * 15 + "Creative Computing Morristown, New Jersey" +print; print; print +print "The board is numbered." +print; print; print +print " 1 2 3" +print " 4 5 6" +print " 7 8 9" +print +ans = input("Do you want to 'X' or 'O'? ") +if ans.upper != "X" then ans = "O" +TicTacToe.setMarkers(ans.upper) +winner = null +print +while TicTacToe.moveAvailable and winner == null + + if TicTacToe.next == TicTacToe.AI then + move = TicTacToe.selectAI + TicTacToe.set(TicTacToe.AI, move) + TicTacToe.next = TicTacToe.human + print "The computer moves to..." + else + move = input("Where do you move? ").val + if move < 1 or move > 9 then + print "Thanks for the game." + exit + else if not TicTacToe.set(TicTacToe.human, move-1) then + print "That square is occupied." + print + continue + else + TicTacToe.next = TicTacToe.AI + end if + end if + + TicTacToe.show + winner = TicTacToe.getWinner +end while + +if winner == null then + print "It's a draw. Thank you." +else if winner == TicTacToe.AI then + print "I win, turkey!!" +else + print "You beat me! Good game!" +end if + From e40ed4e55d603cd9b19eaa6dab5bb897b699c471 Mon Sep 17 00:00:00 2001 From: RFigCon Date: Mon, 25 Sep 2023 02:49:58 +0100 Subject: [PATCH 290/377] train in Lua and D --- 00_Alternate_Languages/91_Train/D/README.md | 3 ++ 00_Alternate_Languages/91_Train/D/train.d | 50 +++++++++++++++++ 91_Train/lua/train.lua | 59 +++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 00_Alternate_Languages/91_Train/D/README.md create mode 100644 00_Alternate_Languages/91_Train/D/train.d create mode 100644 91_Train/lua/train.lua diff --git a/00_Alternate_Languages/91_Train/D/README.md b/00_Alternate_Languages/91_Train/D/README.md new file mode 100644 index 000000000..6c77f0a9e --- /dev/null +++ b/00_Alternate_Languages/91_Train/D/README.md @@ -0,0 +1,3 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://dlang.org). \ No newline at end of file diff --git a/00_Alternate_Languages/91_Train/D/train.d b/00_Alternate_Languages/91_Train/D/train.d new file mode 100644 index 000000000..b4e595a0b --- /dev/null +++ b/00_Alternate_Languages/91_Train/D/train.d @@ -0,0 +1,50 @@ +import std.stdio; +import std.random : uniform; + +float abs(float num) { + if(num<0){ + return num*-1; + } + + return num; +} + +void main() { + + writeln("\nTIME - SPEED DISTANCE EXERCISE"); + + bool keep_playing = true; + float error_margin = 5.0; + + while(keep_playing){ + int car_speed = uniform!"[]"(40,65); //Random number between 40 and 65 + int delta_time = uniform!"(]"(4,20); //Between 5 and 20 + int train_speed = uniform!"[)"(20,40); //Between 20 and 39; This is the default if not specified: uniform(x,y) + + writeln("\nA CAR TRAVELING AT ", car_speed, " MPH CAN MAKE A CERTAIN TRIP IN ", delta_time, + " HOURS LESS THAN A TRAIN TRAVELING AT ", train_speed, "MPH." ); + + float input; + write("HOW LONG DOES THE TRIP TAKE BY CAR? "); + readf!"%f\n"(input); + + float car_time = cast(float)delta_time * train_speed / (car_speed - train_speed); + int percent = cast(int)( abs(car_time-input) * 100 / car_time + .5); + + if(percent > error_margin){ + writeln("SORRY. YOU WERE OFF BY ", percent, " PERCENT."); + }else{ + writeln("GOOD! ANSWER WITHIN ", percent, " PERCENT."); + } + writeln("CORRECT ANSWER IS ", car_time, " HOURS."); + + string answer; + write("\nANOTHER PROBLEM (YES OR NO)? "); + readf!"%s\n"(answer); + + if( !(answer == "YES" || answer == "Y" || answer == "yes" || answer == "y") ){ + keep_playing = false; + } + } + +} \ No newline at end of file diff --git a/91_Train/lua/train.lua b/91_Train/lua/train.lua new file mode 100644 index 000000000..0d11e73c6 --- /dev/null +++ b/91_Train/lua/train.lua @@ -0,0 +1,59 @@ +print [[ + TRAIN + CREATIVE COMPUTING MORRISTOWN, NEW JERSY + + + + TIME - SPEED DISTANCE EXERCISE]] + +math.randomseed(os.time()) + +local error_margin = 5.0 + +function play() + local car_speed = math.random(40, 65) + local delta_time = math.random(5, 20) + local train_speed = math.random(20, 39) + + print( string.format("\nA CAR TRAVELING AT %u MPH CAN MAKE A CERTAIN TRIP IN %u HOURS LESS THAN A TRAIN TRAVELING AT %u MPH.", car_speed, delta_time, train_speed) ) + + local try = true + local input + while try do + io.write("HOW LONG DOES THE TRIP TAKE BY CAR? ") + input = io.read("n") + if input == nil then + print("PLEASE INSERT A NUMBER") + else + try = false + end + io.read() + end + + local car_time = delta_time * train_speed / (car_speed - train_speed) + local percent = ( math.abs(car_time-input) * 100 / car_time + .5) + + if percent > error_margin then + print( string.format("SORRY. YOU WERE OFF BY %f PERCENT.", percent) ) + else + print( string.format("GOOD! ANSWER WITHIN %f PERCENT.", percent) ) + end + + print( string.format("CORRECT ANSWER IS %f HOURS.", car_time) ) +end + +function game_loop() + local keep_playing = true + while keep_playing do + play() + io.write("\nANOTHER PROBLEM (YES OR NO)? ") + answer = io.read("l") + + if not (answer == "YES" or answer == "Y" or answer == "yes" or answer == "y") then + keep_playing = false + end + end + +end + +game_loop() \ No newline at end of file From 75b0ce9c46da2b1ae90112a3df5995315ba15a58 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 30 Sep 2023 17:02:12 -0700 Subject: [PATCH 291/377] Added MiniScript implementation of 71_Poker. --- .../70_Poetry/MiniScript/poetry.ms | 4 +- .../71_Poker/MiniScript/README.md | 18 + .../71_Poker/MiniScript/poker.ms | 557 ++++++++++++++++++ 71_Poker/README.md | 11 + 4 files changed, 588 insertions(+), 2 deletions(-) create mode 100644 00_Alternate_Languages/71_Poker/MiniScript/README.md create mode 100644 00_Alternate_Languages/71_Poker/MiniScript/poker.ms diff --git a/00_Alternate_Languages/70_Poetry/MiniScript/poetry.ms b/00_Alternate_Languages/70_Poetry/MiniScript/poetry.ms index 7c136bbb6..f55d32901 100644 --- a/00_Alternate_Languages/70_Poetry/MiniScript/poetry.ms +++ b/00_Alternate_Languages/70_Poetry/MiniScript/poetry.ms @@ -1,5 +1,5 @@ -print ""*30 + "POETRY" -print ""*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +print " "*30 + "POETRY" +print " "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" print; print; print I = 0; J = 0; K = 0; U = 0 diff --git a/00_Alternate_Languages/71_Poker/MiniScript/README.md b/00_Alternate_Languages/71_Poker/MiniScript/README.md new file mode 100644 index 000000000..95144dcfd --- /dev/null +++ b/00_Alternate_Languages/71_Poker/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 poker.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 "poker" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/71_Poker/MiniScript/poker.ms b/00_Alternate_Languages/71_Poker/MiniScript/poker.ms new file mode 100644 index 000000000..b367db031 --- /dev/null +++ b/00_Alternate_Languages/71_Poker/MiniScript/poker.ms @@ -0,0 +1,557 @@ +print " "*33 + "POKER" +print " "*15 + "Creative Computing Morristown, New Jersey" +print; print; print + +print "Welcome to the casino. We each have $200." +print "I will open the betting before the draw; you open after." +print "To fold bet 0; to check bet .5." +print "Enough talk -- let's get down to business." +print + +askYesNo = function(prompt) + while true + yn = input(prompt + "? ").lower + " " + if yn[0] == "y" then return "yes" + if yn[0] == "n" then return "no" + print "Answer yes or no, please." + end while +end function +askNumber = function(prompt, maxQty=3, minQty=1, maxErr=null, minErr=null) + while true + value = input(prompt + "? ").val + if minQty <= value <= maxQty then return value + if value < minQty and minErr != null then + print minErr + else if maxErr != null then + print maxErr + else + print "Enter a value between " + minQty + " and " + maxQty + ", please." + end if + end while +end function +random = function(n) + return floor(n * rnd) +end function +rand10 = function + return floor(10 * rnd) +end function +pad = function(s, width) + return s + " " * (width - s.len) +end function + +// Bonus little feature when running in Mini Micro: display a header bar +// always at the top of the screen, showing current balances. Does nothing +// on other platforms. +drawHeaders = function + if version.hostName != "Mini Micro" then return + display(2).mode = displayMode.text; td = display(2) + td.color = color.black; td.backColor = text.color + td.row = 25; td.column = 0 + td.print pad("Computer: $" + computer.balance, 25) + + pad("Table: $" + Table.pot, 25) + + pad("Player: $" + human.balance, 18) +end function + + +// Card class: represents a single playing card +Card = {} +Card.rank = 0 // from 2 to 14 (Ace) +Card.suit = "Clubs" +Card.keep = false // temp flag, used to note which cards to keep vs. discard +Card.make = function(rank, suit) + result = new Card + result.rank = rank + result.suit = suit + return result +end function +Card.rankStr = function(plural=false) + if self.rank > 10 then + return ["Jack", "Queen", "King", "Ace"][self.rank-11] + "s"*plural + else + return str(self.rank) + "'s" * plural + end if +end function +Card.str = function + return self.rankStr + " of " + self.suit +end function + +// Prepare a standard deck of 52 cards, and functions to draw and discard +deck = [] +for suit in ["Clubs", "Diamonds", "Hearts", "Spades"] + for rank in range(2, 14) + deck.push Card.make(rank, suit) + end for +end for +deck.shuffle +discardPile = [] +drawCard = function + if not deck then + globals.deck = discardPile + deck.shuffle + globals.discardPile = [] + end if + return deck.pop +end function +discard = function(cardOrCards) + if cardOrCards isa Hand then + globals.discardPile += cardOrCards.cards + else if cardOrCards isa list then + globals.discardPile += cardOrCards + else + discardPile.push cardOrCards + end if +end function + +// Hand ranks: how we compare Poker hands +HandRank = {} +HandRank.value = 0 +HandRank.str = function(highCard); return ""; end function +HandRank.make = function(value) + result = new HandRank + result.value = value + return result +end function + +HandRank.None = new HandRank +HandRank.Schmaltz = HandRank.make(1) +HandRank.Schmaltz.str = function(c); return "schmaltz, " + c.rankStr + " high"; end function +HandRank.PartialStraight = HandRank.make(2) +HandRank.PartialStraight.str = function(c); return ""; end function // (no display string; this is used only internally) +HandRank.Pair = HandRank.make(3) +HandRank.Pair.str = function(c); return "a pair of " + c.rankStr(true); end function +HandRank.TwoPair = HandRank.make(4) +HandRank.TwoPair.str = function(c); return "two pair, " + c.rankStr(true); end function +HandRank.Three = HandRank.make(5) +HandRank.Three.str = function(c); return "three " + c.rankStr(true); end function +HandRank.Straight = HandRank.make(6) +HandRank.Straight.str = function(c); return "straight, " + c.rankStr + " high"; end function +HandRank.Flush = HandRank.make(7) +HandRank.Flush.str = function(c); return "a flush in " + c.suit; end function +HandRank.FullHouse = HandRank.make(8) +HandRank.FullHouse.str = function(c); return "full house, " + c.rankStr(true); end function +HandRank.Four = HandRank.make(9) +HandRank.Four.str = function(c); return "four " + c.rankStr(true); end function +// Note: original code does not detect a straight flush or royal flush. + +// Hand: represents a set of cards in the hand of one player. +Hand = {} +Hand.cards = null // list of Card +Hand.rank = null // HandRank instance +Hand.highCard = null // reference to which (of self.cards) determines relative value +Hand.afterDraw = false // true if we've already had a chance to draw cards +Hand.make = function(cards) + result = new Hand + result.cards = cards + result.analyze + return result +end function +Hand.deal = function + return Hand.make([drawCard, drawCard, drawCard, drawCard, drawCard]) +end function +Hand.replaceCard = function(index) + discard self.cards[index] + self.cards[index] = drawCard +end function +Hand.rankStr = function + return self.rank.str(self.highCard) +end function +Hand.isWeak = function + return self.rank.value < HandRank.PartialStraight.value or + (self.rank.value == HandRank.PartialStraight.value and self.afterDraw) or + (self.rank <= HandRank.TwoPair.value and self.highCard.rank <= 6) +end function +Hand.beats = function(other) + if self.rank.value > other.rank.value then return true + if self.rank.value < other.rank.value then return false + return self.highCard.rank > other.highCard.rank +end function +Hand.print = function(startingNumber=1) + num = startingNumber + for c in self.cards + s = " " * (num < 10) + num + " -- " + c.str + print " " + s, "" + if num % 2 == 0 then + print + else + print " " * (28-s.len), "" + end if + num += 1 + end for + if num % 2 == 0 then print +end function +Hand.analyze = function + allSameSuit = true + for i in range(1, self.cards.len-1) + if self.cards[i].suit != self.cards[0].suit then allSameSuit = false + end for + if allSameSuit then + self.rank = HandRank.Flush + self.highCard = self.cards[0] + return + end if + + sortedCards = self.cards[:] + sortedCards.sort "rank" + self.rank = HandRank.Schmaltz + for c in sortedCards; c.keep = false; end for + keepAny = false + + for i in range(0, sortedCards.len-2) + matchesNextCard = (sortedCards[i].rank == sortedCards[i+1].rank) + if matchesNextCard then + self.highCard = sortedCards[i] + matchesPrevCard = (i > 0 and sortedCards[i].rank == sortedCards[i-1].rank) + sortedCards[i].keep = true + sortedCards[i+1].keep = true + keepAny = true + if self.rank.value < HandRank.Pair.value then + self.rank = HandRank.Pair + else if matchesPrevCard and self.rank == HandRank.Pair then + self.rank = HandRank.Three + else if self.rank == HandRank.Pair then + self.rank = HandRank.TwoPair + else if self.rank == HandRank.TwoPair then + self.rank = HandRank.FullHouse + else if matchesPrevCard then + self.rank = HandRank.Four + else + self.rank = HandRank.FullHouse + end if + end if + end for + if not keepAny then + if sortedCards[3].rank - sortedCards[0].rank == 3 then + for i in range(0,3); sortedCards[i].keep = true; end for + self.rank = HandRank.PartialStraight + end if + if sortedCards[4].rank - sortedCards[1].rank == 3 then + if self.rank == HandRank.PartialStraight then + self.rank = HandRank.Straight + sortedCards[4].keep = true + self.highCard = sortedCards[4] + else + self.rank = HandRank.PartialStraight + for i in range(1,4); sortedCards[i].keep = true; end for + end if + end if + end if + if self.rank == HandRank.Schmaltz then + self.highCard = sortedCards[4] + sortedCards[4].keep = true + sortedCards[3].keep = true + end if + +end function + +// Some global constants, just to make the code more understandable +Ante = 5 + +// Player -- base class for computer and human +Player = {} +Player.balance = 200 +Player.hand = null +Player.totalBet = 0 +Player.anteUp = function + self.balance -= Ante + return Ante +end function +Player.newHand = function + if self.hand then discard self.hand + self.hand = Hand.deal + self.totalBet = 0 +end function +Player.addToPot = function(amount) + self.balance -= amount + Table.pot += amount + drawHeaders +end function +Player.win = function + self.balance += Table.pot + Table.pot = 0 + drawHeaders +end function + +// strategies the computer player might employ +Strategy = {} +Strategy.make = function(name, value=2, drawCount=null) + result = new Strategy + result.name = name + result.value = value + result.drawCount = drawCount + return result +end function +Strategy.fold = Strategy.make("FOLD") +Strategy.check = Strategy.make("CHECK") +Strategy.raise = Strategy.make("RAISE", 2) +Strategy.bluff = function(value, drawCount); return Strategy.make("BLUFF", value, drawCount); end function +Strategy.bet = function(value); return Strategy.make("BET", value); end function + +// computer player +computer = new Player +computer.strategy = null +computer.newHand = function + super.newHand + if self.hand.isWeak then + if rand10 < 2 then + self.strategy = Strategy.bluff(23, 2) + else if rand10 < 2 then + self.strategy = Strategy.bluff(23, 1) + else if rand10 < 1 then + self.strategy = Strategy.bluff(23, 0) + else + self.strategy = Strategy.fold + end if + else if self.hand.rank.value < HandRank.Three.value then + if rand10 < 2 then self.strategy = Strategy.bluff(23, null) else self.strategy = Strategy.check + else if self.hand.rank.value < HandRank.FullHouse.value then + self.strategy = Strategy.bet(35) + else + if rand10 < 1 then self.strategy = Strategy.bet(35) else self.strategy = Strategy.raise + end if +end function +computer.bet = function(minBet=1, openingBet=false) + //print "My hand: "; self.hand.print; print "Strategy: " + self.strategy + if self.balance < minBet then + print "I fold." + return 0 + end if + if openingBet and (self.strategy == Strategy.check or self.strategy == Strategy.fold) then + print "I check." + return 0.5 + else if self.strategy == Strategy.fold and human.totalBet > 5 then + print "I fold." + return 0 + else if self.strategy == Strategy.check then + print "I'll see you." + return minBet + else if openingBet then + result = self.strategy.value + rand10 + if result > self.balance then result = self.balance + if result == 0 then + print "I check." + return 0.5 + end if + print "I'll open with $" + result + return result + else + bet = self.strategy.value + rand10 + if self.strategy == Strategy.raise then bet += minBet + if bet > self.balance then bet = self.balance + raise = bet - minBet + if raise <= 0 then + print "I'll see you." + return minBet + else + print "I'll see you, and raise you " + raise + return bet + end if + end if +end function +computer.drawCards = function + //print "My hand:"; self.hand.print + drawCount = 0 + for c in self.hand.cards; if not c.keep then drawCount += 1; end for + print "I am taking " + drawCount + " card" + "s" * (drawCount != 1) + for i in self.hand.cards.indexes + if not self.hand.cards[i].keep then self.hand.replaceCard i + end for + self.hand.analyze + //print "My new hand: "; self.hand.print + if self.strategy.name == "BLUFF" then + self.strategy = Strategy.bluff(28) + else if self.hand.isWeak then + self.strategy = Strategy.fold + else if self.hand.rank.value < HandRank.Three.value then + if rand10 == 0 then self.strategy = Strategy.bet(19) else self.strategy = Strategy.raise + else if self.hand.rank.value < HandRank.FullHouse.value then + if rand10 == 0 then self.strategy = Strategy.bet(11) else self.strategy = Strategy.bet(19) + else + self.strategy = Strategy.raise + end if +end function +computer.win = function + print; print "I win." + super.win +end function +computer.checkFunds = function + if self.balance >= Ante then return + if human.balance < 50 then return // BUGFIX + if human.hasWatch or askYesNo("Would you like to buy back your watch for $50") == "no" then + print "I'm busted. Conglatulations!" + exit + end if + self.balance += 50 + // Note: original BASIC code does not take money from the player, but let's fix that: + human.balance -= 50 // BUGFIX + human.hasWatch = true + drawHeaders +end function + + +human = new Player +human.hasWatch = true +human.bet = function(minBet=1, openingBet=false) + while true + betStr = input("What is your bet? ") + bet = betStr.val + if bet == 0 and betStr != "0" then + print "Enter 0 to fold, 0.5 to check, or a value of 1 or more to bet." + continue + else if bet == 0.5 and openingBet then + return bet // (check) + else if 0 < bet < 1 then + print "No small change, please." + continue + else if bet < minBet then + print "If you can't see my bet, then fold." + continue + else if bet > self.balance then + print "You can't bet with what you haven't got." + self.trySellWatch + continue + end if + return bet + end while +end function +human.drawCards = function + qty = askNumber("How many cards do you want", 3, 0, "You can't draw more than three cards.") + if qty == 0 then return + print "What are their numbers: " + for i in range(1, qty) + num = askNumber("", 5, 1) + self.hand.replaceCard num - 1 + end for + print "Your new hand:" + self.hand.print + self.hand.analyze +end function +human.win = function + print; print "You win." + super.win +end function +human.checkFunds = function + if self.balance < Ante then self.trySellWatch + if self.balance < Ante then + print "Your wad is shot. So long, sucker!" + exit + end if +end function +human.trySellWatch = function + if not self.hasWatch then return + if rand10 < 7 then + value = 75 + msg = "I'll give you $" + value + " for it." + else + value = 25 + msg = "That's a pretty crummy watch - I'll give you $" + value + "." + end if + if computer.balance < value then return // BUGFIX + if askYesNo("Would you like to sell your watch") == "no" then return + print msg + self.balance += value + self.hasWatch = false + // Note: the original BASIC program does not actually take any money from the computer. + // But let's do it right here: + computer.balance -= value // BUGFIX + drawHeaders +end function + +Table = {} +Table.pot = 0 + + +deal = function + Table.pot += computer.anteUp + human.anteUp + drawHeaders + computer.newHand + human.newHand +end function + +// Do a round of betting. Return true to continue, or false +// if either player folds (ending the hand). +takeBets = function(computerFirst) + if computerFirst then + bet = computer.bet(1, true) + if bet == 0 then + human.win + return false + end if + if bet == 0.5 then bet = 0 // "check" (no bet, but stay in the hand) + computer.addToPot bet + else + bet = 0 + end if + raise = bet + canCheck = (bet == 0) + while true + bet = human.bet(raise, canCheck) + if bet == 0 then + computer.win + return false + end if + if bet == 0.5 then // (checked) + if computerFirst then return true + bet = 0 + else + human.addToPot bet + raise = bet - raise + if raise == 0 then return true + end if + if computerFirst or bet > 0 then canCheck = false + + bet = computer.bet(raise, canCheck) + if bet == 0 then + human.win + return false + end if + if bet == 0.5 then return true // (checked) + canCheck = false + computer.addToPot bet + raise = bet - raise + if raise == 0 then return true + end while +end function + +playHand = function + print + computer.checkFunds + human.checkFunds + print "The ante is " + Ante + ". I will deal:" + print + + deal + + print "Your hand:" + human.hand.print + + print + if not takeBets(true) then return + + print; print "Now we draw -- ", "" + human.drawCards + computer.drawCards + + if not takeBets(false) then return + + print; print "Now we compare hands:" + print "My hand:" + computer.hand.print 6 + print + print "You have " + human.hand.rankStr + print "I have " + computer.hand.rankStr + if computer.hand.beats(human.hand) then + computer.win + else if human.hand.beats(computer.hand) then + human.win + else + print "The hand is drawn." + print "All $" + Table.pot + " remains in the pot." + end if +end function + +drawHeaders +while true + playHand + print "Now I have $" + computer.balance + " and you have $" + human.balance + if askYesNo("Do you wish to continue") == "no" then break +end while \ No newline at end of file diff --git a/71_Poker/README.md b/71_Poker/README.md index a80820598..08bc04c63 100644 --- a/71_Poker/README.md +++ b/71_Poker/README.md @@ -15,6 +15,17 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- If you bet more than the computer has, it will still see you, resulting in a negative balance. (To handle this properly, the computer would need to go "all in" and reduce your bet to an amount it can match; or else lose the game, which is what happens to the human player in the same situation.) + +- If you are low on cash and sell your watch, then make a bet much smaller than the amount you just gained from the watch, it sometimes nonetheless tells you you "blew your wad" and ends the game. + +- When the watch is sold (in either direction), the buyer does not actually lose any money. + +- The code in the program about selling your tie tack is unreachable due to a logic bug. + + #### Porting Notes (please note any difficulties or challenges in porting here) From 22e011349c46545f6b905391c460609ea951ce46 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sun, 1 Oct 2023 15:38:34 -0700 Subject: [PATCH 292/377] Added MiniScript versions of 72_Queen and 74_Rock_Scissors_Paper. --- .../72_Queen/MiniScript/README.md | 18 +++ .../72_Queen/MiniScript/queen.ms | 151 ++++++++++++++++++ .../MiniScript/README.md | 21 +++ .../MiniScript/rockscissors.ms | 40 +++++ 4 files changed, 230 insertions(+) create mode 100644 00_Alternate_Languages/72_Queen/MiniScript/README.md create mode 100644 00_Alternate_Languages/72_Queen/MiniScript/queen.ms create mode 100644 00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/README.md create mode 100644 00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/rockscissors.ms diff --git a/00_Alternate_Languages/72_Queen/MiniScript/README.md b/00_Alternate_Languages/72_Queen/MiniScript/README.md new file mode 100644 index 000000000..cf8463343 --- /dev/null +++ b/00_Alternate_Languages/72_Queen/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 queen.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 "queen" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/72_Queen/MiniScript/queen.ms b/00_Alternate_Languages/72_Queen/MiniScript/queen.ms new file mode 100644 index 000000000..d3e882b91 --- /dev/null +++ b/00_Alternate_Languages/72_Queen/MiniScript/queen.ms @@ -0,0 +1,151 @@ +print " "*33 + "QUEEN" +print " "*15 + "Creative Computing Morristown New Jersey" +print; print; print + +getYesNo = function(prompt) + while true + inp = input(prompt + "? ").lower + " " + if inp[0] == "y" then return "yes" + if inp[0] == "n" then return "no" + print "Please answer 'yes' or 'no'." + end while +end function + +printDirections = function + print "We are going to play a game based on one of the chess" + print "moves. Our queen will be able to move only to the left " + print "down or diagonally down and to the left." + print + print "The object of the game is to place the queen in the lower" + print "left hand square by alternating moves between you and the" + print "computer. The first one to place the queen there wins." + print + print "You go first and place the queen in any one of the squares" + print "on the top row or right hand column." + print "That will be your first move." + print "We alternate moves." + print "You may forfeit by typing '0' as your move." + print "Be sure to press the return key after each response." + print + input "(Press Return to continue.)" + print +end function + +printCoordinates = function + // Porting note: I cannot imagine what possessed the original author to + // use such a crazy numbering scheme, which is not easy for the human + // player OR the code. But assumptions about it are scattered throughout + // the whole program, so we're stuck with it. + print + print " 81 71 61 51 41 31 21 11" + print " 92 82 72 62 52 42 32 22" + print " 103 93 83 73 63 53 43 33" + print " 114 104 94 84 74 64 54 44" + print " 125 115 105 95 85 75 65 55" + print " 136 126 116 106 96 86 76 66" + print " 147 137 127 117 107 97 87 77" + print " 158 148 138 128 118 108 98 88" + print +end function + +getStartPos = function + while true + m1 = input("Where would you like to start? ").val + tens = floor(m1/10) + ones = m1 % 10 + if ones == 1 or tens == ones or m1 == 0 then return m1 + print "Please read the directions again." + print "You have begun illegally." + print + end while +end function + +isGoodMove = function(ones, tens) + pos = 10 * tens + ones + return [158, 127, 126, 75, 73].indexOf(pos) != null +end function + +getRandomMove = function(queenPos) + tens = floor(queenPos/10) + ones = queenPos % 10 + z = rnd + if z > 0.6 then + return 10 * (tens+1) + ones + else if z > 0.3 then + return 10 * (tens+2) + (ones+1) + else + return 10 * (tens+1) + ones + end if +end function + +getComputerMove = function(queenPos) + tens = floor(queenPos/10) + ones = queenPos % 10 + if [41, 44, 73, 75, 126, 127].indexOf(queenPos) != null then return getRandomMove(queenPos) + for k in range(7, 1) + if isGoodMove(ones, tens+k) then return 10 * (tens+k) + ones // left + if isGoodMove(ones+k, tens+k) then return 10 * (tens+k) + (ones+k) // down + if isGoodMove(ones+k, tens+k*2) then return 10 * (tens+k*2) + (ones+k) // down-left + end for + return getRandomMove(queenPos) +end function + +getHumanMove = function(queenPos) + tens = floor(queenPos/10) + ones = queenPos % 10 + while true + pos = input("What is your move? ").val + if pos == 0 then return 0 + dTens = floor(pos/10) - tens + dOnes = pos % 10 - ones + ok = false + if dOnes == 0 and dTens > 0 then ok = true // moving left + if dOnes == dTens and dOnes > 0 then ok = true // moving down + if dTens == dOnes*2 and dOnes > 0 then ok = true // moving down-left + if ok then return pos + print + print "Y O U C H E A T . . . Try again"; + end while +end function + +playGame = function + queenPos = getStartPos + while true + if queenPos == 0 then + print "It looks like I have won by forfeit." + return + end if + + // computer move + queenPos = getComputerMove(queenPos) + print "Computer moves to square " + queenPos + if queenPos == 158 then + print + print "Nice try, but it looks like I have won." + return + end if + + // human move + queenPos = getHumanMove(queenPos) + if queenPos == 158 then + print + print "C O N G R A T U L A T I O N S . . ." + print + print "You have won--very well played." + print "It looks like I have met my match." + print "Thanks for playing---I can't win all the time." + return + end if + end while +end function + +// Main program +if getYesNo("Do you want instructions") == "yes" then printDirections +while true + printCoordinates + playGame + print + if getYesNo("Anyone else care to try") == "no" then break +end while +print +print "OK --- Thanks again." diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/README.md new file mode 100644 index 000000000..bfec2da94 --- /dev/null +++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/README.md @@ -0,0 +1,21 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of rockscissors.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 rockscissors.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 "rockscissors" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/rockscissors.ms b/00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/rockscissors.ms new file mode 100644 index 000000000..322e354b6 --- /dev/null +++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/rockscissors.ms @@ -0,0 +1,40 @@ +print " "*21 + "Game of Rock, Scissors, Paper" +print " "*15 + "Creative Computing Morristown New Jersey" +print; print; print + +while true + numGames = input("How many games? ").val + if 0 < numGames < 11 then break + print "Sorry, but we aren't allowed to play that many." +end while + +computerWins = 0 +playerWins = 0 +for game in range(1, numGames) + print; print "Game number " + game + myChoice = floor(rnd*3 + 1) + while true + print "3=Rock...2=Scissors...1=Paper" + playerChoice = input("1...2...3...What's your choice? ").val + if [1,2,3].indexOf(playerChoice) != null then break + print "Invalid." + end while + print "This is my choice..." + print ["...Paper", "...Scissors", "...Rock"][myChoice-1] + diff = myChoice - playerChoice + if diff == 0 then + print "Tie game. No winner." + else if diff == 1 or diff == -2 then + print "Wow! I win!!!" + computerWins += 1 + else + print "You win!!!" + playerWins += 1 + end if +end for + +print; print "Here is the final game score:" +print "I have won " + computerWins + " game(s)." +print "You have won " + playerWins + " game(s)." +print "And " + (numGames - computerWins - playerWins) + " game(s) ended in a tie." +print; print "Thanks for playing!!" From bd23c4778be8663acf48d6e9747aba0e416ea309 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 2 Oct 2023 09:40:53 -0700 Subject: [PATCH 293/377] Added MiniScript version of 75_Roulette. --- .../75_Roulette/MiniScript/README.md | 18 ++ .../75_Roulette/MiniScript/roulette.ms | 200 ++++++++++++++++++ 75_Roulette/README.md | 2 +- 3 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/75_Roulette/MiniScript/README.md create mode 100644 00_Alternate_Languages/75_Roulette/MiniScript/roulette.ms diff --git a/00_Alternate_Languages/75_Roulette/MiniScript/README.md b/00_Alternate_Languages/75_Roulette/MiniScript/README.md new file mode 100644 index 000000000..4a2e49289 --- /dev/null +++ b/00_Alternate_Languages/75_Roulette/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 roulette.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 "roulette" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/75_Roulette/MiniScript/roulette.ms b/00_Alternate_Languages/75_Roulette/MiniScript/roulette.ms new file mode 100644 index 000000000..60e7087bc --- /dev/null +++ b/00_Alternate_Languages/75_Roulette/MiniScript/roulette.ms @@ -0,0 +1,200 @@ +print " "*32 + "Roulette" +print " "*15 + "Creative Computing Morristown New Jersey" +print; print; print + +if version.hostName == "Mini Micro" then + import "dateTime" + globals.date = dateTime.str(dateTime.now, "MMM d, yyyy") +else + globals.date = input("Enter the current date (as in 'Jan 23, 1979') - ") +end if + +yn = input("Do you want instructions? ").lower + " " +if yn[0] != "n" then + print + print "This is the betting layout" + print " (*=Red)" + print + print " 1* 2 3*" + print " 4 5* 6 " + print " 7* 8 9*" + print "10 11 12*" + print "---------------" + print "13 14* 15 " + print "16* 17 18*" + print "19* 20 21*" + print "22 23* 24 " + print "---------------" + print "25* 26 27*" + print "28 29 30*" + print "31 32* 33 " + print "34* 35 36*" + print "---------------" + print " 00 0 " + print + input "(Press Return at each pause.)" + print + print "Types of Bets" + print + print "The numbers 1 to 36 signify a straight bet" + print "on that number." + print "These pay off 35:1" + print + print "The 2:1 bets are:" + print " 37) 1-12 40) first column" + print " 38) 13-24 41) second column" + print " 39) 25-36 42) third column" + print + print "The even money bets are:" + print " 43) 1-18 46) odd" + print " 44) 19-36 47) red" + print " 45) even 48) black" + print + print " 49)0 and 50)00 pay off 35:1" + print " NOTE: 0 and 00 do not count under any" + print " bets except their own." + input + print "When I ask for each bet, type the number" + print "and the amount, separated by a comma." + print "For example: to bet $500 on black, type 48,500" + print "when I ask for a bet." + print + print "The minimum bet is $5, the maximum is $500." + print +end if + +redNumbers = [1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36] + +// function to convert a number 1-38 to a number/description, like "00" +// or "7 RED" +numDesc = function(number) + if number == 37 then return "0" + if number == 38 then return "00" + s = str(number) + if redNumbers.indexOf(number) == null then + return s + " BLACK" + else + return s + " RED" + end if +end function + +// function to calculate the payout factor (positive if player wins, +// or -1 if player loses) for the given bet and actual spin. +payoutFactor = function(bet, spin) + if bet <= 36 then // straight bet, pays 35:1 + if bet == spin then return 35 else return -1 + else if bet == 49 then // 0, pays 35:1 + if spin == 37 then return 35 else return -1 + else if bet == 50 then // 00, pays 35:1 + if spin == 38 then return 35 else return -1 + else if bet == 37 then // 1-12, pays 2:1 + if 1 <= spin <= 12 then return 2 else return -1 + else if bet == 38 then // 13-24, pays 2:1 + if 13 <= spin <= 24 then return 2 else return -1 + else if bet == 39 then // 25-36, pays 2:1 + if 25 <= spin <= 36 then return 2 else return -1 + else if bet == 40 then // first column, pays 2:1 + if spin % 3 == 1 then return 2 else return -1 + else if bet == 41 then // second column, pays 2:1 + if spin % 3 == 2 then return 2 else return -1 + else if bet == 42 then // third column, pays 2:1 + if spin % 3 == 0 then return 2 else return -1 + else if bet == 43 then // 1-18, even money + if 1 <= spin <= 18 then return 1 else return -1 + else if bet == 44 then // 19-36, even money + if 19 <= spin <= 36 then return 1 else return -1 + else if bet == 45 then // even number, even money + if spin % 2 == 0 then return 1 else return -1 + else if bet == 46 then // odd number, even money + if spin % 2 == 1 then return 1 else return -1 + else if bet == 47 then // red, even money + if redNumbers.indexOf(spin) != null then return 1 else return -1 + else if bet == 48 then // black, even money + if redNumbers.indexOf(spin) == null then return 1 else return -1 + end if + print "Invalid bet " + bet + " in payoutFactor" +end function + +playerCash = 1000 +houseCash = 100000 +x = [0] * 38 // (keeps track of how often each number comes up) +while playerCash > 0 + // Get the player's bets + numBets = input("How many bets? ").val + if numBets < 1 then continue + bets = []; amounts = [] + for i in range(1, numBets) + while true + s = input("Number " + i + "? ").replace(",", " ").replace(" ", " ").split + if s.len != 2 then continue + bet = s[0].val; amount = s[1].val + if bets.indexOf(bet) != null then + print "You made that bet once already,dum-dum" + continue + end if + if 1 <= bet <= 50 and 5 <= amount <= 500 then + bets.push bet + amounts.push amount + break + end if + end while + end for + + // Spin the wheel! + print "Spinning" + print + print + spin = floor(38 * rnd + 1) + x[spin] += 1 + print numDesc(spin) + print + + // Now, pay out the bets + for i in bets.indexes + f = payoutFactor(bets[i], spin) + if f > 0 then + print "You win " + f*amounts[i] + " on bet " + i + else + print "You lose " + (-f)*amounts[i] + " on bet " + i + end if + playerCash += f * amounts[i] + houseCash -= f * amounts[i] + end for + print + print "Totals: ME YOU" + print " " + (houseCash+" "*12)[:12] + playerCash + if playerCash > 0 and houseCash > 0 then + yn = input("Again? ").lower + " " + if yn[0] != "y" then break + end if +end while + +if houseCash < 1 then + print "You broke the house!" + playerCash = 101000 +end if +if playerCash < 1 then + print "Oops! You just spent your last dollar!" + print "Thanks for your money." + print "I'll use it to buy a solid gold roulette wheel" + print +else + name = input("To whom shall I make the check? ") + print + print "-"*68 + print " "*55 + "Check No. " + floor(rnd*100) + print + print " "*(67 - date.len) + date + print + print + print "Pay to the order of-----" + name + "-----$ " + playerCash + print + print + print " "*10 + "The Memory Bank of New York" + print + print " "*35 + "The Computer" + print " "*35 + "----------X-----" + print + print "-"*68 + print "Come back soon!" +end if diff --git a/75_Roulette/README.md b/75_Roulette/README.md index 4902aa9ba..b68a2ad1b 100644 --- a/75_Roulette/README.md +++ b/75_Roulette/README.md @@ -17,4 +17,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -(please note any difficulties or challenges in porting here) +- The program keeps a count of how often each number comes up in array `X`, but never makes use of this information. From 91a494df5b3ec3fc16c3b8e9a0f59202d621938d Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Mon, 2 Oct 2023 15:30:55 -0700 Subject: [PATCH 294/377] Added MiniScript version of 76_Russian_Roulette. --- .../76_Russian_Roulette/MiniScript/README.md | 21 +++++++++++ .../MiniScript/russianroulette.ms | 37 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 00_Alternate_Languages/76_Russian_Roulette/MiniScript/README.md create mode 100644 00_Alternate_Languages/76_Russian_Roulette/MiniScript/russianroulette.ms diff --git a/00_Alternate_Languages/76_Russian_Roulette/MiniScript/README.md b/00_Alternate_Languages/76_Russian_Roulette/MiniScript/README.md new file mode 100644 index 000000000..79d028a92 --- /dev/null +++ b/00_Alternate_Languages/76_Russian_Roulette/MiniScript/README.md @@ -0,0 +1,21 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). + +Conversion to [MiniScript](https://miniscript.org). + +Ways to play: + +0. Try-It! Page: +Go to https://miniscript.org/tryit/, clear the sample code from the code editor, and paste in the contents of russianroulette.ms. Then click the "Run Script" button. Program output (and input) will appear in the green-on-black terminal display to the right of or below the code editor. + +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 russianroulette.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 "russianroulette" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/76_Russian_Roulette/MiniScript/russianroulette.ms b/00_Alternate_Languages/76_Russian_Roulette/MiniScript/russianroulette.ms new file mode 100644 index 000000000..3eb896f94 --- /dev/null +++ b/00_Alternate_Languages/76_Russian_Roulette/MiniScript/russianroulette.ms @@ -0,0 +1,37 @@ +print " "*28 + "Russian Roulette" +print " "*15 + "Creative Computing Morristown New Jersey" +print; print; print + +print "This is a game of >>>>>>>>>>Russian Roulette." + +while true + print; print "Here is a revolver." + print "Type '1' to spin chamber and pull trigger." + print "Type '2' to give up." + print "GO" + + n = 0 + while n < 10 + inp = input("? ").val + if inp == 2 then + print " CHICKEN!!!!!" + break + else if rnd > 0.833333 then + print " BANG!!!!! You're dead!" + print "Condolences will be sent to your relatives." + break + else + n += 1 + print "- CLICK -" + print + end if + end while + + if n >= 10 then + print "You win!!!!!" + print "Let someone else blow his brains out." + else + print; print; print + print "...Next victim..." + end if +end while From 691664d902192453756c0c8aa471a6d86bf4549e Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 3 Oct 2023 13:03:47 -0700 Subject: [PATCH 295/377] Added MiniScript version of 77_Salvo. --- .../77_Salvo/MiniScript/README.md | 18 ++ .../77_Salvo/MiniScript/salvo.ms | 240 ++++++++++++++++++ 77_Salvo/README.md | 7 +- 3 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 00_Alternate_Languages/77_Salvo/MiniScript/README.md create mode 100644 00_Alternate_Languages/77_Salvo/MiniScript/salvo.ms diff --git a/00_Alternate_Languages/77_Salvo/MiniScript/README.md b/00_Alternate_Languages/77_Salvo/MiniScript/README.md new file mode 100644 index 000000000..d31694466 --- /dev/null +++ b/00_Alternate_Languages/77_Salvo/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 salvo.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 "salvo" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/77_Salvo/MiniScript/salvo.ms b/00_Alternate_Languages/77_Salvo/MiniScript/salvo.ms new file mode 100644 index 000000000..e7c2796e7 --- /dev/null +++ b/00_Alternate_Languages/77_Salvo/MiniScript/salvo.ms @@ -0,0 +1,240 @@ +print " "*33 + "Salvo" +print " "*15 + "Creative Computing Morristown New Jersey" +print; print; print + +import "listUtil" + +Ship = {} +Ship.name = "Ship" +Ship.positions = null // list of [x,y] coordinates for this ship +Ship.shots = 1 // how many shots this ship provides +Ship.hitPoints = 1 // how many hits this ship can take before sinking +Ship.make = function(name, shots=1, size=2) + result = new Ship + result.name = name + result.shots = shots + result.positions = [] + result.hitPoints = size + return result +end function + +Board = {} +Board.ships = null // list of Ship instances +Board.splash = null // 2D array of: none, or turn on which it was hit +Board.shipAt = function(xy) + for ship in self.ships + if ship.positions.contains(xy) then return ship + end for +end function +Board.isEmptySpot = function(xy) + return 0 < xy[0] < 11 and 0 < xy[1] < 11 and self.shipAt(xy) == null +end function +Board.make = function + result = new Board + result.ships = [] + result.splash = list.init2d(11, 11) + return result +end function +Board.totalShots = function + sum = 0 + for ship in self.ships + sum += ship.shots + end for + return sum +end function + +computerBoard = Board.make +playerBoard = Board.make + +directions = [[-1,-1], [-1,0], [-1,1], [0,-1], [0,1], [1,-1], [1,0], [1,1]] + +randomPosition = function + return [1 + floor(rnd*10), 1 + floor(rnd*10)] +end function + +inputCoords = function(prompt="?") + while true + inp = input(prompt + "? ").replace(",", " ").replace(" ", " ").split + if inp.len != 2 then + print "Please enter coordinates such as: 5,3" + else + x = inp[0].val + y = inp[1].val + if 0 < x < 11 and 0 < y < 11 then return [x,y] + print "X and Y coordinates must be in the range 1-10." + end if + end while +end function + +inBounds = function(pos) + return 0 < pos[0] < 11 and 0 < pos[1] < 11 +end function + +placeComputerShips = function + placeOne = function(ship) + while true + pos = randomPosition + dir = directions.any + ok = true + p = pos[:] + for i in range(0, ship.hitPoints - 1) + if not computerBoard.isEmptySpot(p) then ok = false + p.add dir + end for + if ok then break + end while + for i in range(0, ship.hitPoints - 1) + ship.positions.push pos[:] + pos.add dir + end for + computerBoard.ships.push ship + end function + placeOne Ship.make("Battleship", 3, 5) + placeOne Ship.make("Cruiser", 2, 3) + placeOne Ship.make("Destroyer", 1, 2) + placeOne Ship.make("Destroyer", 1, 2) +end function + +placePlayerShips = function + placeOne = function(ship) + print ship.name + playerBoard.ships.push ship + // Note: like the original BASIC program, we do no validation on + // the input other than making sure it is in range. So you can + // have a ship scattered all over the map, have ships overlap, etc. + for i in range(1, ship.hitPoints) + ship.positions.push inputCoords + end for + end function + print "Enter coordinates for..." + placeOne Ship.make("Battleship", 3, 5) + placeOne Ship.make("Cruiser", 2, 3) + placeOne Ship.make("Destroyer", 1, 2) + placeOne Ship.make("Destroyer", 1, 2) +end function + +printComputerShips = function + for ship in computerBoard.ships + print ship.name + for pos in ship.positions + print " " + pos.join(" ") + end for + end for +end function + +doPlayerTurn = function(turnNum = 1) + shots = playerBoard.totalShots + print "You have " + shots + " shot" + "s"*(shots!=1) + "." + if shots < 1 then + print "I have won." + exit + end if + hits = [] + for i in range(1, shots) + while true + pos = inputCoords + prevHitOnTurn = computerBoard.splash[pos[0]][pos[1]] + if prevHitOnTurn == null then break + print "You shot there before on turn " + prevHitOnTurn + end while + computerBoard.splash[pos[0]][pos[1]] = turnNum + hit = computerBoard.shipAt(pos) + if hit then hits.push hit + end for + for hit in hits + print "You hit my " + hit.name + "." + hit.hitPoints -= 1 + if hit.hitPoints == 0 then + print "...and sank it!" // (not in original BASIC program) + computerBoard.ships.removeVal hit + end if + end for +end function + +pickShot = function + // Pick a spot for the computer to shoot at. We'll do this by + // computing a "neighbor score" for each spot: the number of + // neighboring spots that (1) we have previously hit, and (2) + // contain an enemy ship. Then we'll pick randomly from the + // set of spots with the highest neighbor score. + bestScore = 0 + spots = [] + for i in range(1,10) + for j in range(1,10) + pos = [i,j] + if playerBoard.splash[pos[0]][pos[1]] then continue + score = 0 + for dir in directions + n = pos.plus(dir) + if inBounds(n) and playerBoard.splash[n[0]][n[1]] and playerBoard.shipAt(n) then + score += 1 + end if + end for + if score > bestScore then + bestScore = score + spots = [pos] + else if score == bestScore then + spots.push pos + end if + end for + end for + return spots.any +end function + +doComputerTurn = function(turnNum = 1) + shots = computerBoard.totalShots + print "I have " + shots + " shot" + "s"*(shots!=1) + "." + if shots < 1 then + print "You have won." + exit + end if + hits = [] + for i in range(1, shots) + pos = pickShot + playerBoard.splash[pos[0]][pos[1]] = turnNum + hit = playerBoard.shipAt(pos) + if hit then hits.push hit + if seeComputerShots then print " " + pos.join(" ") + end for + for hit in hits + print "I hit your " + hit.name + "." + hit.hitPoints -= 1 + if hit.hitPoints == 0 then + print "...and sank it!" // (not in original BASIC program) + playerBoard.ships.removeVal hit + end if + end for +end function + +// Main Program + +placeComputerShips +placePlayerShips +while true + yn = input("Do you want to start? ").lower + if yn == "where are your ships?" then + printComputerShips + else if yn and (yn[0] == "y" or yn[0] == "n") then + break + end if +end while +startWithPlayer = (yn[0] == "y") +while true + yn = input("Do you want to see my shots? ").lower + if yn and (yn[0] == "y" or yn[0] == "n") then break +end while +seeComputerShots = (yn[0] == "y") + +turnNumber = 1 +while true + print + print "Turn " + turnNumber + if startWithPlayer then + doPlayerTurn turnNumber + doComputerTurn turnNumber + else + doComputerTurn turnNumber + doPlayerTurn turnNumber + end if + turnNumber += 1 +end while \ No newline at end of file diff --git a/77_Salvo/README.md b/77_Salvo/README.md index 4bb40487e..3ef9f21c9 100644 --- a/77_Salvo/README.md +++ b/77_Salvo/README.md @@ -26,7 +26,9 @@ http://www.vintage-basic.net/games.html #### Porting Notes -As per the analysis in +The program does no validation of ship positions; your ship coordinates may be scattered around the board in any way you like. (Computer ships will not do this, but they may be placed diagonally in such a way that they cross each other.) Scattering your ships in this way probably defeats whatever all that spaghetti-code logic the computer is using to pick its moves, which is based on the assumption of contiguous ships. + +Moreover: as per the analysis in https://forums.raspberrypi.com/viewtopic.php?p=1997950#p1997950 @@ -40,4 +42,5 @@ This typo is interesting because it causes the program to play by a much weaker `3970 K(R,S)=K(R,S)+E(U)-2*INT(H(U)+.5)` -and to change the JavaScript program accordingly. +and to change the JavaScript program accordingly. (And note that some ports — looking at you, Python — do not implement the original strategy at all, but merely pick random unshot locations for every shot.) + From 55ec0811478b3738cde869339df49701a17d8ce1 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 3 Oct 2023 16:10:16 -0700 Subject: [PATCH 296/377] Added MiniScript version of 79_Slalom. --- .../79_Slalom/MiniScript/README.md | 18 ++ .../79_Slalom/MiniScript/slalom.ms | 170 ++++++++++++++++++ 00_Alternate_Languages/79_Slalom/slalom.bas | 2 +- 79_Slalom/README.md | 8 +- 79_Slalom/slalom.bas | 2 +- 5 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 00_Alternate_Languages/79_Slalom/MiniScript/README.md create mode 100644 00_Alternate_Languages/79_Slalom/MiniScript/slalom.ms diff --git a/00_Alternate_Languages/79_Slalom/MiniScript/README.md b/00_Alternate_Languages/79_Slalom/MiniScript/README.md new file mode 100644 index 000000000..c954f090c --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/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 slalom.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 "slalom" + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/79_Slalom/MiniScript/slalom.ms b/00_Alternate_Languages/79_Slalom/MiniScript/slalom.ms new file mode 100644 index 000000000..41bb0b829 --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/MiniScript/slalom.ms @@ -0,0 +1,170 @@ +print " "*33 + "Slalom" +print " "*15 + "Creative Computing Morristown New Jersey" +print; print; print + +gateSpeeds = [14,18,26,29,18,25,28,32,29,20,29,29,25,21,26,29,20,21,20, + 18,26,25,33,31,22] + +medals = {} +medals.gold = 0 +medals.silver = 0 +medals.bronze = 0 + +while true + qtyGates = input("How many gates does this course have (1 to 25)? ").val + if qtyGates > 25 then + print "25 is the limit." + qtyGates = 25 + end if + if qtyGates >= 1 then break + print "Try again," +end while + +print "Type ""ins"" for instructions" +print "Type ""max"" for approximate maximum speeds" +print "Type ""run"" for the beginning of the race" +while true + cmd = input("Command--").lower + if cmd == "ins" then + print + print "*** Slalom: This is the 1976 Winter Olympic Giant Slalom. You are" + print " the American team's only hope of a gold medal." + print + print " 0 -- type this if you want to see how long you've taken." + print " 1 -- type this if you want to speed up a lot." + print " 2 -- type this if you want to speed up a little." + print " 3 -- type this if you want to speed up a teensy." + print " 4 -- type this if you want to keep going the same speed." + print " 5 -- type this if you want to check a teensy." + print " 6 -- type this if you want to check a little." + print " 7 -- type this if you want to check a lot." + print " 8 -- type this if you want to cheat and try to skip a gate." + print + print " The place to use these options is when the computer asks:" + print + print "Option?" + print + print " Good luck!" + print + else if cmd == "max" then + print "GATE MAX" + print " # M.P.H." + print "-----------" + for i in range(1, qtyGates) + print " " + i + " "*(i<10) + " " + gateSpeeds[i-1] + end for + else if cmd == "run" then + break + end if +end while + +while true + skill = input("Rate yourself as a skier, (1=worst, 3=best)? ").val + if 1 <= skill <= 3 then break + print "The bounds are 1-3" +end while + +doOneRace = function + print "The starter counts down...5...4...3...2...1..GO!" + time = 0 + speed = floor(rnd * 9 + 9) + print + print "You're off!" + gate = 0 + while gate+1 <= qtyGates + gate += 1 + gateSpeed = gateSpeeds[(gate-1) % gateSpeeds.len] + print + print "Here comes gate #" + gate + ":" + print speed + " M.P.H." + prevSpeed = speed + while true + opt = input("Option? ").val + if opt == 0 then + print "You've taken " + time + " seconds." + else if opt < 1 or opt > 8 then + print "What?" + else + break + end if + end while + if opt == 1 then + speed += floor(rnd*(10-5)+5) + else if opt == 2 then + speed += floor(rnd*(5-3)+3) + else if opt == 3 then + speed += floor(rnd*(4-1)+1) + else if opt == 4 then + // (no change) + else if opt == 5 then + speed -= floor(rnd*(4-1)+1) + else if opt == 6 then + speed -= floor(rnd*(5-3)+3) + else if opt == 7 then + speed -= floor(rnd*(10-5)+5) + else if opt == 8 then + print "***CHEAT" + if rnd < 0.7 then + print "An official caught you!" + print "You took " + round(time+rnd, 3) + " seconds." + break + else + print "You made it!" + char(7) + time += 1.5 + continue + end if + end if + print speed + " M.P.H." + if speed > gateSpeed then + if rnd < (speed - gateSpeed)*0.1 + 0.2 then + msg = "You went over the maximum speed and " + if rnd < 0.5 then msg += "snagged a flag!" else msg += "wiped out!" + print msg + print "You took " + round(time+rnd, 3) + " seconds." + else + print "You went over the maximum speed and made it!" + end if + else if speed > gateSpeed - 1 then + print "Close one!" + end if + if speed < 7 then + print "Let's be realistic, OK? Let's go back and try again..." + speed = prevSpeed + gate -= 1 + continue + end if + time += gateSpeed - speed + 1 + if speed > gateSpeed then time += 0.5 + end while + + print + print "You took " + round(time+rnd, 3) + " seconds." + avg = time / qtyGates + if avg < 1.5 - (skill * 0.1) then + print "You won a gold medal!" + medals.gold += 1 + else if avg < 2.9 - (skill * 0.1) then + print "You won a silver medal" + medals.silver += 1 + else if avg < 4.4 - (skill * 0.01) then + print "You won a bronze medal" + medals.bronze += 1 + end if +end function + +while true + doOneRace + while true + yesno = input("Do you want to race again? ").lower + " " + if yesno[0] == "y" or yesno[0] == "n" then break + print "Please type 'yes' or 'no'" + end while + if yesno[0] == "n" then break + print +end while + +print +print "Thanks for the race" +if medals.gold then print "Gold medals: " + medals.gold +if medals.silver then print "Silver medals: " + medals.silver +if medals.bronze then print "Bronze medals: " + medals.bronze diff --git a/00_Alternate_Languages/79_Slalom/slalom.bas b/00_Alternate_Languages/79_Slalom/slalom.bas index b46cc39be..47c6d8010 100644 --- a/00_Alternate_Languages/79_Slalom/slalom.bas +++ b/00_Alternate_Languages/79_Slalom/slalom.bas @@ -58,7 +58,7 @@ 825 PRINT "*** SLALOM: THIS IS THE 1976 WINTER OLYMPIC GIANT SLALOM. YOU ARE" 830 PRINT " THE AMERICAN TEAM'S ONLY HOPE OF A GOLD MEDAL." 840 PRINT -845 PRINT " 0 -- TYPE THIS IS YOU WANT TO SEE HOW LONG YOU'VE TAKEN." +845 PRINT " 0 -- TYPE THIS IF YOU WANT TO SEE HOW LONG YOU'VE TAKEN." 850 PRINT " 1 -- TYPE THIS IF YOU WANT TO SPEED UP A LOT." 860 PRINT " 2 -- TYPE THIS IF YOU WANT TO SPEED UP A LITTLE." 870 PRINT " 3 -- TYPE THIS IF YOU WANT TO SPEED UP A TEENSY." diff --git a/79_Slalom/README.md b/79_Slalom/README.md index 8c45820c0..c95309ceb 100644 --- a/79_Slalom/README.md +++ b/79_Slalom/README.md @@ -15,8 +15,10 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html -#### Porting Notes +#### Known Bugs + +- In the original version, the data pointer doesn't reset after a race is completed. This causes subsequent races to error at some future point at line 540, `READ Q'. -In the original version, the data pointer doesn't reset after a race is completed. This causes subsequent races to error at some future point at line 540, +- It also doesn't restore the data pointer after executing the MAX command to see the gate speeds, meaning that if you use this command, it effectively skips those gates, and the speeds shown are completely incorrect. - 540 READ Q +#### Porting Notes diff --git a/79_Slalom/slalom.bas b/79_Slalom/slalom.bas index b46cc39be..47c6d8010 100644 --- a/79_Slalom/slalom.bas +++ b/79_Slalom/slalom.bas @@ -58,7 +58,7 @@ 825 PRINT "*** SLALOM: THIS IS THE 1976 WINTER OLYMPIC GIANT SLALOM. YOU ARE" 830 PRINT " THE AMERICAN TEAM'S ONLY HOPE OF A GOLD MEDAL." 840 PRINT -845 PRINT " 0 -- TYPE THIS IS YOU WANT TO SEE HOW LONG YOU'VE TAKEN." +845 PRINT " 0 -- TYPE THIS IF YOU WANT TO SEE HOW LONG YOU'VE TAKEN." 850 PRINT " 1 -- TYPE THIS IF YOU WANT TO SPEED UP A LOT." 860 PRINT " 2 -- TYPE THIS IF YOU WANT TO SPEED UP A LITTLE." 870 PRINT " 3 -- TYPE THIS IF YOU WANT TO SPEED UP A TEENSY." From 3bd8b2f614cac666d31ea8a05870ea312248648a Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 4 Oct 2023 15:12:39 -0700 Subject: [PATCH 297/377] Added MiniScript version of 80_Slots. --- .../80_Slots/MiniScript/README.md | 18 +++ .../80_Slots/MiniScript/slots.ms | 108 ++++++++++++++++++ 80_Slots/README.md | 4 + 3 files changed, 130 insertions(+) create mode 100644 00_Alternate_Languages/80_Slots/MiniScript/README.md create mode 100644 00_Alternate_Languages/80_Slots/MiniScript/slots.ms diff --git a/00_Alternate_Languages/80_Slots/MiniScript/README.md b/00_Alternate_Languages/80_Slots/MiniScript/README.md new file mode 100644 index 000000000..a8b56b3d6 --- /dev/null +++ b/00_Alternate_Languages/80_Slots/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 slots.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 "slots" + run +``` diff --git a/00_Alternate_Languages/80_Slots/MiniScript/slots.ms b/00_Alternate_Languages/80_Slots/MiniScript/slots.ms new file mode 100644 index 000000000..310ff95e7 --- /dev/null +++ b/00_Alternate_Languages/80_Slots/MiniScript/slots.ms @@ -0,0 +1,108 @@ +print " "*30 + "Slots" +print " "*15 + "Creative Computing Morristown New Jersey" +print; print; print + +// PRODUCED BY FRED MIRABELLE AND BOB HARPER ON JAN 29, 1973 +// IT SIMULATES THE SLOT MACHINE. +// (Ported to MiniScript by Joe Strout on Oct 04, 2023) + +print "You are in the H&M casino,in front of one of our" +print "one-arm bandits. Bet from $1 to $100." +print "To pull the arm, punch the return key after making your bet." + +symbols = ["BAR", "BELL", "ORANGE", "LEMON", "PLUM", "CHERRY"] + + +winTriple = function(symbol, bet) + if symbol == "BAR" then + print "***JACKPOT***" + globals.profit += 101 * bet + else + print "**TOP DOLLAR**" + globals.profit += 11 * bet + end if + print "You won!" +end function + +winDouble = function(symbol, bet) + if symbol == "BAR" then + print "*DOUBLE BAR*" + globals.profit += 6 * bet + else + print "Double!" + globals.profit += 3 * bet + end if + print "You won!" +end function + +lose = function(bet) + print "You lost." + globals.profit -= bet +end function + +calcWinLoss = function(spun, bet) + if spun[0] == spun[1] then + if spun[0] == spun[2] then + winTriple spun[0], bet + else + winDouble spun[0], bet + end if + else if spun[0] == spun[2] then + winDouble spun[0], bet + else if spun[1] == spun[2] then + winDouble spun[1], bet + else + lose bet + end if +end function + +ringBells = function(qty=5) + // I believe all the obnoxious beeping was to slow down the game + // and build suspense as each "wheel" appears. Our version: + wait 0.1 + for i in range(1, qty) + print char(7), "" + wait 0.05 + end for +end function + +// Main program +profit = 0 +while true + print + + // Get bet + while true + bet = input("Your bet? ").val + if 1 <= bet <= 100 then break + if bet < 1 then print "Minimum bet is $1" else print "House limits are $100" + end while + + // Spin 3 wheels (randomly picking a symbol for each one) + spun = [] + spun.push symbols[rnd * symbols.len] + spun.push symbols[rnd * symbols.len] + spun.push symbols[rnd * symbols.len] + print + ringBells 10; print spun[0], " " + ringBells 5; print spun[1], " " + ringBells 5; print spun[2] + print + + // Calculate and display win/loss + wait 0.5 + calcWinLoss spun, bet + + // Show new state, and maybe play again + print "Your standings are $ " + profit + yn = input("Again? ").lower + " " + if yn[0] != "y" then break +end while + +if profit == 0 then + print "Hey, you broke even." +else if profit > 0 then + print "Collect your winnings from the H&M cashier." +else + print "Pay up! Please leave your money on the terminal." +end if diff --git a/80_Slots/README.md b/80_Slots/README.md index dcc3aabe2..522c7c811 100644 --- a/80_Slots/README.md +++ b/80_Slots/README.md @@ -17,6 +17,10 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html +#### Known Bugs + +- The original program does not correctly detect identical draws in the first and third position as a double (instead, it counts as a loss). This is probably not intended. Some of the ports fix this, so that any two matches count as a double. + #### Porting Notes (please note any difficulties or challenges in porting here) From 753327db4452c33514ddcd30a598e00a0becce64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Concei=C3=A7=C3=A3o?= Date: Fri, 6 Oct 2023 11:50:51 +0100 Subject: [PATCH 298/377] Tower game in Lua --- 90_Tower/lua/train.lua | 268 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 90_Tower/lua/train.lua diff --git a/90_Tower/lua/train.lua b/90_Tower/lua/train.lua new file mode 100644 index 000000000..c5e07b76b --- /dev/null +++ b/90_Tower/lua/train.lua @@ -0,0 +1,268 @@ +print [[ + + TOWERS +CREATIVE COMPUTING MORRISTOWN, NEW JERSY + + +]] + +local MAX_DISKS = 7 --"" can be used starting in Lua 5.4, as such: "local MAX_DISKS = 7" +local MAX_DISK_SIZE = 15 +local MAX_MOVES = 128 +local NUM_TOWERS = 3 + +local towers = { + { size = 0, elem = {} }, + { size = 0, elem = {} }, + { size = 0, elem = {} }, +} + +local total_disks +function ask_how_many_disks() + + local keep_asking = true + local input + local errors = 0 + + while keep_asking do + + io.write(string.format("HOW MANY DISKS DO YOU WANT TO MOVE (%d IS MAX)? ", MAX_DISKS) ) + input = io.read("*number") + io.read() --get rid of the remaining newline character + + if input ~= nil and input>0 and input<=MAX_DISKS then + keep_asking = false + + else + errors = errors + 1 + if errors > 2 then + print "ALL RIGHT, WISE GUY, IF YOU CAN'T PLAY THE GAME RIGHT, I'LL" + print "JUST TAKE MY PUZZLE AND GO HOME. SO LONG." + os.exit() + end + + print "SORRY, BUT I CAN'T DO THAT JOB FOR YOU." + end + end + total_disks = input +end + +function init_game() + print("TOWERS OF HANOIR PUZZLE\n") --'\n' indicates a new line + + print "YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT TOWER," + print "ONE AT A TIME, NEVER PUTTING A LARGER DISK ON A SMALLER DISK.\n" + + ask_how_many_disks() + + print() -- print() already creates a new line at the end, so an empty print leaves an empty line + print "IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE." + print "3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE, 7 THE" + print "NEXT, AND SO ON, UP TO 15. IF YOU DO THE PUZZLE WITH 2 DISKS," + print "THEIR CODE NAMES WOULD BE 13 AND 15, ETC. THE NEEDLES ARE" + print "NUMBERED FROM LEFT TO RIGHT, 1 TO 3. WE WILL START WITH THE" + print "DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM TO NEEDLE 3.\n" + + print "GOOD LUCK!\n" + + local i = 1 + local max = MAX_DISK_SIZE + while i<= total_disks do + towers[1].elem[i] = max + max = max-2 + i = i+1 + end + + towers[1].size = total_disks + + local idx = 2 + while idx <= NUM_TOWERS do + towers[idx].size = 0 + end +end + +function print_towers() + local line = MAX_DISKS + + while line > 0 do + local twr = 1 + + while twr <=3 do + local rpt = 10 + local offset = 0 + if line <= towers[twr].size then + offset = (towers[twr].elem[line] - 1) / 2 + rpt = rpt - offset + end + io.write( string.rep(' ', rpt) ) + io.write( string.rep('*', offset) ) + io.write '*' + io.write( string.rep('*', offset) ) + io.write( string.rep(' ', rpt) ) + twr = twr + 1 + end + print '' + line = line - 1 + end + +end + +function ask_which_disk() + + local keep_asking = true + local input + local errors = 0 + while keep_asking do + + io.write("WHICH DISK WOULD YOU LIKE TO MOVE? ") + input = io.read("*number") + io.read() --get rid of the remaining newline character + + if input==nil or input > MAX_DISK_SIZE or input%2==0 or input <= MAX_DISK_SIZE-(total_disks*2) then + print "ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13 or 15." + errors = errors + 1 + if errors > 1 then + print "STOP WASTING MY TIME. GO BOTHER SOMEONE ELSE." + os.exit() + end + + --[[ + Since there are only 3 towers, it's easier to do an 'if' with three + conditions than to do a loop + ]] + elseif towers[1].elem[ towers[1].size ] ~= input and + towers[2].elem[ towers[2].size ] ~= input and + towers[3].elem[ towers[3].size ] ~= input then + + print "THAT DISK IS BELOW ANOTHER ONE. MAKE ANOTHER CHOICE." + else + keep_asking = false + end + end + + return input +end + +function ask_which_needle(dsk) + + local keep_asking = true + local input + local errors = 0 + + while keep_asking do + + io.write("PLACE DISK ON WHICH NEEDLE? ") + input = io.read("*number") + io.read() --get rid of the remaining newline character + + if input~=nil and towers[input].size > 0 and towers[input].elem[ towers[input].size ] < dsk then + print "YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE," + print "IT MIGHT CRUSH IT!" + return 0 + + elseif input~=nil and input>=1 and input<=3 then + keep_asking = false + + else + errors = errors + 1 + if errors > 1 then + print "I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN." + print "BYE BYE, BIG SHOT." + os.exit() --Stop program + else + print "I'LL ASSUME YOU HIT THE WRONG KEY THIS TIME. BUT WATCH IT," + print "I ONLY ALLOW ONE MISTAKE." + end + end + end + return input +end + +function is_game_over() + if towers[1].size == 0 and towers[2].size == 0 then + return true + else + return false + end +end + +function game_loop() + local moves = 0 + local dsk + local twr_to + local twr_fr + + while not is_game_over() do + moves = moves + 1 + + if moves > MAX_MOVES then + print(string.format("SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN %d MOVES.", MAX_MOVES)) + os.exit() + end + + + repeat + dsk = ask_which_disk() + twr_to = ask_which_needle(dsk) + until twr_to ~= 0 + + + if towers[1].elem[ towers[1].size ] == dsk then + twr_fr = 1 + elseif towers[2].elem[ towers[2].size ] == dsk then + twr_fr = 2 + else + twr_fr = 3 + end + + towers[twr_fr].size = towers[twr_fr].size - 1 + + towers[twr_to].size = towers[twr_to].size + 1 + towers[twr_to].elem[ towers[twr_to].size ] = dsk + + print_towers() + end + + return moves +end + +function keep_playing() + + while true do + io.write("TRY AGAIN (YES OR NO)? ") + local input = io.read("*line") + + if input == "YES" or input == "yes" then + return true + elseif input == "NO" or input == "no" then + return false + else + print "'YES' OR 'NO' PLEASE" + end + end +end + +function start_loop() + + while true do + init_game() + print_towers() + + local moves = game_loop() + + --check ideal solution + if moves == (2^total_disks) - 1 then + print "CONGRATULATIONS!!" + end + + print ( string.format("YOU HAVE PERFORMED THE TASK IN %d MOVES.\n", moves) ) + + if not keep_playing() then + break + end + end + + print "\nTHANKS FOR THE GAME!" +end + +start_loop() From 58c04852331f11ca59b9d3f699a31246e5052db1 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Fri, 6 Oct 2023 08:16:39 -0700 Subject: [PATCH 299/377] Updated formatting in some of the MiniScript README files; commented out a Mini Micro -specific call in splat.ms. --- 00_Alternate_Languages/81_Splat/MiniScript/README.md | 6 ++++-- 00_Alternate_Languages/81_Splat/MiniScript/splat.ms | 2 +- 00_Alternate_Languages/82_Stars/MiniScript/README.md | 8 +++++--- .../89_Tic-Tac-Toe/MiniScript/README.md | 8 +++++--- 00_Alternate_Languages/90_Tower/MiniScript/README.md | 8 +++++--- 00_Alternate_Languages/91_Train/MiniScript/README.md | 5 +++-- 00_Alternate_Languages/93_23_Matches/MiniScript/README.md | 8 +++++--- 7 files changed, 28 insertions(+), 17 deletions(-) diff --git a/00_Alternate_Languages/81_Splat/MiniScript/README.md b/00_Alternate_Languages/81_Splat/MiniScript/README.md index f7d3b016b..2d133f871 100644 --- a/00_Alternate_Languages/81_Splat/MiniScript/README.md +++ b/00_Alternate_Languages/81_Splat/MiniScript/README.md @@ -6,11 +6,13 @@ 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 splat.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 "splat" run +``` diff --git a/00_Alternate_Languages/81_Splat/MiniScript/splat.ms b/00_Alternate_Languages/81_Splat/MiniScript/splat.ms index befff4319..d38ddd237 100644 --- a/00_Alternate_Languages/81_Splat/MiniScript/splat.ms +++ b/00_Alternate_Languages/81_Splat/MiniScript/splat.ms @@ -9,7 +9,7 @@ splatMsg = ["Requiescat in pace.", "May the Angel of Heaven lead you into Paradi "Pushing up daisies.", "Easy come, easy go."] history = [] -clear +//clear // (works on Mini Micro only) print " " * 33 + "Splat" print " " * 15 + "Creative Computing Morristown, New Jersey" print;print;print diff --git a/00_Alternate_Languages/82_Stars/MiniScript/README.md b/00_Alternate_Languages/82_Stars/MiniScript/README.md index bcbbd39a6..2e4b6d024 100644 --- a/00_Alternate_Languages/82_Stars/MiniScript/README.md +++ b/00_Alternate_Languages/82_Stars/MiniScript/README.md @@ -6,11 +6,13 @@ 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 stars.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 "stars" - run \ No newline at end of file + run +``` diff --git a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md index 6774c0d95..526bbfb3e 100644 --- a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md +++ b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md @@ -6,11 +6,13 @@ 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 tictactoe.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 "tictactoe" - run \ No newline at end of file + run +``` \ No newline at end of file diff --git a/00_Alternate_Languages/90_Tower/MiniScript/README.md b/00_Alternate_Languages/90_Tower/MiniScript/README.md index d8c97a891..fc9672037 100644 --- a/00_Alternate_Languages/90_Tower/MiniScript/README.md +++ b/00_Alternate_Languages/90_Tower/MiniScript/README.md @@ -6,11 +6,13 @@ 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 tower.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 "tower" - run \ No newline at end of file + run +``` diff --git a/00_Alternate_Languages/91_Train/MiniScript/README.md b/00_Alternate_Languages/91_Train/MiniScript/README.md index a19701581..13928cccc 100644 --- a/00_Alternate_Languages/91_Train/MiniScript/README.md +++ b/00_Alternate_Languages/91_Train/MiniScript/README.md @@ -4,6 +4,9 @@ Conversion to [MiniScript](https://miniscript.org). Ways to play: +0. "Try-It!" page on the web: +Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of train.ms, and click the "Run Script" button. + 1. Command-Line MiniScript: Download for your system from https://miniscript.org/cmdline/, install, and then run the program with a command such as: @@ -17,5 +20,3 @@ Download Mini Micro from https://miniscript.org/MiniMicro/, launch, and then cli load "train" run ``` -3. "Try-It!" page on the web: -Go to https://miniscript.org/tryit/, clear the default program from the source code editor, paste in the contents of train.ms, and click the "Run Script" button. diff --git a/00_Alternate_Languages/93_23_Matches/MiniScript/README.md b/00_Alternate_Languages/93_23_Matches/MiniScript/README.md index 9156a730e..8b9bc04ca 100644 --- a/00_Alternate_Languages/93_23_Matches/MiniScript/README.md +++ b/00_Alternate_Languages/93_23_Matches/MiniScript/README.md @@ -6,11 +6,13 @@ 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 23matches.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 "23matches" - run \ No newline at end of file + run +``` From a76db6de91de1687414588b371f7dbcc66793b5b Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Sat, 7 Oct 2023 06:51:11 -0700 Subject: [PATCH 300/377] Added MiniScript version of 83_Stock_Market. --- .../83_Stock_Market/MiniScript/README.md | 18 ++ .../83_Stock_Market/MiniScript/stockmarket.ms | 199 ++++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 00_Alternate_Languages/83_Stock_Market/MiniScript/README.md create mode 100644 00_Alternate_Languages/83_Stock_Market/MiniScript/stockmarket.ms diff --git a/00_Alternate_Languages/83_Stock_Market/MiniScript/README.md b/00_Alternate_Languages/83_Stock_Market/MiniScript/README.md new file mode 100644 index 000000000..ac3893185 --- /dev/null +++ b/00_Alternate_Languages/83_Stock_Market/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/83_Stock_Market/MiniScript/stockmarket.ms b/00_Alternate_Languages/83_Stock_Market/MiniScript/stockmarket.ms new file mode 100644 index 000000000..850cb725f --- /dev/null +++ b/00_Alternate_Languages/83_Stock_Market/MiniScript/stockmarket.ms @@ -0,0 +1,199 @@ +print " "*30 + "Stock Market" +print " "*15 + "Creative Computing Morristown New Jersey" +print; print; print + +// Stock Market Simulation -STOCK- +// Revised 8/18/70 (D. Pessel, L. Braun, C. Losik) +// Ported to MiniScript 10/07/23 (J. Strout) + + +// Ask a yes/no question; return true if yes, false if no +yes = function(prompt) + while true + response = input(prompt + " (YES-Type 1, NO-Type 0)? ") + if not response then continue + if response == "1" or response[0].lower == "y" then return true + if response == "0" or response[0].lower == "n" then return false + end while +end function + +printInstructions = function + print; print + print "This program plays the stock market. You will be given" + print "$10,000 and may buy or sell stocks. The stock prices will" + print "be generated randomly and therefore this model does not" + print "represent exactly what happens on the exchange. A table" + print "of available stocks, their prices, and the number of shares" + print "in your portfolio will be printed. Following this, the" + print "initials of each stock will be printed with a question" + print "mark. Here you indicate a transaction. To buy a stock" + print "type +NNN, to sell a stock type -NNN, where NNN is the" + print "number of shares. A brokerage fee of 1% will be charged" + print "on all transactions. Note that if a stock's value drops" + print "to zero it may rebound to a positive value again. You" + print "have $10,000 to invest. Use integers for all your inputs." + print "(Note: To get a 'feel' for the market run for at least" + print "10 days)" + print "-----Good luck!-----" + print + input "(Press Return to continue.)" +end function + +randomIndex = function; return floor(rnd * stockPrices.len); end function + +// Randomly produce new stock values based on previous day's values. +// N1,N2 are random numbers of days which respectively determine +// when a stock will increase or decrease 10 points. +adjustStockPrices = function + for i in changePerShare.indexes + changePerShare[i] = 0 + end for + // if N1 days have passed, increase a random stock by 10 + if N1 < 1 then + changePerShare[randomIndex] = 10 + globals.N1 = floor(4.99 * rnd + 1) + end if + // if N2 days have passed, decrease a random stock by 10 + if N2 < 1 then + changePerShare[randomIndex] = -10 + globals.N2 = floor(4.99 * rnd + 1) + end if + // Deduct one day from N1 and N2 + globals.N1 -= 1 + globals.N2 -= 1 + // update all stocks + for i in stockPrices.indexes + smallChange = rnd + if smallChange < 0.25 then smallChange = 0.25 + if smallChange > 0.5 then smallChange = 0.5 + changePerShare[i] += marketTrendSlope * stockPrices[i] + smallChange + floor(3 - 6*rnd + 0.5) + changePerShare[i] = round(changePerShare[i], 2) + stockPrices[i] += changePerShare[i] + if stockPrices[i] < 0 then + changePerShare[i] = 0 + stockPrices[i] = 0 + end if + stockPrices[i] = round(stockPrices[i], 2) + end for + // After trendDaysLeft, randomly change trend sign and slope + globals.trendDaysLeft -= 1 + if trendDaysLeft < 1 then + globals.trendDaysLeft = floor(4.99 * rnd + 1) + globals.marketTrendSlope = floor(rnd*10 + 0.5)/100 + if rnd < 0.5 then globals.marketTrendSlope = -marketTrendSlope + end if +end function + +pad = function(s, width=20) + s = str(s) + return s + " "*(width - s.len) +end function + +printInitialPortfolio = function + print pad("Stock", 30) + pad("Initials", 12) + "Price/Share" + for i in stockSymbols.indexes + print pad(stockNames[i], 32) + pad(stockSymbols[i], 14) + stockPrices[i] + end for +end function + +printMarketResults = function + print + print "********** END OF DAY'S TRADING **********" + print + print + print pad("Stock", 8) + pad("Price/Share", 14) + pad("Holdings", 12) + + pad("Value", 10) + "Net Price Change" + for i in stockSymbols.indexes + value = round(stockPrices[i] + sharesOwned[i], 2) + print pad(stockSymbols[i], 9) + pad(stockPrices[i], 14) + + pad(sharesOwned[i], 12) + pad(value, 10) + changePerShare[i] + end for + print +end function + +printStatus = function + average = stockPrices.sum / stockPrices.len + print + print "New York Stock Exchange Average: " + round(average, 2), "" + if prevAverage != null then + print " Net Change " + round(average - prevAverage, 2) + else + print + end if + globals.prevAverage = average + print + stockValue = 0 + for i in stockPrices.indexes + stockValue += stockPrices[i] * sharesOwned[i] + end for + print "Total stock assets are $ " + round(stockValue, 2) + print "Total cash assets are $ " + round(cash, 2) + print "Total assets are $ " + round(stockValue + cash, 2) + print + // Uncomment the following line to cheat/debug: + //print "marketTrendSlope: " + marketTrendSlope + "; trendDaysLeft: " + trendDaysLeft +end function + +// Calculate total cost, including brokerage fee, to buy the given +// stock (or if qtyToBuy < 0, negative cash gains minus the fee). +totalCost = function(stockIndex, qtyToBuy) + baseVal = stockPrices[stockIndex] * qtyToBuy + fee = round(abs(baseVal) * 0.01, 2) + return baseVal + fee +end function + +buySell = function + print "What is your transaction in" + i = 0 + while i < stockSymbols.len + while true + qty = input(stockSymbols[i] + "? ") + if qty == "" or qty == "0" or qty.val != 0 then break + print "Enter quantity to buy/sell like +10 or -2." + end while + qty = qty.val + if qty < 0 and -qty > sharesOwned[i] then + print "You have only " + sharesOwned[i] + " of " + stockSymbols[i] + "; try again." + continue + end if + if totalCost(i, qty) > cash then + print "This would cost " + (totalCost(i, qty) - cash) + " more than you have." + continue + end if + sharesOwned[i] += qty + globals.cash -= totalCost(i, qty) + i += 1 + end while +end function + +// Introduction +if yes("Do you want the instructions") then printInstructions +print; print + +// Initial stock values and trends +stockSymbols = ["IBM", "RCA", "LBJ", "ABC", "CBS"] +stockNames = ["Int. Ballistic Missiles", "Red Cross of America", + "Lichtenstein, Bumrap & Joke", "American Bankrupt Co.", "Censured Books Store"] +sharesOwned = [0] * stockSymbols.len +cash = 10000 +stockPrices = [100, 85, 150, 140, 110] +changePerShare = [0] * stockSymbols.len +trendDaysLeft = floor(4.99 * rnd + 1) +marketTrendSlope = floor(rnd*10 + 0.5)/100 +if rnd > 0.5 then marketTrendSlope = -marketTrendSlope +N1 = 0 // days until a big positive jump in a random price +N2 = 0 // days until a big negative jump in a random price +adjustStockPrices +prevAverage = null + +printInitialPortfolio +printStatus +while true + buySell + adjustStockPrices + printMarketResults + printStatus + if not yes("Do you wish to continue") then break +end while +print "Hope you had fun!!" + From 2aa6776dd7425a733442d6fc67d5dafdfd76ccef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Concei=C3=A7=C3=A3o?= Date: Tue, 10 Oct 2023 11:17:51 +0100 Subject: [PATCH 301/377] update train and tower Lua --- 90_Tower/lua/{train.lua => tower.lua} | 8 ++++---- 91_Train/lua/train.lua | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) rename 90_Tower/lua/{train.lua => tower.lua} (97%) diff --git a/90_Tower/lua/train.lua b/90_Tower/lua/tower.lua similarity index 97% rename from 90_Tower/lua/train.lua rename to 90_Tower/lua/tower.lua index c5e07b76b..b86539a48 100644 --- a/90_Tower/lua/train.lua +++ b/90_Tower/lua/tower.lua @@ -6,10 +6,10 @@ CREATIVE COMPUTING MORRISTOWN, NEW JERSY ]] -local MAX_DISKS = 7 --"" can be used starting in Lua 5.4, as such: "local MAX_DISKS = 7" -local MAX_DISK_SIZE = 15 -local MAX_MOVES = 128 -local NUM_TOWERS = 3 +local MAX_DISKS = 7 +local MAX_DISK_SIZE = 15 +local MAX_MOVES = 128 +local NUM_TOWERS = 3 local towers = { { size = 0, elem = {} }, diff --git a/91_Train/lua/train.lua b/91_Train/lua/train.lua index 0d11e73c6..dde7cd4d2 100644 --- a/91_Train/lua/train.lua +++ b/91_Train/lua/train.lua @@ -8,12 +8,12 @@ print [[ math.randomseed(os.time()) -local error_margin = 5.0 +local ERROR_MARGIN = 5.0 function play() - local car_speed = math.random(40, 65) - local delta_time = math.random(5, 20) - local train_speed = math.random(20, 39) + local car_speed = math.random(40, 65) --Between 40 and 64 + local delta_time = math.random(5, 20) --Between 5 and 19 + local train_speed = math.random(20, 39) --Between 20 and 38 print( string.format("\nA CAR TRAVELING AT %u MPH CAN MAKE A CERTAIN TRIP IN %u HOURS LESS THAN A TRAIN TRAVELING AT %u MPH.", car_speed, delta_time, train_speed) ) @@ -33,7 +33,7 @@ function play() local car_time = delta_time * train_speed / (car_speed - train_speed) local percent = ( math.abs(car_time-input) * 100 / car_time + .5) - if percent > error_margin then + if percent > ERROR_MARGIN then print( string.format("SORRY. YOU WERE OFF BY %f PERCENT.", percent) ) else print( string.format("GOOD! ANSWER WITHIN %f PERCENT.", percent) ) From 7b0554f4c972d618e3bc38ab254237ae0d1e680f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Concei=C3=A7=C3=A3o?= Date: Tue, 10 Oct 2023 11:21:04 +0100 Subject: [PATCH 302/377] fix train.ua random bounds --- 91_Train/lua/train.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/91_Train/lua/train.lua b/91_Train/lua/train.lua index dde7cd4d2..50214fa90 100644 --- a/91_Train/lua/train.lua +++ b/91_Train/lua/train.lua @@ -11,9 +11,9 @@ math.randomseed(os.time()) local ERROR_MARGIN = 5.0 function play() - local car_speed = math.random(40, 65) --Between 40 and 64 - local delta_time = math.random(5, 20) --Between 5 and 19 - local train_speed = math.random(20, 39) --Between 20 and 38 + local car_speed = 25*math.random() + 40--Between 40 and 64 + local delta_time = 15*math.random() + 5--Between 5 and 19 + local train_speed = 19*math.random() + 20--Between 20 and 38 print( string.format("\nA CAR TRAVELING AT %u MPH CAN MAKE A CERTAIN TRIP IN %u HOURS LESS THAN A TRAIN TRAVELING AT %u MPH.", car_speed, delta_time, train_speed) ) From 0c90f7c3936cafde8a4c18bedc588d3b41e8ce83 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 17 Oct 2023 10:37:25 -0700 Subject: [PATCH 303/377] Added MiniScript version of 84_Super_Star_Trek. (Though I still need to port the instructions, superstartreckins.bas.) --- .../84_Super_Star_Trek/MiniScript/README.md | 18 + .../MiniScript/superstartrek.ms | 1120 +++++++++++++++++ .../84_Super_Star_Trek/instructions.txt | 4 +- 3 files changed, 1140 insertions(+), 2 deletions(-) create mode 100644 00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md create mode 100644 00_Alternate_Languages/84_Super_Star_Trek/MiniScript/superstartrek.ms diff --git a/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md b/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md new file mode 100644 index 000000000..b749c2c0d --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/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 superstartrek.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 "superstartrek" + run +``` diff --git a/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/superstartrek.ms b/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/superstartrek.ms new file mode 100644 index 000000000..12d42db8e --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/superstartrek.ms @@ -0,0 +1,1120 @@ +// SUPER STARTREK - MAY 16,1978 - REQUIRES 24K MEMORY +// +// **** **** STAR TREK **** **** +// **** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE, +// **** AS SEEN ON THE STAR TREK TV SHOW. +// **** ORIGIONAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION +// **** PUBLISHED IN DEC'S "101 BASIC GAMES", BY DAVE AHL. +// **** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB +// *** LEEDOM - APRIL & DECEMBER 1974, +// *** WITH A LITTLE HELP FROM HIS FRIENDS . . . +// *** COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED -- +// *** SEND TO; R. C. LEEDOM +// *** WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR. +// *** BOX 746, M.S. 338 +// *** BALTIMORE, MD 21203 +// *** +// *** CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN GORDERS +// *** Convertod te MiniScript 10/10/23 by Joe Strout +// *** (based heavily on the Python port by @jkboyce) + +import "listUtil" +import "stringUtil" +import "mathUtil" + +//================================================================= +// Constants (tweak these to make the game easier or harder!) +//================================================================= +Constant = {} +Constant.klingonShieldStrength = 200 +Constant.maxEnergy = 3000 +Constant.maxTorpedos = 10 +Constant.minDays = 25 +Constant.maxDays = 34 + +// Directions. NOTE: this game has an unusual coordinate +// system, where x is the row (higher X values are further +// down on the screen), and y is the column (higher Y values +// are further to the right). +dirs = [ // (down, right) + [0, 1], // 1: go right (same as #9) + [-1, 1], // 2: go up-right + [-1, 0], // 3: go up (lower x-coordines; north) + [-1, -1], // 4: go up-left (north-west) + [0, -1], // 5: go left (west) + [1, -1], // 6: go down-left (south-west) + [1, 0], // 7: go down (higher x-coordines; south) + [1, 1], // 8: go down-right + [0, 1]] // 9: go right (east) + + + +//================================================================= +// Global Utility Functions +//================================================================= + +// Generate a random integer from 0 to 7 inclusive. +fnr = function + return floor(rnd * 8) +end function + +// Generate a random integer between any two limits (inclusive). +randInt = function(minVal, maxVal) + return floor(rnd * (maxVal - minVal + 1)) + minVal +end function + +// Print distance and direction between two points on a grid. +printDirection = function(source, dest) + delta1 = -(dest.x - source.x) + delta2 = dest.y - source.y + + if delta2 > 0 then + if delta1 < 0 then + base = 7 + else + base = 1 + temp = delta1; delta1 = delta2; delta2 = temp + end if + else + if delta1 > 0 then + base = 3 + else + base = 5 + temp = delta1; delta1 = delta2; delta2 = temp + end if + end if + + delta1 = abs(delta1) + delta2 = abs(delta2) + if delta1 or delta2 then // bug in original: failed when source == dest + if delta1 >= delta2 then + print "Direction = " + round(base + delta2 / delta1, 6) + else + print "Direction = " + round(base + 2 - delta1 / delta2, 6) + end if + end if + print "Distance = " + round(sqrt(delta1 ^ 2 + delta2 ^ 2), 6) +end function + +getYesNo = function(prompt) + while true + ans = input(prompt + "? ").lower + " " + if ans[0] == "y" then return "yes" + if ans[0] == "n" then return "no" + print "Please answer Yes or No." + end while +end function + +getXY = function(prompt) + while true + ans = input(prompt + "? ").split(",") + if ans.len == 2 then return {"x":ans[0].val, "y":ans[1].val} + print "Please enter two numbers separated by a comma. Example: 5,2" + end while +end function + +string.padBoth = function(length, padChar=" ") + // Pad a string on BOTH sides, so that it ends up centered. + if self.len > length then return self.len[:length] + extra = length - self.len + leftExtra = floor(extra/2) + rightExtra = extra - leftExtra + return padChar * leftExtra + self + padChar * rightExtra +end function + +//================================================================= +// Entity: map of strings used both as unique identifiers for +// things that can be at any position in a quadrant, AND also used +// as display strings in the short-range scan. +//================================================================= +Entity = {} +Entity.klingon = "+K+" +Entity.ship = "<*>" +Entity.empty = " " +Entity.starbase = ">!<" +Entity.star = " * " + +//================================================================= +// Point class: represents an X,Y position. Note that because +// the original game used 1-based coordinates, we have a conversion +// to string method that adds 1 to X and Y. But internally, these +// are assumed to be 0-based. +//================================================================= +Point = {} +Point.make = function(x,y) + p = new Point + p.x = x + p.y = y + return p +end function +Point.random = function + return Point.make(fnr, fnr) +end function +Point.oneBasedStr = function + return (self.x + 1) + " , " + (self.y + 1) +end function + +//================================================================= +// Position: combination of quadrant and sector +//================================================================= +Position = {} +Position.make = function(quadX, quadY, secX, secY) + pos = new Position + pos.quadrant = Point.make(quadX, quadY) + pos.sector = Point.make(secX, secY) + return pos +end function +Position.random = function + return Position.make(fnr, fnr, fnr, fnr) +end function + +//================================================================= +// Quadrant: represents one area of the map +//================================================================= +Quadrant = {} +Quadrant.make = function(quadrantX, quadrantY, klingons, bases, stars) + q = new Quadrant + q.point = Point.make(quadrantX, quadrantY) + q.klingons = klingons + q.bases = bases + q.stars = stars + q.extraRepairTime = rnd * 0.5 + q.klingonShips = [] // (list of KlingonShip) + q.starbase = null // (Point of starbase, if any) + q.charted = false + q.data = null + return q +end function + +// Get the name of the region of this quadrant (e.g. "Rigel"). +Quadrant.name = function + region1 = [ + "Antares", + "Rigel", + "Procyon", + "Vega", + "Canopus", + "Altair", + "Sagittarius", + "Pollux"] + region2 = [ + "Sirius", + "Deneb", + "Capella", + "Betelgeuse", + "Aldebaran", + "Regulus", + "Arcturus", + "Spica"] + if self.point.y < 4 then return region1[self.point.x] + return region2[self.point.x] +end function + +// Get the full name of this quadrant (e.g. "Rigel IV") +Quadrant.fullName = function + return self.name + " " + ["I", "II", "III", "IV"][self.point.y % 4] +end function + +// Store the given entity for the given cell in this quadrant +// (rounding to the nearest integer coordinates). +Quadrant.setValue = function(x, y, entity) + self.data[round(x)][round(y)] = entity +end function + +// Get the entity in the given cell of this quadrant +// (again rounding to the nearest integers). +Quadrant.value = function(x, y) + return self.data[round(x)][round(y)] +end function + +// Find an empty position within this quadrant. +Quadrant.findEmptyPoint = function + while true + p = Point.random + if self.value(p.x, p.y) == Entity.empty then return p + end while +end function + +Quadrant.addStarbase = function + pos = self.findEmptyPoint + self.setValue pos.x, pos.y, Entity.starbase + self.starbase = pos // (note: assumes 0 or 1 starbases) +end function + +// Fill out the contents of this quadrant, given the position of +// the ship and our number of klingons, bases, and stars. +Quadrant.populate = function(shipPos) + self.data = list.init2d(8, 8, Entity.empty) + if shipPos != null then self.setValue shipPos.x, shipPos.y, Entity.ship + for i in range(0, self.klingons-1, 1) + pos = self.findEmptyPoint + self.setValue pos.x, pos.y, Entity.klingon + self.klingonShips.push KlingonShip.make(pos.x, pos.y) + end for + if self.bases > 0 then self.addStarbase + for i in range(0, self.stars-1, 1) + pos = self.findEmptyPoint + self.setValue pos.x, pos.y, Entity.star + end for +end function + +// Return the three-digit number that represents the contents of +// this quadrant in a long-range scan: +Quadrant.lrsValue = function + return str(self.klingons) + str(self.bases) + str(self.stars) +end function + +// Return a list of lines representing the short-range scan +// of this quadrant (i.e., a representation of what entities +// it contains). +Quadrant.scanLines = function + result = [] + for row in self.data + result.push row.join + end for + return result +end function + +//================================================================= +// KlingonShip: represents an enemy ship. These are very simple; +// they need only their position (sector) within the quadrant, +// and their current shield level. +//================================================================= +KlingonShip = {} +KlingonShip.make = function(x, y) + k = new KlingonShip + k.sector = Point.make(x,y) + k.shield = Constant.klingonShieldStrength * (rnd + 0.5) + return k +end function +KlingonShip.distance = function(ship) + // Find distance, in sector units, between this ship and the given + // (player) ship. Assumes both are in the same quadrant. + return mathUtil.distance(self.sector, ship.position.sector) +end function + +//================================================================= +// Ship: represents the starship Enterprise and all its systems. +//================================================================= +Ship = {} +Ship.maxEnergy = Constant.maxEnergy +Ship.maxTorpedos = Constant.maxTorpedos +Ship.init = function + self.position = Position.random + self.devices = [ + "Warp Engines", + "Short Range Sensors", + "Long Range Sensors", + "Phaser Control", + "Photon Tubes", + "Damage Control", + "Shield Control", + "Library-Computer", + ] + self.deviceStatus = [0] * self.devices.len // > 0 means working; < 0 means broken + self.docked = false + self.shields = 0 + self.refill +end function + +Ship.useWarpEnergy = function(warpRounds) + // Note: movement costs 10 energy per sub-step (sector change). + self.energy -= warpRounds * 10 + if self.energy < 0 then + print "Shield control supplies energy to complete the maneuver." + self.shields += self.energy + self.energy = 0 + if self.shields < 0 then self.shields = 0 + end if +end function + +Ship.refill = function + self.energy = self.maxEnergy + self.torpedos = self.maxTorpedos +end function + +Ship.stranded = function + return self.shields + self.energy <= 10 or + (self.energy <= 10 and self.deviceStatus[6] < 0) +end function + +//================================================================= +// Galaxy: all 64 quadrants, plus global information about how many +// klingons there are, the current game time, etc. Basically +// represents the state of the game (but not the flow; that happens +// in the Game class). +//================================================================= +Galaxy = {} +Galaxy.init = function(minDuration=20) + self.qtyKlingons = 0 + self.qtyBases = 0 + self.startDate = 100 * randInt(20, 39) + self.endDate = self.startDate + randInt(Constant.minDays, Constant.maxDays) + self.stardate = self.startDate + self.ship = new Ship + self.ship.init + self.quadrants = list.init2d(8, 8) + for x in range(0, 7) + for y in range(0, 7) + klingons = 0 + r1 = rnd + if r1 > 0.80 then klingons = 1 + if r1 > 0.95 then klingons = 2 + if r1 > 0.98 then klingons = 3 + bases = (rnd > 0.96) + self.quadrants[x][y] = Quadrant.make(x, y, klingons, bases, fnr+1) + self.qtyKlingons += klingons + self.qtyBases += bases + end for + end for + self.missionDuration = minDuration + if self.qtyKlingons > self.missionDuration then + self.missionDuration = self.qtyKlingons + 1 + end if + here = self.localQuadrant + if self.qtyBases == 0 then self.qtyBases = 1 + self.ship.position.sector = Point.random +end function + +Galaxy.daysElapsed = function; return self.stardate - self.startDate; end function +Galaxy.daysLeft = function; return self.endDate - self.stardate; end function +Galaxy.missionOver = function; return self.stardate > self.endDate; end function + +Galaxy.localQuadrant = function + qp = self.ship.position.quadrant + return self.quadrants[qp.x][qp.y] +end function + +Galaxy.printLongRangeScan = function(point) + sep = "-" * 19 + for x in range(point.x - 1, point.x + 1) + print sep + entries = [] + for y in range(point.y - 1, point.y + 1) + if not (0 <= x <= 7 and 0 <= y <= 7) then + entries.push "***" + else + q = self.quadrants[x][y] + entries.push q.lrsValue + q.charted = true + end if + end for + print ": " + entries.join(" : ") + " :" + end for + print sep +end function + +//================================================================= +// Game: represents the flow of the game, and handles user actions. +//================================================================= +Game = {} +Game.init = function + self.galaxy = new Galaxy + self.galaxy.init + self.gameOver = false +end function + +Game.printIntro = function + print;print;print;print;print;print;print;print;print;print;print + print " ,------*------," + print " ,------------- '--- ------'" + print " '-------- --' / /" + print " ,---' '-------/ /--," + print " '----------------'";print + print " THE USS ENTERPRISE --- NCC-1701" + print;print;print;print;print + k = self.galaxy.qtyKlingons + sb = self.galaxy.qtyBases + if sb == 1 then isAre = "is" else isAre = "are" + days = self.galaxy.endDate - self.galaxy.startDate + orders = ["Your orders are as follows:"] + orders.push " Destroy the " + k + " Klingon warships which have invaded" + orders.push " the galaxy before they can attack federation headquarters" + orders.push " on stardate " + self.galaxy.endDate + ". This gives you " + + days + " days. There " + isAre + orders.push " " + sb + " starbase" + "s"*(sb!=1) + " in the galaxy for resupplying your ship." + for line in orders + print line // for extra drama, add a `wait 0.5` line here! + end for + print + input "Press Return when ready to accept command" + print + self.enterQuadrant +end function + +Game.enterQuadrant = function + // Populate the local quadrant and print a short-range scan. + ship = self.galaxy.ship + here = self.galaxy.localQuadrant + here.charted = true + here.populate ship.position.sector + + if self.galaxy.daysElapsed == 0 then + print "Your mission begins with your ship located" + print "in the galactic quadrant, '" + here.fullName + "'" + else + print "Now entering " + here.fullName + " quadrant . . ." + end if + print + + if here.klingons > 0 then + print "COMBAT AREA CONDITION RED" + if ship.shields <= 200 then print " SHIELDS DANGEROUSLY LOW" + end if + self.shortRangeScan +end function + +Game.shortRangeScan = function + ship = self.galaxy.ship + ship.docked = false + quad = self.galaxy.localQuadrant + cs = null + for x in range(ship.position.sector.x - 1, ship.position.sector.x + 1) + for y in range(ship.position.sector.y - 1, ship.position.sector.y + 1) + if 0 <= x <= 7 and 0 <= y <= 7 and quad.value(x, y) == Entity.starbase then + ship.docked = true + cs = "DOCKED" + ship.refill + print "Shields dropped for docking purposes" + ship.shields = 0 + end if + end for + end for + if not cs then + if quad.klingons then + cs = "*RED*" + else if ship.energy < ship.maxEnergy * 0.1 then + cs = "*YELLOW*" + else + cs = "GREEN" + end if + end if + if ship.deviceStatus[1] < 0 then + print + print "*** Short range sensors are out ***" + return + end if + print "-"*33 + for x in range(0, 7) + line = quad.data[x].join + if x == 0 then + line += " STARDATE " + round(self.galaxy.stardate, 1) + else if x == 1 then + line += " CONDITION " + cs + else if x == 2 then + line += " QUADRANT " + ship.position.quadrant.oneBasedStr + else if x == 3 then + line += " SECTOR " + ship.position.sector.oneBasedStr + else if x == 4 then + line += " PHOTON TORPEDOES " + ship.torpedos + else if x == 5 then + line += " TOTAL ENERGY " + floor(ship.energy + ship.shields) + else if x == 6 then + line += " SHIELDS " + floor(ship.shields) + else if x == 7 then + line += " KLINGONS REMAINING " + self.galaxy.qtyKlingons + end if + print line + end for + print "-"*33 +end function + +Game.longRangeScan = function + ship = self.galaxy.ship + if ship.deviceStatus[2] < 0 then + print "Long range sensors are inoperable" + return + end if + print "Long range scan for quadrant " + ship.position.quadrant.oneBasedStr + self.galaxy.printLongRangeScan ship.position.quadrant +end function + +Game.updateKlingons = function + // Move klingons around randomly within the sector + here = self.galaxy.localQuadrant + if not here.klingonShips then return + + for klingonShip in here.klingonShips + if klingonShip.shield <= 0 then continue // (already disabled/destroyed) + here.setValue klingonShip.sector.x, klingonShip.sector.y, Entity.empty + klingonShip.sector = here.findEmptyPoint + here.setValue klingonShip.sector.x, klingonShip.sector.y, Entity.klingon + end for + + self.klingonsFire +end function + +Game.klingonsFire = function + // Nearby klingons fire on the player ship. + here = self.galaxy.localQuadrant + if here.klingons <= 0 then return + ship = self.galaxy.ship + if ship.docked then + print "Starbase shields protect the Enterprise" + return + end if + for klingonShip in here.klingonShips + if klingonShip.shield <= 0 then continue // (already disabled/destroyed) + hit = floor((klingonShip.shield / klingonShip.distance(ship)) * (rnd + 2)) + ship.shields -= hit + print " " + hit + " unit hit on Enterprise from sector " + klingonShip.sector.oneBasedStr + if ship.shields <= 0 then + self.endGame false, false, true + return + end if + print " " + if hit >= 20 and rnd < 0.60 and hit / ship.shields > 0.02 then + deviceNum = floor(rnd * ship.devices.len) + ship.deviceStatus[deviceNum] -= hit / ship.shields + 0.5 * rnd + print "Damage control reports '" + ship.devices[deviceNum] + " damaged by the hit'" + end if + end for +end function + +Game.damControlWhileUnderway = function(improvement=1) + // Work on repairing damaged devices, and 20% of the time, do additional work on + // some random device (which may make it better or worse). + ship = self.galaxy.ship + first = true + for i in range(0, ship.devices.len-1) + if ship.deviceStatus[i] >= 0 then continue + ship.deviceStatus[i] += improvement + if -0.1 < ship.deviceStatus[i] < 0 then ship.deviceStatus[i] = -0.1 + if ship.deviceStatus[i] >= 0 then + if first then s = "Damage control report:" else s = "" + s += " " + ship.devices[i] + " repair completed" + print s + first = false + end if + end for + + if rnd > 0.2 then return + deviceNum = floor(rnd * ship.devices.len) + if rnd < 0.6 then + ship.deviceStatus[deviceNum] -= rnd * 5 + 1 + print "Damage control report: " + ship.devices[deviceNum] + " damaged" + else + ship.deviceStatus[deviceNum] += rnd * 3 + 1 + print "Damage control report: " + ship.devices[deviceNum] + " state of repair improved" + end if +end function + +Game.navigate = function + galaxy = self.galaxy + ship = galaxy.ship + cd = input("Course (1-9)? ").val - 1 // (convert input to 0-8) + if cd == dirs.len - 1 then cd == 0 + if cd < 0 or cd >= dirs.len then + print " Lt. Sulu reports, 'Incorrect course data, sir!'" + return + end if + + if ship.deviceStatus[0] < 0 then maxWarp = 0.2 else maxWarp = 8 + warp = input("Warp factor (0-" + maxWarp + ")? ").val + if warp > maxWarp and maxWarp < 1 then + print "Warp engines are damaged. Maximum speed = warp " + maxWarp + return + end if + if warp == 0 then return + if warp < 0 or warp > 8 then + print " Chief engineer Scott reports 'The engines won't take warp " + warp + "!'" + return + end if + + warpRounds = round(warp * 8) + // Note that we check for sufficient energy based on 1/10th of what it + // will actually cost. This is apparently intentional. + if ship.energy < warpRounds then + print "Engineering reports 'Insufficient energy available" + print " for maneuvering at warp " + warp + "!'" + if ship.shields >= warpRounds - ship.energy and ship.deviceStatus[6] >= 0 then + print "Deflector control room acknowledges " + ship.shields + " units of energy" + print " presently deployed to shields." + end if + return + end if + + self.updateKlingons + self.damControlWhileUnderway + + here = galaxy.localQuadrant + here.setValue ship.position.sector.x, ship.position.sector.y, Entity.empty + startQuad = Point.make(here.point.x, here.point.y) +// print "DEBUG set value at " + ship.position.sector.x + "," + ship.position.sector.y + " to Entity.empty" + // interpolate the direction + cdi = floor(cd) + dx = mathUtil.lerp(dirs[cdi][0], dirs[cdi+1][0], cd - cdi) + dy = mathUtil.lerp(dirs[cdi][1], dirs[cdi+1][1], cd - cdi) + finalGlobalX = ship.position.quadrant.x * 8 + ship.position.sector.x + dx * warpRounds + finalGlobalY = ship.position.quadrant.y * 8 + ship.position.sector.y + dy * warpRounds + for i in range(1, warpRounds) + ship.position.sector.x += dx + ship.position.sector.y += dy + if not (0 <= ship.position.sector.x <= 7 and 0 <= ship.position.sector.y <= 7) then + // Exceeded quadrant limits; calculate final position. + // Note that we randomly re-generate all the stuff in a quadrant every + // time we enter it. So we can jump right to the final position now; + // We only check for collisions when moving *within* your starting sector. + // your starting sector. + ship.position.quadrant.x = floor(finalGlobalX / 8) + ship.position.quadrant.y = floor(finalGlobalY / 8) + ship.position.sector.x = finalGlobalX - ship.position.quadrant.x * 8 + ship.position.sector.y = finalGlobalY - ship.position.quadrant.y * 8 + hitEdge = false + if ship.position.quadrant.x < 0 then + hitEdge = true + ship.position.quadrant.x = 0 + ship.position.sector.x = 0 + else if ship.position.quadrant.x > 7 then + hitEdge = true + ship.position.quadrant.x = 7 + ship.position.sector.x = 7 + end if + if ship.position.quadrant.y < 0 then + hitEdge = true + ship.position.quadrant.y = 0 + ship.position.sector.y = 0 + else if ship.position.quadrant.y > 7 then + hitEdge = true + ship.position.quadrant.y = 7 + ship.position.sector.y = 7 + end if + if hitEdge then + print "Lt. Uhura reports message from Starfleet Command:" + print " 'Permission to attempt crossing of galactic perimeter" + print " is hereby *denied*. Shut down your engines.'" + print "Chief Engineer Scott reports 'Warp engines shut down" + print " at sector " + ship.position.sector.oneBasedStr + + " of quadrant " + ship.position.quadrant.oneBasedStr + ".'" + end if + break + end if + x = floor(ship.position.sector.x) + y = floor(ship.position.sector.y) + if here.value(x, y) != Entity.empty then + ship.position.sector.x = floor(x - dx) + ship.position.sector.y = floor(y - dy) + print "Warp engines shut down at sector " + ship.position.sector.oneBasedStr + + " due to bad navigation" + break + end if + end for + ship.position.sector.x = floor(ship.position.sector.x) + ship.position.sector.y = floor(ship.position.sector.y) + doScan = true + if ship.position.quadrant != startQuad then + self.enterQuadrant + doScan = false + else + here.setValue ship.position.sector.x, ship.position.sector.y, Entity.ship +// print "DEBUG set value at " + ship.position.sector.x + "," + ship.position.sector.y + " to Entity.ship" + end if + ship.useWarpEnergy warpRounds + if warp < 1 then galaxy.stardate += round(warp, 1) else galaxy.stardate += 1 + if galaxy.missionOver then + self.endGame false, false, false + else if doScan then + self.shortRangeScan + end if +end function + +Game.damageControl = function + ship = self.galaxy.ship + if ship.deviceStatus[5] < 0 then + print "Damage control report not available." + else + print + print "DEVICE STATE OF REPAIR" + for i in range(0, ship.devices.len-1) + print ship.devices[i].pad(26) + round(ship.deviceStatus[i], 2) + end for + print + end if + + if not ship.docked then return + + repairTime = 0 + for status in ship.deviceStatus + if status < 0 then repairTime += 0.1 + end for + if repairTime == 0 then return + + repairTime += self.galaxy.localQuadrant.extraRepairTime + if repairTime >= 1 then repairTime = 0.9 + print + print "Technicians standing by to effect repairs to your ship;" + print "estimated time to repair: " + round(repairTime, 2) + " stardates" + if getYesNo("Will you authorize the repair order (Y/N)") == "no" then return + + for i in range(0, ship.devices.len-1) + if ship.deviceStatus[i] < 0 then ship.deviceStatus[i] = 0 + end for + self.galaxy.stardate += repairTime + 0.1 +end function + +Game.shieldControl = function + ship = self.galaxy.ship + if ship.deviceStatus[6] < 0 then + print "Shield control inoperable" + return + end if + totalEnergy = ship.energy + ship.shields + shieldEnergy = input("Energy available = " + totalEnergy + " Number of units to shields? ") + if shieldEnergy == "" then shieldEnergy = ship.shields else shieldEnergy = shieldEnergy.val + if shieldEnergy > totalEnergy then + print "Shield control reports 'This is not the federation treasury.'" + print + shieldEnergy = -1 + end if + if shieldEnergy < 0 or shieldEnergy == ship.shields then + print "" + return + end if + ship.energy += ship.shields - shieldEnergy + ship.shields = shieldEnergy + print "Deflector control room report:" + print " 'Shields now at " + ship.shields + " units per your command.'" +end function + +Game.computer = function + galaxy = self.galaxy + ship = galaxy.ship + if ship.deviceStatus[7] < 0 then + print "Computer disabled" + return + end if + + while true + command = input("Computer active and awaiting command? ") + print + if command == "0" then // Cumulative Galactic Record + print + print " COMPUTER RECORD OF GALAXY FOR QUADRANT " + + ship.position.quadrant.oneBasedStr + print " 1 2 3 4 5 6 7 8" + sep = " ----- ----- ----- ----- ----- ----- ----- -----" + print sep + for i in range(0,7) + line = " " + (i+1) + " " + for j in range(0, 7) + line += " " + if galaxy.quadrants[i][j].charted then + line += galaxy.quadrants[i][j].lrsValue + else + line += "***" + end if + end for + print line + print sep + end for + else if command == "1" then // Status Report + print " STATUS REPORT:" + print "Klingon" + "s" * (galaxy.qtyKlingons != 1) + " left: " + galaxy.qtyKlingons + print "Mission must be completed in " + round(galaxy.daysLeft, 1) + " stardates" + + if galaxy.qtyBases == 0 then + print "Your stupidity has left you on your own in" + print " the galaxy -- you have no starbases left!" + else + print "The Federation is maintaining " + galaxy.qtyBases + + " starbase" + "s" * (galaxy.qtyBases != 1) + " in the galaxy" + end if + + self.damageControl + else if command == "2" then // Photon Torpedo Data + here = galaxy.localQuadrant + if here.klingons <= 0 then + print "Science officer Spock reports 'Sensors show no enemy ships" + print " in this quadrant'" + else + print "FROM ENTERPRISE TO KLINGON BATTLE CRUISER" + "S" * (here.klingons != 1) + for klingonShip in here.klingonShips + if klingonShip.shield <= 0 then continue + printDirection ship.position.sector, klingonShip.sector + end for + end if + else if command == "3" then // Starbase Nav Data + here = galaxy.localQuadrant + if not here.starbase then + print "Science officer Spock reports, 'Sensors show no starbases" + print " in this quadrant.'" + else + print "FROM ENTERPRISE TO STARBASE:" + printDirection ship.position.sector, here.starbase + end if + else if command == "4" then // Direction/Distance Calculator + print "DIRECTION/DISTANCE CALCULATOR:" + print "You are at quadrant " + ship.position.quadrant.oneBasedStr + + " SECTOR " + ship.position.sector.oneBasedStr + print "Please enter" + fromXY = getXY(" Initial coordinates (X,Y)") + toXY = getXY(" Final coordinates (X,Y)") + printDirection fromXY, toXY + else if command == "5" then // Galaxy 'Region Name' Map + print + print " THE GALAXY" + print " 1 2 3 4 5 6 7 8" + sep = " ----- ----- ----- ----- ----- ----- ----- -----" + print sep + for i in range(0,7) + line = " " + (i+1) + " " + line += galaxy.quadrants[i][0].name.padBoth(25) + line += galaxy.quadrants[i][4].name.padBoth(25) + print line + print sep + end for + else + print "Functions available from Library-Computer:" + print " 0 = Cumulative Galactic Record" + print " 1 = Status Report" + print " 2 = Photon Torpedo Data" + print " 3 = Starbase Nav Data" + print " 4 = Direction/Distance Calculator" + print " 5 = Galaxy 'Region Name' Map" + continue + end if + print + break // break out after any valid command + end while +end function + +Game.destroyKlingon = function(x, y) + // Destroy the Klingon in the local quadrant at sector x,y. + // Return true if the game is now won (last klingon destroyed), + // or false otherwise. + galaxy = self.galaxy + here = galaxy.localQuadrant + print "*** KLINGON DESTROYED ***" + galaxy.qtyKlingons -= 1 + here.klingons -= 1 + here.setValue x, y, Entity.empty + for i in here.klingonShips.indexes + ks = here.klingonShips[i] + if ks.sector.x == x and ks.sector.y == y then + ks.shield = 0 + here.klingonShips.remove i + break + end if + end for + + if galaxy.qtyKlingons <= 0 then + self.endGame true, false, false + return true + end if + return false +end function + + +Game.phasers = function + galaxy = self.galaxy + ship = galaxy.ship + here = galaxy.localQuadrant + klingonShips = here.klingonShips + + if ship.deviceStatus[3] < 0 then + print "Phasers inoperative" + return + end if + + if here.klingons <= 0 then + print "Science officer Spock reports 'Sensors show no enemy ships" + print " in this quadrant'" + return + end if + + if ship.deviceStatus[7] < 0 then + print "Computer failure hampers accuracy" + end if + + print "Phasers locked on target; energy available = " + ship.energy + " units" + while true + phaserPower = input("Number of units to fire? ").val + if phaserPower <= 0 then return + if phaserPower <= ship.energy then break + print "Energy available = " + ship.energy + " units" + end while + + ship.energy -= phaserPower + if ship.deviceStatus[7] < 0 then // (bug in original; was d(6) + phaserPower *= rnd + end if + + phaserPerKlingon = floor(phaserPower / here.klingons) + for i in range(klingonShips.len - 1) + ks = klingonShips[i] + if ks.shield <= 0 then continue + distance = mathUtil.distance(ks.sector, ship.position.sector) + hit = floor((phaserPerKlingon / distance) * (rnd + 2)) + if hit <= 0.15 * ks.shield then + print "Sensors show no damage to enemy at " + ks.sector.oneBasedStr + else + ks.shield -= hit + print " " + hit + " unit hit on Klingon at sector " + ks.sector.oneBasedStr + if ks.shield <= 0 then + if self.destroyKlingon(ks.sector.x, ks.sector.y) then return + else + print " (Sensors show " + round(ks.shield, 6) + " units remaining)" + end if + end if + end for + + self.klingonsFire +end function + +Game.torpedos = function + galaxy = self.galaxy + ship = galaxy.ship + here = galaxy.localQuadrant + klingonShips = here.klingonShips + + if ship.torpedos <= 0 then + print "All photon torpedos expended" + return + else if ship.deviceStatus[4] < 0 then + print "Photon tubes are not operational" + return + end if + + cd = input("Course (1-9)? ").val - 1 // (convert input to 0-8) + if cd == dirs.len - 1 then cd == 0 + if cd < 0 or cd >= dirs.len then + print " Lt. Sulu reports, 'Incorrect course data, sir!'" + return + end if + + cdi = floor(cd) + dx = mathUtil.lerp(dirs[cdi][0], dirs[cdi+1][0], cd - cdi) + dy = mathUtil.lerp(dirs[cdi][1], dirs[cdi+1][1], cd - cdi) + + ship.energy -= 2 + ship.torpedos -= 1 + + x = ship.position.sector.x + y = ship.position.sector.y + print "Torpedo track:" + while true + x += dx + y += dy + roundX = round(x); roundY = round(y) + if not (0 <= roundX <= 7) or not (0 <= roundY <= 7) then + print "Torpedo missed" + self.klingonsFire + return + end if + print " " + (roundX+1) + " , " + (roundY+1) + wait 0.5 // (added for dramatic effect) + entityHit = here.value(roundX, roundY) + if entityHit != Entity.empty then break + end while + + if entityHit == Entity.klingon then + if self.destroyKlingon(roundX, roundY) then return + else if entityHit == Entity.star then + print "Star at " + (roundX+1) + " , " + (roundY+1) + " absorbed torpedo energy." + else if entityHit == Entity.starbase then + print "*** STARBASE DESTROYED ***" + here.bases -= 1 + here.setValue roundX, roundY, Entity.empty + galaxy.qtyBases -= 1 + if galaxy.qtyBases == 0 and galaxy.qtyKlingons <= galaxy.daysLeft then + // (Note: bug in original code, compared qtyKlingons to + // quantity daysLeft - missionDuration, which would always be a negative + // number. So this hard-labor message could never appear. I've chosen + // a different comparison which at least can be true sometimes.) + print "That does it, captain!! You are hereby relieved of command" + print "and sentenced to 99 stardates at hard labor on Cygnus 12!!" + self.endGame false, false, false + return + end if + print "Starfleet Command reviewing your record to consider" + print "court martial!" + ship.docked = false + end if + + self.klingonsFire +end function + +Game.endGame = function(won=false, quit=true, shipDestroyed=false) + if won then + print "Congratulations, captain! The last klingon battle cruiser" + print "menacing the federation has been destroyed." + efficiency = round(1000 * self.galaxy.qtyKlingons / self.galaxy.daysElapsed^2, 4) + print "Your efficiency rating is " + efficiency + print + else + if not quit then + if shipDestroyed then + print + print "The enterprise has been destroyed. The Federation " + print "will be conquered." + end if + print "It is stardate " + round(self.galaxy.stardate, 1) + end if + + print "There were " + self.galaxy.qtyKlingons + " klingon battle cruisers left at" + print "the end of your mission." + print + end if + if self.galaxy.qtyBases == 0 then exit + print "The Federation is in need of a new starship commander" + print "for a similar mission -- if there is a volunteer," + if input("let him step forward and enter 'aye'? ").lower().trim != "aye" then exit + self.gameOver = true +end function + +notImplemented = function + print + print "Not implemented yet." + print +end function + +Game.commands = [] // each entry is [command, summary, function] +Game.addCommand = function(command, summary, func) + self.commands.push [command, summary, @func] +end function + +Game.addCommand "NAV", "to set course", @Game.navigate +Game.addCommand "SRS", "for short range sensor scan", @Game.shortRangeScan +Game.addCommand "LRS", "for long range sensor scan", @Game.longRangeScan +Game.addCommand "PHA", "to fire phasers", @Game.phasers +Game.addCommand "TOR", "to fire photon torpedos", @Game.torpedos +Game.addCommand "SHE", "to raise or lower shields", @Game.shieldControl +Game.addCommand "DAM", "for damage control reports", @Game.damageControl +Game.addCommand "COM", "to call on library-computer", @Game.computer +Game.addCommand "XXX", "to resign your command", @Game.endGame + + +Game.doOneCommand = function + cmd = input("Command? ").upper + for entry in self.commands + if cmd == entry[0] then + self.curCmdFunc = entry[2] + self.curCmdFunc + return + end if + end for + print "Enter one of the following:" + for entry in self.commands + print " " + entry[0] + " (" + entry[1] + ")" + end for + print +end function + +Game.mainLoop = function + while not self.gameOver + self.doOneCommand + if self.galaxy.ship.stranded then + print + print "** FATAL ERROR ** You've just stranded your ship in space." + print "You have insufficient maneuvering energy, and shield control" + print "is presently incapable of cross-circuiting to engine room!!" + end if + end while +end function + +while true + game = new Game + game.init + game.printIntro + game.mainLoop +end while \ No newline at end of file diff --git a/00_Alternate_Languages/84_Super_Star_Trek/instructions.txt b/00_Alternate_Languages/84_Super_Star_Trek/instructions.txt index 59124d9d6..837558347 100644 --- a/00_Alternate_Languages/84_Super_Star_Trek/instructions.txt +++ b/00_Alternate_Languages/84_Super_Star_Trek/instructions.txt @@ -57,7 +57,7 @@ OF THE STARSHIP ENTERPRISE: ITSELF IS EQUIVALENT TO 1.0" COURSE ONE WARP FACTOR IS THE SIZE OF - ONE QUADTANT. THEREFORE, TO GET + ONE QUADRANT. THEREFORE, TO GET FROM QUADRANT 6,5 TO 5,5, YOU WOULD USE COURSE 3, WARP FACTOR 1. @@ -77,7 +77,7 @@ OF THE STARSHIP ENTERPRISE: OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN) THE SCAN IS CODED IN THE FORM \###\, WHERE TH UNITS DIGIT IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF - STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF + STARBASES, AND THE HUNDREDS DIGIT IS THE NUMBER OF KLINGONS. EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS. From 11de8ff9b098d82b382930d5c5634fe0561ffb92 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 17 Oct 2023 10:58:52 -0700 Subject: [PATCH 304/377] Added instructions. Chose to incorporate these into the main program rather than as a separate program; I think the original BASIC programs were separated only due to memory limitations. --- .../MiniScript/superstartrek.ms | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/superstartrek.ms b/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/superstartrek.ms index 12d42db8e..7b7a247c9 100644 --- a/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/superstartrek.ms +++ b/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/superstartrek.ms @@ -22,6 +22,139 @@ import "listUtil" import "stringUtil" import "mathUtil" +//================================================================= +// Instructions +// (This was originally in a separate program, superstartreckins.bas, +// for memory reasons. I've chosen to incorporate it into the main +// program, as that's more convenient for everybody.) +//================================================================= +Instructions = {} +Instructions.print = function + print + print "At each pause, press Return to continue." + input + + print " Instructions for 'Super Star Trek'" + print + print "1. When you see \Command?\ printed, enter one of the legal" + print " commands (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX)." + print "2. If you should type in an illegal command, you'll get a short" + print " list of the legal commands printed out." + print "3. Some commands require you to enter data (for example, the" + print " 'NAV' command comes back with 'Course (1-9)?'.) If you" + print " type in illegal data (like negative numbers), that command" + print " will be aborted" + print + print " The galaxy is divided into an 8 x 8 quadrant grid," + print "and each quadrant is further divided into an 8 x 8 sector grid." + print + print " You will be assigned a starting point somewhere in the" + print "galaxy to begin a tour of duty as comander of the starship" + print "\Enterprise\; your mission: to seek and destroy the fleet of" + print "klingon warwhips which are menacing the United Federation of" + print "Planets." + input + + print + print " You have the following commands available to you as captain" + print "of the starship Enterprise:" + print + print "\NAV\ command = warp engine control --" + print " course is in a circular numerical 4 3 2" + print " vector arrangement as shown . | ." + print " integer and real values may be .|." + print " used. (Thus course 1.5 is half- 5 ---*--- 1" + print " way between 1 and 2.) .|." + print " . | ." + print " Values may approach 9.0, which 6 7 8" + print " itself is equivalent to 1.0" + print " course" + print " One warp factor is the size of " + print " one quadrant. Therefore, to get" + print " from quadrant 6,5 to 5,5, you would" + print " use course 3, warp factor 1." + input + + print + print "\SRS\ command = short range sensor scan" + print " Shows you a scan of your present quadrant." + print + print " Symbology on your sensor screen is as follows:" + print " <*> = your starship's position" + print " +K+ = klingon battle cruiser" + print " >!< = federation starbase (refuel/repair/re-arm here!)" + print " * = star" + print + print " A condensed 'status report' will also be presented." + input + + print + print "\LRS\ command = long range sensor scan" + print " Shows conditions in space for one quadrant on each side" + print " of the enterprise (which is in the middle of the scan)." + print " The scan is coded in the form \###\, where the units digit" + print " is the number of stars, the tens digit is the number of" + print " starbases, and the hundresds digit is the number of" + print " klingons." + print + print " Example - 207 = 2 klingons, no starbases, & 7 stars." + input + + print + print "\PHA\ command = phaser control." + print " Allows you to destroy the klingon battle cruisers by " + print " zapping them with suitably large units of energy to" + print " deplete their shield power. (Remember, klingons have" + print " phasers too!)" + print + print "\TOR\ command = photon torpedo control" + print " Torpedo course is the same as used in warp engine control." + print " If you hit the klingon vessel, he is destroyed and" + print " cannot fire back at you. If you miss, you are subject to" + print " his phaser fire. In either case, you are also subject to " + print " the phaser fire of all other klingons in the quadrant." + print + print " The library-computer (\COM\ command) has an option to " + print " compute torpedo trajectory for you (option 2)." + input + + print + print "\SHE\ command = shield control" + print " Defines the number of energy units to be assigned to the" + print " shields. Energy is taken from total ship's energy. Note" + print " that the status display total energy includes shield energy." + print + print "\DAM\ command = dammage control report" + print " Gives the state of repair of all devices, where a negative" + print " 'state of repair' shows that the device is temporarily" + print " damaged." + input + + print + print "\COM\ command = library-computer" + print " The library-computer contains six options:" + print " option 0 = cumulative galactic record" + print " This option showes computer memory of the results of all" + print " previous short and long range sensor scans." + print " option 1 = status report" + print " This option shows the number of klingons, stardates," + print " and starbases remaining in the game." + print " option 2 = photon torpedo data" + print " Which gives directions and distance from the enterprise" + print " to all klingons in your quadrant." + print " option 3 = starbase nav data" + print " This option gives direction and distance to any " + print " starbase within your quadrant." + print " option 4 = direction/distance calculator" + print " This option allows you to enter coordinates for" + print " direction/distance calculations." + print " option 5 = galactic /region name/ map" + print " This option prints the names of the sixteen major " + print " galactic regions referred to in the game." + input + print +end function + //================================================================= // Constants (tweak these to make the game easier or harder!) //================================================================= @@ -1081,6 +1214,7 @@ Game.addCommand "TOR", "to fire photon torpedos", @Game.torpedos Game.addCommand "SHE", "to raise or lower shields", @Game.shieldControl Game.addCommand "DAM", "for damage control reports", @Game.damageControl Game.addCommand "COM", "to call on library-computer", @Game.computer +Game.addCommand "HLP", "for help, i.e. instructions", @Instructions.print // (not in original game) Game.addCommand "XXX", "to resign your command", @Game.endGame @@ -1112,6 +1246,19 @@ Game.mainLoop = function end while end function +for i in range(1,12); print; end for +print " "*10 + "*************************************" +print " "*10 + "* *" +print " "*10 + "* *" +print " "*10 + "* * * SUPER STAR TREK * * *" +print " "*10 + "* *" +print " "*10 + "* *" +print " "*10 + "*************************************" +for i in range(1,8); print; end for +if getYesNo("Do you need instructions (y/n)") == "yes" then + Instructions.print +end if + while true game = new Game game.init From f7db28ec301b3466ed2338a18113e6c435c34a44 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 18 Oct 2023 13:53:57 -0700 Subject: [PATCH 305/377] Added MiniScript version of 88_3-D_Tic-Tac-Toe. (Also fixed a bug in the JavaScript port.) --- .../88_3-D_Tic-Tac-Toe/MiniScript/README.md | 18 + .../88_3-D_Tic-Tac-Toe/MiniScript/qubit.ms | 361 ++++++++++++++++++ 88_3-D_Tic-Tac-Toe/README.md | 2 + 88_3-D_Tic-Tac-Toe/javascript/qubit.js | 2 +- 4 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/README.md create mode 100644 00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/qubit.ms 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 000000000..ac3893185 --- /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 000000000..3074be2d4 --- /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 969de3d83..2ab13480d 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 0057619fb..6f1cbe64e 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); From c45a80b074cae5df21698b48234687a469c7c211 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Wed, 18 Oct 2023 14:03:44 -0700 Subject: [PATCH 306/377] Fixed/elaborated two MiniScript README files. --- .../84_Super_Star_Trek/MiniScript/README.md | 2 +- .../88_3-D_Tic-Tac-Toe/MiniScript/README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md b/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md index b749c2c0d..0b383f4b5 100644 --- a/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md +++ b/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md @@ -1,6 +1,6 @@ Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). -Conversion to [MiniScript](https://miniscript.org). +Conversion to [MiniScript](https://miniscript.org). Note that while the original game separated the instructions into a separate BASIC program (probably due to memory limitations), we have chosen here to combine them into one MiniScript program with both instructions and gameplay. The instructions are available at the start of the game, and later at any time via the HLP command. Ways to play: 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 index ac3893185..12d6406ec 100644 --- 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 @@ -7,12 +7,12 @@ 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 + miniscript qubit.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" + load "qubit" run ``` From b17510fb06426ff6ebf8fce6b936bc4d8de10496 Mon Sep 17 00:00:00 2001 From: kpcyrd Date: Sun, 22 Oct 2023 20:00:32 +0200 Subject: [PATCH 307/377] Port 69_Pizza to Rust --- 69_Pizza/rust/Cargo.lock | 23 +++++ 69_Pizza/rust/Cargo.toml | 10 +++ 69_Pizza/rust/README.md | 3 + 69_Pizza/rust/src/main.rs | 178 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 214 insertions(+) create mode 100644 69_Pizza/rust/Cargo.lock create mode 100644 69_Pizza/rust/Cargo.toml create mode 100644 69_Pizza/rust/README.md create mode 100644 69_Pizza/rust/src/main.rs diff --git a/69_Pizza/rust/Cargo.lock b/69_Pizza/rust/Cargo.lock new file mode 100644 index 000000000..b4abe0dca --- /dev/null +++ b/69_Pizza/rust/Cargo.lock @@ -0,0 +1,23 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "anyhow", + "fastrand", +] diff --git a/69_Pizza/rust/Cargo.toml b/69_Pizza/rust/Cargo.toml new file mode 100644 index 000000000..5224dbab6 --- /dev/null +++ b/69_Pizza/rust/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.75" +fastrand = "2.0.1" diff --git a/69_Pizza/rust/README.md b/69_Pizza/rust/README.md new file mode 100644 index 000000000..ce0d38dc2 --- /dev/null +++ b/69_Pizza/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/). diff --git a/69_Pizza/rust/src/main.rs b/69_Pizza/rust/src/main.rs new file mode 100644 index 000000000..4bfe4f226 --- /dev/null +++ b/69_Pizza/rust/src/main.rs @@ -0,0 +1,178 @@ +use anyhow::Result; +use std::io; + +fn print_centered(text: &str) { + println!("{:^72}", text); +} + +fn read_line() -> Result { + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + input.truncate(input.trim_end().len()); + Ok(input) +} + +fn read_number() -> Result { + let line = read_line()?; + let num = line.parse()?; + Ok(num) +} + +fn print_banner() { + print_centered("PIZZA"); + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + println!(); + println!(); + println!(); +} + +fn print_instructions() -> Result { + println!("PIZZA DELIVERY GAME"); + println!(); + println!("WHAT IS YOUR FIRST NAME"); + + let name = read_line()?; + println!("HI, {name}. IN THIS GAME YOU ARE TO TAKE ORDERS"); + println!("FOR PIZZAS. THEN YOU ARE TO TELL A DELIVERY BOY"); + println!("WHERE TO DELIVER THE ORDERED PIZZAS."); + println!(); + println!(); + + print_map(); + + println!("THE OUTPUT IS A MAP OF THE HOMES WHERE"); + println!("YOU ARE TO SEND PIZZAS."); + println!(); + println!("YOUR JOB IS TO GIVE A TRUCK DRIVER"); + println!("THE LOCATION OR COORDINATES OF THE"); + println!("HOME ORDERING THE PIZZA."); + println!(); + + Ok(name) +} + +fn print_ruler() { + println!(" -----1-----2-----3-----4-----"); +} + +fn print_ticks() { + println!("-"); + println!("-"); + println!("-"); + println!("-"); +} + +fn print_street(i: u32) { + let street_number = 3 - i; + let street_name = (street_number + 1).to_string(); + + let mut line = street_name.clone(); + let space = " "; + for customer_idx in 0..4 { + line.push_str(space); + let customer = 4 * street_number + customer_idx; + line.push(char::from_u32(65 + customer).unwrap()); + } + line.push_str(space); + line.push_str(&street_name); + println!("{line}"); +} + +fn print_map() { + println!("MAP OF THE CITY OF HYATTSVILLE"); + println!(); + print_ruler(); + for i in 0..4 { + print_ticks(); + print_street(i); + } + print_ticks(); + print_ruler(); + println!(); +} + +fn yes_no_prompt(text: &str) -> Result> { + println!("{text}"); + let input = read_line()?; + match input.as_str() { + "YES" => Ok(Some(true)), + "NO" => Ok(Some(false)), + _ => Ok(None), + } +} + +fn play_game(turns: u32, player_name: &str) -> Result<()> { + for _ in 0..turns { + let customer = fastrand::char('A'..='P'); + println!("HELLO {player_name}'S PIZZA. THIS IS {customer}."); + println!(" PLEASE SEND A PIZZA."); + loop { + println!(" DRIVER TO {player_name}: WHERE DOES {customer} LIVE"); + + let x = read_number()?; + let y = read_number()?; + + let input = x - 1 + (y - 1) * 4; + match char::from_u32(65 + input) { + Some(c) if c == customer => { + println!("HELLO {player_name}. THIS IS {customer}, THANKS FOR THE PIZZA."); + break; + } + Some(c @ 'A'..='P') => { + println!("THIS IS {c}. I DID NOT ORDER A PIZZA."); + println!("I LIVE AT {x},{y}"); + } + // this is out of bounds in the original game + _ => (), + } + } + } + + Ok(()) +} + +fn main() -> Result<()> { + print_banner(); + let player_name = print_instructions()?; + let more_directions = loop { + if let Some(x) = yes_no_prompt("DO YOU NEED MORE DIRECTIONS")? { + break x; + } else { + println!("'YES' OR 'NO' PLEASE, NOW THEN,"); + } + }; + + if more_directions { + println!(); + println!("SOMEBODY WILL ASK FOR A PIZZA TO BE"); + println!("DELIVERED. THEN A DELIVERY BOY WILL"); + println!("ASK YOU FOR THE LOCATION."); + println!(" EXAMPLE:"); + println!("THIS IS J. PLEASE SEND A PIZZA."); + println!("DRIVER TO {player_name}. WHERE DOES J LIVE?"); + println!("YOUR ANSWER WOULD BE 2,3"); + println!(); + + if let Some(true) = yes_no_prompt("UNDERSTAND")? { + println!("GOOD. YOU ARE NOW READY TO START TAKING ORDERS."); + println!(); + println!("GOOD LUCK!!"); + println!(); + } else { + println!("THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY"); + return Ok(()); + } + } + + loop { + play_game(5, &player_name)?; + println!(); + + if let Some(false) | None = yes_no_prompt("DO YOU WANT TO DELIVER MORE PIZZAS")? { + println!(); + println!("O.K. {player_name}, SEE YOU LATER!"); + println!(); + return Ok(()); + } + } +} From 870df015c37613309e360e9d6546204f30e846ee Mon Sep 17 00:00:00 2001 From: Flavio Poletti Date: Sun, 22 Oct 2023 22:35:43 +0200 Subject: [PATCH 308/377] Add Perl implementation for Hammurabi --- .../perl/lib/BasicComputerGames/Hammurabi.pm | 472 ++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 43_Hammurabi/perl/lib/BasicComputerGames/Hammurabi.pm diff --git a/43_Hammurabi/perl/lib/BasicComputerGames/Hammurabi.pm b/43_Hammurabi/perl/lib/BasicComputerGames/Hammurabi.pm new file mode 100644 index 000000000..cfcffb343 --- /dev/null +++ b/43_Hammurabi/perl/lib/BasicComputerGames/Hammurabi.pm @@ -0,0 +1,472 @@ +#!/usr/bin/env perl +package BasicComputerGames::Hammurabi; + +use v5.24; +use warnings; +use experimental 'signatures'; + +{ + # Quick and dirty accessors + no strict 'refs'; + for my $feature ( + qw< year population store rats_toll had_plague planted + production_per_acre acres new_arrivals starved status max_year fed + percent_starved total_starved cost_per_acre > + ) + { + *{__PACKAGE__ . '::' . $feature} = sub ($self, @new) { + $self->{$feature} = $new[0] if @new; + return $self->{$feature}; + }; + } ## end for my $feature (...) +} + +sub new ($package, %args) { + my $self = bless { + + # These defaults can be overridden by %args + population => 100, + store => 2800, + rats_toll => 200, + production_per_acre => 3, + acres => 1000, + new_arrivals => 5, + fed => 0, + max_year => 10, + + %args, + + # These starting values cannot be overridden by %args + status => 'start', + year => 1, + starved => 0, + total_starved => 0, + percent_starved => 0, + had_plague => 0, + planted => 0, + cost_per_acre => 0, + }, $package; + + return $self; +} ## end sub new + +sub step ($self, $input) { + my $method = $self->can('_handle_' . $self->status); + $self->$method($input); +} + +######################################################################## +# +# All _handle_* methods below represents handlers for different states +# of the game, e.g. state `start` is managed by _handle_start(). Each +# handler receives two input arguments: an instance to the game object and +# the input that was collected by the UI for that particular state (if +# any). + +# start of the game +sub _handle_start ($self, $input) { + $self->status('start_of_year'); +} + +# start of each year +sub _handle_start_of_year ($self, $input) { + $self->cost_per_acre(int(rand(10)) + 17); + $self->status('advertise_cost_per_acre'); +} + +# intermediate state to allow for printing the cost per acre, moves +# directly to following state +sub _handle_advertise_cost_per_acre ($self, $input) { + $self->status('buy_acres'); +} + +# buy acres of land, making sure to be able to cover for the cost +sub _handle_buy_acres ($self, $input) { + return $self->status('bail_out') if $input < 0; + return $self->status('sell_acres') if $input == 0; + my $cpa = $self->cost_per_acre; + my $cost = $cpa * $input; + return $self->status('buy_acres_again') + if $cost > $self->store; + $self->acres($self->acres + $input); + $self->store($self->store - $cost); + return $self->status('feeding'); +} ## end sub _handle_buy_acres + +# intermediate state to allow for notifying that the request for new +# acres of land could not be covered, moves directly to the following +# state +sub _handle_buy_acres_again ($self, $input) { + $self->status('buy_acres'); +} + +# sell acres of land, making sure to sell only what can be sold. +sub _handle_sell_acres ($self, $input) { + return $self->status('bail_out') if $input < 0; + return $self->status('sell_acres_again') if $input >= $self->acres; + $self->acres($self->acres - $input); + $self->store($self->store + $self->cost_per_acre * $input); + return $self->status('feeding'); +} ## end sub _handle_sell_acres + +# intermediate state to allow for notifying that the request to sell +# acres of land could not be covered, moves directly to the following +# state +sub _handle_sell_acres_again ($self, $input) { + $self->status('sell_acres'); +} + +# feed people, making sure we have the necessary resources +sub _handle_feeding ($self, $input) { + return $self->status('bail_out') if $input < 0; + return $self->status('feeding_again') if $input >= $self->store; + $self->store($self->store - $input); + $self->fed($input); + $self->status('planting'); +} ## end sub _handle_feeding + +# intermediate state to allow for notifying that the request to use +# bushels of grain could not be covered, moves directly to the following +# state +sub _handle_feeding_again ($self, $input) { + $self->status('feeding'); +} + +# plant crops, making sure we have the land, the seeds and the workers. +sub _handle_planting ($self, $input) { + return $self->status('bail_out') if $input < 0; + + return $self->status('planting_fail_acres') if $input > $self->acres; + + my $store = $self->store; + return $self->status('planting_fail_seeds') + if $store < int($input / 2); + + return $self->status('planting_fail_people') + if $input >= $self->population * 10; + + $self->planted($input); + $self->store($store - int($input / 2)); + $self->status('simulate_year'); +} ## end sub _handle_planting + +# complain about lack of land to cover the planting request +sub _handle_planting_fail_acres ($self, $input) { + $self->status('planting'); +} + +# complain about lack of seeds to cover the planting request +sub _handle_planting_fail_seeds ($self, $input) { + $self->status('planting'); +} + +# complain about lack of workers to cover the planting request +sub _handle_planting_fail_people ($self, $input) { + $self->status('planting'); +} + +# simulate the rest of the year after all inputs, i.e. rats, crops, etc. +sub _handle_simulate_year ($self, $input) { + my $store = $self->store; + + # rats might take a toll during the year + my $c = 1 + int(rand(5)); + my $rats_toll = $c % 2 ? 0 : int($store / $c); + $self->rats_toll($rats_toll); + + # planting also gains us grain after the harvest + my $ppa = $self->production_per_acre(1 + int(rand(5))); + my $harvest = $ppa * $self->planted; + + # let's update the stored seeds finally + $self->store($store += $harvest - $rats_toll); + + # let's see how population evolved + my $population = $self->population; + + # how many people had full tummies + my $fed_people = int($self->fed / 20); + my $starved = $population - $fed_people; + $starved = 0 if $starved < 0; # cannot create people from seeds + $self->starved($starved); + + # check preliminary exit condition for a very bad year + return $self->status('impeach_year') + if $starved > $population * 0.45; + + # update statistics + $self->total_starved($self->total_starved + $starved); + my $perc = $self->percent_starved; + my $year = $self->year; + $perc = (($year - 1) * $perc + $starved * 100 / $population) / $year; + $self->percent_starved($perc); + + # babies + my $acres = $self->acres; + my $rand = 1 + int(rand(5)); + my $arrivals = $self->new_arrivals( + int(1 + $rand * (20 * $acres + $store) / $population / 100)); + + $population += $arrivals - $starved; + + # HORROS, A 15% CHANCE OF PLAGUE + my $had_plague = $self->had_plague(rand(1) < 0.15); + $population = int($population / 2) if $had_plague; + + # save population for next round + $self->population($population); + + # advance to next year + $self->year(++$year); + if ($year > $self->max_year) { + $self->status('summary'); + } + else { + $self->status('start_of_year'); + } +} ## end sub _handle_simulate_year + +# this is a transition after the impeachment message +sub _handle_impeach_year ($self, $input) { + $self->status('goodbye'); +} + +# this is a transition after printing the summary +sub _handle_summary ($self, $input) { + $self->status('goodbye'); +} + +# this is a transition after printing the final salutation message +sub _handle_goodbye ($self, $input) { + $self->status('game_over'); +} + +# this is a transition after asking the king to hire someone else! +sub _handle_bail_out ($self, $input) { + $self->status('game_over'); +} + +# The following package implements all the User Interface, using the +# game state (as exposed by $game->status) to figure out what to print +# and if an input is needed from the user. It all happens on the +# standard input and output. +package BasicComputerGames::Hammurabi::DefaultIO; + +# All __io_* functions take a $game object as input, in case of need for +# some specific data (e.g. population amount or amassed grain bushels). +# They usually print something out and collect input from standard +# input for states that require a user input. All functions are named +# after the available states in BasicComputerGames::Hammurabi. + +sub __io_start ($game) { + say ' ' x 32, 'HAMURABI'; + say ' ' x 15, 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'; + print "\n\n\n"; + say 'TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA'; + say 'FOR A TEN-YEAR TERM OF OFFICE'; + print "\n"; + return; +} ## end sub __io_start + +sub __io_start_of_year ($game) { + print "\n\n"; + say "HAMURABI: I BEG TO REPORT TO YOU,"; + printf "IN YEAR %d , %d PEOPLE STARVED, %d CAME TO THE CITY,\n", + $game->year, $game->starved, $game->new_arrivals; + say 'A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED.' + if $game->had_plague; + say 'POPULATION IS NOW ', $game->population; + say 'THE CITY NOW OWNS ', $game->acres, ' ACRES.'; + say 'YOU HARVESTED ', $game->production_per_acre, ' BUSHELS PER ACRE.'; + say 'THE RATS ATE ', $game->rats_toll, ' BUSHELS.'; + say 'YOU NOW HAVE ', $game->store, ' BUSHELS IN STORE.'; + print "\n"; + return; +} ## end sub __io_start_of_year + +sub get_input ($game = undef) { + while () { + chomp(my $input = $_); + return 0 unless $input; + return $input if $input =~ m{\A -? \d+ \z}mxs; + print "REENTER?\n?? "; + } ## end while () + die "\n"; +} ## end sub get_input + +sub __io_bail_out ($game) { + say "\nHAMURABI: I CANNOT DO WHAT YOU WISH."; + say 'GET YOURSELF ANOTHER STEWARD!!!!!'; + return; +} + +sub __not_enough_bushels ($game) { + say 'HAMURABI: THINK AGAIN. YOU HAVE ONLY'; + say $game->store, ' BUSHELS OF GRAIN. NOW, THEN,'; +} + +sub __not_enough_acres ($game) { + say 'HAMURABI: THINK AGAIN. YOU OWN ONLY ', + $game->acres, ' ACRES. NOW, THEN,'; +} + +sub __io_buy_acres ($game) { + print 'HOW MANY ACRES DO YOU WISH TO BUY?? '; + return get_input(); +} + +sub __io_advertise_cost_per_acre ($game) { + say 'LAND IS TRADING AT ', $game->cost_per_acre, ' BUSHELS PER ACRE.'; + return; +} + +sub __io_sell_acres ($game) { + print 'HOW MANY ACRES DO YOU WISH TO SELL?? '; + return get_input(); +} + +sub __io_feeding ($game) { + print "\nHOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE?? "; + return get_input(); +} + +sub __io_planting ($game) { + print "\nHOW MANY ACRES DO YOU WISH TO PLANT WITH SEED?? "; + return get_input(); +} + +sub __io_buy_acres_again ($game) { __not_enough_bushels($game) } + +sub __io_sell_acres_again ($game) { __not_enough_acres($game) } + +sub __io_feeding_again ($game) { __not_enough_bushels($game) } + +sub __io_planting_fail_acres ($game) { __not_enough_acres($game) } + +sub __io_planting_fail_seeds ($game) { __not_enough_bushels($game) } + +sub __io_planting_fail_people ($game) { + say 'BUT YOU HAVE ONLY ', $game->population, + ' PEOPLE TO TEND THE FIELDS! NOW, THEN,'; +} + +sub __impeachment { + say 'DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY'; + say 'BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE'; + say 'ALSO BEEN DECLARED NATIONAL FINK!!!!'; +} + +sub __io_impeach_year ($game) { + printf "\nYOU STARVED %d PEOPLE IN ONE YEAR!!!\n", $game->starved; + return __impeachment(); +} + +sub __io_goodbye ($game) { + say "\nSO LONG FOR NOW.\n"; + return; +} + +# Final summary for the game, print statistics and evaluation +sub __io_summary ($game) { + my $starved = $game->total_starved; + my $years = $game->max_years; + my $p1 = 100 * $starved / $years; + my $l = $game->acres / $game->population; + printf "IN YOUR %d-YEAR TERM OF OFFICE, %d PERCENT OF THE\n", + $years, $p1; + say 'POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF'; + printf "%d PEOPLE DIED!!\n", $starved; + say 'YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH'; + printf "%.2f ACRES PER PERSON.\n\n", $l; + + if ($p1 > 33 || $l < 7) { + __impeachment(); + } + elsif ($p1 > 10 || $l < 9) { + say 'YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.'; + say 'THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,'; + say 'FRANKLY, HATE YOUR GUTS!!'; + } + elsif ($p1 > 3 || $l < 10) { + my $haters = int($game->population * rand(0.8)); + say 'YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT'; + say "REALLY WASN'T TOO BAD AT ALL. $haters PEOPLE"; + say 'WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR'; + say 'TRIVIAL PROBLEMS.'; + } ## end elsif ($p1 > 3 || $l < 10) + else { + say 'A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND'; + say 'JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!'; + } + + return; +} ## end sub __io_summary + +# this class method allows using this module... easily. Call with +# arguments to be fed to the BasicComputerGames::Hammurabi constructor. +sub run ($package, @args) { + my $game = BasicComputerGames::Hammurabi->new(@args); + while ((my $status = $game->status) ne 'game_over') { + eval { + my $retval; + if (my $cb = $package->can('__io_' . $status)) { + $retval = $cb->($game); + } + $game->step($retval); + 1; + } or last; + } ## end while ((my $status = $game...)) + say ''; + return 0; +} ## end sub run + +# Modulino (https://gitlab.com/polettix/notechs/-/snippets/1868370) +exit __PACKAGE__->run(@ARGV) unless caller; + +1; +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +BasicComputerGames::Hammurabi - the Hammurabi game from BASIC + +=head1 SYNOPSIS + + use BasicComputerGames::Hammurabi; + + # if you have a way to manage the UI yourself, then you can get the + # game logic handler + my $game_handler = BasicComputerGames::Hammurabi->new; + while ((my $status = $game_handler->status) ne 'game_over') { + # figure out what to print out with $status, this is totally + # up to the interface implementation, which also has to collect + # the inputs + my $retval = manage_ui_for($game_handler); + + # now we feed whatever came from the interface back to the handler + $game_handler->step($retval); + } + + # Want the plain terminal experience? No problem: + BasicComputerGames::Hammurabi::DefaultIO->run; + +=head1 IMPLEMENTATION DETAILS + +The code tries to behave like the original BASIC, including some dubious +conditions checks that e.g. do not allow using the full potential of +available resources for lack of an equal sign. + +The calculation of the final average of starved people per year is +differnet from the original and avoids what is considered (by me) a bug +that kicks in when there are years in which nobody starves. + +=head1 AUTHOR + +Adapted by Flavio Poletti from the BASIC version by David Ahl. Game text +copied verbatim from the original BASIC implementation, including typos. + +=cut From 892b75ce8c7bfba7f5c9b7f1bf73ae991ef075a5 Mon Sep 17 00:00:00 2001 From: nrezmerski <108252649+nrezmerski@users.noreply.github.com> Date: Tue, 24 Oct 2023 07:37:33 -0500 Subject: [PATCH 309/377] Create hello.c Initial commit - ANSI C version of "hello.bas" --- 00_Alternate_Languages/45_Hello/hello.c | 164 ++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 00_Alternate_Languages/45_Hello/hello.c diff --git a/00_Alternate_Languages/45_Hello/hello.c b/00_Alternate_Languages/45_Hello/hello.c new file mode 100644 index 000000000..ac70709ef --- /dev/null +++ b/00_Alternate_Languages/45_Hello/hello.c @@ -0,0 +1,164 @@ +#include +#include + +#define TRUE 1 +#define FALSE 0 +#define MAX_INPUT_LENGTH 80 + +void tab(int number_of_spaces); +void get_input(char *input_buffer); +int strings_match(char *string1, char *string2); + +int main() { + int done = FALSE; + int paid = FALSE; + int maybe_more, sure; + + char name[MAX_INPUT_LENGTH]; + char reply[MAX_INPUT_LENGTH]; + + tab(33); + printf("HELLO\n"); + tab(15); + printf("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); + printf("\n\n\n"); + printf("HELLO. MY NAME IS CREATIVE COMPUTER.\n"); + printf("\n\nWHAT'S YOUR NAME "); + get_input(name); + printf("\nHI THERE, %s, ARE YOU ENJOYING YOURSELF HERE ", name); + + get_input(reply); + while (!strings_match(reply, "YES") && !strings_match(reply, "NO")) { + printf("%s, I DON'T UNDERSTAND YOUR ANSWER OF '%s'.\n", name, reply); + printf("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE "); + get_input(reply); + } + + if (strings_match(reply, "YES")) { + printf("I'M GLAD TO HEAR THAT, %s.\n", name); + } + else { + printf("OH, I'M SORRY TO HEAR THAT, %s. MAYBE WE CAN " + "BRIGHTEN UP YOUR VISIT A BIT.\n", name); + } + + printf("\nSAY, %s, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT " + "THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO " + "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB) ", name); + + while (!done) { + get_input(reply); + + if (strings_match(reply, "JOB")) { + printf("I CAN SYMPATHIZE WITH YOU %s. I HAVE TO WORK " + "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES " + "REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, %s, IS TO " + "OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.\n\n", name, name); + } + + else if (strings_match(reply, "MONEY")) { + printf("SORRY, %s, I'M BROKE TOO. WHY DON'T YOU SELL " + "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING " + "SO YOU WON'T NEED SO MUCH MONEY?\n\n", name); + } + + else if (strings_match(reply, "HEALTH")) { + printf("MY ADVICE TO YOU %s IS:\n", name); + printf(" 1. TAKE TWO ASPRIN\n"); + printf(" 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\n"); + printf(" 3. GO TO BED (ALONE)\n\n"); + } + + else if (strings_match(reply, "SEX")) { + printf("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE "); + + sure = FALSE; + while (!sure) { + get_input(reply); + if (strings_match(reply, "TOO MUCH")) { + printf("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!\n"); + printf("IF IT BOTHERS YOU, %s, TAKE A COLD SHOWER.\n\n", name); + sure = TRUE; + } + else if (strings_match(reply, "TOO LITTLE")) { + printf("WHY ARE YOU HERE IN SUFFERN, %s? YOU SHOULD BE " + "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME " + "REAL ACTION.\n\n", name); + sure = TRUE; + } + else { + printf("DON'T GET ALL SHOOK, %s, JUST ANSWER THE QUESTION " + "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT ", name); + } + } + } + + else { // not one of the prescribed categories + printf("OH, %s, YOUR ANSWER OF '%s' IS GREEK TO ME.\n\n", name, reply); + } + + printf("ANY MORE PROBLEMS YOU WANT SOLVED, %s ", name); + + maybe_more = TRUE; + while (maybe_more) { + get_input(reply); + if (strings_match(reply, "NO")) { + done = TRUE; + maybe_more = FALSE; + } + else if (strings_match(reply, "YES")) { + printf("WHAT KIND (SEX, MONEY, HEALTH, JOB) "); + maybe_more = FALSE; + } + else { + printf("JUST A SIMPLE 'YES' OR 'NO' PLEASE, %s. ", name); + } + } // no further questions + } // end of 'not done' loop + + printf("\nTHAT WILL BE $5.00 FOR THE ADVICE, %s.\n", name); + printf("PLEASE LEAVE THE MONEY ON THE TERMINAL.\n"); + // pause a few seconds + printf("\n\n\nDID YOU LEAVE THE MONEY "); + get_input(reply); + while (!paid) { + if (strings_match(reply, "YES")) { + printf("HEY, %s??? YOU LEFT NO MONEY AT ALL!\n", name); + printf("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\n"); + printf("\nWHAT A RIP OFF, %s!!!\n", name); + printf("TAKE A WALK, %s.\n\n", name); + paid = TRUE; + } + else if (strings_match(reply, "NO")) { + printf("THAT'S HONEST, %s, BUT HOW DO YOU EXPECT " + "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS " + "DON'T PAY THEIR BILLS?\n\n", name); + printf("NICE MEETING YOU, %s, HAVE A NICE DAY.\n", name); + paid = TRUE; + } + else { + printf("YOUR ANSWER OF '%s' CONFUSES ME, %s.\n", reply, name); + printf("PLEASE RESPOND WITH 'YES' OR 'NO'.\n"); + } + } +} + + +void tab(int number_of_spaces) { + for (int i=0; i < number_of_spaces; i++) + putchar(' '); +} + + +void get_input(char *input_buffer) { + fgets(input_buffer, MAX_INPUT_LENGTH - 1, stdin); + input_buffer[strcspn(input_buffer, "\n")] = '\0'; // trim the trailing line break +} + + +int strings_match(char *string1, char *string2) { + if (strncmp(string1, string2, MAX_INPUT_LENGTH - 1) != 0) + return FALSE; + else // strings do not match within maximum input line length + return TRUE; +} From cf021f6c7b7e7129ee7acd5d481565fb0c51aa5f Mon Sep 17 00:00:00 2001 From: nrezmerski <108252649+nrezmerski@users.noreply.github.com> Date: Tue, 24 Oct 2023 08:03:13 -0500 Subject: [PATCH 310/377] Create hello.c Initial commit of ANSI C version of "hello.bas" --- .../45_Hello/ANSI_C/hello.c | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 00_Alternate_Languages/45_Hello/ANSI_C/hello.c diff --git a/00_Alternate_Languages/45_Hello/ANSI_C/hello.c b/00_Alternate_Languages/45_Hello/ANSI_C/hello.c new file mode 100644 index 000000000..6d6eae786 --- /dev/null +++ b/00_Alternate_Languages/45_Hello/ANSI_C/hello.c @@ -0,0 +1,164 @@ +#include +#include + +#define TRUE 1 +#define FALSE 0 +#define MAX_INPUT_LENGTH 80 + +void tab(int number_of_spaces); +void get_input(char *input_buffer); +int strings_match(char *string1, char *string2); + +int main() { + int done = FALSE; + int paid = FALSE; + int maybe_more, sure; + + char name[MAX_INPUT_LENGTH]; + char reply[MAX_INPUT_LENGTH]; + + tab(33); + printf("HELLO\n"); + tab(15); + printf("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); + printf("\n\n\n"); + printf("HELLO. MY NAME IS CREATIVE COMPUTER.\n"); + printf("\n\nWHAT'S YOUR NAME "); + get_input(name); + printf("\nHI THERE, %s, ARE YOU ENJOYING YOURSELF HERE ", name); + + get_input(reply); + while (!strings_match(reply, "YES") && !strings_match(reply, "NO")) { + printf("%s, I DON'T UNDERSTAND YOUR ANSWER OF '%s'.\n", name, reply); + printf("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE "); + get_input(reply); + } + + if (strings_match(reply, "YES")) { + printf("I'M GLAD TO HEAR THAT, %s.\n", name); + } + else { + printf("OH, I'M SORRY TO HEAR THAT, %s. MAYBE WE CAN " + "BRIGHTEN UP YOUR VISIT A BIT.\n", name); + } + + printf("\nSAY, %s, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT " + "THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO " + "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB) ", name); + + while (!done) { + get_input(reply); + + if (strings_match(reply, "JOB")) { + printf("I CAN SYMPATHIZE WITH YOU %s. I HAVE TO WORK " + "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES " + "REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, %s, IS TO " + "OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.\n\n", name, name); + } + + else if (strings_match(reply, "MONEY")) { + printf("SORRY, %s, I'M BROKE TOO. WHY DON'T YOU SELL " + "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING " + "SO YOU WON'T NEED SO MUCH MONEY?\n\n", name); + } + + else if (strings_match(reply, "HEALTH")) { + printf("MY ADVICE TO YOU %s IS:\n", name); + printf(" 1. TAKE TWO ASPRIN\n"); + printf(" 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\n"); + printf(" 3. GO TO BED (ALONE)\n\n"); + } + + else if (strings_match(reply, "SEX")) { + printf("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE "); + + sure = FALSE; + while (!sure) { + get_input(reply); + if (strings_match(reply, "TOO MUCH")) { + printf("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!\n"); + printf("IF IT BOTHERS YOU, %s, TAKE A COLD SHOWER.\n\n", name); + sure = TRUE; + } + else if (strings_match(reply, "TOO LITTLE")) { + printf("WHY ARE YOU HERE IN SUFFERN, %s? YOU SHOULD BE " + "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME " + "REAL ACTION.\n\n", name); + sure = TRUE; + } + else { + printf("DON'T GET ALL SHOOK, %s, JUST ANSWER THE QUESTION " + "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT ", name); + } + } + } + + else { // not one of the prescribed categories + printf("OH, %s, YOUR ANSWER OF '%s' IS GREEK TO ME.\n\n", name, reply); + } + + printf("ANY MORE PROBLEMS YOU WANT SOLVED, %s ", name); + + maybe_more = TRUE; + while (maybe_more) { + get_input(reply); + if (strings_match(reply, "NO")) { + done = TRUE; + maybe_more = FALSE; + } + else if (strings_match(reply, "YES")) { + printf("WHAT KIND (SEX, MONEY, HEALTH, JOB) "); + maybe_more = FALSE; + } + else { + printf("JUST A SIMPLE 'YES' OR 'NO' PLEASE, %s. ", name); + } + } // no further questions + } // end of 'not done' loop + + printf("\nTHAT WILL BE $5.00 FOR THE ADVICE, %s.\n", name); + printf("PLEASE LEAVE THE MONEY ON THE TERMINAL.\n"); + // pause a few seconds + printf("\n\n\nDID YOU LEAVE THE MONEY "); + get_input(reply); + while (!paid) { + if (strings_match(reply, "YES")) { + printf("HEY, %s??? YOU LEFT NO MONEY AT ALL!\n", name); + printf("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\n"); + printf("\nWHAT A RIP OFF, %s!!!\n", name); + printf("TAKE A WALK, %s.\n\n", name); + paid = TRUE; + } + else if (strings_match(reply, "NO")) { + printf("THAT'S HONEST, %s, BUT HOW DO YOU EXPECT " + "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS " + "DON'T PAY THEIR BILLS?\n\n", name); + printf("NICE MEETING YOU, %s, HAVE A NICE DAY.\n", name); + paid = TRUE; + } + else { + printf("YOUR ANSWER OF '%s' CONFUSES ME, %s.\n", reply, name); + printf("PLEASE RESPOND WITH 'YES' OR 'NO'.\n"); + } + } +} + + +void tab(int number_of_spaces) { + for (int i=0; i < number_of_spaces; i++) + putchar(' '); +} + + +void get_input(char *input_buffer) { + fgets(input_buffer, MAX_INPUT_LENGTH - 1, stdin); + input_buffer[strcspn(input_buffer, "\n")] = '\0'; // trim the trailing line break +} + + +int strings_match(char *string1, char *string2) { + if (strncmp(string1, string2, MAX_INPUT_LENGTH - 1) != 0) + return FALSE; + else // strings match, at least within maximum input line length + return TRUE; +} From 83e5dccfa9b0c926ed95128c781d57f148532337 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 24 Oct 2023 12:24:20 -0700 Subject: [PATCH 311/377] Commented out debug line in hangman.ms. --- 00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms b/00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms index 50c4e4466..53966d45e 100644 --- a/00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms +++ b/00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms @@ -63,7 +63,7 @@ doOneGame = function for i in range(1,12); ps[i][1] = "X"; end for for i in range(1, 7); ps[1][i] = "X"; end for; ps[2][7] = "X" secretWord = words.pull.upper - print "(Secret word: " + secretWord + ")" + //print "(Secret word: " + secretWord + ")" visibleWord = ["-"] * secretWord.len wrongGuesses = 0 while true From 437bfc36f0c37eed3ef73a3377d3c9274c5a1ff3 Mon Sep 17 00:00:00 2001 From: JoeStrout Date: Tue, 24 Oct 2023 12:26:46 -0700 Subject: [PATCH 312/377] Improved error handling in pizza.ms. --- 00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms b/00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms index 5d52fbb77..84c33bb63 100644 --- a/00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms +++ b/00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms @@ -78,7 +78,7 @@ while true while true inp = input(" Driver to " + name + ": Where does " + buyer + " live? ") inp = inp.replace(",", " ").replace(" ", " ") - inp = inp.split + [0,0] + inp = inp.split + ["0","0"] guess = [inp[0].val, inp[1].val] if 1 <= guess[0] <= 4 and 1 <= guess[1] <= 4 then break end while From 5293edcd89eaaf37117056abb35f0b13de2eefaa Mon Sep 17 00:00:00 2001 From: nrezmerski <108252649+nrezmerski@users.noreply.github.com> Date: Tue, 24 Oct 2023 15:08:24 -0500 Subject: [PATCH 313/377] Update hello.c Fix mixed spaces/tabs indentation --- .../45_Hello/ANSI_C/hello.c | 60 +++++++------------ 1 file changed, 22 insertions(+), 38 deletions(-) diff --git a/00_Alternate_Languages/45_Hello/ANSI_C/hello.c b/00_Alternate_Languages/45_Hello/ANSI_C/hello.c index 6d6eae786..7e93e3c5a 100644 --- a/00_Alternate_Languages/45_Hello/ANSI_C/hello.c +++ b/00_Alternate_Languages/45_Hello/ANSI_C/hello.c @@ -1,22 +1,17 @@ #include #include - #define TRUE 1 #define FALSE 0 #define MAX_INPUT_LENGTH 80 - void tab(int number_of_spaces); void get_input(char *input_buffer); int strings_match(char *string1, char *string2); - int main() { int done = FALSE; int paid = FALSE; int maybe_more, sure; - char name[MAX_INPUT_LENGTH]; char reply[MAX_INPUT_LENGTH]; - tab(33); printf("HELLO\n"); tab(15); @@ -26,14 +21,12 @@ int main() { printf("\n\nWHAT'S YOUR NAME "); get_input(name); printf("\nHI THERE, %s, ARE YOU ENJOYING YOURSELF HERE ", name); - get_input(reply); while (!strings_match(reply, "YES") && !strings_match(reply, "NO")) { printf("%s, I DON'T UNDERSTAND YOUR ANSWER OF '%s'.\n", name, reply); printf("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE "); get_input(reply); } - if (strings_match(reply, "YES")) { printf("I'M GLAD TO HEAR THAT, %s.\n", name); } @@ -41,11 +34,9 @@ int main() { printf("OH, I'M SORRY TO HEAR THAT, %s. MAYBE WE CAN " "BRIGHTEN UP YOUR VISIT A BIT.\n", name); } - printf("\nSAY, %s, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT " "THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO " "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB) ", name); - while (!done) { get_input(reply); @@ -55,7 +46,6 @@ int main() { "REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, %s, IS TO " "OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.\n\n", name, name); } - else if (strings_match(reply, "MONEY")) { printf("SORRY, %s, I'M BROKE TOO. WHY DON'T YOU SELL " "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING " @@ -74,23 +64,23 @@ int main() { sure = FALSE; while (!sure) { - get_input(reply); - if (strings_match(reply, "TOO MUCH")) { - printf("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!\n"); - printf("IF IT BOTHERS YOU, %s, TAKE A COLD SHOWER.\n\n", name); - sure = TRUE; - } - else if (strings_match(reply, "TOO LITTLE")) { - printf("WHY ARE YOU HERE IN SUFFERN, %s? YOU SHOULD BE " - "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME " - "REAL ACTION.\n\n", name); - sure = TRUE; - } - else { - printf("DON'T GET ALL SHOOK, %s, JUST ANSWER THE QUESTION " - "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT ", name); - } - } + get_input(reply); + if (strings_match(reply, "TOO MUCH")) { + printf("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!\n"); + printf("IF IT BOTHERS YOU, %s, TAKE A COLD SHOWER.\n\n", name); + sure = TRUE; + } + else if (strings_match(reply, "TOO LITTLE")) { + printf("WHY ARE YOU HERE IN SUFFERN, %s? YOU SHOULD BE " + "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME " + "REAL ACTION.\n\n", name); + sure = TRUE; + } + else { + printf("DON'T GET ALL SHOOK, %s, JUST ANSWER THE QUESTION " + "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT ", name); + } + } } else { // not one of the prescribed categories @@ -115,7 +105,6 @@ int main() { } } // no further questions } // end of 'not done' loop - printf("\nTHAT WILL BE $5.00 FOR THE ADVICE, %s.\n", name); printf("PLEASE LEAVE THE MONEY ON THE TERMINAL.\n"); // pause a few seconds @@ -142,23 +131,18 @@ int main() { } } } - - void tab(int number_of_spaces) { for (int i=0; i < number_of_spaces; i++) putchar(' '); } - - void get_input(char *input_buffer) { fgets(input_buffer, MAX_INPUT_LENGTH - 1, stdin); input_buffer[strcspn(input_buffer, "\n")] = '\0'; // trim the trailing line break } - - int strings_match(char *string1, char *string2) { - if (strncmp(string1, string2, MAX_INPUT_LENGTH - 1) != 0) - return FALSE; - else // strings match, at least within maximum input line length - return TRUE; + if (strncasecmp(string1, string2, MAX_INPUT_LENGTH - 1) != 0) + return FALSE; + else // strings match, at least within maximum input line length + return TRUE; } + From 63865151b6bfdfc48f1ccaf38c459d13f04d8956 Mon Sep 17 00:00:00 2001 From: nrezmerski <108252649+nrezmerski@users.noreply.github.com> Date: Tue, 24 Oct 2023 15:12:07 -0500 Subject: [PATCH 314/377] Update hello.c Replace 3-space indents with 4-space --- .../45_Hello/ANSI_C/hello.c | 270 ++++++++++-------- 1 file changed, 144 insertions(+), 126 deletions(-) diff --git a/00_Alternate_Languages/45_Hello/ANSI_C/hello.c b/00_Alternate_Languages/45_Hello/ANSI_C/hello.c index 7e93e3c5a..74b0275f2 100644 --- a/00_Alternate_Languages/45_Hello/ANSI_C/hello.c +++ b/00_Alternate_Languages/45_Hello/ANSI_C/hello.c @@ -1,148 +1,166 @@ #include #include + #define TRUE 1 #define FALSE 0 #define MAX_INPUT_LENGTH 80 + void tab(int number_of_spaces); void get_input(char *input_buffer); int strings_match(char *string1, char *string2); + int main() { - int done = FALSE; - int paid = FALSE; - int maybe_more, sure; - char name[MAX_INPUT_LENGTH]; - char reply[MAX_INPUT_LENGTH]; - tab(33); - printf("HELLO\n"); - tab(15); - printf("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); - printf("\n\n\n"); - printf("HELLO. MY NAME IS CREATIVE COMPUTER.\n"); - printf("\n\nWHAT'S YOUR NAME "); - get_input(name); - printf("\nHI THERE, %s, ARE YOU ENJOYING YOURSELF HERE ", name); - get_input(reply); - while (!strings_match(reply, "YES") && !strings_match(reply, "NO")) { - printf("%s, I DON'T UNDERSTAND YOUR ANSWER OF '%s'.\n", name, reply); - printf("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE "); - get_input(reply); - } - if (strings_match(reply, "YES")) { - printf("I'M GLAD TO HEAR THAT, %s.\n", name); - } - else { - printf("OH, I'M SORRY TO HEAR THAT, %s. MAYBE WE CAN " - "BRIGHTEN UP YOUR VISIT A BIT.\n", name); - } - printf("\nSAY, %s, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT " - "THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO " - "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB) ", name); - while (!done) { - get_input(reply); - - if (strings_match(reply, "JOB")) { - printf("I CAN SYMPATHIZE WITH YOU %s. I HAVE TO WORK " - "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES " - "REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, %s, IS TO " - "OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.\n\n", name, name); - } - else if (strings_match(reply, "MONEY")) { - printf("SORRY, %s, I'M BROKE TOO. WHY DON'T YOU SELL " - "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING " - "SO YOU WON'T NEED SO MUCH MONEY?\n\n", name); - } - - else if (strings_match(reply, "HEALTH")) { - printf("MY ADVICE TO YOU %s IS:\n", name); - printf(" 1. TAKE TWO ASPRIN\n"); - printf(" 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\n"); - printf(" 3. GO TO BED (ALONE)\n\n"); - } - - else if (strings_match(reply, "SEX")) { - printf("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE "); - - sure = FALSE; - while (!sure) { - get_input(reply); - if (strings_match(reply, "TOO MUCH")) { - printf("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!\n"); - printf("IF IT BOTHERS YOU, %s, TAKE A COLD SHOWER.\n\n", name); - sure = TRUE; + int done = FALSE; + int paid = FALSE; + int maybe_more, sure; + + char name[MAX_INPUT_LENGTH]; + char reply[MAX_INPUT_LENGTH]; + + tab(33); + printf("HELLO\n"); + tab(15); + printf("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); + printf("\n\n\n"); + printf("HELLO. MY NAME IS CREATIVE COMPUTER.\n"); + printf("\n\nWHAT'S YOUR NAME "); + get_input(name); + printf("\nHI THERE, %s, ARE YOU ENJOYING YOURSELF HERE ", name); + + get_input(reply); + while (!strings_match(reply, "YES") && !strings_match(reply, "NO")) { + printf("%s, I DON'T UNDERSTAND YOUR ANSWER OF '%s'.\n", name, reply); + printf("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE "); + get_input(reply); + } + + if (strings_match(reply, "YES")) { + printf("I'M GLAD TO HEAR THAT, %s.\n", name); + } + else { + printf("OH, I'M SORRY TO HEAR THAT, %s. MAYBE WE CAN " + "BRIGHTEN UP YOUR VISIT A BIT.\n", name); + } + + printf("\nSAY, %s, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT " + "THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO " + "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB) ", name); + + while (!done) { + get_input(reply); + + if (strings_match(reply, "JOB")) { + printf("I CAN SYMPATHIZE WITH YOU %s. I HAVE TO WORK " + "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES " + "REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, %s, IS TO " + "OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.\n\n", name, name); + } + + else if (strings_match(reply, "MONEY")) { + printf("SORRY, %s, I'M BROKE TOO. WHY DON'T YOU SELL " + "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING " + "SO YOU WON'T NEED SO MUCH MONEY?\n\n", name); + } + + else if (strings_match(reply, "HEALTH")) { + printf("MY ADVICE TO YOU %s IS:\n", name); + printf(" 1. TAKE TWO ASPRIN\n"); + printf(" 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\n"); + printf(" 3. GO TO BED (ALONE)\n\n"); + } + + else if (strings_match(reply, "SEX")) { + printf("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE "); + + sure = FALSE; + while (!sure) { + get_input(reply); + if (strings_match(reply, "TOO MUCH")) { + printf("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!\n"); + printf("IF IT BOTHERS YOU, %s, TAKE A COLD SHOWER.\n\n", name); + sure = TRUE; + } + else if (strings_match(reply, "TOO LITTLE")) { + printf("WHY ARE YOU HERE IN SUFFERN, %s? YOU SHOULD BE " + "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME " + "REAL ACTION.\n\n", name); + sure = TRUE; + } + else { + printf("DON'T GET ALL SHOOK, %s, JUST ANSWER THE QUESTION " + "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT ", name); + } + } + } + + else { // not one of the prescribed categories + printf("OH, %s, YOUR ANSWER OF '%s' IS GREEK TO ME.\n\n", name, reply); + } + + printf("ANY MORE PROBLEMS YOU WANT SOLVED, %s ", name); + + maybe_more = TRUE; + while (maybe_more) { + get_input(reply); + if (strings_match(reply, "NO")) { + done = TRUE; + maybe_more = FALSE; } - else if (strings_match(reply, "TOO LITTLE")) { - printf("WHY ARE YOU HERE IN SUFFERN, %s? YOU SHOULD BE " - "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME " - "REAL ACTION.\n\n", name); - sure = TRUE; + else if (strings_match(reply, "YES")) { + printf("WHAT KIND (SEX, MONEY, HEALTH, JOB) "); + maybe_more = FALSE; } else { - printf("DON'T GET ALL SHOOK, %s, JUST ANSWER THE QUESTION " - "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT ", name); + printf("JUST A SIMPLE 'YES' OR 'NO' PLEASE, %s. ", name); } - } - } - - else { // not one of the prescribed categories - printf("OH, %s, YOUR ANSWER OF '%s' IS GREEK TO ME.\n\n", name, reply); - } - - printf("ANY MORE PROBLEMS YOU WANT SOLVED, %s ", name); - - maybe_more = TRUE; - while (maybe_more) { - get_input(reply); - if (strings_match(reply, "NO")) { - done = TRUE; - maybe_more = FALSE; - } - else if (strings_match(reply, "YES")) { - printf("WHAT KIND (SEX, MONEY, HEALTH, JOB) "); - maybe_more = FALSE; - } - else { - printf("JUST A SIMPLE 'YES' OR 'NO' PLEASE, %s. ", name); - } - } // no further questions - } // end of 'not done' loop - printf("\nTHAT WILL BE $5.00 FOR THE ADVICE, %s.\n", name); - printf("PLEASE LEAVE THE MONEY ON THE TERMINAL.\n"); - // pause a few seconds - printf("\n\n\nDID YOU LEAVE THE MONEY "); - get_input(reply); - while (!paid) { - if (strings_match(reply, "YES")) { - printf("HEY, %s??? YOU LEFT NO MONEY AT ALL!\n", name); - printf("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\n"); - printf("\nWHAT A RIP OFF, %s!!!\n", name); - printf("TAKE A WALK, %s.\n\n", name); - paid = TRUE; - } - else if (strings_match(reply, "NO")) { - printf("THAT'S HONEST, %s, BUT HOW DO YOU EXPECT " - "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS " - "DON'T PAY THEIR BILLS?\n\n", name); - printf("NICE MEETING YOU, %s, HAVE A NICE DAY.\n", name); + } // no further questions + } // end of 'not done' loop + + printf("\nTHAT WILL BE $5.00 FOR THE ADVICE, %s.\n", name); + printf("PLEASE LEAVE THE MONEY ON THE TERMINAL.\n"); + // pause a few seconds + printf("\n\n\nDID YOU LEAVE THE MONEY "); + get_input(reply); + while (!paid) { + if (strings_match(reply, "YES")) { + printf("HEY, %s??? YOU LEFT NO MONEY AT ALL!\n", name); + printf("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\n"); + printf("\nWHAT A RIP OFF, %s!!!\n", name); + printf("TAKE A WALK, %s.\n\n", name); paid = TRUE; - } - else { - printf("YOUR ANSWER OF '%s' CONFUSES ME, %s.\n", reply, name); - printf("PLEASE RESPOND WITH 'YES' OR 'NO'.\n"); - } - } + } + else if (strings_match(reply, "NO")) { + printf("THAT'S HONEST, %s, BUT HOW DO YOU EXPECT " + "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS " + "DON'T PAY THEIR BILLS?\n\n", name); + printf("NICE MEETING YOU, %s, HAVE A NICE DAY.\n", name); + paid = TRUE; + } + else { + printf("YOUR ANSWER OF '%s' CONFUSES ME, %s.\n", reply, name); + printf("PLEASE RESPOND WITH 'YES' OR 'NO'.\n"); + } + } } + + void tab(int number_of_spaces) { - for (int i=0; i < number_of_spaces; i++) - putchar(' '); + for (int i=0; i < number_of_spaces; i++) + putchar(' '); } + + void get_input(char *input_buffer) { - fgets(input_buffer, MAX_INPUT_LENGTH - 1, stdin); - input_buffer[strcspn(input_buffer, "\n")] = '\0'; // trim the trailing line break + fgets(input_buffer, MAX_INPUT_LENGTH - 1, stdin); + input_buffer[strcspn(input_buffer, "\n")] = '\0'; // trim the trailing line break } + + int strings_match(char *string1, char *string2) { - if (strncasecmp(string1, string2, MAX_INPUT_LENGTH - 1) != 0) - return FALSE; - else // strings match, at least within maximum input line length - return TRUE; + if (strncasecmp(string1, string2, MAX_INPUT_LENGTH - 1) != 0) + return FALSE; + else // strings match, at least within maximum input line length + return TRUE; } + From e9aa366a8b39d41e1062cc4335f1c21781fec2eb Mon Sep 17 00:00:00 2001 From: apeng2012 Date: Tue, 14 Nov 2023 21:27:26 +0800 Subject: [PATCH 315/377] Port 06_Banner to Rust --- 06_Banner/rust/Cargo.toml | 8 ++ 06_Banner/rust/src/main.rs | 173 +++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+) create mode 100644 06_Banner/rust/Cargo.toml create mode 100644 06_Banner/rust/src/main.rs diff --git a/06_Banner/rust/Cargo.toml b/06_Banner/rust/Cargo.toml new file mode 100644 index 000000000..1ec696335 --- /dev/null +++ b/06_Banner/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/06_Banner/rust/src/main.rs b/06_Banner/rust/src/main.rs new file mode 100644 index 000000000..dcfe9a4e0 --- /dev/null +++ b/06_Banner/rust/src/main.rs @@ -0,0 +1,173 @@ +use std::collections::HashMap; +use std::io::{self, stdin}; + +const LETTERS: [(char, [usize; 7]); 42] = [ + (' ', [0, 0, 0, 0, 0, 0, 0]), + ('A', [505, 37, 35, 34, 35, 37, 505]), + ('G', [125, 131, 258, 258, 290, 163, 101]), + ('E', [512, 274, 274, 274, 274, 258, 258]), + ('T', [2, 2, 2, 512, 2, 2, 2]), + ('W', [256, 257, 129, 65, 129, 257, 256]), + ('L', [512, 257, 257, 257, 257, 257, 257]), + ('S', [69, 139, 274, 274, 274, 163, 69]), + ('O', [125, 131, 258, 258, 258, 131, 125]), + ('N', [512, 7, 9, 17, 33, 193, 512]), + ('F', [512, 18, 18, 18, 18, 2, 2]), + ('K', [512, 17, 17, 41, 69, 131, 258]), + ('B', [512, 274, 274, 274, 274, 274, 239]), + ('D', [512, 258, 258, 258, 258, 131, 125]), + ('H', [512, 17, 17, 17, 17, 17, 512]), + ('M', [512, 7, 13, 25, 13, 7, 512]), + ('?', [5, 3, 2, 354, 18, 11, 5]), + ('U', [128, 129, 257, 257, 257, 129, 128]), + ('R', [512, 18, 18, 50, 82, 146, 271]), + ('P', [512, 18, 18, 18, 18, 18, 15]), + ('Q', [125, 131, 258, 258, 322, 131, 381]), + ('Y', [8, 9, 17, 481, 17, 9, 8]), + ('V', [64, 65, 129, 257, 129, 65, 64]), + ('X', [388, 69, 41, 17, 41, 69, 388]), + ('Z', [386, 322, 290, 274, 266, 262, 260]), + ('I', [258, 258, 258, 512, 258, 258, 258]), + ('C', [125, 131, 258, 258, 258, 131, 69]), + ('J', [65, 129, 257, 257, 257, 129, 128]), + ('1', [0, 0, 261, 259, 512, 257, 257]), + ('2', [261, 387, 322, 290, 274, 267, 261]), + ('*', [69, 41, 17, 512, 17, 41, 69]), + ('3', [66, 130, 258, 274, 266, 150, 100]), + ('4', [33, 49, 41, 37, 35, 512, 33]), + ('5', [160, 274, 274, 274, 274, 274, 226]), + ('6', [194, 291, 293, 297, 305, 289, 193]), + ('7', [258, 130, 66, 34, 18, 10, 8]), + ('8', [69, 171, 274, 274, 274, 171, 69]), + ('9', [263, 138, 74, 42, 26, 10, 7]), + ('=', [41, 41, 41, 41, 41, 41, 41]), + ('!', [1, 1, 1, 384, 1, 1, 1]), + ('0', [57, 69, 131, 258, 131, 69, 57]), + ('.', [1, 1, 129, 449, 129, 1, 1]), +]; + +fn main() { + print_banner().ok(); +} + +fn read_input() -> io::Result { + let mut input = String::new(); + stdin().read_line(&mut input)?; + Ok(input.trim().to_uppercase()) +} + +fn read_input_number() -> io::Result { + loop { + match read_input()?.parse::() { + Ok(num) => { + if num > 0 { + break Ok(num); + } else { + println!("Must be greater than zero"); + } + } + Err(_) => println!("Please enter a number greater than zero"), + } + } +} + +fn user_input() -> io::Result<(usize, usize, bool, String, String)> { + println!("Horizontal"); + let horizontal = read_input_number()?; + println!(); + + println!("Vertical "); + let vertical = read_input_number()?; + println!(); + + println!("Centered "); + let is_entered = read_input()?.starts_with('Y'); + println!(); + + println!("Character (type 'ALL' if you want character being printed) "); + let character = read_input()?; + println!(); + + println!("Statement "); + let statement = read_input()?; + println!(); + + // This means to prepare printer, just press Enter + println!("Set page "); + read_input()?; + println!(); + + Ok((horizontal, vertical, is_entered, character, statement)) +} + +fn print_banner() -> io::Result<()> { + let letters = HashMap::from(LETTERS); + + let (horizontal, vertical, is_entered, character, statement) = user_input()?; + + for statement_char in statement.chars() { + let x_str = if character == "ALL" { + statement_char.to_string() + } else { + character.clone() + }; + + if x_str == " " { + for _ in 0..(7 * horizontal) { + println!(); + } + continue; + } + + let mut s = [0; 7]; + if let Some(ss) = letters.get(&statement_char) { + s.copy_from_slice(ss); + } else { + println!("\nCannot print {statement_char}\n"); + } + let mut f = [0; 7]; + let mut j = [false; 9]; + + for u in 0..s.len() { + for k in (0..=8).rev() { + let mask = 1usize << k; + j[8 - k] = if mask >= s[u] { + false + } else { + s[u] -= mask; + true + }; + if s[u] == 1 { + f[u] = 8 - k; + break; + } + } + + let offset_str = if is_entered { + let n = (63 * 2 - vertical * 9) / 2 / x_str.len() + 1; + " ".repeat(n) + } else { + "".to_string() + }; + + let mut content_str = String::new(); + for b in &j[0..=f[u]] { + if *b { + content_str += &x_str.repeat(vertical); + } else { + content_str += &" ".repeat(x_str.len()).repeat(vertical); + } + } + + for _ in 0..horizontal { + println!("{offset_str}{content_str}"); + } + } + + for _ in 0..(2 * horizontal - 1) { + println!(); + } + } + + Ok(()) +} From 84f15fdb46a20e6c2b06cbdfbaa2b7be15183cfb Mon Sep 17 00:00:00 2001 From: apeng2012 Date: Tue, 14 Nov 2023 21:30:49 +0800 Subject: [PATCH 316/377] Revert "Port 06_Banner to Rust" This reverts commit e9aa366a8b39d41e1062cc4335f1c21781fec2eb. --- 06_Banner/rust/Cargo.toml | 8 -- 06_Banner/rust/src/main.rs | 173 ------------------------------------- 2 files changed, 181 deletions(-) delete mode 100644 06_Banner/rust/Cargo.toml delete mode 100644 06_Banner/rust/src/main.rs diff --git a/06_Banner/rust/Cargo.toml b/06_Banner/rust/Cargo.toml deleted file mode 100644 index 1ec696335..000000000 --- a/06_Banner/rust/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "rust" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/06_Banner/rust/src/main.rs b/06_Banner/rust/src/main.rs deleted file mode 100644 index dcfe9a4e0..000000000 --- a/06_Banner/rust/src/main.rs +++ /dev/null @@ -1,173 +0,0 @@ -use std::collections::HashMap; -use std::io::{self, stdin}; - -const LETTERS: [(char, [usize; 7]); 42] = [ - (' ', [0, 0, 0, 0, 0, 0, 0]), - ('A', [505, 37, 35, 34, 35, 37, 505]), - ('G', [125, 131, 258, 258, 290, 163, 101]), - ('E', [512, 274, 274, 274, 274, 258, 258]), - ('T', [2, 2, 2, 512, 2, 2, 2]), - ('W', [256, 257, 129, 65, 129, 257, 256]), - ('L', [512, 257, 257, 257, 257, 257, 257]), - ('S', [69, 139, 274, 274, 274, 163, 69]), - ('O', [125, 131, 258, 258, 258, 131, 125]), - ('N', [512, 7, 9, 17, 33, 193, 512]), - ('F', [512, 18, 18, 18, 18, 2, 2]), - ('K', [512, 17, 17, 41, 69, 131, 258]), - ('B', [512, 274, 274, 274, 274, 274, 239]), - ('D', [512, 258, 258, 258, 258, 131, 125]), - ('H', [512, 17, 17, 17, 17, 17, 512]), - ('M', [512, 7, 13, 25, 13, 7, 512]), - ('?', [5, 3, 2, 354, 18, 11, 5]), - ('U', [128, 129, 257, 257, 257, 129, 128]), - ('R', [512, 18, 18, 50, 82, 146, 271]), - ('P', [512, 18, 18, 18, 18, 18, 15]), - ('Q', [125, 131, 258, 258, 322, 131, 381]), - ('Y', [8, 9, 17, 481, 17, 9, 8]), - ('V', [64, 65, 129, 257, 129, 65, 64]), - ('X', [388, 69, 41, 17, 41, 69, 388]), - ('Z', [386, 322, 290, 274, 266, 262, 260]), - ('I', [258, 258, 258, 512, 258, 258, 258]), - ('C', [125, 131, 258, 258, 258, 131, 69]), - ('J', [65, 129, 257, 257, 257, 129, 128]), - ('1', [0, 0, 261, 259, 512, 257, 257]), - ('2', [261, 387, 322, 290, 274, 267, 261]), - ('*', [69, 41, 17, 512, 17, 41, 69]), - ('3', [66, 130, 258, 274, 266, 150, 100]), - ('4', [33, 49, 41, 37, 35, 512, 33]), - ('5', [160, 274, 274, 274, 274, 274, 226]), - ('6', [194, 291, 293, 297, 305, 289, 193]), - ('7', [258, 130, 66, 34, 18, 10, 8]), - ('8', [69, 171, 274, 274, 274, 171, 69]), - ('9', [263, 138, 74, 42, 26, 10, 7]), - ('=', [41, 41, 41, 41, 41, 41, 41]), - ('!', [1, 1, 1, 384, 1, 1, 1]), - ('0', [57, 69, 131, 258, 131, 69, 57]), - ('.', [1, 1, 129, 449, 129, 1, 1]), -]; - -fn main() { - print_banner().ok(); -} - -fn read_input() -> io::Result { - let mut input = String::new(); - stdin().read_line(&mut input)?; - Ok(input.trim().to_uppercase()) -} - -fn read_input_number() -> io::Result { - loop { - match read_input()?.parse::() { - Ok(num) => { - if num > 0 { - break Ok(num); - } else { - println!("Must be greater than zero"); - } - } - Err(_) => println!("Please enter a number greater than zero"), - } - } -} - -fn user_input() -> io::Result<(usize, usize, bool, String, String)> { - println!("Horizontal"); - let horizontal = read_input_number()?; - println!(); - - println!("Vertical "); - let vertical = read_input_number()?; - println!(); - - println!("Centered "); - let is_entered = read_input()?.starts_with('Y'); - println!(); - - println!("Character (type 'ALL' if you want character being printed) "); - let character = read_input()?; - println!(); - - println!("Statement "); - let statement = read_input()?; - println!(); - - // This means to prepare printer, just press Enter - println!("Set page "); - read_input()?; - println!(); - - Ok((horizontal, vertical, is_entered, character, statement)) -} - -fn print_banner() -> io::Result<()> { - let letters = HashMap::from(LETTERS); - - let (horizontal, vertical, is_entered, character, statement) = user_input()?; - - for statement_char in statement.chars() { - let x_str = if character == "ALL" { - statement_char.to_string() - } else { - character.clone() - }; - - if x_str == " " { - for _ in 0..(7 * horizontal) { - println!(); - } - continue; - } - - let mut s = [0; 7]; - if let Some(ss) = letters.get(&statement_char) { - s.copy_from_slice(ss); - } else { - println!("\nCannot print {statement_char}\n"); - } - let mut f = [0; 7]; - let mut j = [false; 9]; - - for u in 0..s.len() { - for k in (0..=8).rev() { - let mask = 1usize << k; - j[8 - k] = if mask >= s[u] { - false - } else { - s[u] -= mask; - true - }; - if s[u] == 1 { - f[u] = 8 - k; - break; - } - } - - let offset_str = if is_entered { - let n = (63 * 2 - vertical * 9) / 2 / x_str.len() + 1; - " ".repeat(n) - } else { - "".to_string() - }; - - let mut content_str = String::new(); - for b in &j[0..=f[u]] { - if *b { - content_str += &x_str.repeat(vertical); - } else { - content_str += &" ".repeat(x_str.len()).repeat(vertical); - } - } - - for _ in 0..horizontal { - println!("{offset_str}{content_str}"); - } - } - - for _ in 0..(2 * horizontal - 1) { - println!(); - } - } - - Ok(()) -} From 7fa5200072a437818783e2b550fbcca9cbf24e79 Mon Sep 17 00:00:00 2001 From: apeng2012 Date: Sat, 2 Dec 2023 03:39:54 +0800 Subject: [PATCH 317/377] Port 08_Batnum to Rust --- 08_Batnum/rust/Cargo.lock | 7 ++ 08_Batnum/rust/Cargo.toml | 8 ++ 08_Batnum/rust/src/main.rs | 239 +++++++++++++++++++++++++++++++++++++ README.md | 4 +- 4 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 08_Batnum/rust/Cargo.lock create mode 100644 08_Batnum/rust/Cargo.toml create mode 100644 08_Batnum/rust/src/main.rs diff --git a/08_Batnum/rust/Cargo.lock b/08_Batnum/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/08_Batnum/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/08_Batnum/rust/Cargo.toml b/08_Batnum/rust/Cargo.toml new file mode 100644 index 000000000..1ec696335 --- /dev/null +++ b/08_Batnum/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/08_Batnum/rust/src/main.rs b/08_Batnum/rust/src/main.rs new file mode 100644 index 000000000..761e1939b --- /dev/null +++ b/08_Batnum/rust/src/main.rs @@ -0,0 +1,239 @@ +use std::io::{self, Write}; + +/// Print out the introduction and rules for the game. +fn print_intro() { + println!(); + println!(); + println!("{:>33}", "BATNUM"); + println!("{:>15}", "CREATIVE COMPUTING MORRISSTOWN, NEW JERSEY"); + println!(); + println!(); + println!(); + println!("THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE"); + println!("COMPUTER IS YOUR OPPONENT."); + println!(); + println!("THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU"); + println!("AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE."); + println!("WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR"); + println!("NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS."); + println!("DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME."); + println!("ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING."); + println!(); +} + +/// This requests the necessary parameters to play the game. +/// five game parameters: +/// * pile_size - the starting size of the object pile +/// * min_select - minimum selection that can be made on each turn +/// * max_select - maximum selection that can be made on each turn +/// * start_option - computer first or player first +/// * win_option - goal is to take the last object +/// or the goal is to not take the last object +struct Params { + pub pile_size: usize, + pub min_select: usize, + pub max_select: usize, + pub start_option: StartOption, + pub win_option: WinOption, +} + +#[derive(PartialEq, Eq)] +enum StartOption { + ComputerFirst, + PlayerFirst, +} + +#[derive(PartialEq, Eq)] +enum WinOption { + TakeLast, + AvoidLast, +} + +impl Params { + pub fn get_params() -> Self { + let pile_size = Self::get_pile_size(); + let (min_select, max_select) = Self::get_min_max(); + let start_option = Self::get_start_option(); + let win_option = Self::get_win_option(); + + Self { + pile_size, + min_select, + max_select, + start_option, + win_option, + } + } + + fn get_pile_size() -> usize { + print!("ENTER PILE SIZE "); + let _ = io::stdout().flush(); + read_input_integer() + } + + fn get_win_option() -> WinOption { + print!("ENTER WIN OPTION: 1 TO TAKE LAST, 2 TO AVOID LAST: "); + let _ = io::stdout().flush(); + + loop { + match read_input_integer() { + 1 => { + return WinOption::TakeLast; + } + 2 => { + return WinOption::AvoidLast; + } + _ => { + print!("Please enter 1 or 2 "); + let _ = io::stdout().flush(); + continue; + } + } + } + } + + fn get_start_option() -> StartOption { + print!("ENTER START OPTION: 1 COMPUTER FIRST, 2 YOU FIRST "); + let _ = io::stdout().flush(); + + loop { + match read_input_integer() { + 1 => { + return StartOption::ComputerFirst; + } + 2 => { + return StartOption::PlayerFirst; + } + _ => { + print!("Please enter 1 or 2 "); + let _ = io::stdout().flush(); + continue; + } + } + } + } + + fn get_min_max() -> (usize, usize) { + print!("ENTER MIN "); + let _ = io::stdout().flush(); + let min = read_input_integer(); + + print!("ENTER MAX "); + let _ = io::stdout().flush(); + let max = read_input_integer(); + + (min, max) + } +} + +fn read_input_integer() -> usize { + loop { + let mut input = String::new(); + io::stdin() + .read_line(&mut input) + .expect("Failed to read line"); + match input.trim().parse::() { + Ok(num) => { + if num == 0 { + print!("Must be greater than zero "); + let _ = io::stdout().flush(); + continue; + } + return num; + } + Err(_err) => { + print!("Please enter a number greater than zero "); + let _ = io::stdout().flush(); + continue; + } + } + } +} + +fn player_move(pile_size: &mut usize, params: &Params) -> bool { + loop { + print!("YOUR MOVE "); + let _ = io::stdout().flush(); + + let player_move = read_input_integer(); + if player_move == 0 { + println!("I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT."); + return true; + } + if player_move > params.max_select || player_move < params.min_select { + println!("ILLEGAL MOVE, REENTER IT"); + continue; + } + *pile_size -= player_move; + if *pile_size == 0 { + if params.win_option == WinOption::AvoidLast { + println!("TOUGH LUCK, YOU LOSE."); + } else { + println!("CONGRATULATIONS, YOU WIN.") + } + return true; + } + return false; + } +} + +fn computer_pick(pile_size: usize, params: &Params) -> usize { + let q = if params.win_option == WinOption::AvoidLast { + pile_size - 1 + } else { + pile_size + }; + let c = params.min_select + params.max_select; + let computer_pick = q - (c * (q / c)); + let computer_pick = if computer_pick < params.min_select { + params.min_select + } else { + computer_pick + }; + if computer_pick > params.max_select { + params.max_select + } else { + computer_pick + } +} + +fn computer_move(pile_size: &mut usize, params: &Params) -> bool { + if params.win_option == WinOption::TakeLast && *pile_size <= params.max_select { + println!("COMPUTER TAKES {pile_size} AND WINS."); + return true; + } + if params.win_option == WinOption::AvoidLast && *pile_size >= params.min_select { + println!("COMPUTER TAKES {} AND LOSES.", params.min_select); + return true; + } + + let curr_sel = computer_pick(*pile_size, params); + *pile_size -= curr_sel; + println!("COMPUTER TAKES {curr_sel} AND LEAVES {pile_size}"); + false +} + +fn play_game(params: &Params) { + let mut pile_size = params.pile_size; + + if params.start_option == StartOption::ComputerFirst && computer_move(&mut pile_size, params) { + return; + } + + loop { + if player_move(&mut pile_size, params) { + return; + } + if computer_move(&mut pile_size, params) { + return; + } + } +} + +fn main() -> ! { + loop { + print_intro(); + let params = Params::get_params(); + play_game(¶ms); + } +} diff --git a/README.md b/README.md index 0ddd2748f..31a2ada8a 100644 --- a/README.md +++ b/README.md @@ -83,9 +83,9 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 03_Animal | x | x | x | x | x | x | x | x | x | x | | 04_Awari | x | x | x | | | x | x | x | x | x | | 05_Bagels | x | x | x | x | x | x | x | x | x | x | -| 06_Banner | x | x | x | | | x | x | x | | x | +| 06_Banner | x | x | x | | | x | x | x | x | x | | 07_Basketball | x | x | x | | | x | x | x | | x | -| 08_Batnum | x | x | x | | | x | x | x | | x | +| 08_Batnum | x | x | x | | | x | x | x | x | x | | 09_Battle | x | x | x | | | | x | | | x | | 10_Blackjack | x | x | x | | | | x | x | x | x | | 11_Bombardment | x | x | x | | | x | x | x | x | x | From 9b4153dce864597f419263476f79662a616e6c04 Mon Sep 17 00:00:00 2001 From: Jack Boyce Date: Fri, 8 Dec 2023 13:32:21 -0800 Subject: [PATCH 318/377] Update README.md fix typos from original book --- 84_Super_Star_Trek/README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/84_Super_Star_Trek/README.md b/84_Super_Star_Trek/README.md index 07da653f2..32f827c67 100644 --- a/84_Super_Star_Trek/README.md +++ b/84_Super_Star_Trek/README.md @@ -3,12 +3,12 @@ #### Brief History Many versions of Star Trek have been kicking around various college campuses since the late sixties. I recall playing one at Carnegie-Mellon Univ. in 1967 or 68, and a very different one at Berkeley. However, these were a far cry from the one written by Mike Mayfield of Centerline Engineering and/or Custom Data. This was written for an HP2000C and completed in October 1972. It became the “standard” Star Trek in February 1973 when it was put in the HP contributed program library and onto a number of HP Data Center machines. -In the summer of 1973, I converted the HP version to BASIC-PLUS for DEC’s RSTS-11 compiler and added a few bits and pieces while I was at it. Mary Cole at DEC contributed enormously to this task too. Later that year I published it under the name SPACWE (Space War — in retrospect, an incorrect name) in my book _101 Basic Computer Games_.It is difficult today to find an interactive computer installation that does not have one of these versions of Star Trek available. +In the summer of 1973, I converted the HP version to BASIC-PLUS for DEC’s RSTS-11 compiler and added a few bits and pieces while I was at it. Mary Cole at DEC contributed enormously to this task too. Later that year I published it under the name SPACWR (Space War — in retrospect, an incorrect name) in my book _101 Basic Computer Games_. It is difficult today to find an interactive computer installation that does not have one of these versions of Star Trek available. #### Quadrant Nomenclature Recently, certain critics have professed confusion as to the origin on the “quadrant” nomenclature used on all standard CG (Cartesian Galactic) maps. Naturally, for anyone with the remotest knowledge of history, no explanation is necessary; however, the following synopsis should suffice for the critics: -As everybody schoolboy knows, most of the intelligent civilizations in the Milky Way had originated galactic designations of their own choosing well before the Third Magellanic Conference, at which the so-called “2⁶ Agreement” was reached. In that historic document, the participant cultures agreed, in all two-dimensional representations of the galaxy, to specify 64 major subdivisions, ordered as an 8 x 8 matrix. This was partially in deference to the Earth culture (which had done much in the initial organization of the Federation), whose century-old galactic maps had landmarks divided into four “quadrants,” designated by ancient “Roman Numerals” (the origin of which has been lost). +As every schoolboy knows, most of the intelligent civilizations in the Milky Way had originated galactic designations of their own choosing well before the Third Magellanic Conference, at which the so-called “2⁶ Agreement” was reached. In that historic document, the participant cultures agreed, in all two-dimensional representations of the galaxy, to specify 64 major subdivisions, ordered as an 8 x 8 matrix. This was partially in deference to the Earth culture (which had done much in the initial organization of the Federation), whose century-old galactic maps had always shown 16 major regions named after celestial landmarks divided into four “quadrants,” designated by ancient “Roman Numerals” (the origin of which has been lost). To this day, the official logs of starships originating on near-Earth starbases still refer to the major galactic areas as “quadrants.” @@ -17,7 +17,7 @@ The relation between the Historical and Standard nomenclatures is shown in the s | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |---|--------------|----|-----|----|------------|----|-----|----| | 1 | ANTARES | | | | SIRIUS | | | | -| | I | II | III | IV | I | | III | IV | +| | I | II | III | IV | I | II | III | IV | | 2 | RIGEL | | | | DENEB | | | | | | I | II | III | IV | I | II | III | IV | | 3 | PROCYON | | | | CAPELLA | | | | @@ -88,11 +88,13 @@ The relation between the Historical and Standard nomenclatures is shown in the s 15. This version of Star Trek was created for a Data General Nova 800 system with 32K or core. So that it would fit, the instructions are separated from the main program via a CHAIN. For conversion to DEC BASIC-PLUS, Statement 160 (Randomize) should be moved after the return from the chained instructions, say to Statement 245. For Altair BASIC, Randomize and the chain instructions should be eliminated. +† Designates trademark of Paramount Pictures Corporation. Used by permission of Paramount Pictures Corporation. + --- As published in Basic Computer Games (1978): - [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=157) -- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=166) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=172) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html @@ -110,6 +112,5 @@ Many of the programs in this book and this collection have bugs in the original - lines `8310`,`8330`,`8430`,`8450` : Division by zero is possible - line `440` : `B9` should be initialised to 0, not 2 - #### External Links - C++: https://www.codeproject.com/Articles/28399/The-Object-Oriented-Text-Star-Trek-Game-in-C From e893704987c561b2550a8e9eb9f6a02fa4a34376 Mon Sep 17 00:00:00 2001 From: apeng2012 Date: Fri, 29 Dec 2023 06:38:02 +0800 Subject: [PATCH 319/377] Port 09_Battle to Rust --- 09_Battle/rust/Cargo.lock | 75 ++++++++++ 09_Battle/rust/Cargo.toml | 9 ++ 09_Battle/rust/src/main.rs | 273 +++++++++++++++++++++++++++++++++++++ README.md | 2 +- 4 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 09_Battle/rust/Cargo.lock create mode 100644 09_Battle/rust/Cargo.toml create mode 100644 09_Battle/rust/src/main.rs diff --git a/09_Battle/rust/Cargo.lock b/09_Battle/rust/Cargo.lock new file mode 100644 index 000000000..10a595996 --- /dev/null +++ b/09_Battle/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/09_Battle/rust/Cargo.toml b/09_Battle/rust/Cargo.toml new file mode 100644 index 000000000..3b1d02f52 --- /dev/null +++ b/09_Battle/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" diff --git a/09_Battle/rust/src/main.rs b/09_Battle/rust/src/main.rs new file mode 100644 index 000000000..f9e8d36ec --- /dev/null +++ b/09_Battle/rust/src/main.rs @@ -0,0 +1,273 @@ +use rand::Rng; +use std::{ + cmp::Ordering, + fmt, + io::{self, Write}, +}; + +#[derive(Clone, Copy)] +#[repr(C)] +enum ShipLength { + Destroyer = 2, + Cruiser = 3, + AircraftCarrier = 4, +} + +#[derive(Clone, Copy, PartialEq)] +struct Point(i8, i8); + +impl core::ops::Add for Point { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self(self.0 + rhs.0, self.1 + rhs.1) + } +} + +impl Point { + pub fn is_outside(&self, width: usize) -> bool { + let w = width as i8; + (!(0..w).contains(&self.0)) || (!(0..w).contains(&self.1)) + } + + pub fn userinput2coordinate(self) -> Self { + Self(self.0 - 1, See::WIDTH as i8 - self.1) + } +} + +struct Ship(Vec); + +impl Ship { + pub fn new(length: ShipLength) -> Self { + 'try_again: loop { + let start = Point( + rand::thread_rng().gen_range(0..See::WIDTH) as i8, + rand::thread_rng().gen_range(0..See::WIDTH) as i8, + ); + let vector = Self::random_vector(); + + let mut ship = vec![start]; + for _ in 1..length as usize { + let last = ship.last().unwrap(); + let new_part = *last + vector; + if new_part.is_outside(See::WIDTH) { + continue 'try_again; + } + ship.push(new_part); + } + + return Self(ship); + } + } + + fn random_vector() -> Point { + loop { + let vector = Point( + rand::thread_rng().gen_range(-1..2), + rand::thread_rng().gen_range(-1..2), + ); + if vector != Point(0, 0) { + return vector; + } + } + } + + pub fn collide(&self, see: &[Vec]) -> bool { + self.0.iter().any(|p| see[p.0 as usize][p.1 as usize] != 0) + } + + pub fn place(self, see: &mut [Vec], code: i8) { + for p in self.0.iter() { + see[p.0 as usize][p.1 as usize] = code; + } + } +} + +enum Report { + Already(i8), + Splash, + Hit(i8), +} + +struct See { + data: Vec>, +} + +impl See { + pub const WIDTH: usize = 6; + + fn place_ship(data: &mut [Vec], length: ShipLength, code: i8) { + let ship = loop { + let ship = Ship::new(length); + if ship.collide(data) { + continue; + } + break ship; + }; + ship.place(data, code); + } + + pub fn new() -> Self { + let mut data = vec![vec![0; Self::WIDTH]; Self::WIDTH]; + + Self::place_ship(&mut data, ShipLength::Destroyer, 1); + Self::place_ship(&mut data, ShipLength::Destroyer, 2); + Self::place_ship(&mut data, ShipLength::Cruiser, 3); + Self::place_ship(&mut data, ShipLength::Cruiser, 4); + Self::place_ship(&mut data, ShipLength::AircraftCarrier, 5); + Self::place_ship(&mut data, ShipLength::AircraftCarrier, 6); + + Self { data } + } + + pub fn report(&mut self, point: Point) -> Report { + let (x, y) = (point.0 as usize, point.1 as usize); + let value = self.data[x][y]; + match value.cmp(&0) { + Ordering::Less => Report::Already(-value), + Ordering::Equal => Report::Splash, + Ordering::Greater => { + self.data[x][y] = -value; + Report::Hit(value) + } + } + } + + pub fn has_ship(&self, code: i8) -> bool { + self.data.iter().any(|v| v.contains(&code)) + } + + pub fn has_any_ship(&self) -> bool { + (1..=6).any(|c| self.has_ship(c)) + } + + pub fn count_sunk(&self, ship: ShipLength) -> i32 { + let codes = match ship { + ShipLength::Destroyer => (1, 2), + ShipLength::Cruiser => (3, 4), + ShipLength::AircraftCarrier => (5, 6), + }; + + let ret = if self.has_ship(codes.0) { 0 } else { 1 }; + ret + if self.has_ship(codes.1) { 0 } else { 1 } + } +} + +impl fmt::Display for See { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for row in &self.data { + write!(f, "\r\n")?; + for cell in row { + write!(f, "{:2} ", cell)?; + } + } + write!(f, "\r\n") + } +} + +fn input_point() -> Result { + let mut input = String::new(); + io::stdin() + .read_line(&mut input) + .expect("Failed to read line"); + let point_str: Vec<&str> = input.trim().split(',').collect(); + + if point_str.len() != 2 { + return Err(()); + } + + let x = point_str[0].parse::().map_err(|_| ())?; + let y = point_str[1].parse::().map_err(|_| ())?; + + Ok(Point(x, y)) +} + +fn get_next_target() -> Point { + loop { + print!("? "); + let _ = io::stdout().flush(); + + if let Ok(p) = input_point() { + let p = p.userinput2coordinate(); + if !p.is_outside(See::WIDTH) { + return p; + } + } + + println!( + "INVALID. SPECIFY TWO NUMBERS FROM 1 TO {}, SEPARATED BY A COMMA.", + See::WIDTH + ); + } +} + +fn main() { + let mut see = See::new(); + println!( + " + BATTLE +CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + +THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION +HAS BEEN CAPTURED BUT NOT DECODED: + " + ); + + println!("{see}"); + + println!( + " + +DE-CODE IT AND USE IT IF YOU CAN +BUT KEEP THE DE-CODING METHOD A SECRET. + +START GAME + " + ); + + let mut splashes = 0; + let mut hits = 0; + + loop { + let target = get_next_target(); + + let r = see.report(target); + if let Report::Hit(c) = r { + println!("A DIRECT HIT ON SHIP NUMBER {c}"); + hits += 1; + + if !see.has_ship(c) { + println!("AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS."); + println!("SO FAR, THE BAD GUYS HAVE LOST"); + println!("{} DESTROYER(S),", see.count_sunk(ShipLength::Destroyer)); + println!("{} CRUISER(S),", see.count_sunk(ShipLength::Cruiser)); + println!( + "AND {} AIRCRAFT CARRIER(S),", + see.count_sunk(ShipLength::AircraftCarrier) + ); + } + } else { + if let Report::Already(c) = r { + println!("YOU ALREADY PUT A HOLE IN SHIP NUMBER {c} AT THAT POINT."); + } + println!("SPLASH! TRY AGAIN."); + splashes += 1; + continue; + } + + if see.has_any_ship() { + println!("YOUR CURRENT SPLASH/HIT RATIO IS {splashes}/{hits}"); + continue; + } + + println!("YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET "); + println!("WITH A FINAL SPLASH/HIT RATIO OF {splashes}/{hits}"); + + if splashes == 0 { + println!("CONGRATULATIONS -- A DIRECT HIT EVERY TIME."); + } + + println!("\n****************************"); + break; + } +} diff --git a/README.md b/README.md index 31a2ada8a..f714bc89b 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 06_Banner | x | x | x | | | x | x | x | x | x | | 07_Basketball | x | x | x | | | x | x | x | | x | | 08_Batnum | x | x | x | | | x | x | x | x | x | -| 09_Battle | x | x | x | | | | x | | | x | +| 09_Battle | x | x | x | | | | x | | x | x | | 10_Blackjack | x | x | x | | | | x | x | x | x | | 11_Bombardment | x | x | x | | | x | x | x | x | x | | 12_Bombs_Away | x | x | x | | x | x | x | | | x | From c9f91288f00b58db2ff3990d1feec072cb4201a5 Mon Sep 17 00:00:00 2001 From: Aldrin Misquitta Date: Sun, 24 Mar 2024 16:12:10 +0000 Subject: [PATCH 320/377] 72. Queen ported to Java --- 72_Queen/java/Queen.java | 370 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 72_Queen/java/Queen.java diff --git a/72_Queen/java/Queen.java b/72_Queen/java/Queen.java new file mode 100644 index 000000000..7dfb6353c --- /dev/null +++ b/72_Queen/java/Queen.java @@ -0,0 +1,370 @@ +import java.util.List; +import java.util.Optional; +import java.util.Scanner; + +/** + * QUEEN + *

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + */ +public class Queen { + + public static final int WINNING_POSITION = 158; + public static final int FORFEIT_MOVE = 0; + + // @formatter:off + private static final int[] S = { + 81, 71, 61, 51, 41, 31, 21, 11, + 92, 82, 72, 62, 52, 42, 32, 22, + 103, 93, 83, 73, 63, 53, 43, 33, + 114, 104, 94, 84, 74, 64, 54, 44, + 125, 115, 105, 95, 85, 75, 65, 55, + 136, 126, 116, 106, 96, 86, 76, 66, + 147, 137, 127, 117, 107, 97, 87, 77, + 158, 148, 138, 128, 118, 108, 98, 88 + }; + // @formatter:on + + private static final Scanner scanner = new Scanner(System.in); + + + public static void main(String[] args) { + printWithTab("QUEEN", 33); + printWithTab("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY", 15); + System.out.println("\n\n"); + + askAndShowInstructions(); + + boolean anotherGame; + do { + printBoard(); + + Move firstMove = getUserFirstMove(); + if (firstMove.move == 0) { + printWonByForfeit(); + } + + if (isTopmostRowOrRightmostColumn(firstMove)) { + playOneGame(firstMove); + } + + anotherGame = askForAnotherGame(); + + } while (anotherGame); + + + System.out.println("\nOK --- THANKS AGAIN."); + } + + /** + * Play one game starting with the first move from the user + */ + private static void playOneGame(Move firstMove) { + boolean gameInProgress = true; + Move userMove = firstMove; + + while (gameInProgress) { + + if (userMove.move == WINNING_POSITION) { + //players wins + printCongratulatoryMessage(); + gameInProgress = false; + } else { + + ComputerMove computerMove = getComputerMove(userMove); + + System.out.printf("COMPUTER MOVES TO SQUARE %d\n", computerMove.move); + + if (computerMove.move == WINNING_POSITION) { + printComputerWins(); + gameInProgress = false; + } else { + userMove = getValidUserMove(computerMove); + + if (userMove.move == FORFEIT_MOVE) { + printWonByForfeit(); + gameInProgress = false; + } else if (userMove.move == WINNING_POSITION) { + printCongratulatoryMessage(); + gameInProgress = false; + } + } + } + } + } + + /** + * Get the user's first move + */ + private static Move getUserFirstMove() { + boolean validMove; + Move move; + do { + System.out.print("WHERE WOULD YOU LIKE TO START? "); + int movePosition = scanner.nextInt(); + move = new Move(movePosition); + validMove = false; + if (!isTopmostRowOrRightmostColumn(move)) { + System.out.println("PLEASE READ THE DIRECTIONS AGAIN."); + System.out.println("YOU HAVE BEGUN ILLEGALLY."); + System.out.println(); + } else { + validMove = true; + } + scanner.nextLine(); + } while (!validMove); + return move; + } + + /** + * Prompt and get a valid move from the user. Uses the computer's latest move to validate the next move. + */ + private static Move getValidUserMove(ComputerMove latestComputerMove) { + boolean validUserMove = false; + Move userMove = null; + while (!validUserMove) { + userMove = getUserMove(); + if (!validateUserMove(userMove, latestComputerMove)) { + System.out.println("\nY O U C H E A T . . . TRY AGAIN"); + } else { + validUserMove = true; + } + } + return userMove; + } + + private static void printWonByForfeit() { + System.out.println("\nIT LOOKS LIKE I HAVE WON BY FORFEIT.\n"); + } + + private static boolean validateUserMove(Move userMove, ComputerMove computerMove) { + if (userMove.move <= computerMove.move) { + return false; + } + + if (userMove.move == FORFEIT_MOVE || userMove.move == WINNING_POSITION) { + return true; + } + + int tensValueUser = userMove.move / 10; + int unitsValueUser = userMove.move - (tensValueUser * 10); + int unitsValueComputer = computerMove.u; + int tensValueComputer = computerMove.t; + int p = unitsValueUser - unitsValueComputer; + if (p != 0) { + if ((tensValueUser - tensValueComputer) != p) { + return (tensValueUser - tensValueComputer) == 2 * p; + } else { + return true; + } + } else { + int l = tensValueUser - tensValueComputer; + return l > 0; + } + } + + private static Move getUserMove() { + System.out.print("WHAT IS YOUR MOVE? "); + int movePosition = scanner.nextInt(); + scanner.nextLine(); + return new Move(movePosition); + } + + private static void printComputerWins() { + System.out.println("\nNICE TRY, BUT IT LOOKS LIKE I HAVE WON."); + System.out.println("THANKS FOR PLAYING.\n"); + } + + private static boolean askForAnotherGame() { + System.out.print("ANYONE ELSE CARE TO TRY? "); + do { + String response = Queen.scanner.nextLine(); + if (response.equals("NO")) { + return false; + } else if (response.equals("YES")) { + return true; + } else { + System.out.println("PLEASE ANSWER 'YES' OR 'NO'."); + } + } while (true); + } + + private static boolean isTopmostRowOrRightmostColumn(Move move) { + return move.unitsPlaceValue == 1 || move.unitsPlaceValue == move.tensPlaceValue; + } + + private static ComputerMove getComputerMove(Move userMove) { + int unitsValueUser = userMove.unitsPlaceValue; + int tensValueUser = userMove.tensPlaceValue; + + List moveRandomlyFromPositions = List.of(41, 44, 73, 75, 126, 127); + + if (moveRandomlyFromPositions.contains(userMove.move)) { + //random move + return getMovePositionInRandomDirection(unitsValueUser, tensValueUser); + } else { + + for (int k = 7; k >= 1; k--) { + // consider same row first, left-most position + Optional move = evaluatePositionAndGetMove(unitsValueUser, tensValueUser + k); + if (move.isPresent()) return move.get(); + + //try same column, bottom-most + move = evaluatePositionAndGetMove(unitsValueUser + k, tensValueUser + k); + if (move.isPresent()) return move.get(); + + //now left-most at the bottom-most + move = evaluatePositionAndGetMove(unitsValueUser + k, tensValueUser + k + k); + if (move.isPresent()) return move.get(); + } + + //else move one step in a random direction + return getMovePositionInRandomDirection(unitsValueUser, tensValueUser); + } + + } + + private static Optional evaluatePositionAndGetMove(int newUnitsValue, int newTensValue) { + EvaluationResult result = evaluateComputerMove(newUnitsValue, newTensValue); + if (result.favourablePosition) { + return Optional.of(new ComputerMove(result.move)); + } + return Optional.empty(); + } + + private static EvaluationResult evaluateComputerMove(int u, int t) { + int m = 10 * t + u; + if (m == 158 || m == 127 || m == 126 || m == 75 || m == 73) { + return new EvaluationResult(m, true); + } else { + return new EvaluationResult(m, false); + } + } + + private static void printCongratulatoryMessage() { + System.out.println(); + System.out.println("C O N G R A T U L A T I O N S . . ."); + System.out.println(); + System.out.println("YOU HAVE WON--VERY WELL PLAYED."); + System.out.println("IT LOOKS LIKE I HAVE MET MY MATCH."); + System.out.println("THANKS FOR PLAYING---I CAN'T WIN ALL THE TIME."); + System.out.println(); + + } + + private static ComputerMove getMovePositionInRandomDirection(int u1, int t1) { + double randomValue = Math.random(); + + if (randomValue > 0.6) { + // Move directly down + return new ComputerMove(calculateMove(u1, t1, 1, 1)); + } else if (randomValue > 0.3) { + // Move down left + return new ComputerMove(calculateMove(u1, t1, 1, 2)); + } else { + // Move left + return new ComputerMove(calculateMove(u1, t1, 0, 1)); + } + } + + private static int calculateMove(int u, int t, int uChange, int tChange) { + int newU = u + uChange; + int newT = t + tChange; + return 10 * newT + newU; // Combine units and tens to corresponding position value + } + + + private static void printBoard() { + System.out.println(); + for (int A = 0; A <= 7; A++) { + for (int B = 0; B <= 7; B++) { + int I = 8 * A + B; + System.out.printf(" %d ", S[I]); + } + System.out.println(); + System.out.println(); + System.out.println(); + } + System.out.println(); + } + + private static void askAndShowInstructions() { + do { + System.out.print("DO YOU WANT INSTRUCTIONS? "); + String wish = scanner.nextLine(); + if (wish.equals("NO")) { + break; + } else if (wish.equals("YES")) { + showInstructions(); + break; + } else { + System.out.println("PLEASE ANSWER 'YES' OR 'NO'."); + } + } while (true); + } + + private static void printWithTab(String message, int tab) { + for (int i = 0; i < tab; i++) { + System.out.print(" "); + } + System.out.println(message); + } + + + private static void showInstructions() { + System.out.println("WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS"); + System.out.println("MOVES. OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,"); + System.out.println("DOWN, OR DIAGONALLY DOWN AND TO THE LEFT."); + System.out.println(); + System.out.println("THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER"); + System.out.println("LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE"); + System.out.println("COMPUTER. THE FIRST ONE TO PLACE THE QUEEN THERE WINS."); + System.out.println(); + System.out.println("YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES"); + System.out.println("ON THE TOP ROW OR RIGHT HAND COLUMN."); + System.out.println("THAT WILL BE YOUR FIRST MOVE."); + System.out.println("WE ALTERNATE MOVES."); + System.out.println("YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE."); + System.out.println("BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE."); + System.out.println(); + } + + + private static class ComputerMove { + private final int move; + private final int u; + private final int t; + + private ComputerMove(int move) { + this.move = move; + this.t = move / 10; + this.u = move - (t * 10); + } + + } + + private static class EvaluationResult { + private final int move; + private final boolean favourablePosition; + + public EvaluationResult(int move, boolean favourablePosition) { + this.move = move; + this.favourablePosition = favourablePosition; + } + + + } + + private static class Move { + private final int move; + private final int unitsPlaceValue; + private final int tensPlaceValue; + + private Move(int move) { + this.move = move; + this.tensPlaceValue = move / 10; + this.unitsPlaceValue = move % 10; + } + + } +} From a34fa0e581323ff2d914aa731246993c47710d4c Mon Sep 17 00:00:00 2001 From: apeng2012 Date: Fri, 19 Apr 2024 20:03:25 +0800 Subject: [PATCH 321/377] Port 12_Bombs_Away to Rust --- 12_Bombs_Away/rust/Cargo.lock | 75 ++++++++ 12_Bombs_Away/rust/Cargo.toml | 9 + 12_Bombs_Away/rust/src/main.rs | 309 +++++++++++++++++++++++++++++++++ 3 files changed, 393 insertions(+) create mode 100644 12_Bombs_Away/rust/Cargo.lock create mode 100644 12_Bombs_Away/rust/Cargo.toml create mode 100644 12_Bombs_Away/rust/src/main.rs diff --git a/12_Bombs_Away/rust/Cargo.lock b/12_Bombs_Away/rust/Cargo.lock new file mode 100644 index 000000000..59dc11cca --- /dev/null +++ b/12_Bombs_Away/rust/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/12_Bombs_Away/rust/Cargo.toml b/12_Bombs_Away/rust/Cargo.toml new file mode 100644 index 000000000..3b1d02f52 --- /dev/null +++ b/12_Bombs_Away/rust/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" diff --git a/12_Bombs_Away/rust/src/main.rs b/12_Bombs_Away/rust/src/main.rs new file mode 100644 index 000000000..d049fd849 --- /dev/null +++ b/12_Bombs_Away/rust/src/main.rs @@ -0,0 +1,309 @@ +use std::{ + io::{self, Write}, + str::FromStr, +}; + +use rand::Rng; + +struct Italy; +struct Allies; +struct Japan; +struct Germany; + +#[derive(Debug, PartialEq, Eq)] +struct ParseChoiceTargetError; + +#[derive(PartialEq)] +enum ThreeTarget { + One, + Two, + Three, +} + +impl FromStr for ThreeTarget { + type Err = ParseChoiceTargetError; + + fn from_str(s: &str) -> Result { + let n = s.parse::().map_err(|_| ParseChoiceTargetError)?; + match n { + 1 => Ok(Self::One), + 2 => Ok(Self::Two), + 3 => Ok(Self::Three), + _ => Err(ParseChoiceTargetError), + } + } +} + +enum FourTarget { + One, + Two, + Three, + Four, +} + +impl FromStr for FourTarget { + type Err = ParseChoiceTargetError; + + fn from_str(s: &str) -> Result { + let n = s.parse::().map_err(|_| ParseChoiceTargetError)?; + match n { + 1 => Ok(Self::One), + 2 => Ok(Self::Two), + 3 => Ok(Self::Three), + 4 => Ok(Self::Four), + _ => Err(ParseChoiceTargetError), + } + } +} + +pub trait Brefing { + type TargetOption; + fn prompt<'a>(&self) -> &'a str; + fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str; +} + +impl Brefing for Italy { + type TargetOption = ThreeTarget; + + fn prompt<'a>(&self) -> &'a str { + "YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)" + } + + fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str { + match target { + ThreeTarget::One => "SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.", + ThreeTarget::Two => "BE CAREFUL!!!", + ThreeTarget::Three => "YOU'RE GOING FOR THE OIL, EH?", + } + } +} + +impl Brefing for Allies { + type TargetOption = FourTarget; + + fn prompt<'a>(&self) -> &'a str { + "AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4): " + } + + fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str { + match target { + FourTarget::One => "YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.", + FourTarget::Two => "YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.", + FourTarget::Three => "YOU'RE CHASING THE BISMARK IN THE NORTH SEA.", + FourTarget::Four => "YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.", + } + } +} + +impl Brefing for Germany { + type TargetOption = ThreeTarget; + + fn prompt<'a>(&self) -> &'a str { + "A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\nENGLAND(2), OR FRANCE(3)? " + } + + fn targets_to_messages<'a>(&self, target: Self::TargetOption) -> &'a str { + match target { + ThreeTarget::One => "YOU'RE NEARING STALINGRAD.", + ThreeTarget::Two => "NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR.", + ThreeTarget::Three => "NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.", + } + } +} + +enum Side { + Italy(Italy), + Allies(Allies), + Japan(Japan), + Germany(Germany), +} + +impl From for Side { + fn from(value: FourTarget) -> Self { + match value { + FourTarget::One => Self::Italy(Italy), + FourTarget::Two => Self::Allies(Allies), + FourTarget::Three => Self::Japan(Japan), + FourTarget::Four => Self::Germany(Germany), + } + } +} + +fn stdin_choice(prompt: &str) -> C { + let mut buffer = String::new(); + + print!("{prompt}"); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut buffer).unwrap(); + loop { + if let Ok(choice) = buffer.trim().parse::() { + return choice; + } + print!("TRY AGAIN..."); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut buffer).unwrap(); + } +} + +fn stdin_y_or_n(prompt: &str) -> bool { + let mut buffer = String::new(); + + print!("{prompt}"); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut buffer).unwrap(); + buffer.trim().to_uppercase() == "Y" +} + +fn commence_non_kamikazi_attack() { + let nmissions = loop { + let nmissions = stdin_choice::("HOW MANY MISSIONS HAVE YOU FLOWN? "); + if nmissions < 160 { + break nmissions; + } + println!("MISSIONS, NOT MILES..."); + println!("150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS"); + print!("NOW THEN, "); + }; + + if nmissions >= 100 { + println!("THAT'S PUSHING THE ODDS!"); + } + + if nmissions < 25 { + println!("FRESH OUT OF TRAINING, EH?"); + } + + println!(); + + let mut rng = rand::thread_rng(); + let y: f32 = rng.gen(); + + if nmissions as f32 >= 160_f32 * y { + mission_success(); + } else { + mission_failure(); + } +} + +fn play_japan() { + if !stdin_y_or_n("YOUR FIRST KAMIKAZE MISSION? (Y OR N): ") { + player_death(); + return; + } + + let mut rng = rand::thread_rng(); + let y: f32 = rng.gen(); + if y > 0.65 { + mission_success(); + } else { + player_death(); + } +} + +fn player_death() { + println!("* * * * BOOM * * * *"); + println!("YOU HAVE BEEN SHOT DOWN....."); + println!("DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR"); + println!("LAST TRIBUTE..."); +} + +fn mission_success() { + let mut rng = rand::thread_rng(); + let y: f32 = rng.gen(); + + let killed = (100f32 * y) as i32; + println!("DIRECT HIT!!!! {killed} KILLED."); + println!("MISSION SUCCESSFUL."); +} + +fn mission_failure() { + let mut rng = rand::thread_rng(); + let y: f32 = rng.gen(); + let miles = 2 + (30f32 * y) as i32; + println!("MISSED TARGET BY {miles} MILES!"); + println!("NOW YOU'RE REALLY IN FOR IT !!"); + println!(); + let enemy_weapons = + stdin_choice::("DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? "); + + let enemy_gunner_accuracy = if enemy_weapons != ThreeTarget::Two { + let m = loop { + let m = + stdin_choice::("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? "); + if m <= 50 { + break m; + } + println!("TRY AGAIN..."); + }; + if m < 10 { + println!("YOU LIE, BUT YOU'LL PAY..."); + player_death(); + return; + } + m + } else { + 0 + }; + + let missile_threat_weighting = if enemy_weapons == ThreeTarget::One { + 0 + } else { + 35 + }; + + let death = + death_with_chance((enemy_gunner_accuracy + missile_threat_weighting) as f32 / 100f32); + + if death { + player_death(); + } else { + player_survived(); + } +} + +fn player_survived() { + println!("YOU MADE IT THROUGH TREMENDOUS FLAK!!"); +} + +fn death_with_chance(p_death: f32) -> bool { + let mut rng = rand::thread_rng(); + let y: f32 = rng.gen(); + p_death > y +} + +fn main() { + loop { + println!("YOU ARE A PILOT IN A WORLD WAR II BOMBER."); + let side: Side = + stdin_choice::("WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4): ") + .into(); + + match side { + Side::Japan(_) => { + println!("YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON."); + } + Side::Italy(ref s) => { + let target = stdin_choice(s.prompt()); + println!("{}", s.targets_to_messages(target)); + } + Side::Allies(ref s) => { + let target = stdin_choice(s.prompt()); + println!("{}", s.targets_to_messages(target)); + } + Side::Germany(ref s) => { + let target = stdin_choice(s.prompt()); + println!("{}", s.targets_to_messages(target)); + } + } + + match side { + Side::Japan(_) => play_japan(), + _ => commence_non_kamikazi_attack(), + } + + println!(); + if !stdin_y_or_n("ANOTHER MISSION? (Y OR N): ") { + break; + } + } +} From 456f228e17a8396ae676e0e231ffe5032afbd92e Mon Sep 17 00:00:00 2001 From: Martin Martin Date: Fri, 31 May 2024 14:00:46 -0400 Subject: [PATCH 322/377] Add explanation of variables and code structure. --- 59_Lunar_LEM_Rocket/README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/59_Lunar_LEM_Rocket/README.md b/59_Lunar_LEM_Rocket/README.md index c0ec8df01..98db7aed6 100644 --- a/59_Lunar_LEM_Rocket/README.md +++ b/59_Lunar_LEM_Rocket/README.md @@ -35,3 +35,33 @@ http://www.vintage-basic.net/games.html #### Porting Notes (please note any difficulties or challenges in porting here) + +### LUNAR + +Variables: + +`A`: Altitude in miles. Up is positive. +`V`: Velocity in miles / sec. Down is positive. + +`M`: Weight of capsule in pounds, both fuel and machine +`N`: Empty weight of capsule in pounds. So, weight of fuel is M - N. + +`G`: Gravity in miles / sec^2, down is positive. +`Z`: Exhaust velocity in miles / sec + +`L`: time in seconds since start of simulation. +`K`: Burn rate for this 10 second turn, pounds of fuel per sec +`T`: Time left in this 10 second turn, in seconds. +`S`: Burn time in this 10 second turn, input to subroutine 420. + +Subroutines: + +330, Apply updates from one call to subroutine 420. + +370, If you started descending and ended ascending, figure out whether you hit the surface in between. + +420, Compute new velocity and altitude using the Tsiolkovsky rocket equation for S seconds: + +`Q`: Fraction of initial mass that's burnt, i.e. 1 - mf / mo, exactly what we need for the Taylor series of `ln` in the rocket equation. Local to this subroutine. +`J`: Final velocity after S seconds, down is positive. Return value. +`I`: Altitude after S seconds, up is positive. Return value. From a2215f4f903551fa08debc3efd87c8d035c705a9 Mon Sep 17 00:00:00 2001 From: Martin Martin Date: Fri, 31 May 2024 14:15:52 -0400 Subject: [PATCH 323/377] Revert "Fix bug in Lunar: wrong capsule weight." This reverts commit 52e1bf49984960f0030f81bf968029c78b9729c9. The original commit modified the game away from what was in BASIC Computer Games, replacing it with the value from the original FOCAL version. The difference was intentional, as the introductory text makes clear, which is also in the README.md here: "To make the landing more of a challenge, but more closely approximate the real Apollo LEM capsule, you should make the available fuel at the start (N) equal to 16,000 lbs, and the weight of the capsule (M) equal to 32,500 lbs." Here we bring the value back into line with the BASIC Computer Games book & the README.md text. If we wanted to keep the FOCAL value, we should update the text in the README.md to explain why. See issue #867 --- 59_Lunar_LEM_Rocket/javascript/lunar.js | 2 +- 59_Lunar_LEM_Rocket/lunar.bas | 2 +- 59_Lunar_LEM_Rocket/python/lunar.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/59_Lunar_LEM_Rocket/javascript/lunar.js b/59_Lunar_LEM_Rocket/javascript/lunar.js index 4f693d009..43a0e892c 100644 --- a/59_Lunar_LEM_Rocket/javascript/lunar.js +++ b/59_Lunar_LEM_Rocket/javascript/lunar.js @@ -113,7 +113,7 @@ async function main() print("\n"); a = 120; v = 1; - m = 32500; + m = 33000; n = 16500; g = 1e-3; z = 1.8; diff --git a/59_Lunar_LEM_Rocket/lunar.bas b/59_Lunar_LEM_Rocket/lunar.bas index 256eedffc..301336150 100644 --- a/59_Lunar_LEM_Rocket/lunar.bas +++ b/59_Lunar_LEM_Rocket/lunar.bas @@ -12,7 +12,7 @@ 110 PRINT: PRINT: PRINT: PRINT "GOOD LUCK" 120 L=0 130 PRINT: PRINT "SEC","MI + FT","MPH","LB FUEL","BURN RATE":PRINT -140 A=120:V=1:M=32500:N=16500:G=1E-03:Z=1.8 +140 A=120:V=1:M=33000:N=16500:G=1E-03:Z=1.8 150 PRINT L,INT(A);INT(5280*(A-INT(A))),3600*V,M-N,:INPUT K:T=10 160 IF M-N<1E-03 THEN 240 170 IF T<1E-03 THEN 150 diff --git a/59_Lunar_LEM_Rocket/python/lunar.py b/59_Lunar_LEM_Rocket/python/lunar.py index fa7da3de8..46a066746 100644 --- a/59_Lunar_LEM_Rocket/python/lunar.py +++ b/59_Lunar_LEM_Rocket/python/lunar.py @@ -127,7 +127,7 @@ def advance(self, delta_t: float) -> None: class Capsule: altitude: float = 120 # in miles above the surface velocity: float = 1 # downward - m: float = 32500 # mass_with_fuel + m: float = 33000 # mass_with_fuel n: float = 16500 # mass_without_fuel g: float = 1e-3 z: float = 1.8 From 71d02673a9e5736a56e0159b5839c57e7477dcac Mon Sep 17 00:00:00 2001 From: Sourcery AI <> Date: Wed, 24 May 2023 23:55:27 +0000 Subject: [PATCH 324/377] 'Refactored by Sourcery' --- 02_Amazing/python/amazing.py | 4 +- 03_Animal/python/animal.py | 22 +-- 04_Awari/python/awari.py | 16 +- 05_Bagels/python/bagels.py | 5 +- 06_Banner/python/banner.py | 6 +- 07_Basketball/python/basketball.py | 167 +++++++++--------- 08_Batnum/python/batnum.py | 9 +- 09_Battle/python/battle.py | 4 +- 10_Blackjack/python/blackjack.py | 85 ++++----- 13_Bounce/python/bounce.py | 2 +- 14_Bowling/python/bowling.py | 15 +- 15_Boxing/python/boxing.py | 22 ++- 17_Bullfight/python/bullfight.py | 35 ++-- 18_Bullseye/python/bullseye.py | 17 +- 21_Calendar/python/calendar.py | 2 +- 23_Checkers/python/checkers.py | 20 +-- 25_Chief/python/chief.py | 6 +- 26_Chomp/python/chomp.py | 10 +- 27_Civil_War/python/Civilwar.py | 8 +- 28_Combat/python/combat.py | 47 +++-- 30_Cube/python/cube.py | 6 +- 31_Depth_Charge/python/depth_charge.py | 2 +- 32_Diamond/python/diamond.py | 7 +- 35_Even_Wins/python/evenwins.py | 15 +- 37_Football/python/football.py | 3 +- 38_Fur_Trader/python/furtrader.py | 20 +-- 39_Golf/python/golf.py | 85 +++------ 40_Gomoko/python/Gomoko.py | 99 +++++------ 42_Gunner/python/gunner.py | 10 +- 43_Hammurabi/python/hamurabi.py | 15 +- 44_Hangman/python/hangman.py | 16 +- 45_Hello/python/hello.py | 15 +- 46_Hexapawn/python/hexapawn.py | 47 ++--- 48_High_IQ/python/High_IQ.py | 22 +-- 49_Hockey/python/hockey.py | 53 +++--- 50_Horserace/python/horserace.py | 6 +- 53_King/python/king.py | 9 +- 55_Life/python/life.py | 12 +- 56_Life_for_Two/python/life_for_two.py | 65 ++++--- 59_Lunar_LEM_Rocket/python/lunar.py | 7 +- 60_Mastermind/python/mastermind.py | 12 +- 61_Math_Dice/python/mathdice.py | 12 +- 62_Mugwump/python/mugwump.py | 3 +- 63_Name/python/name.py | 4 +- 64_Nicomachus/python/nicomachus.py | 4 +- 65_Nim/python/Traditional_NIM.py | 20 +-- 68_Orbit/python/orbit.py | 4 +- 69_Pizza/python/pizza.py | 6 +- 70_Poetry/python/poetry.py | 2 +- 72_Queen/python/queen.py | 22 +-- 73_Reverse/python/reverse.py | 2 +- 74_Rock_Scissors_Paper/python/rockscissors.py | 35 ++-- 75_Roulette/python/roulette.py | 14 +- 76_Russian_Roulette/python/russianroulette.py | 14 +- 77_Salvo/python/salvo.py | 26 +-- 79_Slalom/python/slalom.py | 4 +- 80_Slots/python/slots.py | 4 +- 81_Splat/python/splat.py | 6 +- 82_Stars/python/stars.py | 8 +- 83_Stock_Market/python/Stock_Market.py | 11 +- 84_Super_Star_Trek/python/superstartrek.py | 23 ++- 84_Super_Star_Trek/python/superstartrekins.py | 14 +- 88_3-D_Tic-Tac-Toe/python/qubit.py | 40 ++--- 89_Tic-Tac-Toe/python/TicTacToe_Hard.py | 28 +-- 89_Tic-Tac-Toe/python/tictactoe2.py | 41 ++--- 90_Tower/python/tower.py | 11 +- 92_Trap/python/trap.py | 9 +- 93_23_Matches/python/23matches.py | 4 +- 95_Weekday/python/weekday.py | 18 +- 96_Word/python/word.py | 2 +- 70 files changed, 583 insertions(+), 836 deletions(-) diff --git a/02_Amazing/python/amazing.py b/02_Amazing/python/amazing.py index 9d7ab4195..22f141c9f 100644 --- a/02_Amazing/python/amazing.py +++ b/02_Amazing/python/amazing.py @@ -47,7 +47,7 @@ def display(self) -> None: print(" ", end="") print() for col in range(self.width): - if self.walls[row][col] == 0 or self.walls[row][col] == 2: + if self.walls[row][col] in [0, 2]: print(":--", end="") else: print(": ", end="") @@ -148,7 +148,7 @@ def make_opening( maze.walls[pos.row][pos.col] = maze.walls[pos.row][pos.col] + EXIT_DOWN pos.row = pos.row + 1 maze.used[pos.row][pos.col] = count - count = count + 1 + count += 1 return pos, count diff --git a/03_Animal/python/animal.py b/03_Animal/python/animal.py index 618ef7d64..077b93d7f 100644 --- a/03_Animal/python/animal.py +++ b/03_Animal/python/animal.py @@ -104,17 +104,13 @@ def parse_input(message: str, check_list: bool, root_node: Optional[Node]) -> st list_known_animals(root_node) print("\n") - if len(inp) > 0: - token = inp[0].lower() - else: - token = "" - + token = inp[0].lower() if len(inp) > 0 else "" return token def avoid_void_input(message: str) -> str: answer = "" - while answer == "": + while not answer: answer = input(message) return answer @@ -134,8 +130,12 @@ def main() -> None: # Main loop of game print_intro() - keep_playing = parse_input("Are you thinking of an animal? ", True, root) == "y" - while keep_playing: + while ( + keep_playing := parse_input( + "Are you thinking of an animal? ", True, root + ) + == "y" + ): keep_asking = True # Start traversing the tree by the root actual_node: Node = root @@ -170,17 +170,13 @@ def main() -> None: f"for a {new_animal} the answer would be: ", False, None ) - actual_node.update_node( - new_question + "?", answer_new_question, new_animal - ) + actual_node.update_node(f"{new_question}?", answer_new_question, new_animal) else: print("Why not try another animal?") keep_asking = False - keep_playing = parse_input("Are you thinking of an animal? ", True, root) == "y" - ######################################################## # Porting Notes diff --git a/04_Awari/python/awari.py b/04_Awari/python/awari.py index 85669cee5..df4906f58 100644 --- a/04_Awari/python/awari.py +++ b/04_Awari/python/awari.py @@ -83,11 +83,10 @@ def draw_pit(line: str, board, pit_index) -> str: val = board[pit_index] - line = line + " " + line += " " if val < 10: - line = line + " " - line = line + str(val) + " " - return line + line += " " + return line + str(val) + " " def draw_board(board) -> None: @@ -148,7 +147,7 @@ def play_game(board: List[int]) -> None: print(msg) break if landing_spot == home: - landing_spot, is_still_going, home, msg = computer_move(msg + " , ", board) + landing_spot, is_still_going, home, msg = computer_move(f"{msg} , ", board) if not is_still_going: print(msg) break @@ -248,7 +247,7 @@ def computer_move(msg: str, board) -> Tuple[int, bool, int, str]: move_str = chr(42 + selected_move) if msg: - msg += ", " + move_str + msg += f", {move_str}" else: msg = move_str @@ -323,10 +322,7 @@ def execute_move(move, home: int, board) -> Tuple[int, bool, int]: # losses. losing_book[game_number] = losing_book[game_number] * 6 + move_digit - if player_has_stones(board) and computer_has_stones(board): - is_still_going = True - else: - is_still_going = False + is_still_going = bool(player_has_stones(board) and computer_has_stones(board)) return last_location, is_still_going, home diff --git a/05_Bagels/python/bagels.py b/05_Bagels/python/bagels.py index c9c0ca844..e0662d18c 100644 --- a/05_Bagels/python/bagels.py +++ b/05_Bagels/python/bagels.py @@ -49,9 +49,8 @@ def pick_number() -> List[str]: # as separate strings, not a single integer or string numbers = list(range(10)) random.shuffle(numbers) - num = numbers[0:3] - num_str = [str(i) for i in num] - return num_str + num = numbers[:3] + return [str(i) for i in num] def get_valid_guess(guesses: int) -> str: diff --git a/06_Banner/python/banner.py b/06_Banner/python/banner.py index ad85b807a..d42a7763d 100644 --- a/06_Banner/python/banner.py +++ b/06_Banner/python/banner.py @@ -74,9 +74,7 @@ def print_banner() -> None: except ValueError: print("Please enter a number greater than zero") - g1 = 0 - if input("Centered ").lower().startswith("y"): - g1 = 1 + g1 = 1 if input("Centered ").lower().startswith("y") else 0 character = input( "Character (type 'ALL' if you want character being printed) " ).upper() @@ -87,7 +85,7 @@ def print_banner() -> None: for statement_char in statement: s = letters[statement_char].copy() x_str = character - if character == "ALL": + if x_str == "ALL": x_str = statement_char if x_str == " ": print("\n" * (7 * horizontal)) diff --git a/07_Basketball/python/basketball.py b/07_Basketball/python/basketball.py index 758e5cb9e..e3a598628 100644 --- a/07_Basketball/python/basketball.py +++ b/07_Basketball/python/basketball.py @@ -122,32 +122,30 @@ def dartmouth_jump_shot(self) -> None: if random.random() > 0.782 * self.defense / 8: if random.random() > 0.843 * self.defense / 8: print("Charging foul. Dartmouth loses ball.\n") - self.opponent_ball() else: # player is fouled self.foul_shots(1) - self.opponent_ball() + self.opponent_ball() + elif random.random() > 0.5: + print( + "Shot is blocked. Ball controlled by " + + self.opponent + + ".\n" + ) + self.opponent_ball() else: - if random.random() > 0.5: - print( - "Shot is blocked. Ball controlled by " - + self.opponent - + ".\n" - ) - self.opponent_ball() - else: - print("Shot is blocked. Ball controlled by Dartmouth.") - self.dartmouth_ball() + print("Shot is blocked. Ball controlled by Dartmouth.") + self.dartmouth_ball() else: print("Shot is off target.") if self.defense / 6 * random.random() > 0.45: - print("Rebound to " + self.opponent + "\n") + print(f"Rebound to {self.opponent}" + "\n") self.opponent_ball() else: print("Dartmouth controls the rebound.") if random.random() > 0.4: if self.defense == 6 and random.random() > 0.6: - print("Pass stolen by " + self.opponent + ", easy lay up") + print(f"Pass stolen by {self.opponent}, easy lay up") self.add_points(0, 2) self.dartmouth_ball() else: @@ -186,13 +184,11 @@ def dartmouth_non_jump_shot(self) -> None: if 7 / self.defense * random.random() > 0.875: if 7 / self.defense * random.random() > 0.925: print("Charging foul. Dartmouth loses the ball.\n") - self.opponent_ball() else: - print("Shot blocked. " + self.opponent + "'s ball.\n") - self.opponent_ball() + print(f"Shot blocked. {self.opponent}" + "'s ball.\n") else: self.foul_shots(1) - self.opponent_ball() + self.opponent_ball() else: print("Shot is off the rim.") if random.random() > 2 / 3: @@ -216,35 +212,35 @@ def dartmouth_ball(self) -> None: self.shot = shot if self.time < 100 or random.random() < 0.5: - if self.shot == 1 or self.shot == 2: + if self.shot in [1, 2]: self.dartmouth_jump_shot() else: self.dartmouth_non_jump_shot() + elif self.score[0] == self.score[1]: + print("\n ***** End Of Second Half *****") + print("Score at end of regulation time:") + print( + " Dartmouth: " + + str(self.score[1]) + + " " + + self.opponent + + ": " + + str(self.score[0]) + ) + print("Begin two minute overtime period") + self.time = 93 + self.start_of_period() + else: - if self.score[0] != self.score[1]: - print("\n ***** End Of Game *****") - print( - "Final Score: Dartmouth: " - + str(self.score[1]) - + " " - + self.opponent - + ": " - + str(self.score[0]) - ) - else: - print("\n ***** End Of Second Half *****") - print("Score at end of regulation time:") - print( - " Dartmouth: " - + str(self.score[1]) - + " " - + self.opponent - + ": " - + str(self.score[0]) - ) - print("Begin two minute overtime period") - self.time = 93 - self.start_of_period() + print("\n ***** End Of Game *****") + print( + "Final Score: Dartmouth: " + + str(self.score[1]) + + " " + + self.opponent + + ": " + + str(self.score[0]) + ) def opponent_jumpshot(self) -> None: """Simulate the opponents jumpshot""" @@ -253,32 +249,35 @@ def opponent_jumpshot(self) -> None: if 8 / self.defense * random.random() > 0.75: if 8 / self.defense * random.random() > 0.9: print("Offensive foul. Dartmouth's ball.\n") - self.dartmouth_ball() else: self.foul_shots(0) - self.dartmouth_ball() + self.dartmouth_ball() else: print("Shot is off the rim.") if self.defense / 6 * random.random() > 0.5: - print(self.opponent + " controls the rebound.") - if self.defense == 6: - if random.random() > 0.75: - print("Ball stolen. Easy lay up for Dartmouth.") - self.add_points(1, 2) - self.opponent_ball() - else: - if random.random() > 0.5: - print() - self.opponent_non_jumpshot() - else: - print("Pass back to " + self.opponent + " guard.\n") - self.opponent_ball() + print(f"{self.opponent} controls the rebound.") + if ( + self.defense == 6 + and random.random() <= 0.75 + and random.random() > 0.5 + ): + print() + self.opponent_non_jumpshot() + elif ( + self.defense == 6 + and random.random() <= 0.75 + and random.random() <= 0.5 + or self.defense != 6 + and random.random() <= 0.5 + ): + print(f"Pass back to {self.opponent}" + " guard.\n") + self.opponent_ball() + elif self.defense == 6 and random.random() > 0.75: + print("Ball stolen. Easy lay up for Dartmouth.") + self.add_points(1, 2) + self.opponent_ball() else: - if random.random() > 0.5: - self.opponent_non_jumpshot() - else: - print("Pass back to " + self.opponent + " guard.\n") - self.opponent_ball() + self.opponent_non_jumpshot() else: print("Dartmouth controls the rebound.\n") self.dartmouth_ball() @@ -296,26 +295,30 @@ def opponent_non_jumpshot(self) -> None: if 7 / self.defense * random.random() > 0.413: print("Shot is missed.") if self.defense / 6 * random.random() > 0.5: - print(self.opponent + " controls the rebound.") - if self.defense == 6: - if random.random() > 0.75: - print("Ball stolen. Easy lay up for Dartmouth.") - self.add_points(1, 2) - self.opponent_ball() - else: - if random.random() > 0.5: - print() - self.opponent_non_jumpshot() - else: - print("Pass back to " + self.opponent + " guard.\n") - self.opponent_ball() + print(f"{self.opponent} controls the rebound.") + if ( + self.defense == 6 + and random.random() <= 0.75 + and random.random() > 0.5 + or self.defense != 6 + and random.random() > 0.5 + ): + print() + self.opponent_non_jumpshot() + elif ( + self.defense == 6 + and random.random() <= 0.75 + and random.random() <= 0.5 + ): + print(f"Pass back to {self.opponent}" + " guard.\n") + self.opponent_ball() + elif self.defense == 6 and random.random() > 0.75: + print("Ball stolen. Easy lay up for Dartmouth.") + self.add_points(1, 2) + self.opponent_ball() else: - if random.random() > 0.5: - print() - self.opponent_non_jumpshot() - else: - print("Pass back to " + self.opponent + " guard\n") - self.opponent_ball() + print(f"Pass back to {self.opponent}" + " guard\n") + self.opponent_ball() else: print("Dartmouth controls the rebound.\n") self.dartmouth_ball() diff --git a/08_Batnum/python/batnum.py b/08_Batnum/python/batnum.py index 3a54ee49b..bb41d8619 100644 --- a/08_Batnum/python/batnum.py +++ b/08_Batnum/python/batnum.py @@ -153,11 +153,8 @@ def computer_pick( q = pile_size - 1 if win_option == WinOptions.AvoidLast else pile_size c = min_select + max_select computer_pick = q - (c * int(q / c)) - if computer_pick < min_select: - computer_pick = min_select - if computer_pick > max_select: - computer_pick = max_select - return computer_pick + computer_pick = max(computer_pick, min_select) + return min(computer_pick, max_select) def computer_move( @@ -184,7 +181,7 @@ def computer_move( # Otherwise, we determine how many the computer selects curr_sel = computer_pick(pile_size, min_select, max_select, win_option) - pile_size = pile_size - curr_sel + pile_size -= curr_sel print(f"COMPUTER TAKES {curr_sel} AND LEAVES {pile_size}") return (False, pile_size) diff --git a/09_Battle/python/battle.py b/09_Battle/python/battle.py index 993b9f458..2418b35d5 100755 --- a/09_Battle/python/battle.py +++ b/09_Battle/python/battle.py @@ -40,8 +40,8 @@ def place_ship(sea: SeaType, size: int, code: int) -> None: point = add_vector(point, vector) points.append(point) - if not all([is_within_sea(point, sea) for point in points]) or any( - [value_at(point, sea) for point in points] + if not all(is_within_sea(point, sea) for point in points) or any( + value_at(point, sea) for point in points ): # ship out of bounds or crosses other ship, trying again continue diff --git a/10_Blackjack/python/blackjack.py b/10_Blackjack/python/blackjack.py index a2c38260c..615aec79b 100644 --- a/10_Blackjack/python/blackjack.py +++ b/10_Blackjack/python/blackjack.py @@ -58,10 +58,7 @@ def add_card(self, card: Card) -> None: def get_total(self) -> int: """returns the total points of the cards in this hand""" - total: int = 0 - for card in self.cards: - total += int(card.value) - + total: int = sum(int(card.value) for card in self.cards) # if there is an ACE, and the hand would otherwise bust, # treat the ace like it's worth 1 if total > 21 and any(card.name == "ACE" for card in self.cards): @@ -109,24 +106,21 @@ def draw_card(self) -> Card: draw card from deck, and return it if deck is empty, shuffles discard pile into it and tries again """ - if len(self.deck) == 0: - _len = len(self.discard_pile) - - if _len > 0: - # deck is empty, shuffle discard pile into deck and try again - print("deck is empty, shuffling") - for _i in range(_len): - if len(self.discard_pile) == 0: - raise ValueError("discard pile is empty") - self.deck.append(self.discard_pile.pop()) - self.shuffle() - return self.draw_card() - else: - # discard pile and deck are empty, should never happen - raise Exception("discard pile empty") - else: - card = self.deck.pop() - return card + if len(self.deck) != 0: + return self.deck.pop() + _len = len(self.discard_pile) + + if _len <= 0: + # discard pile and deck are empty, should never happen + raise Exception("discard pile empty") + # deck is empty, shuffle discard pile into deck and try again + print("deck is empty, shuffling") + for _i in range(_len): + if len(self.discard_pile) == 0: + raise ValueError("discard pile is empty") + self.deck.append(self.discard_pile.pop()) + self.shuffle() + return self.draw_card() @dataclass @@ -171,24 +165,19 @@ def hand_as_string(self, hide_dealer: bool) -> str: by *'s for every other card if player is a player, returns every card and the total """ - if not hide_dealer: - s = "" - for cards_in_hand in self.hand.cards[::-1]: - s += f"{cards_in_hand.name}\t" + if hide_dealer and self.player_type == PlayerType.Dealer: + return "".join(f"{c.name}\t" for c in self.hand.cards[1::-1]) + elif ( + hide_dealer + and self.player_type == PlayerType.Player + or not hide_dealer + ): + s = "".join( + f"{cards_in_hand.name}\t" + for cards_in_hand in self.hand.cards[::-1] + ) s += f"total points = {self.hand.get_total()}" return s - else: - if self.player_type == PlayerType.Dealer: - s = "" - for c in self.hand.cards[1::-1]: - s += f"{c.name}\t" - return s - elif self.player_type == PlayerType.Player: - s = "" - for cards_in_hand in self.hand.cards[::-1]: - s += f"{cards_in_hand.name}\t" - s += f"total points = {self.hand.get_total()}" - return s raise Exception("This is unreachable") def get_play(self) -> Play: @@ -197,10 +186,7 @@ def get_play(self) -> Play: # if it's a dealer, use an algorithm to determine the play # if it's a player, ask user for input if self.player_type == PlayerType.Dealer: - if self.hand.get_total() > 16: - return Play.Stand - else: - return Play.Hit + return Play.Stand if self.hand.get_total() > 16 else Play.Hit elif self.player_type == PlayerType.Player: valid_results: List[str] if len(self.hand.cards) > 2: @@ -232,15 +218,11 @@ class Game: @classmethod def new(cls, num_players: int) -> "Game": - players: List[Player] = [] + players: List[Player] = [Player.new(PlayerType.Dealer, 0)] - # add dealer - players.append(Player.new(PlayerType.Dealer, 0)) # create human player(s) (at least one) players.append(Player.new(PlayerType.Player, 1)) - for i in range(2, num_players): # one less than num_players players - players.append(Player.new(PlayerType.Player, i)) - + players.extend(Player.new(PlayerType.Player, i) for i in range(2, num_players)) if get_char_from_user_input("Do you want instructions", ["y", "n"]) == "y": print_instructions() print() @@ -322,9 +304,6 @@ def play_game(self) -> None: else: player.bet = player.balance player.hand.add_card(self.decks.draw_card()) - elif play == Play.Split: - pass - # add player to score cache thing player_hands_message += ( f"{player.get_name()} Hand:\t{player.hand_as_string(True)}\n" @@ -460,7 +439,7 @@ def get_number_from_user_input(prompt: str, min_value: int, max_value: int) -> i # input loop user_input = None while user_input is None or user_input < min_value or user_input > max_value: - raw_input = input(prompt + f" ({min_value}-{max_value})? ") + raw_input = input(f"{prompt} ({min_value}-{max_value})? ") try: user_input = int(raw_input) @@ -475,7 +454,7 @@ def get_char_from_user_input(prompt: str, valid_results: List[str]) -> str: """returns the first character they type""" user_input = None while user_input not in valid_results: - user_input = input(prompt + f" {valid_results}? ").lower() + user_input = input(f"{prompt} {valid_results}? ").lower() if user_input not in valid_results: print("Invalid input, please try again") assert user_input is not None diff --git a/13_Bounce/python/bounce.py b/13_Bounce/python/bounce.py index f36acc94f..e454183b0 100644 --- a/13_Bounce/python/bounce.py +++ b/13_Bounce/python/bounce.py @@ -83,7 +83,7 @@ def run_simulation(delta_t: float, v0: float, coeff_rest: float) -> None: if -16 * tm**2 + v0 * coeff_rest ** (i - 1) * tm < h: break print(line) - h = h - 0.5 + h -= 0.5 print("." * (int((total_time + 1) / delta_t) + 1)) print diff --git a/14_Bowling/python/bowling.py b/14_Bowling/python/bowling.py index c7773978d..fc923ddbc 100644 --- a/14_Bowling/python/bowling.py +++ b/14_Bowling/python/bowling.py @@ -57,10 +57,9 @@ def play_frame(self, frame: int) -> None: break # cannot roll more than once in a frame else: print(f"next roll {self.name}") - else: - if score == 10: - print("SPARE!") - extra = 1 + elif score == 10: + print("SPARE!") + extra = 1 prev_score = score # remember previous pins to distinguish ... if frame == 9 and extra > 0: @@ -112,12 +111,12 @@ def main() -> None: print("SCORES.") total_players = int(input("FIRST OF ALL...HOW MANY ARE PLAYING? ")) - player_names = [] print() print("VERY GOOD...") - for index in range(total_players): - player_names.append(Player(input(f"Enter name for player {index + 1}: "))) - + player_names = [ + Player(input(f"Enter name for player {index + 1}: ")) + for index in range(total_players) + ] for frame in range(10): for player in player_names: player.play_frame(frame) diff --git a/15_Boxing/python/boxing.py b/15_Boxing/python/boxing.py index 1943e74ec..9d8c87d58 100755 --- a/15_Boxing/python/boxing.py +++ b/15_Boxing/python/boxing.py @@ -39,12 +39,11 @@ class Player: def get_punch_choice(self) -> Literal[1, 2, 3, 4]: if self.is_computer: return random.randint(1, 4) # type: ignore - else: - punch = -1 - while punch not in [1, 2, 3, 4]: - print(f"{self.name}'S PUNCH", end="? ") - punch = int(input()) - return punch # type: ignore + punch = -1 + while punch not in [1, 2, 3, 4]: + print(f"{self.name}'S PUNCH", end="? ") + punch = int(input()) + return punch # type: ignore KNOCKOUT_THRESHOLD = 35 @@ -55,8 +54,7 @@ def get_punch_choice(self) -> Literal[1, 2, 3, 4]: def get_vulnerability() -> int: print("WHAT IS HIS VULNERABILITY", end=QUESTION_PROMPT) - vulnerability = int(input()) - return vulnerability + return int(input()) def get_opponent_stats() -> Tuple[int, int]: @@ -71,10 +69,10 @@ def get_opponent_stats() -> Tuple[int, int]: def read_punch_profiles(filepath: Path) -> Dict[Literal[1, 2, 3, 4], PunchProfile]: with open(filepath) as f: punch_profile_dict = json.load(f) - result = {} - for key, value in punch_profile_dict.items(): - result[int(key)] = PunchProfile(**value) - return result # type: ignore + return { + int(key): PunchProfile(**value) + for key, value in punch_profile_dict.items() + } def main() -> None: diff --git a/17_Bullfight/python/bullfight.py b/17_Bullfight/python/bullfight.py index 2bb789e2a..32a6ac107 100644 --- a/17_Bullfight/python/bullfight.py +++ b/17_Bullfight/python/bullfight.py @@ -29,11 +29,8 @@ def determine_player_kills( print(f"THE {player_type}{plural_form} DID A {job_qualities[job_quality]} JOB.") if job_quality >= 4: if job_quality == 5: - player_was_killed = random.choice([True, False]) - if player_was_killed: + if player_was_killed := random.choice([True, False]): print(f"ONE OF THE {player_type}{plural_form} WAS KILLED.") - elif player_was_killed: - print(f"NO {player_type}{plural_form} WERE KILLED.") else: if player_type != "TOREAD": killed_horses = random.randint(1, 2) @@ -177,12 +174,13 @@ def handle_bullkill_attempt( * job_quality_by_round[3] ) ) - if kill_method == 4: - if kill_probability > 0.8: - gore = 1 - else: - if kill_probability > 0.2: - gore = 1 + if ( + kill_method == 4 + and kill_probability > 0.8 + or kill_method != 4 + and kill_probability > 0.2 + ): + gore = 1 if gore == 0: print("YOU KILLED THE BULL!") job_quality_by_round[5] = 2 @@ -254,7 +252,7 @@ def main() -> None: # Round 3 job_quality_by_round[3] = 0 while True: - job_quality_by_round[3] = job_quality_by_round[3] + 1 + job_quality_by_round[3] += 1 print(f"PASS NUMBER {job_quality_by_round[3]}") if job_quality_by_round[3] >= 3: run_from_ring = ask_bool("HERE COMES THE BULL. TRY FOR A KILL? ") @@ -299,8 +297,13 @@ def main() -> None: print("YOU ARE STILL ALIVE.") print() print("DO YOU RUN FROM THE RING? ", end="") - run_from_ring = ask_bool("DO YOU RUN FROM THE RING? ") - if not run_from_ring: + if run_from_ring := ask_bool("DO YOU RUN FROM THE RING? "): + print("COWARD") + job_quality_by_round[4] = 0 + death = True + break + + else: print("YOU ARE BRAVE. STUPID, BUT BRAVE.") if random.randint(1, 2) == 1: job_quality_by_round[4] = 2 @@ -308,12 +311,6 @@ def main() -> None: break else: print("YOU ARE GORED AGAIN!") - else: - print("COWARD") - job_quality_by_round[4] = 0 - death = True - break - if death: break diff --git a/18_Bullseye/python/bullseye.py b/18_Bullseye/python/bullseye.py index 490a08984..df931f35c 100644 --- a/18_Bullseye/python/bullseye.py +++ b/18_Bullseye/python/bullseye.py @@ -54,7 +54,7 @@ def main() -> None: players.append(Player(player_name)) round_number = 0 - while len(winners) == 0: + while not winners: round_number += 1 print() print(f"ROUND {round_number}---------") @@ -62,10 +62,10 @@ def main() -> None: print() while True: throw = int(input(f"{player.name}'S THROW? ")) - if throw not in [1, 2, 3]: - print("INPUT 1, 2, OR 3!") - else: + if throw in {1, 2, 3}: break + else: + print("INPUT 1, 2, OR 3!") if throw == 1: probability_1 = 0.65 probability_2 = 0.55 @@ -99,10 +99,11 @@ def main() -> None: points = 0 player.score += points print(f"TOTAL SCORE = {player.score}") - for player_index, player in enumerate(players): - if player.score > 200: - winners.append(player_index) - + winners.extend( + player_index + for player_index, player in enumerate(players) + if player.score > 200 + ) print_outro(players, winners) diff --git a/21_Calendar/python/calendar.py b/21_Calendar/python/calendar.py index 922e348e6..5c59e37e3 100644 --- a/21_Calendar/python/calendar.py +++ b/21_Calendar/python/calendar.py @@ -44,7 +44,7 @@ def parse_input() -> Tuple[int, bool]: while not correct_day_input: weekday = input("INSERT THE STARTING DAY OF THE WEEK OF THE YEAR:") - for day_k in days_mapping.keys(): + for day_k in days_mapping: if weekday.lower() in day_k: day = days_mapping[day_k] correct_day_input = True diff --git a/23_Checkers/python/checkers.py b/23_Checkers/python/checkers.py index 7ae2b7e55..42ae48c8b 100644 --- a/23_Checkers/python/checkers.py +++ b/23_Checkers/python/checkers.py @@ -64,7 +64,7 @@ def is_legal_board_coordinate(x: int, y: int) -> bool: class Board: def __init__(self) -> None: - self.spaces = [[0 for y in range(8)] for x in range(8)] + self.spaces = [[0 for _ in range(8)] for _ in range(8)] for x in range(8): if (x % 2) == 0: self.spaces[x][6] = COMPUTER_PIECE @@ -114,11 +114,10 @@ def get_spaces_with_human_pieces(self) -> Iterator[Tuple[int, int]]: def get_legal_deltas_for_space(self, x: int, y: int) -> Iterator[Tuple[int, int]]: contents = self.spaces[x][y] - if contents == COMPUTER_PIECE: - for delta_x in (-1, 1): + for delta_x in (-1, 1): + if contents == COMPUTER_PIECE: yield (delta_x, -1) - else: - for delta_x in (-1, 1): + else: for delta_y in (-1, 1): yield (delta_x, delta_y) @@ -183,7 +182,7 @@ def evaluate_move( if start_y == 7: # prefer to defend back row quality -= 2 - if dest_x in (0, 7): + if dest_x in {0, 7}: # moving to edge column quality += 1 for delta_x in (-1, 1): @@ -272,9 +271,8 @@ def play_computer_move(self, move_record: MoveRecord) -> None: if best_move is None: return - else: - print(f"TO {best_move.dest_x} {best_move.dest_y}") - move_record = best_move + print(f"TO {best_move.dest_x} {best_move.dest_y}") + move_record = best_move def try_extend( self, start_x: int, start_y: int, delta_x: int, delta_y: int @@ -352,10 +350,10 @@ def play_human_move( self.spaces[dest_x][dest_y] = HUMAN_KING def check_pieces(self) -> bool: - if len(list(self.get_spaces_with_computer_pieces())) == 0: + if not list(self.get_spaces_with_computer_pieces()): print_human_won() return False - if len(list(self.get_spaces_with_computer_pieces())) == 0: + if not list(self.get_spaces_with_computer_pieces()): print_computer_won() return False return True diff --git a/25_Chief/python/chief.py b/25_Chief/python/chief.py index d8af319b5..050e281f3 100644 --- a/25_Chief/python/chief.py +++ b/25_Chief/python/chief.py @@ -39,7 +39,6 @@ def game() -> None: print("\nHuh, I Knew I was unbeatable") print("And here is how i did it") print_solution(comp_guess) - input() else: original_number = float(input("\nHUH!! what was you original number? ")) @@ -50,7 +49,6 @@ def game() -> None: ) print("Here is how i did it") print_solution(comp_guess) - input() else: print("\nSo you think you're so smart, EH?") print("Now, Watch") @@ -60,14 +58,14 @@ def game() -> None: if believe_me.lower() == "yes": print("\nOk, Lets play again sometime bye!!!!") - input() else: print("\nYOU HAVE MADE ME VERY MAD!!!!!") print("BY THE WRATH OF THE MATHEMATICS AND THE RAGE OF THE GODS") print("THERE SHALL BE LIGHTNING!!!!!!!") print_lightning_bolt() print("\nI Hope you believe me now, for your own sake") - input() + + input() if __name__ == "__main__": diff --git a/26_Chomp/python/chomp.py b/26_Chomp/python/chomp.py index 69810a5fd..d7b67950e 100755 --- a/26_Chomp/python/chomp.py +++ b/26_Chomp/python/chomp.py @@ -13,16 +13,16 @@ class Canvas: def __init__(self, width=9, height=9, fill="*") -> None: self._buffer = [] for _ in range(height): - line = [] - for _ in range(width): - line.append(fill) + line = [fill for _ in range(width)] self._buffer.append(line) self._buffer[0][0] = "P" def render(self) -> str: lines = [" 1 2 3 4 5 6 7 8 9"] - for row, line in enumerate(self._buffer, start=1): - lines.append(" " + str(row) + " " * 5 + " ".join(line)) + lines.extend( + f" {str(row)}" + " " * 5 + " ".join(line) + for row, line in enumerate(self._buffer, start=1) + ) return "\n".join(lines) def chomp(self, r, c) -> str: diff --git a/27_Civil_War/python/Civilwar.py b/27_Civil_War/python/Civilwar.py index 14b88e017..309a35172 100644 --- a/27_Civil_War/python/Civilwar.py +++ b/27_Civil_War/python/Civilwar.py @@ -46,10 +46,7 @@ class PlayerStat: excessive_losses = False def set_available_money(self): - if self.is_player: - factor = 1 + (self.r - self.q) / (self.r + 1) - else: - factor = 1 + factor = 1 + (self.r - self.q) / (self.r + 1) if self.is_player else 1 self.available_money = 100 * math.floor( (self.army_m * (100 - self.inflation) / 2000) * factor + 0.5 ) @@ -70,8 +67,7 @@ def simulate_losses(player1: PlayerStat, player2: PlayerStat) -> float: 1 + 1 / (2 * (abs(player1.strategy - player2.strategy) + 1)) ) tmp = tmp * (1.28 + (5 * player1.army_m / 6) / (player1.ammunition + 1)) - tmp = math.floor(tmp * (1 + 1 / player1.morale) + 0.5) - return tmp + return math.floor(tmp * (1 + 1 / player1.morale) + 0.5) def update_army(player: PlayerStat, enemy: PlayerStat, use_factor=False) -> None: diff --git a/28_Combat/python/combat.py b/28_Combat/python/combat.py index f8a7a5de3..0543b205a 100644 --- a/28_Combat/python/combat.py +++ b/28_Combat/python/combat.py @@ -15,7 +15,7 @@ def show_intro() -> None: print(" " * 14 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print("\n\n") print("I AM AT WAR WITH YOU.") - print("WE HAVE " + str(MAX_UNITS) + " SOLDIERS APIECE.") + print(f"WE HAVE {str(MAX_UNITS)} SOLDIERS APIECE.") def get_forces() -> None: @@ -24,11 +24,11 @@ def get_forces() -> None: while True: print("DISTRIBUTE YOUR FORCES.") print(" ME YOU") - print("ARMY " + str(cpu_army) + " ? ", end="") + print(f"ARMY {str(cpu_army)} ? ", end="") usr_army = int(input()) - print("NAVY " + str(cpu_navy) + " ? ", end="") + print(f"NAVY {str(cpu_navy)} ? ", end="") usr_navy = int(input()) - print("A. F. " + str(cpu_air) + " ? ", end="") + print(f"A. F. {str(cpu_air)} ? ", end="") usr_air = int(input()) if (usr_army + usr_navy + usr_air) <= MAX_UNITS: break @@ -38,7 +38,6 @@ def attack_first() -> None: global usr_army, usr_navy, usr_air global cpu_army, cpu_navy, cpu_air - num_units = 0 unit_type = 0 while True: @@ -46,32 +45,28 @@ def attack_first() -> None: print("AND (3) FOR AIR FORCE.") print("?", end=" ") unit_type = int(input()) - if not (unit_type < 1 or unit_type > 3): + if unit_type >= 1 and unit_type <= 3: break + num_units = 0 while True: print("HOW MANY MEN") print("?", end=" ") num_units = int(input()) - if not ( - (num_units < 0) - or ((unit_type == 1) and (num_units > usr_army)) - or ((unit_type == 2) and (num_units > usr_navy)) - or ((unit_type == 3) and (num_units > usr_air)) + if ( + num_units >= 0 + and (unit_type != 1 or num_units <= usr_army) + and (unit_type != 2 or num_units <= usr_navy) + and (unit_type != 3 or num_units <= usr_air) ): break if unit_type == 1: if num_units < (usr_army / 3): - print("YOU LOST " + str(num_units) + " MEN FROM YOUR ARMY.") + print(f"YOU LOST {str(num_units)} MEN FROM YOUR ARMY.") usr_army = usr_army - num_units elif num_units < (2 * usr_army / 3): - print( - "YOU LOST " - + str(int(num_units / 3)) - + " MEN, BUT I LOST " - + str(int(2 * cpu_army / 3)) - ) + print(f"YOU LOST {int(num_units / 3)} MEN, BUT I LOST {int(2 * cpu_army / 3)}") usr_army = int(usr_army - (num_units / 3)) cpu_army = 0 else: @@ -85,7 +80,7 @@ def attack_first() -> None: print("YOUR ATTACK WAS STOPPED!") usr_navy = usr_navy - num_units elif num_units < 2 * cpu_navy / 3: - print("YOU DESTROYED " + str(int(2 * cpu_navy / 3)) + " OF MY ARMY.") + print(f"YOU DESTROYED {int(2 * cpu_navy / 3)} OF MY ARMY.") cpu_navy = int(cpu_navy / 3) else: print("YOU SUNK ONE OF MY PATROL BOATS, BUT I WIPED OUT TWO") @@ -113,7 +108,6 @@ def attack_first() -> None: def attack_second() -> None: global usr_army, usr_navy, usr_air, cpu_army, cpu_navy, cpu_air global plane_crash_win - num_units = 0 unit_type = 0 print() @@ -130,18 +124,19 @@ def attack_second() -> None: print("ARMY=1 NAVY=2 AIR FORCE=3") print("? ", end="") unit_type = int(input()) - if not ((unit_type < 1) or (unit_type > 3)): + if unit_type >= 1 and unit_type <= 3: break + num_units = 0 while True: print("HOW MANY MEN") print("? ", end="") num_units = int(input()) - if not ( - (num_units < 0) - or ((unit_type == 1) and (num_units > usr_army)) - or ((unit_type == 2) and (num_units > usr_navy)) - or ((unit_type == 3) and (num_units > usr_air)) + if ( + num_units >= 0 + and (unit_type != 1 or num_units <= usr_army) + and (unit_type != 2 or num_units <= usr_navy) + and (unit_type != 3 or num_units <= usr_air) ): break diff --git a/30_Cube/python/cube.py b/30_Cube/python/cube.py index 4928b08e9..260882dd1 100755 --- a/30_Cube/python/cube.py +++ b/30_Cube/python/cube.py @@ -31,7 +31,11 @@ def play_game() -> None: for _ in range(5): while True: mine = mine_position() - if not (mine in mines or mine == (1, 1, 1) or mine == (3, 3, 3)): + if ( + mine not in mines + and mine != (1, 1, 1) + and mine != (3, 3, 3) + ): break mines.append(mine) wager = -1 diff --git a/31_Depth_Charge/python/depth_charge.py b/31_Depth_Charge/python/depth_charge.py index a177af9ab..6134f8ce9 100644 --- a/31_Depth_Charge/python/depth_charge.py +++ b/31_Depth_Charge/python/depth_charge.py @@ -14,7 +14,7 @@ def show_welcome() -> None: # Clear screen. chr(27) is `Esc`, and the control sequence is # initiated by Ctrl+[ # `J` is "Erase in Display" and `2J` means clear the entire screen - print(chr(27) + "[2J") + print(f"{chr(27)}[2J") # Show the intro text, centered print("DEPTH CHARGE".center(45)) diff --git a/32_Diamond/python/diamond.py b/32_Diamond/python/diamond.py index 5ebcd2aab..3b261d36c 100644 --- a/32_Diamond/python/diamond.py +++ b/32_Diamond/python/diamond.py @@ -16,10 +16,7 @@ def print_diamond(begin_width, end_width, step, width, count) -> None: line_buffer = " " * ((width - n) // 2) for across in range(count): for a in range(n): - if a >= len(edge_string): - line_buffer += fill - else: - line_buffer += edge_string[a] + line_buffer += fill if a >= len(edge_string) else edge_string[a] line_buffer += " " * ( (width * (across + 1) + (width - n) // 2) - len(line_buffer) ) @@ -39,7 +36,7 @@ def main() -> None: PAGE_WIDTH = 60 - count = int(PAGE_WIDTH / width) + count = PAGE_WIDTH // width for _down in range(count): print_diamond(1, width, 2, width, count) diff --git a/35_Even_Wins/python/evenwins.py b/35_Even_Wins/python/evenwins.py index 066c7d57b..b5a198298 100644 --- a/35_Even_Wins/python/evenwins.py +++ b/35_Even_Wins/python/evenwins.py @@ -46,9 +46,7 @@ def print_intro() -> None: def marbles_str(n: int) -> str: - if n == 1: - return "1 marble" - return f"{n} marbles" + return "1 marble" if n == 1 else f"{n} marbles" def choose_first_player() -> PlayerType: @@ -66,10 +64,7 @@ def choose_first_player() -> PlayerType: def toggle_player(whose_turn: PlayerType) -> PlayerType: - if whose_turn == "human": - return "computer" - else: - return "human" + return "computer" if whose_turn == "human" else "human" def to_int(s: str) -> Tuple[bool, int]: @@ -132,11 +127,7 @@ def computer_turn(marbles: MarbleCounts) -> None: r = marbles.middle - 6 * int(marbles.middle / 6) if int(marbles.human / 2) == marbles.human / 2: - if r < 1.5 or r > 5.3: - marbles_to_take = 1 - else: - marbles_to_take = r - 1 - + marbles_to_take = 1 if r < 1.5 or r > 5.3 else r - 1 elif marbles.middle < 4.2: marbles_to_take = marbles.middle elif r > 3.4: diff --git a/37_Football/python/football.py b/37_Football/python/football.py index 748bc997a..c84c8df61 100644 --- a/37_Football/python/football.py +++ b/37_Football/python/football.py @@ -49,8 +49,7 @@ def ask_int(prompt: str) -> int: while True: answer = input(prompt) try: - int_answer = int(answer) - return int_answer + return int(answer) except Exception: pass diff --git a/38_Fur_Trader/python/furtrader.py b/38_Fur_Trader/python/furtrader.py index 190b7c3fd..0755c4100 100755 --- a/38_Fur_Trader/python/furtrader.py +++ b/38_Fur_Trader/python/furtrader.py @@ -82,7 +82,7 @@ def show_fort_comment(which_fort) -> None: print("FOR YOUR FURS. THE COST OF YOUR SUPPLIES") print("WILL BE LOWER THAN AT ALL THE OTHER FORTS.") else: - print("Internal error #1, fort " + str(which_fort) + " does not exist") + print(f"Internal error #1, fort {str(which_fort)} does not exist") sys.exit(1) # you have a bug print() @@ -109,7 +109,7 @@ def get_furs_purchase() -> List[int]: Accept numeric inputs, re-prompting on incorrect input values""" results: List[int] = [] - print("YOUR " + str(MAX_FURS) + " FURS ARE DISTRIBUTED AMONG THE FOLLOWING") + print(f"YOUR {str(MAX_FURS)} FURS ARE DISTRIBUTED AMONG THE FOLLOWING") print("KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.") print() @@ -130,9 +130,9 @@ def main() -> None: print(" " * 15 + "(Ported to Python Oct 2012 krt@krt.com.au)") print("\n\n\n") - game_state = "starting" fox_price = None # sometimes this takes the "last" price (probably this was a bug) + game_state = "starting" while True: if game_state == "starting": @@ -150,7 +150,7 @@ def main() -> None: elif game_state == "trading": print() print("YOU HAVE $ %1.2f IN SAVINGS" % (player_funds)) - print("AND " + str(MAX_FURS) + " FURS TO BEGIN THE EXPEDITION") + print(f"AND {str(MAX_FURS)} FURS TO BEGIN THE EXPEDITION") player_furs = get_furs_purchase() if sum(player_furs) > MAX_FURS: @@ -221,10 +221,7 @@ def main() -> None: print("NO ONE WILL BUY THEM.") player_furs[FUR_FOX] = 0 else: - print( - "Internal Error #3, Out-of-bounds event_picker" - + str(event_picker) - ) + print(f"Internal Error #3, Out-of-bounds event_picker{str(event_picker)}") sys.exit(1) # you have a bug print() @@ -268,10 +265,7 @@ def main() -> None: print("YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.") print("YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.") else: - print( - "Internal Error #4, Out-of-bounds event_picker" - + str(event_picker) - ) + print(f"Internal Error #4, Out-of-bounds event_picker{str(event_picker)}") sys.exit(1) # you have a bug print() @@ -280,7 +274,7 @@ def main() -> None: player_funds -= 105 else: - print("Internal error #2, fort " + str(which_fort) + " does not exist") + print(f"Internal error #2, fort {str(which_fort)} does not exist") sys.exit(1) # you have a bug # Calculate sales diff --git a/39_Golf/python/golf.py b/39_Golf/python/golf.py index 9132da2e6..d60bb60bb 100644 --- a/39_Golf/python/golf.py +++ b/39_Golf/python/golf.py @@ -565,13 +565,9 @@ def tee_up(self) -> None: ): self.putt = 10 print("[PUTTER: average 10 yards]") - if odds(20): - msg = "Keep your head down.\n" - else: - msg = "" - + msg = "Keep your head down.\n" if odds(20) else "" self.ask( - msg + "Choose your putt potency. (1-10)", + f"{msg}Choose your putt potency. (1-10)", 1, 10, self.set_putter_and_stroke, @@ -599,7 +595,7 @@ def stroke(self, club_amt: float, club_index: int) -> None: self.is_in_rough(self.ball) or self.is_in_hazard(self.ball, GameObjType.SAND) ) - and not (club_index == 8 or club_index == 9) + and club_index not in {8, 9} and odds(40) ): flags |= dub @@ -637,11 +633,10 @@ def stroke(self, club_amt: float, club_index: int) -> None: flags |= slice_ else: flags |= hook + elif odds(50): + flags |= hook else: - if odds(50): - flags |= hook - else: - flags |= slice_ + flags |= slice_ # beginner's luck ! # If handicap is greater than 15, there's a 10% chance of avoiding all errors @@ -664,21 +659,14 @@ def stroke(self, club_amt: float, club_index: int) -> None: distance: float rnd = random.randint(1, 101) - if self.handicap < 15: - if rnd <= 25: - distance = club_amt - (club_amt * (self.handicap / 100.0)) - elif rnd > 25 and rnd <= 75: - distance = club_amt - else: - distance = club_amt + (club_amt * 0.10) + if self.handicap < 15 and rnd <= 25 or self.handicap >= 15 and rnd <= 75: + distance = club_amt - (club_amt * (self.handicap / 100.0)) + elif self.handicap < 15 and rnd <= 75 or self.handicap >= 15: + distance = club_amt else: - if rnd <= 75: - distance = club_amt - (club_amt * (self.handicap / 100.0)) - else: - distance = club_amt - + distance = club_amt + (club_amt * 0.10) if self.player_difficulty == 3 and odds(80): # poor distance - distance = distance * 0.80 + distance *= 0.80 if (flags & luck) == luck: distance = club_amt @@ -755,7 +743,7 @@ def interpret_results(self, plot: Plot, flags: int) -> None: msg = "Your ball has gone to a watery grave." else: msg = "Your ball is lost in the water." - print(msg + " Take a penalty stroke.") + print(f"{msg} Take a penalty stroke.") self.score_card_record_stroke(self.ball) self.tee_up() return @@ -773,27 +761,18 @@ def interpret_results(self, plot: Plot, flags: int) -> None: return if (flags & in_cup) == in_cup: - if odds(50): - msg = "You holed it." - else: - msg = "It's in!" + msg = "You holed it." if odds(50) else "It's in!" print(msg) self.score_card_record_stroke(Ball(plot.x, plot.y, 0, GameObjType.BALL)) self.report_current_score() return - if ((flags & slice_) == slice_) and not ((flags & on_green) == on_green): - if (flags & out_of_bounds) == out_of_bounds: - bad = "badly" - else: - bad = "" + if (flags & slice_) == slice_ and flags & on_green != on_green: + bad = "badly" if (flags & out_of_bounds) == out_of_bounds else "" print(f"You sliced{bad}: {plot.offline} yards offline.") - if ((flags & hook) == hook) and not ((flags & on_green) == on_green): - if (flags & out_of_bounds) == out_of_bounds: - bad = "badly" - else: - bad = "" + if (flags & hook) == hook and flags & on_green != on_green: + bad = "badly" if (flags & out_of_bounds) == out_of_bounds else "" print(f"You hooked{bad}: {plot.offline} yards offline.") if self.stroke_num > 1: @@ -814,7 +793,7 @@ def interpret_results(self, plot: Plot, flags: int) -> None: if (flags & on_green) == on_green: if cup_distance < 4: - pd = str(cup_distance * 3) + " feet" + pd = f"{str(cup_distance * 3)} feet" else: pd = f"{cup_distance} yards" print(f"You're on the green. It's {pd} from the pin.") @@ -844,16 +823,10 @@ def report_current_score(self) -> None: if len(self.score_card[self.hole_num]) == (par - 3): print("Double Eagle! Unbelievable.") - total_par: int = 0 - for i in range(1, self.hole_num + 1): - total_par += CourseInfo[i].par - + total_par: int = sum(CourseInfo[i].par for i in range(1, self.hole_num + 1)) print(" ") print("-----------------------------------------------------") - if self.hole_num > 1: - hole_str = "holes" - else: - hole_str = "hole" + hole_str = "holes" if self.hole_num > 1 else "hole" print( f" Total par for {self.hole_num} {hole_str} is: {total_par}. " f"Your total is: {self.score_card_get_total()}." @@ -908,10 +881,7 @@ def is_on_green(self, ball: Ball) -> bool: def hazard_hit(self, h: Hazard, ball: Ball, hazard: GameObjType) -> bool: d = get_distance(Point(ball.X, ball.Y), Point(h.X, h.Y)) - result = False - if (d < h.Radius) and h.Type == hazard: - result = True - return result + return d < h.Radius and h.Type == hazard def is_in_hazard(self, ball: Ball, hazard: GameObjType) -> bool: result: bool = False @@ -938,9 +908,7 @@ def score_card_get_previous_stroke(self) -> Ball: return self.score_card[self.hole_num][len(self.score_card[self.hole_num]) - 1] def score_card_get_total(self) -> int: - total: int = 0 - for h in self.score_card: - total += len(h) + total: int = sum(len(h) for h in self.score_card) return total def ask( @@ -963,11 +931,8 @@ def ask( success = False n = 0 - if success: - if n >= min_ and n <= max_: - callback(n) - else: - self.ask(question, min_, max_, callback) + if success and n >= min_ and n <= max_: + callback(n) else: self.ask(question, min_, max_, callback) diff --git a/40_Gomoko/python/Gomoko.py b/40_Gomoko/python/Gomoko.py index 7036d7f22..cc4930a3e 100644 --- a/40_Gomoko/python/Gomoko.py +++ b/40_Gomoko/python/Gomoko.py @@ -13,9 +13,7 @@ def print_board(A: List[List[Any]], n: int) -> None: def check_move(_I, _J, _N) -> bool: # 910 - if _I < 1 or _I > _N or _J < 1 or _J > _N: - return False - return True + return _I >= 1 and _I <= _N and _J >= 1 and _J <= _N def print_banner() -> None: @@ -36,11 +34,10 @@ def get_board_dimensions() -> int: n = 0 while True: n = int(input("WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)? ")) - if n < 7 or n > 19: - print("I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.") - print() - else: + if n >= 7 and n <= 19: break + print("I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.") + print() return n @@ -62,9 +59,7 @@ def initialize_board(n: int) -> List[List[int]]: # Initialize the board board = [] for _x in range(n): - sub_a = [] - for _y in range(n): - sub_a.append(0) + sub_a = [0 for _y in range(n)] board.append(sub_a) return board @@ -87,51 +82,49 @@ def main() -> None: break elif not check_move(x, y, n): print("ILLEGAL MOVE. TRY AGAIN...") - else: - if board[x - 1][y - 1] != 0: - print("SQUARE OCCUPIED. TRY AGAIN...") - else: - board[x - 1][y - 1] = 1 - # COMPUTER TRIES AN INTELLIGENT MOVE - skip_ef_loop = False - for E in range(-1, 2): - for F in range(-1, 2): - if E + F - E * F == 0 or skip_ef_loop: - continue - X = x + F - Y = y + F - if not check_move(X, Y, n): - continue - if board[X - 1][Y - 1] == 1: - skip_ef_loop = True - X = x - E - Y = y - F - if not check_move(X, Y, n): # 750 - while True: # 610 - X = random.randint(1, n) - Y = random.randint(1, n) - if ( - check_move(X, Y, n) - and board[X - 1][Y - 1] == 0 - ): - board[X - 1][Y - 1] = 2 - print_board(board, n) - break - else: - if board[X - 1][Y - 1] != 0: - while True: - X = random.randint(1, n) - Y = random.randint(1, n) - if ( - check_move(X, Y, n) - and board[X - 1][Y - 1] == 0 - ): - board[X - 1][Y - 1] = 2 - print_board(board, n) - break - else: + elif board[x - 1][y - 1] == 0: + board[x - 1][y - 1] = 1 + # COMPUTER TRIES AN INTELLIGENT MOVE + skip_ef_loop = False + for E in range(-1, 2): + for F in range(-1, 2): + if E + F - E * F == 0 or skip_ef_loop: + continue + X = x + F + Y = y + F + if not check_move(X, Y, n): + continue + if board[X - 1][Y - 1] == 1: + skip_ef_loop = True + X = x - E + Y = y - F + if not check_move(X, Y, n): # 750 + while True: # 610 + X = random.randint(1, n) + Y = random.randint(1, n) + if ( + check_move(X, Y, n) + and board[X - 1][Y - 1] == 0 + ): board[X - 1][Y - 1] = 2 print_board(board, n) + break + elif board[X - 1][Y - 1] == 0: + board[X - 1][Y - 1] = 2 + print_board(board, n) + else: + while True: + X = random.randint(1, n) + Y = random.randint(1, n) + if ( + check_move(X, Y, n) + and board[X - 1][Y - 1] == 0 + ): + board[X - 1][Y - 1] = 2 + print_board(board, n) + break + else: + print("SQUARE OCCUPIED. TRY AGAIN...") print() print("THANKS FOR THE GAME!!") repeat = int(input("PLAY AGAIN (1 FOR YES, 0 FOR NO)? ")) diff --git a/42_Gunner/python/gunner.py b/42_Gunner/python/gunner.py index 06d55d188..6c6d19c72 100644 --- a/42_Gunner/python/gunner.py +++ b/42_Gunner/python/gunner.py @@ -50,21 +50,19 @@ def gunner() -> None: print("\n\nTOTAL ROUNDS EXPENDED WERE: ", S1) if S1 > 18: print("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!") - return else: print("NICE SHOOTING !!") - return + return else: killed_enemies += 1 print( "\nTHE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY..." ) break + elif shot_proximity_int > 100: + print("SHORT OF TARGET BY", abs(shot_proximity_int), "YARDS.") else: - if shot_proximity_int > 100: - print("SHORT OF TARGET BY", abs(shot_proximity_int), "YARDS.") - else: - print("OVER TARGET BY", abs(shot_proximity_int), "YARDS.") + print("OVER TARGET BY", abs(shot_proximity_int), "YARDS.") else: print("\nBOOM !!!! YOU HAVE JUST BEEN DESTROYED BY THE ENEMY.\n\n\n") print("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!") diff --git a/43_Hammurabi/python/hamurabi.py b/43_Hammurabi/python/hamurabi.py index c259ec802..46ef975d6 100644 --- a/43_Hammurabi/python/hamurabi.py +++ b/43_Hammurabi/python/hamurabi.py @@ -62,7 +62,7 @@ def main() -> None: while year < 11: # line 270. main loop. while the year is less than 11 print("\n\n\nHAMURABI: I BEG TO REPORT TO YOU") - year = year + 1 # year + year += 1 print( "IN YEAR", year, @@ -97,9 +97,7 @@ def main() -> None: elif bushels_per_acre * plague > grain_stores: # can't afford it bad_input_710(grain_stores) plague = -99 # give'm a second change to get it right - elif ( - bushels_per_acre * plague <= grain_stores - ): # normal case, can afford it + else: acres = acres + plague # increase the number of acres by Q grain_stores = ( grain_stores - bushels_per_acre * plague @@ -169,15 +167,8 @@ def main() -> None: # REM *** A BOUNTIFUL HARVEST! bushels_per_acre = C H = people * bushels_per_acre - eaten_rats = 0 - C = gen_random() - if int(C / 2) == C / 2: # even number. 50/50 chance - # REM *** RATS ARE RUNNING WILD!! - eaten_rats = int( - grain_stores / C - ) # calc losses due to rats, based on previous random number - + eaten_rats = int(grain_stores / C) if int(C / 2) == C / 2 else 0 grain_stores = grain_stores - eaten_rats + H # deduct losses from stores C = gen_random() diff --git a/44_Hangman/python/hangman.py b/44_Hangman/python/hangman.py index 3e84ce8d6..59d443dbc 100755 --- a/44_Hangman/python/hangman.py +++ b/44_Hangman/python/hangman.py @@ -16,9 +16,7 @@ class Canvas: def __init__(self, width: int = 12, height: int = 12, fill: str = " ") -> None: self._buffer = [] for _ in range(height): - line = [] - for _ in range(width): - line.append("") + line = ["" for _ in range(width)] self._buffer.append(line) self.clear() @@ -29,11 +27,7 @@ def clear(self, fill: str = " ") -> None: row[x] = fill def render(self) -> str: - lines = [] - for line in self._buffer: - # Joining by the empty string ("") smooshes all of the - # individual characters together as one line. - lines.append("".join(line)) + lines = ["".join(line) for line in self._buffer] return "\n".join(lines) def put(self, s: str, x: int, y: int) -> None: @@ -192,7 +186,7 @@ def play_game(guess_target: str) -> None: print("".join(guess_progress) + "\n") guess_letter = "" guess_word = "" - while guess_letter == "": + while not guess_letter: guess_letter = input("What is your guess? ").upper()[0] if not guess_letter.isalpha(): @@ -215,7 +209,7 @@ def play_game(guess_target: str) -> None: break else: print("\n" + "".join(guess_progress) + "\n") - while guess_word == "": + while not guess_word: guess_word = input("What is your guess for the word? ").upper() if not guess_word.isalpha(): guess_word = "" @@ -234,7 +228,7 @@ def play_game(guess_target: str) -> None: print("Sorry, that letter isn't in the word.") if wrong_guesses == 10: - print("Sorry, you lose. The word was " + guess_target) + print(f"Sorry, you lose. The word was {guess_target}") break diff --git a/45_Hello/python/hello.py b/45_Hello/python/hello.py index ccf0501c1..661ea60a1 100644 --- a/45_Hello/python/hello.py +++ b/45_Hello/python/hello.py @@ -47,8 +47,7 @@ def prompt_for_problems(user_name: str) -> str: print("THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO") print("YOU HAVE? (ANSWER SEX, HEALTH, MONEY, OR JOB)") - problem_type = input().upper() - return problem_type + return input().upper() def prompt_too_much_or_too_little() -> Tuple[bool, Optional[bool]]: @@ -122,11 +121,10 @@ def ask_question_loop(user_name: str) -> None: valid, value, msg = get_yes_or_no() if valid: - if value: - print("WHAT KIND (SEX, MONEY, HEALTH, JOB)") - break - else: + if not value: return + print("WHAT KIND (SEX, MONEY, HEALTH, JOB)") + break print(f"JUST A SIMPLE 'YES' OR 'NO' PLEASE, {user_name}.") @@ -184,10 +182,7 @@ def main() -> None: ask_for_fee(user_name) - if False: - happy_goodbye(user_name) - else: - unhappy_goodbye(user_name) + unhappy_goodbye(user_name) if __name__ == "__main__": diff --git a/46_Hexapawn/python/hexapawn.py b/46_Hexapawn/python/hexapawn.py index 9a2801c35..f5cac438b 100644 --- a/46_Hexapawn/python/hexapawn.py +++ b/46_Hexapawn/python/hexapawn.py @@ -278,14 +278,7 @@ def is_legal_human_move(board: List[int], m1: int, m2: int) -> bool: # Destination is not open return False - if m2 - m1 < -4: - # too far - return False - - if m1 == 7 and m2 == 3: - # can't jump corner to corner (wrapping around the board) - return False - return True + return False if m2 - m1 < -4 else m1 != 7 or m2 != 3 def player_piece_on_back_row(board: List[int]) -> bool: @@ -297,11 +290,11 @@ def computer_piece_on_front_row(board: List[int]) -> bool: def all_human_pieces_captured(board: List[int]) -> bool: - return len(list(get_human_spaces(board))) == 0 + return not list(get_human_spaces(board)) def all_computer_pieces_captured(board: List[int]) -> bool: - return len(list(get_computer_spaces(board))) == 0 + return not list(get_computer_spaces(board)) def human_win(last_computer_move: ComputerMove) -> None: @@ -312,11 +305,7 @@ def human_win(last_computer_move: ComputerMove) -> None: def computer_win(has_moves: bool) -> None: - if not has_moves: - msg = "YOU CAN'T MOVE, SO " - else: - msg = "" - msg += "I WIN" + msg = ("YOU CAN'T MOVE, SO " if not has_moves else "") + "I WIN" print(msg) global wins wins += 1 @@ -340,14 +329,14 @@ def human_has_move(board: List[int]) -> bool: else: continue elif i < 7: - assert (i == 4) or (i == 6) + assert i in [4, 6] if board_contents(board, 2) == COMPUTER_PIECE: # can capture computer piece at 2 return True else: continue elif board_contents(board, 5) == COMPUTER_PIECE: - assert (i == 7) or (i == 9) + assert i in [7, 9] # can capture computer piece at 5 return True else: @@ -391,20 +380,16 @@ def has_computer_move(board: List[int]) -> bool: board_contents(board, i + 4) == HUMAN_PIECE ): return True - else: - if i > 3: - # beyond the first row - if board_contents(board, 8) == HUMAN_PIECE: - # can capture on 8 - return True - else: - continue - else: - if board_contents(board, 5) == HUMAN_PIECE: - # can capture on 5 - return True - else: - continue + elif ( + i > 3 + and board_contents(board, 8) == HUMAN_PIECE + or i <= 3 + and board_contents(board, 5) == HUMAN_PIECE + ): + # can capture on 8 + return True + elif i <= 3 or board_contents(board, 8) == HUMAN_PIECE: + continue return False diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 6dcceaf5e..5b8c2204f 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -121,13 +121,8 @@ def play_game() -> None: while not move(board): print("ILLEGAL MOVE! TRY AGAIN") - # Check peg count and print the user's score - peg_count = 0 - for key in board.keys(): - if board[key] == "!": - peg_count += 1 - - print("YOU HAD " + str(peg_count) + " PEGS REMAINING") + peg_count = sum(1 for key in board.keys() if board[key] == "!") + print(f"YOU HAD {str(peg_count)} PEGS REMAINING") if peg_count == 1: print("BRAVO! YOU MADE A PERFECT SCORE!") @@ -158,11 +153,7 @@ def move(board: Dict[int, str]) -> bool: difference = abs(start - end) center = int((end + start) / 2) - if ( - (difference == 2 or difference == 18) - and board[end] == "O" - and board[center] == "!" - ): + if difference in [2, 18] and board[center] == "!": board[start] = "O" board[center] = "O" board[end] = "!" @@ -187,9 +178,10 @@ def is_game_finished(board) -> bool: next_to_peg = ((pos + space) in board) and board[pos + space] == "!" # Checks both going forward (+ location) or backwards (-location) has_movable_space = ( - not ((pos - space) in board and board[pos - space] == "!") - ) or ( - not ((pos + space * 2) in board and board[pos + space * 2] == "!") + pos - space not in board + or board[pos - space] != "!" + or pos + space * 2 not in board + or board[pos + space * 2] != "!" ) if next_to_peg and has_movable_space: return False diff --git a/49_Hockey/python/hockey.py b/49_Hockey/python/hockey.py index f18766194..c65d889e4 100644 --- a/49_Hockey/python/hockey.py +++ b/49_Hockey/python/hockey.py @@ -127,8 +127,9 @@ def print_header() -> None: def instructions() -> None: - wants_it = ask_binary("WOULD YOU LIKE THE INSTRUCTIONS? ", "ANSWER YES OR NO!!") - if wants_it: + if wants_it := ask_binary( + "WOULD YOU LIKE THE INSTRUCTIONS? ", "ANSWER YES OR NO!!" + ): print() print("THIS IS A SIMULATED HOCKEY GAME.") print("QUESTION RESPONSE") @@ -228,9 +229,7 @@ def team2_action( z1 = 3 elif pass_value == 2: print("IT'S A ' 3 ON 2 '!\n") - print( - "ONLY " + team_a.players[3] + " AND " + team_a.players[4] + " ARE BACK.\n" - ) + print(f"ONLY {team_a.players[3]} AND {team_a.players[4]}" + " ARE BACK.\n") print( team_b.players[player_index[j - 2]] + " GIVES OFF TO " @@ -290,7 +289,7 @@ def final_message(team_a: Team, team_b: Team, player_index: List[int]) -> None: print("\n") print("SHOTS ON NET\n") print(f"{team_a.name}: {team_a.shots_on_net}\n") - print(team_b.name + f": {team_b.shots_on_net}\n") + print(f"{team_b.name}: {team_b.shots_on_net}\n") def main() -> None: @@ -374,11 +373,8 @@ def handle_hit( print(f"{team_a.name}: {team_a.score}\t{team_b.name}: {team_b.score}\n") else: print(f"{team_b.name}: {team_b.score}\t{team_a.name}: {team_a.score}\n") - if controlling_team == 1: - team = team_a - else: - team = team_b - print("GOAL SCORED BY: " + team.players[goal_player] + "\n") + team = team_a if controlling_team == 1 else team_b + print(f"GOAL SCORED BY: {team.players[goal_player]}" + "\n") if goal_assistant1 != 0: if goal_assistant2 != 0: print( @@ -406,16 +402,16 @@ def handle_miss( saving_player = randint(1, 7) if controlling_team == 1: if saving_player == 1: - print("KICK SAVE AND A BEAUTY BY " + team_b.players[5] + "\n") - print("CLEARED OUT BY " + team_b.players[3] + "\n") + print(f"KICK SAVE AND A BEAUTY BY {team_b.players[5]}" + "\n") + print(f"CLEARED OUT BY {team_b.players[3]}" + "\n") remaining_time -= 1 return ("continue", remaining_time) if saving_player == 2: - print("WHAT A SPECTACULAR GLOVE SAVE BY " + team_b.players[5] + "\n") - print("AND " + team_b.players[5] + " GOLFS IT INTO THE CROWD\n") + print(f"WHAT A SPECTACULAR GLOVE SAVE BY {team_b.players[5]}" + "\n") + print(f"AND {team_b.players[5]}" + " GOLFS IT INTO THE CROWD\n") return ("break", remaining_time) if saving_player == 3: - print("SKATE SAVE ON A LOW STEAMER BY " + team_b.players[5] + "\n") + print(f"SKATE SAVE ON A LOW STEAMER BY {team_b.players[5]}" + "\n") remaining_time -= 1 return ("continue", remaining_time) if saving_player == 4: @@ -451,22 +447,20 @@ def handle_miss( print("ON THE LOOSE PUCK!\n") return ("break", remaining_time) if saving_player == 3: - print("SKATE SAVE BY " + team_a.players[5] + "\n") + print(f"SKATE SAVE BY {team_a.players[5]}" + "\n") print(team_a.players[5] + " WHACKS THE LOOSE PUCK INTO THE STANDS\n") return ("break", remaining_time) if saving_player == 4: - print( - "STICK SAVE BY " + team_a.players[5] + " AND HE CLEARS IT OUT HIMSELF\n" - ) + print(f"STICK SAVE BY {team_a.players[5]}" + " AND HE CLEARS IT OUT HIMSELF\n") remaining_time -= 1 return ("continue", remaining_time) if saving_player == 5: - print("KICKED OUT BY " + team_a.players[5] + "\n") + print(f"KICKED OUT BY {team_a.players[5]}" + "\n") print("AND IT REBOUNDS ALL THE WAY TO CENTER ICE\n") remaining_time -= 1 return ("continue", remaining_time) if saving_player == 6: - print("GLOVE SAVE " + team_a.players[5] + " AND HE HANGS ON\n") + print(f"GLOVE SAVE {team_a.players[5]}" + " AND HE HANGS ON\n") return ("break", remaining_time) return ("continue", remaining_time) @@ -488,8 +482,9 @@ def simulate_game_round( j = 0 for j in range(1, (pass_value + 2) + 1): player_index[j] = randint(1, 5) - if player_index[j - 1] == player_index[j - 2] or ( - pass_value + 2 >= 3 + if ( + player_index[j - 1] == player_index[j - 2] + or pass_value >= 1 and ( player_index[j - 1] == player_index[j - 3] or player_index[j - 2] == player_index[j - 3] @@ -511,7 +506,7 @@ def simulate_game_round( ) while True: shot_type = int(input("SHOT? ")) - if not (shot_type < 1 or shot_type > 4): + if shot_type >= 1 and shot_type <= 4: break if controlling_team == 1: print(team_a.players[goal_player], end="") @@ -521,21 +516,21 @@ def simulate_game_round( print(" LET'S A BIG SLAP SHOT GO!!\n") z = 4 z += z1 - if shot_type == 2: + elif shot_type == 2: print(" RIPS A WRIST SHOT OFF\n") z = 2 z += z1 - if shot_type == 3: + elif shot_type == 3: print(" GETS A BACKHAND OFF\n") z = 3 z += z1 - if shot_type == 4: + elif shot_type == 4: print(" SNAPS OFF A SNAP SHOT\n") z = 2 z += z1 while True: goal_area = int(input("AREA? ")) - if not (goal_area < 1 or goal_area > 4): + if goal_area >= 1 and goal_area <= 4: break if controlling_team == 1: team_a.shots_on_net += 1 diff --git a/50_Horserace/python/horserace.py b/50_Horserace/python/horserace.py index b00a63165..075c4573a 100644 --- a/50_Horserace/python/horserace.py +++ b/50_Horserace/python/horserace.py @@ -73,12 +73,8 @@ def setup_players() -> List[str]: # ensure we get an integer value from the user number_of_players = basic_input("HOW MANY WANT TO BET", int) - # for each user query their name and return the list of names - player_names = [] basic_print("WHEN ? APPEARS,TYPE NAME") - for _ in range(number_of_players): - player_names.append(basic_input("")) - return player_names + return [basic_input("") for _ in range(number_of_players)] def setup_horses() -> List[float]: diff --git a/53_King/python/king.py b/53_King/python/king.py index 4bca76fac..0bf85016c 100644 --- a/53_King/python/king.py +++ b/53_King/python/king.py @@ -179,7 +179,7 @@ def handle_foreign_workers( sm_sell_to_industry + (random() * 10) - (random() * 20) ) if self.foreign_workers <= 0: - foreign_workers_influx = foreign_workers_influx + 20 + foreign_workers_influx += 20 print(f"{foreign_workers_influx} WORKERS CAME TO THE COUNTRY AND") surplus_distributed = distributed_rallods / COST_OF_LIVING - self.countrymen @@ -196,7 +196,7 @@ def handle_foreign_workers( print("CAME TO ", end="") print("THE ISLAND") self.countrymen += population_change - self.foreign_workers += int(foreign_workers_influx) + self.foreign_workers += foreign_workers_influx def handle_too_many_deaths(self) -> None: print(f"\n\n\n{self.died_contrymen} COUNTRYMEN DIED IN ONE YEAR!!!!!") @@ -430,8 +430,9 @@ def main() -> None: if state.countrymen < 343: state.handle_third_died() elif ( - state.rallods / 100 - ) > 5 and state.died_contrymen - state.pollution_deaths >= 2: + state.rallods > 500 + and state.died_contrymen - state.pollution_deaths >= 2 + ): state.handle_money_mismanagement() if state.foreign_workers > state.countrymen: state.handle_too_many_foreigners() diff --git a/55_Life/python/life.py b/55_Life/python/life.py index 5a71dfa88..8707d5015 100644 --- a/55_Life/python/life.py +++ b/55_Life/python/life.py @@ -44,7 +44,7 @@ def get_pattern() -> Dict[int, str]: # staying in. if line[0] == ".": - line = " " + line[1:] + line = f" {line[1:]}" pattern[c] = line c += 1 @@ -64,7 +64,7 @@ def main() -> None: max_x = MAX_HEIGHT - 1 max_y = MAX_WIDTH - 1 - a = [[0 for y in range(MAX_WIDTH)] for x in range(MAX_HEIGHT)] + a = [[0 for _ in range(MAX_WIDTH)] for _ in range(MAX_HEIGHT)] p = 0 g = 0 invalid = False @@ -81,11 +81,7 @@ def main() -> None: print() print() while True: - if invalid: - inv_str = "INVALID!" - else: - inv_str = "" - + inv_str = "INVALID!" if invalid else "" print(f"GENERATION: {g}\tPOPULATION: {p} {inv_str}") next_min_x = MAX_HEIGHT - 1 @@ -151,7 +147,7 @@ def main() -> None: count = 0 for i in range(x - 1, x + 2): for j in range(y - 1, y + 2): - if a[i][j] == 1 or a[i][j] == 2: + if a[i][j] in [1, 2]: count += 1 if a[x][y] == 0: if count == 3: diff --git a/56_Life_for_Two/python/life_for_two.py b/56_Life_for_Two/python/life_for_two.py index da4e16195..c9910f994 100644 --- a/56_Life_for_Two/python/life_for_two.py +++ b/56_Life_for_Two/python/life_for_two.py @@ -5,11 +5,12 @@ Ported by Sajid Sarker (2022). ''' + # Global Variable Initialisation # Initialise the board -gn = [[0 for i in range(6)] for j in range(6)] -gx = [0 for x in range(3)] -gy = [0 for x in range(3)] +gn = [[0 for _ in range(6)] for _ in range(6)] +gx = [0 for _ in range(3)] +gy = [0 for _ in range(3)] gk = [0, 3, 102, 103, 120, 130, 121, 112, 111, 12, 21, 30, 1020, 1030, 1011, 1021, 1003, 1002, 1012] @@ -27,9 +28,9 @@ def tab(number) -> str: def display_header() -> None: - print("{}LIFE2".format(tab(33))) - print("{}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n".format(tab(15))) - print("{}U.B. LIFE GAME".format(tab(10))) + print(f"{tab(33)}LIFE2") + print(f"{tab(15)}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print(f"{tab(10)}U.B. LIFE GAME") # Board Functions @@ -37,7 +38,7 @@ def setup_board() -> None: # Players add symbols to initially setup the board for b in range(1, 3): p1 = 3 if b != 2 else 30 - print("\nPLAYER {} - 3 LIVE PIECES.".format(b)) + print(f"\nPLAYER {b} - 3 LIVE PIECES.") for _ in range(1, 4): query_player(b) gn[gx[b]][gy[b]] = p1 @@ -46,7 +47,7 @@ def setup_board() -> None: def modify_board() -> None: # Players take turns to add symbols and modify the board for b in range(1, 3): - print("PLAYER {} ".format(b)) + print(f"PLAYER {b} ") query_player(b) if b == 99: break @@ -72,36 +73,32 @@ def display_board() -> None: for j in range(7): print("") for k in range(7): - if j == 0 or j == 6: + if j in [0, 6]: if k != 6: - print(" " + str(k) + " ", end="") + print(f" {str(k)} ", end="") else: print(" 0 ", end="") - elif k == 0 or k == 6: - if j != 6: - print(" " + str(j) + " ", end="") - else: - print(" 0\n") + elif k in [0, 6]: + print(f" {str(j)} ", end="") + elif gn[j][k] < 3: + gn[j][k] = 0 + print(" ", end="") else: - if gn[j][k] < 3: + for o1 in range(1, 19): + if gn[j][k] == gk[o1]: + break + if o1 <= 18: + if o1 > 9: + gn[j][k] = 1000 + m3 += 1 + print(" # ", end="") + else: + gn[j][k] = 100 + m2 += 1 + print(" * ", end="") + else: gn[j][k] = 0 print(" ", end="") - else: - for o1 in range(1, 19): - if gn[j][k] == gk[o1]: - break - if o1 <= 18: - if o1 > 9: - gn[j][k] = 1000 - m3 += 1 - print(" # ", end="") - else: - gn[j][k] = 100 - m2 += 1 - print(" * ", end="") - else: - gn[j][k] = 0 - print(" ", end="") # Player Functions @@ -113,8 +110,8 @@ def query_player(b) -> None: b_ = input("???") x_ = [int(num) for num in a_.split() if num.isdigit()] y_ = [int(num) for num in b_.split() if num.isdigit()] - x_ = [0] if len(x_) == 0 else x_ - y_ = [0] if len(y_) == 0 else y_ + x_ = [0] if not x_ else x_ + y_ = [0] if not y_ else y_ gx[b] = y_[0] gy[b] = x_[0] if gx[b] in range(1, 6)\ diff --git a/59_Lunar_LEM_Rocket/python/lunar.py b/59_Lunar_LEM_Rocket/python/lunar.py index fa7da3de8..c48e21a76 100644 --- a/59_Lunar_LEM_Rocket/python/lunar.py +++ b/59_Lunar_LEM_Rocket/python/lunar.py @@ -64,7 +64,7 @@ def add_rjust(line: str, s: Any, pos: int) -> str: def add_ljust(line: str, s: str, pos: int) -> str: """Add a new field to a line left justified starting at pos""" - s = str(s) + s = s if len(line) > pos: line = line[:pos] if len(line) < pos: @@ -324,10 +324,7 @@ def run_simulation() -> None: return if capsule.velocity > 0 and new_state.velocity < 0: - # moving away from the moon - - landed = handle_flyaway(sim_clock, capsule) - if landed: + if landed := handle_flyaway(sim_clock, capsule): process_final_tick(delta_t, sim_clock, capsule) return diff --git a/60_Mastermind/python/mastermind.py b/60_Mastermind/python/mastermind.py index cc77153c4..8fcecc624 100644 --- a/60_Mastermind/python/mastermind.py +++ b/60_Mastermind/python/mastermind.py @@ -77,11 +77,7 @@ def human_turn() -> None: print_score() return # from human turn, triumphant else: - print( - "You have {} blacks and {} whites".format( - guess_results[1], guess_results[2] - ) - ) + print(f"You have {guess_results[1]} blacks and {guess_results[2]} whites") guesses.append(guess_results) num_moves += 1 @@ -193,16 +189,14 @@ def possibility_to_color_code(possibility: int) -> str: def compare_two_positions(guess: str, answer: str) -> List[Union[str, int]]: """Returns blacks (correct color and position) and whites (correct color only) for candidate position (guess) versus reference position (answer).""" - increment = 0 blacks = 0 whites = 0 initial_guess = guess + increment = 0 for pos in range(0, NUM_POSITIONS): if guess[pos] != answer[pos]: for pos2 in range(0, NUM_POSITIONS): - if not ( - guess[pos] != answer[pos2] or guess[pos2] == answer[pos2] - ): # correct color but not correct place + if guess[pos] == answer[pos2] and guess[pos2] != answer[pos2]: # correct color but not correct place whites = whites + 1 answer = answer[:pos2] + chr(increment) + answer[pos2 + 1:] guess = guess[:pos] + chr(increment + 1) + guess[pos + 1:] diff --git a/61_Math_Dice/python/mathdice.py b/61_Math_Dice/python/mathdice.py index 99220e713..4081e0cca 100644 --- a/61_Math_Dice/python/mathdice.py +++ b/61_Math_Dice/python/mathdice.py @@ -22,23 +22,23 @@ def print_2() -> None: print(" ----- ") - if n in [4, 5, 6]: + if n in {4, 5, 6}: print_2() - elif n in [2, 3]: + elif n in {2, 3}: print("| * |") else: print_0() - if n in [1, 3, 5]: + if n in {1, 3, 5}: print("| * |") - elif n in [2, 4]: + elif n in {2, 4}: print_0() else: print_2() - if n in [4, 5, 6]: + if n in {4, 5, 6}: print_2() - elif n in [2, 3]: + elif n in {2, 3}: print("| * |") else: print_0() diff --git a/62_Mugwump/python/mugwump.py b/62_Mugwump/python/mugwump.py index d1e3f7c3d..cc719c172 100644 --- a/62_Mugwump/python/mugwump.py +++ b/62_Mugwump/python/mugwump.py @@ -35,8 +35,7 @@ def reveal_mugwumps(mugwumps: List[List[int]]) -> None: def calculate_distance(guess: Tuple[int, int], mugwump: List[int]) -> float: - d = sqrt(((mugwump[0] - guess[0]) ** 2) + ((mugwump[1] - guess[1]) ** 2)) - return d + return sqrt(((mugwump[0] - guess[0]) ** 2) + ((mugwump[1] - guess[1]) ** 2)) def play_again() -> None: diff --git a/63_Name/python/name.py b/63_Name/python/name.py index 3d7eeb1c0..94b8170d6 100644 --- a/63_Name/python/name.py +++ b/63_Name/python/name.py @@ -9,9 +9,7 @@ def is_yes_ish(answer: str) -> bool: cleaned = answer.strip().upper() - if cleaned in ["Y", "YES"]: - return True - return False + return cleaned in {"Y", "YES"} def main() -> None: diff --git a/64_Nicomachus/python/nicomachus.py b/64_Nicomachus/python/nicomachus.py index 84f477032..e5d1c8253 100644 --- a/64_Nicomachus/python/nicomachus.py +++ b/64_Nicomachus/python/nicomachus.py @@ -43,9 +43,7 @@ def play_game() -> None: print(f"YOUR NUMBER WAS {d}, RIGHT?") - response = get_yes_or_no() - - if response: + if response := get_yes_or_no(): print("HOW ABOUT THAT!!") else: print("I FEEL YOUR ARITHMETIC IS IN ERROR.") diff --git a/65_Nim/python/Traditional_NIM.py b/65_Nim/python/Traditional_NIM.py index bd1470c50..ead90b2d0 100644 --- a/65_Nim/python/Traditional_NIM.py +++ b/65_Nim/python/Traditional_NIM.py @@ -30,11 +30,7 @@ def remove_pegs(self, command) -> None: print("\nInvalid value of either Peg or Pile\n") def get_ai_move(self) -> Tuple[int, int]: - possible_pile = [] - for k, v in self.piles.items(): - if v != 0: - possible_pile.append(k) - + possible_pile = [k for k, v in self.piles.items() if v != 0] pile = random.choice(possible_pile) num = random.randint(1, self.piles[pile]) @@ -46,7 +42,7 @@ def _command_integrity(self, num, pile) -> bool: def print_pegs(self) -> None: for pile, peg in self.piles.items(): - print("Pile {} : {}".format(pile, "O " * peg)) + print(f'Pile {pile} : {"O " * peg}') def help(self) -> None: print("-" * 10) @@ -89,8 +85,7 @@ def main() -> None: # Players Move command = input("\nYOUR MOVE - Number of PILE, Number of Object? ") game.remove_pegs(command) - end = game.check_for_win() - if end: + if end := game.check_for_win(): print("\nPlayer Wins the Game, Congratulations!!") input("\nPress any key to exit") break @@ -98,13 +93,10 @@ def main() -> None: # Computers Move ai_command = game.get_ai_move() print( - "\nA.I MOVE - A.I Removed {} pegs from Pile {}".format( - ai_command[1], ai_command[0] - ) + f"\nA.I MOVE - A.I Removed {ai_command[1]} pegs from Pile {ai_command[0]}" ) - game.remove_pegs(str(ai_command[0]) + "," + str(ai_command[1])) - end = game.check_for_win() - if end: + game.remove_pegs(f"{str(ai_command[0])},{str(ai_command[1])}") + if end := game.check_for_win(): print("\nComputer Wins the Game, Better Luck Next Time\n") input("Press any key to exit") break diff --git a/68_Orbit/python/orbit.py b/68_Orbit/python/orbit.py index f0ce1637e..cfca3c93b 100644 --- a/68_Orbit/python/orbit.py +++ b/68_Orbit/python/orbit.py @@ -107,9 +107,7 @@ def play_game() -> bool: rom_angle = random.randint(0, 359) rom_distance = random.randint(100, 300) rom_angular_velocity = random.randint(10, 30) - hour = 0 - while hour < 7: - hour += 1 + for hour in range(1, 8): print() print() print(f"THIS IS HOUR {hour}, AT WHAT ANGLE DO YOU WISH TO SEND") diff --git a/69_Pizza/python/pizza.py b/69_Pizza/python/pizza.py index e4e36beac..aa4a01e93 100644 --- a/69_Pizza/python/pizza.py +++ b/69_Pizza/python/pizza.py @@ -155,9 +155,7 @@ def main() -> None: player_name = print_instructions() - more_directions = yes_no_prompt("DO YOU NEED MORE DIRECTIONS?") - - if more_directions: + if more_directions := yes_no_prompt("DO YOU NEED MORE DIRECTIONS?"): print_more_directions(player_name) understand = yes_no_prompt("UNDERSTAND?") @@ -171,8 +169,8 @@ def main() -> None: print("GOOD LUCK!!") print() + num_turns = 5 while True: - num_turns = 5 play_game(num_turns, player_name) print() diff --git a/70_Poetry/python/poetry.py b/70_Poetry/python/poetry.py index 302126301..f261db375 100644 --- a/70_Poetry/python/poetry.py +++ b/70_Poetry/python/poetry.py @@ -49,7 +49,7 @@ def process_phrase_2(state: State) -> None: ] words, u_modifier = line_2_options[state.i] state.line += words - if not (u_modifier is None): + if u_modifier is not None: state.u = u_modifier diff --git a/72_Queen/python/queen.py b/72_Queen/python/queen.py index 94f377a1c..285174c49 100755 --- a/72_Queen/python/queen.py +++ b/72_Queen/python/queen.py @@ -82,10 +82,7 @@ def loc_to_num(location: Tuple[int, int], fix_align: bool = False) -> str: """Convert a position given by row, column into a space number.""" row, col = location out_str: str = f"{row + 8 - col}{row + 1}" - if not fix_align or len(out_str) == 3: - return out_str - else: - return out_str + " " + return out_str if not fix_align or len(out_str) == 3 else f"{out_str} " GAME_BOARD: Final[str] = ( @@ -173,15 +170,14 @@ def get_move(current_loc: Optional[Tuple[int, int]]) -> Tuple[int, int]: "YOU HAVE BEGUN ILLEGALLY.\n\n" "WHERE WOULD YOU LIKE TO START? " ) - else: - if ( + elif ( (new_row == row and new_col < col) # move left or (new_col == col and new_row > row) # move down or (new_row - row == col - new_col) # move diag left and down ) and (not FIX_BOARD_BUG or (new_col >= 0 and new_row < 8)): - return new_row, new_col - else: - prompt = "Y O U C H E A T . . . TRY AGAIN? " + return new_row, new_col + else: + prompt = "Y O U C H E A T . . . TRY AGAIN? " except ValueError: prompt = "!NUMBER EXPECTED - RETRY INPUT LINE\n? " @@ -256,12 +252,12 @@ def ask(prompt: str) -> bool: inpt: str while True: # Normalize input to uppercase, no whitespace, then get first character - inpt = input(prompt + "? ").upper().strip()[0] + inpt = input(f"{prompt}? ").upper().strip()[0] print() - if inpt == "Y": - return True - elif inpt == "N": + if inpt == "N": return False + elif inpt == "Y": + return True print("PLEASE ANSWER 'YES' OR 'NO'.") return False diff --git a/73_Reverse/python/reverse.py b/73_Reverse/python/reverse.py index f75ece2f8..e34378406 100755 --- a/73_Reverse/python/reverse.py +++ b/73_Reverse/python/reverse.py @@ -52,7 +52,7 @@ def game_loop() -> None: turns += 1 # Reverse as many items as requested. - newnums = numbers[0:howmany] + newnums = numbers[:howmany] newnums.reverse() newnums.extend(numbers[howmany:]) numbers = newnums diff --git a/74_Rock_Scissors_Paper/python/rockscissors.py b/74_Rock_Scissors_Paper/python/rockscissors.py index 898f709cc..3d150bd4f 100644 --- a/74_Rock_Scissors_Paper/python/rockscissors.py +++ b/74_Rock_Scissors_Paper/python/rockscissors.py @@ -44,22 +44,27 @@ def play_game() -> None: print("...Scissors") elif guess_computer == 3: print("...Rock") - if guess_computer == guess_human: + if ( + guess_computer != guess_human + and guess_computer > guess_human + and (guess_human != 1 or guess_computer != 3) + or guess_computer != guess_human + and guess_computer <= guess_human + and guess_computer == 1 + and guess_human == 3 + ): + print("Wow! I win!!!") + won_computer = won_computer + 1 + elif ( + guess_computer != guess_human + and guess_computer > guess_human + or guess_computer != guess_human + and guess_computer == 1 + ): + print("You win!!!") + won_human = won_human + 1 + elif guess_computer == guess_human: print("Tie Game. No winner") - elif guess_computer > guess_human: - if guess_human != 1 or guess_computer != 3: - print("Wow! I win!!!") - won_computer = won_computer + 1 - else: - print("You win!!!") - won_human = won_human + 1 - elif guess_computer == 1: - if guess_human != 3: - print("You win!!!") - won_human = won_human + 1 - else: - print("Wow! I win!!!") - won_computer = won_computer + 1 print("\nHere is the final game score:") print("I have won", won_computer, "game(s).") print("You have won", won_human, "game(s).") diff --git a/75_Roulette/python/roulette.py b/75_Roulette/python/roulette.py index 7a21d36dc..eec68bed7 100644 --- a/75_Roulette/python/roulette.py +++ b/75_Roulette/python/roulette.py @@ -75,7 +75,7 @@ def query_bets() -> Tuple[List[int], List[int]]: for i in range(bet_count): while bet_ids[i] == -1: try: - in_string = input("NUMBER " + str(i + 1) + "? ").split(",") + in_string = input(f"NUMBER {str(i + 1)}? ").split(",") id_, val = int(in_string[0]), int(in_string[1]) # check other bet_IDs @@ -126,9 +126,9 @@ def get_modifier(id_: int, num: int) -> int: total_winnings += winnings if winnings >= 0: - print("YOU WIN " + str(winnings) + " DOLLARS ON BET " + str(i + 1)) + print(f"YOU WIN {str(winnings)} DOLLARS ON BET {str(i + 1)}") else: - print("YOU LOSE " + str(winnings * -1) + " DOLLARS ON BET " + str(i + 1)) + print(f"YOU LOSE {str(winnings * -1)} DOLLARS ON BET {str(i + 1)}") return winnings @@ -142,7 +142,7 @@ def print_check(amount: int) -> None: print(" " * 40 + "CHECK NO. " + str(random.randint(0, 100))) print(" " * 40 + str(date.today())) print() - print("PAY TO THE ORDER OF -----" + name + "----- $" + str(amount)) + print(f"PAY TO THE ORDER OF -----{name}----- ${amount}") print() print(" " * 40 + "THE MEMORY BANK OF NEW YORK") print(" " * 40 + "THE COMPUTER") @@ -176,9 +176,9 @@ def main() -> None: elif val == 37: print("00") elif val in RED_NUMBERS: - print(str(val) + " RED") + print(f"{val} RED") else: - print(str(val) + " BLACK") + print(f"{val} BLACK") print() total_winnings = bet_results(bet_ids, bet_values, val) @@ -209,7 +209,7 @@ def main() -> None: def string_to_bool(string: str) -> bool: """Converts a string to a bool""" - return string.lower() in ("yes", "y", "true", "t", "yes") + return string.lower() in {"y", "true", "t", "yes"} if __name__ == "__main__": diff --git a/76_Russian_Roulette/python/russianroulette.py b/76_Russian_Roulette/python/russianroulette.py index f402fb03c..71e0ee129 100644 --- a/76_Russian_Roulette/python/russianroulette.py +++ b/76_Russian_Roulette/python/russianroulette.py @@ -29,8 +29,7 @@ def initial_message() -> None: def parse_input() -> int: while True: try: - i = int(input("? ")) - return i + return int(input("? ")) except ValueError: print("Number expected...") @@ -61,13 +60,12 @@ def main() -> None: print("BANG!!!!! You're Dead!") print("Condolences will be sent to your relatives.\n\n\n") print("...Next victim...") + elif n > NUMBER_OF_ROUNDS: + print("You win!!!!!") + print("Let someone else blow his brain out.\n") else: - if n > NUMBER_OF_ROUNDS: - print("You win!!!!!") - print("Let someone else blow his brain out.\n") - else: - print(" Chicken!!!!!\n\n\n") - print("...Next victim....") + print(" Chicken!!!!!\n\n\n") + print("...Next victim....") if __name__ == "__main__": diff --git a/77_Salvo/python/salvo.py b/77_Salvo/python/salvo.py index 368b15da9..417bebc14 100644 --- a/77_Salvo/python/salvo.py +++ b/77_Salvo/python/salvo.py @@ -169,7 +169,7 @@ def generate_ship_coordinates(ship: int) -> List[CoordinateType]: # clockwise. a vector of valid directions where the # ship does not go off the board is determined ship_len = SHIPS[ship][1] - 1 - dirs = [False for x in range(8)] + dirs = [False for _ in range(8)] dirs[0] = (start_x - ship_len) >= 1 dirs[2] = (start_y + ship_len) <= BOARD_WIDTH dirs[1] = dirs[0] and dirs[2] @@ -261,11 +261,7 @@ def generate_board() -> Tuple[BoardType, List[List[CoordinateType]]]: coords = [] while not placed: coords = generate_ship_coordinates(ship) - clear = True - for coord in coords: - if board[coord[0] - 1][coord[1] - 1] is not None: - clear = False - break + clear = all(board[coord[0] - 1][coord[1] - 1] is None for coord in coords) if clear: placed = True place_ship(board, coords, ship) @@ -291,18 +287,17 @@ def execute_shot( def calculate_shots(board: BoardType) -> int: """Examine each board and determine how many shots remaining""" - ships_found = [0 for x in range(len(SHIPS))] + ships_found = [0 for _ in range(len(SHIPS))] for x in range(BOARD_HEIGHT): for y in range(BOARD_WIDTH): square = board[x - 1][y - 1] if square is not None and square >= 0 and square < len(SHIPS): ships_found[square] = 1 - shots = 0 - for ship in range(len(ships_found)): - if ships_found[ship] == 1: - shots += SHIPS[ship][2] - - return shots + return sum( + SHIPS[ship][2] + for ship in range(len(ships_found)) + if ships_found[ship] == 1 + ) def initialize_game() -> None: @@ -413,10 +408,7 @@ def execute_turn(turn: bool, current_turn: int) -> int: # computer, we randomly pick a shot. for the # player we request shots while not valid_shot: - if turn == COMPUTER: - x, y = random_x_y() - else: - x, y = input_coord() + x, y = random_x_y() if turn == COMPUTER else input_coord() square = board[x - 1][y - 1] if square is not None and square > 10: if turn == PLAYER: diff --git a/79_Slalom/python/slalom.py b/79_Slalom/python/slalom.py index a6833331b..e3387e6f6 100644 --- a/79_Slalom/python/slalom.py +++ b/79_Slalom/python/slalom.py @@ -97,7 +97,7 @@ def run(gates, lvl, max_speeds) -> None: case 7: speed -= int(random() * (10 - 5) + 5) - print(f" {int(speed)} M.P.H.") + print(f" {speed} M.P.H.") if speed > max_speeds[i]: if random() < ((speed - max_speeds[i]) * 0.1) + 0.2: print( @@ -184,7 +184,7 @@ def main() -> None: run(gates, lvl, max_speeds) while True: answer = ask("Do you want to play again?") - if answer == "YES" or answer == "NO": + if answer in ["YES", "NO"]: break else: print('Please type "YES" or "NO"') diff --git a/80_Slots/python/slots.py b/80_Slots/python/slots.py index 22c2b3a3f..6464458b6 100644 --- a/80_Slots/python/slots.py +++ b/80_Slots/python/slots.py @@ -59,7 +59,7 @@ def input_betting() -> int: elif b < 1: print("Minium bet is $1") beeping() - return int(b) + return b def beeping() -> None: @@ -113,7 +113,7 @@ def adjust_profits(wheel: List[str], m: int, profits: int) -> int: else: # three different fruits print("\nYou Lost.") - profits = profits - m + profits -= m return profits diff --git a/81_Splat/python/splat.py b/81_Splat/python/splat.py index 30ec74b5d..f521f3a23 100644 --- a/81_Splat/python/splat.py +++ b/81_Splat/python/splat.py @@ -311,9 +311,9 @@ def main() -> None: z = yes_no_input("DO YOU WANT TO PLAY AGAIN") if not z: z = yes_no_input("PLEASE") - if not z: - print("SSSSSSSSSS.") - break + if not z: + print("SSSSSSSSSS.") + break if __name__ == "__main__": diff --git a/82_Stars/python/stars.py b/82_Stars/python/stars.py index d2024d6b4..5a5f9fed0 100644 --- a/82_Stars/python/stars.py +++ b/82_Stars/python/stars.py @@ -40,10 +40,7 @@ def print_instructions() -> None: def print_stars(secret_number, guess) -> None: diff = abs(guess - secret_number) - stars = "" - for i in range(8): - if diff < 2**i: - stars += "*" + stars = "".join("*" for i in range(8) if diff < 2**i) print(stars) @@ -51,8 +48,7 @@ def get_guess(prompt: str) -> int: while True: guess_str = input(prompt) if guess_str.isdigit(): - guess = int(guess_str) - return guess + return int(guess_str) def main() -> None: diff --git a/83_Stock_Market/python/Stock_Market.py b/83_Stock_Market/python/Stock_Market.py index e32572ca6..38d8442a1 100644 --- a/83_Stock_Market/python/Stock_Market.py +++ b/83_Stock_Market/python/Stock_Market.py @@ -35,10 +35,9 @@ def total_assets(self) -> float: def _generate_day_change(self) -> None: self.changes = [] - for _ in range(len(self.data)): - self.changes.append( - round(random.uniform(-5, 5), 2) - ) # Random % Change b/w -5 and 5 + self.changes.extend( + round(random.uniform(-5, 5), 2) for _ in range(len(self.data)) + ) def update_prices(self) -> None: self._generate_day_change() @@ -65,9 +64,9 @@ def print_first_day(self) -> None: print("\nSTOCK\t\t\t\t\tINITIALS\tPRICE/SHARE($)") for stock, data in self.data.items(): if stock != "LBJ": - print("{}\t\t\t{}\t\t{}".format(data["Name"], stock, data["Price"])) + print(f'{data["Name"]}\t\t\t{stock}\t\t{data["Price"]}') else: - print("{}\t\t{}\t\t{}".format(data["Name"], stock, data["Price"])) + print(f'{data["Name"]}\t\t{stock}\t\t{data["Price"]}') self.print_exchange_average() self.print_assets() diff --git a/84_Super_Star_Trek/python/superstartrek.py b/84_Super_Star_Trek/python/superstartrek.py index 805c9d93a..892988c76 100644 --- a/84_Super_Star_Trek/python/superstartrek.py +++ b/84_Super_Star_Trek/python/superstartrek.py @@ -26,8 +26,7 @@ def get_user_float(prompt: str) -> float: while True: answer = input(prompt) try: - answer_float = float(answer) - return answer_float + return float(answer) except ValueError: pass @@ -202,7 +201,7 @@ def quadrant_name(cls, row: int, col: int, region_only: bool = False) -> str: quadrant = region1[row] if col < 4 else region2[row] if not region_only: - quadrant += " " + modifier[col % 4] + quadrant += f" {modifier[col % 4]}" return quadrant @@ -622,7 +621,7 @@ def short_range_scan(self) -> None: for x in range(8): line = "" for y in range(8): - line = line + " " + self.world.quadrant.data[x][y].value + line = f"{line} {self.world.quadrant.data[x][y].value}" if x == 0: line += f" STARDATE {round(int(self.world.stardate * 10) * 0.1, 1)}" @@ -882,8 +881,7 @@ def damage_control(self) -> None: return for i in range(8): - if ship.damage_stats[i] < 0: - ship.damage_stats[i] = 0 + ship.damage_stats[i] = max(ship.damage_stats[i], 0) self.world.stardate += damage_sum + 0.1 def computer(self) -> None: @@ -909,7 +907,7 @@ def computer(self) -> None: print() - if com in [0, 5]: + if com in {0, 5}: if com == 5: print(" THE GALAXY") else: @@ -923,7 +921,7 @@ def computer(self) -> None: print(sep) for i in range(8): - line = " " + str(i + 1) + " " + line = f" {str(i + 1)} " if com == 5: g2s = Quadrant.quadrant_name(i, 0, True) @@ -1121,12 +1119,11 @@ def print_direction(source: Point, to: Point) -> None: else: base = 1 delta1, delta2 = delta2, delta1 + elif delta1 > 0: + base = 3 else: - if delta1 > 0: - base = 3 - else: - base = 5 - delta1, delta2 = delta2, delta1 + base = 5 + delta1, delta2 = delta2, delta1 delta1, delta2 = abs(delta1), abs(delta2) diff --git a/84_Super_Star_Trek/python/superstartrekins.py b/84_Super_Star_Trek/python/superstartrekins.py index 59a8a61bd..6060ad9d4 100644 --- a/84_Super_Star_Trek/python/superstartrekins.py +++ b/84_Super_Star_Trek/python/superstartrekins.py @@ -17,13 +17,13 @@ def print_header() -> None: for _ in range(12): print() t10 = " " * 10 - print(t10 + "*************************************") - print(t10 + "* *") - print(t10 + "* *") - print(t10 + "* * * SUPER STAR TREK * * *") - print(t10 + "* *") - print(t10 + "* *") - print(t10 + "*************************************") + print(f"{t10}*************************************") + print(f"{t10}* *") + print(f"{t10}* *") + print(f"{t10}* * * SUPER STAR TREK * * *") + print(f"{t10}* *") + print(f"{t10}* *") + print(f"{t10}*************************************") for _ in range(8): print() diff --git a/88_3-D_Tic-Tac-Toe/python/qubit.py b/88_3-D_Tic-Tac-Toe/python/qubit.py index 3a8f1e096..e0dd531e8 100644 --- a/88_3-D_Tic-Tac-Toe/python/qubit.py +++ b/88_3-D_Tic-Tac-Toe/python/qubit.py @@ -137,10 +137,7 @@ def move(self, m, player) -> bool: if self.board[m] > 1: return False - if player == Player.MACHINE: - self.board[m] = 40 - else: - self.board[m] = 8 + self.board[m] = 40 if player == Player.MACHINE else 8 return True def get_3d_position(self, m) -> Tuple[int, int, int]: @@ -152,9 +149,7 @@ def get_3d_position(self, m) -> Tuple[int, int, int]: def evaluate_lines(self) -> None: self.lineValues = [0] * 76 for j in range(76): - value = 0 - for k in range(4): - value += self.board[self.lines[j][k]] + value = sum(self.board[self.lines[j][k]] for k in range(4)) self.lineValues[j] = value def strategy_mark_line(self, i) -> None: @@ -174,9 +169,7 @@ def mark_and_move(self, vlow, vhigh, vmove) -> Optional[Tuple[Move, int]]: or the machine and choose best place to play """ for i in range(76): - value = 0 - for j in range(4): - value += self.board[self.lines[i][j]] + value = sum(self.board[self.lines[i][j]] for j in range(4)) self.lineValues[i] = value if vlow <= value < vhigh: if value > vlow: @@ -186,7 +179,7 @@ def mark_and_move(self, vlow, vhigh, vmove) -> Optional[Tuple[Move, int]]: for i in range(76): value = self.lineValues[i] - if value == 4 or value == vmove: + if value in [4, vmove]: return self.move_diagonals(i, 1) return None @@ -232,11 +225,10 @@ def machine_move(self) -> Union[None, Tuple[Move, int], Tuple[Move, int, int]]: if self.board[y] == 0: return (Move.MOVES, y) - for i in range(64): - if self.board[i] == 0: - return (Move.LIKES, i) - - return (Move.DRAW, -1) + return next( + ((Move.LIKES, i) for i in range(64) if self.board[i] == 0), + (Move.DRAW, -1), + ) def human_win(self, i) -> Tuple[Move, int, int]: return (Move.HUMAN_WIN, -1, i) @@ -260,18 +252,12 @@ def move_triple(self, i) -> Tuple[Move, int]: for j in range(4): m = self.lines[i][j] if self.board[m] == 1: - if self.lineValues[i] < 40: - return (Move.YOU_FOX, m) - else: - return (Move.GET_OUT, m) + return (Move.YOU_FOX, m) if self.lineValues[i] < 40 else (Move.GET_OUT, m) return (Move.CONCEDES, -1) # choose move in corners or center boxes of square 4x4 def move_diagonals(self, i, s) -> Optional[Tuple[Move, int]]: - if 0 < (i % 4) < 3: - jrange = [1, 2] - else: - jrange = [0, 3] + jrange = [1, 2] if 0 < (i % 4) < 3 else [0, 3] for j in jrange: m = self.lines[i][j] if self.board[m] == s: @@ -379,11 +365,7 @@ def play(self) -> None: self.show_win(board, m[2]) # type: ignore break elif m[0] == Move.MACHINE_WIN: - print( - "Machine moves to {}, and wins as follows".format( - self.move_code(board, m[1]) - ) - ) + print(f"Machine moves to {self.move_code(board, m[1])}, and wins as follows") self.show_win(board, m[2]) # type: ignore break elif m[0] == Move.DRAW: diff --git a/89_Tic-Tac-Toe/python/TicTacToe_Hard.py b/89_Tic-Tac-Toe/python/TicTacToe_Hard.py index b5708d802..8b3e50ab9 100644 --- a/89_Tic-Tac-Toe/python/TicTacToe_Hard.py +++ b/89_Tic-Tac-Toe/python/TicTacToe_Hard.py @@ -8,9 +8,7 @@ def __init__(self, pick, sz=3) -> None: self.board = self.clear_board() def clear_board(self) -> List[List[str]]: - board = [["blur" for i in range(self.dim_sz)] for j in range(self.dim_sz)] - # made a 3x3 by-default board - return board + return [["blur" for _ in range(self.dim_sz)] for _ in range(self.dim_sz)] def move_record(self, r, c) -> Union[str, bool]: if r > self.dim_sz or c > self.dim_sz: @@ -86,17 +84,12 @@ def check_win(self) -> int: # 1 you won, 0 computer won, -1 tie if flag11 or flag12: return 1 - if flag21 or flag22: - return 0 - - return -1 + return 0 if flag21 or flag22 else -1 def next_move(self) -> Union[Tuple[int, int], Tuple[List[int], List[int]]]: available_moves = [] # will carry all available moves player_win_spot = [] # if player (user Wins) - comp_pick = "O" - if self.pick == "O": - comp_pick = "X" + comp_pick = "X" if self.pick == "O" else "O" for i in range(0, self.dim_sz): for j in range(0, self.dim_sz): @@ -113,13 +106,13 @@ def next_move(self) -> Union[Tuple[int, int], Tuple[List[int], List[int]]]: player_win_spot.append(t) self.board[i][j] = "blur" - if len(player_win_spot) != 0: + if player_win_spot: self.board[player_win_spot[0][0]][player_win_spot[0][1]] = comp_pick return player_win_spot[0][0], player_win_spot[0][1] if len(available_moves) == 1: self.board[available_moves[0][0]][available_moves[0][1]] = comp_pick return [available_moves[0][0]], [available_moves[0][1]] - if len(available_moves) == 0: + if not available_moves: return -1, -1 c1, c2 = self.dim_sz // 2, self.dim_sz // 2 @@ -172,22 +165,19 @@ def display(game: TicTacToe) -> None: for i in range(0, game.dim_sz): for j in range(0, game.dim_sz - 1): if game.board[i][j] == "blur": - line1 = line1 + " |" + line1 = f"{line1} |" else: - line1 = line1 + " " + game.board[i][j] + " |" + line1 = f"{line1} {game.board[i][j]} |" if game.board[i][game.dim_sz - 1] == "blur": line1 = line1 + " \n" else: - line1 = line1 + " " + game.board[i][game.dim_sz - 1] + " \n" + line1 = f"{line1} {game.board[i][game.dim_sz - 1]}" + " \n" print(line1, "\n\n") def main() -> None: pick = input("Pick 'X' or 'O' ").strip().upper() - if pick == "O": - game = TicTacToe("O") - else: - game = TicTacToe("X") + game = TicTacToe("O") if pick == "O" else TicTacToe("X") display(game=game) while True: temp: Union[bool, str] = False diff --git a/89_Tic-Tac-Toe/python/tictactoe2.py b/89_Tic-Tac-Toe/python/tictactoe2.py index 210ff2e7c..e6fce18a2 100755 --- a/89_Tic-Tac-Toe/python/tictactoe2.py +++ b/89_Tic-Tac-Toe/python/tictactoe2.py @@ -52,14 +52,15 @@ def line_170(board, g, h, j, k): def line_150(board, g, h, j, k): if board[k] != g: # line 150 - if ( - board[k] == h # line 160 - or board[k + 6] != g # line 161 - or board[k + 3] != g - ): # line 162 - return -1 # Goto 170 - else: - return k + 3 # Line 163 + return ( + -1 + if ( + board[k] == h # line 160 + or board[k + 6] != g # line 161 + or board[k + 3] != g + ) + else k + 3 + ) elif board[k + 6] != g: # line 152 if board[k + 6] != 0 or board[k + 3] != g: # line 165 return -1 # Goto 170 @@ -70,16 +71,7 @@ def line_150(board, g, h, j, k): def line_120(board, g, h, j, k): - if board[j] != g: - if board[j] == h or board[j + 2] != g or board[j + 1] != g: - if board[k] != g: - if board[k + 6] != g and (board[k + 6] != 0 or board[k + 3] != g): - # 450 IF G=1 THEN 465 - pass - elif board[j + 2] is not g: # Line 122 - pass - elif board[j + 1] is not OccupiedBy.EMPTY: - pass + pass def line_118(board, g, h): @@ -123,12 +115,13 @@ def think(board, g, h, moves): def render_board(board, space_mapping): vertical_divider = "!" horizontal_divider = "---+---+---" - lines = [] - lines.append(vertical_divider.join(space_mapping[space] for space in board[0:3])) - lines.append(horizontal_divider) - lines.append(vertical_divider.join(space_mapping[space] for space in board[3:6])) - lines.append(horizontal_divider) - lines.append(vertical_divider.join(space_mapping[space] for space in board[6:9])) + lines = [ + vertical_divider.join(space_mapping[space] for space in board[:3]), + horizontal_divider, + vertical_divider.join((space_mapping[space] for space in board[3:6])), + horizontal_divider, + vertical_divider.join((space_mapping[space] for space in board[6:9])), + ] return "\n".join(lines) diff --git a/90_Tower/python/tower.py b/90_Tower/python/tower.py index 7d30c9ebb..d0059e86f 100644 --- a/90_Tower/python/tower.py +++ b/90_Tower/python/tower.py @@ -10,7 +10,7 @@ def size(self) -> int: return self.__size def print(self) -> None: - print("[ %s ]" % self.size()) + print(f"[ {self.size()} ]") class Tower: @@ -21,10 +21,7 @@ def empty(self) -> bool: return len(self.__disks) == 0 def top(self) -> Optional[Disk]: - if self.empty(): - return None - else: - return self.__disks[-1] + return None if self.empty() else self.__disks[-1] def add(self, disk: Disk) -> None: if not self.empty(): @@ -42,7 +39,7 @@ def pop(self) -> Disk: return self.__disks.pop() def print(self) -> None: - r = "Needle: [%s]" % (", ".join([str(x.size()) for x in self.__disks])) + r = f'Needle: [{", ".join([str(x.size()) for x in self.__disks])}]' print(r) @@ -87,7 +84,7 @@ def pick_disk(self) -> Optional[Tower]: print("ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15.\n") valids = [t for t in self.__towers if t.top() and t.top().size() == which] - assert len(valids) in (0, 1) + assert len(valids) in {0, 1} if not valids: print("THAT DISK IS BELOW ANOTHER ONE. MAKE ANOTHER CHOICE.\n") return None diff --git a/92_Trap/python/trap.py b/92_Trap/python/trap.py index 64220234d..a85be68e6 100644 --- a/92_Trap/python/trap.py +++ b/92_Trap/python/trap.py @@ -24,11 +24,10 @@ def play_game() -> None: int(item) for item in input("\nGuess # " + str(turn) + " ? ").split(",") ] - if len(user_input) == 2: - if sum(1 < x < number_max for x in user_input) == 2: - user_guess = user_input - else: - raise ValueError + if len(user_input) != 2: + raise ValueError + if sum(1 < x < number_max for x in user_input) == 2: + user_guess = user_input else: raise ValueError except (ValueError, IndexError): diff --git a/93_23_Matches/python/23matches.py b/93_23_Matches/python/23matches.py index 5375a176e..293cfa1f3 100755 --- a/93_23_Matches/python/23matches.py +++ b/93_23_Matches/python/23matches.py @@ -35,7 +35,7 @@ def play_game() -> None: except ValueError: print("Please enter a number.") prompt_human = "How many do you wish to remove " - matches = matches - choice_human + matches -= choice_human if matches == 0: print("You poor boob! You took the last match! I gotcha!!") print("Ha ! Ha ! I beat you !!\n") @@ -48,7 +48,7 @@ def play_game() -> None: choice_computer = 1 elif 1 < matches < 4: choice_computer = matches - 1 - matches = matches - choice_computer + matches -= choice_computer if matches == 0: print("You won, floppy ears !") print("Think you're pretty smart !") diff --git a/95_Weekday/python/weekday.py b/95_Weekday/python/weekday.py index 15cdae442..0a6b0aabd 100644 --- a/95_Weekday/python/weekday.py +++ b/95_Weekday/python/weekday.py @@ -29,11 +29,13 @@ def get_date_from_user(prompt: str) -> Tuple[int, int, int]: def get_date_from_system() -> Tuple[int, int, int]: - dt = datetime.datetime.today() + dt = datetime.datetime.now() return dt.month, dt.day, dt.year def get_day_of_week(weekday_index, day) -> str: + if weekday_index == 6 and day == 13: + return "FRIDAY THE THIRTEENTH---BEWARE!" day_names = { 1: "SUNDAY", 2: "MONDAY", @@ -44,8 +46,6 @@ def get_day_of_week(weekday_index, day) -> str: 7: "SATURDAY", } - if weekday_index == 6 and day == 13: - return "FRIDAY THE THIRTEENTH---BEWARE!" return day_names[weekday_index] @@ -58,11 +58,7 @@ def previous_day(b) -> int: def is_leap_year(year: int) -> bool: if (year % 4) != 0: return False - if (year % 100) != 0: - return True - if (year % 400) != 0: - return False - return True + return True if (year % 100) != 0 else year % 400 == 0 def adjust_day_for_leap_year(b, year): @@ -86,9 +82,9 @@ def calc_day_value(year, month, day): def deduct_time(frac, days, years_remain, months_remain, days_remain): # CALCULATE TIME IN YEARS, MONTHS, AND DAYS days_available = int(frac * days) - years_used = int(days_available / 365) + years_used = days_available // 365 days_available -= years_used * 365 - months_used = int(days_available / 30) + months_used = days_available // 30 days_used = days_available - (months_used * 30) years_remain = years_remain - years_used months_remain = months_remain - months_used @@ -238,7 +234,7 @@ def main() -> None: rem_years, rem_months, rem_days, used_years, used_months, used_days = deduct_time( 0.23, life_days, rem_years, rem_months, rem_days ) - time_report("YOU HAVE " + label, used_years, used_months, used_days) + time_report(f"YOU HAVE {label}", used_years, used_months, used_days) time_report("YOU HAVE RELAXED", rem_years, rem_months, rem_days) print() diff --git a/96_Word/python/word.py b/96_Word/python/word.py index 8b7f0d51f..5ff7604a0 100755 --- a/96_Word/python/word.py +++ b/96_Word/python/word.py @@ -35,7 +35,7 @@ def play_game() -> None: print("You are starting a new game...") while True: guess_word = "" - while guess_word == "": + while not guess_word: guess_word = input("\nGuess a five letter word. ").upper() if guess_word == "?": break From 795d3e20ebd28b90c912b60bd92fafe6358e0fd7 Mon Sep 17 00:00:00 2001 From: amjadkofahi <119040835+amjadkofahi@users.noreply.github.com> Date: Thu, 25 May 2023 01:52:51 +0300 Subject: [PATCH 325/377] Update README.md --- 84_Super_Star_Trek/javascript/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/84_Super_Star_Trek/javascript/README.md b/84_Super_Star_Trek/javascript/README.md index 49b7ece64..1ddcc1d64 100644 --- a/84_Super_Star_Trek/javascript/README.md +++ b/84_Super_Star_Trek/javascript/README.md @@ -1,3 +1,6 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) +Original source downloaded [from Vintage Basic][def] -Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) +Conversion to [**J**avaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) + + +[def]: http://www.vintage-basic.net/games.html \ No newline at end of file From c289c20c7b7bb37e66ec91b7da64dd31896b63ef Mon Sep 17 00:00:00 2001 From: amjadkofahi <119040835+amjadkofahi@users.noreply.github.com> Date: Thu, 25 May 2023 01:54:55 +0300 Subject: [PATCH 326/377] Update README.md --- 84_Super_Star_Trek/javascript/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/84_Super_Star_Trek/javascript/README.md b/84_Super_Star_Trek/javascript/README.md index 1ddcc1d64..06f53f122 100644 --- a/84_Super_Star_Trek/javascript/README.md +++ b/84_Super_Star_Trek/javascript/README.md @@ -1,6 +1,6 @@ Original source downloaded [from Vintage Basic][def] -Conversion to [**J**avaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) +Conversion to [****J****avaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) [def]: http://www.vintage-basic.net/games.html \ No newline at end of file From c518e2b08525bdf83a3d9351903549792ab5d363 Mon Sep 17 00:00:00 2001 From: amjadkofahi Date: Wed, 20 Sep 2023 14:54:04 +0300 Subject: [PATCH 327/377] Update HOW_TO_RUN_THE_GAMES.md --- HOW_TO_RUN_THE_GAMES.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md index 36061f161..06b0256c8 100644 --- a/HOW_TO_RUN_THE_GAMES.md +++ b/HOW_TO_RUN_THE_GAMES.md @@ -29,7 +29,9 @@ To run from the command line, you will need a Java SDK (eg. [Oracle JDK](https:/ 1. Navigate to the corresponding directory. 1. Compile the program with `javac`: - * eg. `javac AceyDuceyGame.java` + * eg. `**```python + javac + ```** AceyDuceyGame.java` 1. Run the compiled program with `java`: * eg. `java AceyDuceyGame` @@ -68,7 +70,7 @@ In addition to the java runtime you will need the `kotlinc` compiler, which can The pascal examples can be run using [Free Pascal](https://www.freepascal.org/). Additionally, `.lsi` project files can be opened with the [Lazarus Project IDE](https://www.lazarus-ide.org/). -The pascal examples include both *simple* (single-file) and *object-oriented* (in the `/object-pascal`directories) examples. +The pascal examples include both ___simple_ (single-file) and_o**bject-oriented_ (in the `/object-pascal`directories) examples. 1. You can compile the program from the command line with the `fpc` command. * eg. `fpc amazing.pas` @@ -92,7 +94,9 @@ The python translations can be run from the command line by using the `py` inter * eg. `python aceyducey.py` **Note** - +{ + "MD013": false +} Some translations include multiple versions for python, such as `acey ducey` which features versions for Python 2 (`aceyducey.py`) and Python 3 (`acey_ducey.py`) as well as an extra object-oriented version (`acey_ducey_oo.py`). You can manage and use different versions of python with [pip](https://pypi.org/project/pip/). From c2cbaa99800cdafd4afbdd2b60faa1235d00e81c Mon Sep 17 00:00:00 2001 From: amjadkofahi Date: Wed, 20 Sep 2023 15:03:09 +0300 Subject: [PATCH 328/377] Update HOW_TO_RUN_THE_GAMES.md --- HOW_TO_RUN_THE_GAMES.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md index 06b0256c8..1d25fe417 100644 --- a/HOW_TO_RUN_THE_GAMES.md +++ b/HOW_TO_RUN_THE_GAMES.md @@ -23,7 +23,7 @@ Alternatively, for non-dotnet compatible translations, you will need [Visual Stu ## java -The Java translations can be run via the command line or from an IDE such as [Eclipse](https://www.eclipse.org/downloads/packages/release/kepler/sr1/eclipse-ide-java-developers) or [IntelliJ](https://www.jetbrains.com/idea/) +The Java translations can be run via the command line or from an IDE such as [Eclipse](https://www.eclipse.org/downloads/packages/release/kepler/sr1/eclipse-ide-java-developers) or [IntelJ][def] To run from the command line, you will need a Java SDK (eg. [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) or [Open JDK](https://openjdk.java.net/)). @@ -120,3 +120,5 @@ If you don't already have Rust on your computer, you can follow the instruction 1. From the command-line, navigate to the corresponding directory. 2. Run the following command. * `cargo run` + +[def]: https://www.jetbrains.com/idea/ From 3b05cad889374eabb2e4493754c557eb6902f682 Mon Sep 17 00:00:00 2001 From: amjadkofahi Date: Wed, 20 Sep 2023 16:20:57 +0300 Subject: [PATCH 329/377] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e28f8fe09..8efd6d4aa 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,5 @@ venv/ **/*.rs.bk /target todo.md + +.fake \ No newline at end of file From 4979a6221974603bc8c77c6b719f7f5da36762a9 Mon Sep 17 00:00:00 2001 From: amjadkofahi Date: Wed, 20 Sep 2023 20:42:48 +0300 Subject: [PATCH 330/377] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8efd6d4aa..878190440 100644 --- a/.gitignore +++ b/.gitignore @@ -38,4 +38,5 @@ venv/ /target todo.md +.fake .fake \ No newline at end of file From 5f01f031c1913b04e57187f1d72c418f5e07bf73 Mon Sep 17 00:00:00 2001 From: amjad <119040835+amjadkofahi@users.noreply.github.com> Date: Mon, 19 Aug 2024 04:09:53 +0300 Subject: [PATCH 331/377] Merge branch 'sourcery/main' of https://github.com/amjadkofahi/basic-computer-games into sourcery/main --- .../89_Tic-Tac-Toe/MiniScript/README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md index 526bbfb3e..c3c2c9259 100644 --- a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md +++ b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md @@ -5,14 +5,16 @@ 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: +Download for your system from , install, and then run the program with a command such as: + ``` - miniscript tictactoe.ms + miniscript tictactoe.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: +Download Mini Micro from , 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 "tictactoe" + run ``` - load "tictactoe" - run -``` \ No newline at end of file From 6a4936c088cfc656adcb795e73ea6f1cea427c58 Mon Sep 17 00:00:00 2001 From: Aldrin Misquitta Date: Tue, 24 Sep 2024 11:31:42 +0400 Subject: [PATCH 332/377] Updates utilities for missing implementations for the languages - kotlin, lua, rust Updates TODO.md --- 00_Utilities/TODO.md | 131 ++++++++++--------- 00_Utilities/find-missing-implementations.js | 3 + 00_Utilities/find-unimplemented.js | 3 + 3 files changed, 72 insertions(+), 65 deletions(-) diff --git a/00_Utilities/TODO.md b/00_Utilities/TODO.md index 6ccc8e7ff..714807486 100644 --- a/00_Utilities/TODO.md +++ b/00_Utilities/TODO.md @@ -3,98 +3,99 @@ ------------------------------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- 01_Acey_Ducey | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ [02_Amazing](../02_Amazing) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ -[03_Animal](../03_Animal) | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[04_Awari](../04_Awari) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[03_Animal](../03_Animal) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[04_Awari](../04_Awari) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ [05_Bagels](../05_Bagels) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[06_Banner](../06_Banner) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ -[07_Basketball](../07_Basketball) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ -[08_Batnum](../08_Batnum) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ -[09_Battle](../09_Battle) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +[06_Banner](../06_Banner) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ +[07_Basketball](../07_Basketball) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[08_Batnum](../08_Batnum) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ +[09_Battle](../09_Battle) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️ [10_Blackjack](../10_Blackjack) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ -[11_Bombardment](../11_Bombardment) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[12_Bombs_Away](../12_Bombs_Away) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[13_Bounce](../13_Bounce) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ -[14_Bowling](../14_Bowling) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[15_Boxing](../15_Boxing) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[16_Bug](../16_Bug) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ -[17_Bullfight](../17_Bullfight) | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[18_Bullseye](../18_Bullseye) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[11_Bombardment](../11_Bombardment) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[12_Bombs_Away](../12_Bombs_Away) | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +[13_Bounce](../13_Bounce) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[14_Bowling](../14_Bowling) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[15_Boxing](../15_Boxing) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[16_Bug](../16_Bug) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ +[17_Bullfight](../17_Bullfight) | ✅ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +[18_Bullseye](../18_Bullseye) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ [19_Bunny](../19_Bunny) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[20_Buzzword](../20_Buzzword) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[21_Calendar](../21_Calendar) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[20_Buzzword](../20_Buzzword) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[21_Calendar](../21_Calendar) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ [22_Change](../22_Change) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ -[23_Checkers](../23_Checkers) | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ -[24_Chemist](../24_Chemist) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[25_Chief](../25_Chief) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[26_Chomp](../26_Chomp) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[23_Checkers](../23_Checkers) | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[24_Chemist](../24_Chemist) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +[25_Chief](../25_Chief) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[26_Chomp](../26_Chomp) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ [27_Civil_War](../27_Civil_War) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[28_Combat](../28_Combat) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[29_Craps](../29_Craps) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[30_Cube](../30_Cube) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ +[28_Combat](../28_Combat) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[29_Craps](../29_Craps) | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[30_Cube](../30_Cube) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ [31_Depth_Charge](../31_Depth_Charge) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[32_Diamond](../32_Diamond) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[33_Dice](../33_Dice) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ -[34_Digits](../34_Digits) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[35_Even_Wins](../35_Even_Wins) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[36_Flip_Flop](../36_Flip_Flop) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ +[32_Diamond](../32_Diamond) | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[33_Dice](../33_Dice) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ +[34_Digits](../34_Digits) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[35_Even_Wins](../35_Even_Wins) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +[36_Flip_Flop](../36_Flip_Flop) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ [37_Football](../37_Football) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[38_Fur_Trader](../38_Fur_Trader) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +[38_Fur_Trader](../38_Fur_Trader) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ [39_Golf](../39_Golf) | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ [40_Gomoko](../40_Gomoko) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[41_Guess](../41_Guess) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[42_Gunner](../42_Gunner) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[43_Hammurabi](../43_Hammurabi) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +[41_Guess](../41_Guess) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[42_Gunner](../42_Gunner) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[43_Hammurabi](../43_Hammurabi) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ [44_Hangman](../44_Hangman) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[45_Hello](../45_Hello) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[45_Hello](../45_Hello) | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ [46_Hexapawn](../46_Hexapawn) | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[47_Hi-Lo](../47_Hi-Lo) | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[47_Hi-Lo](../47_Hi-Lo) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ [48_High_IQ](../48_High_IQ) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[49_Hockey](../49_Hockey) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ -[50_Horserace](../50_Horserace) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[51_Hurkle](../51_Hurkle) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[49_Hockey](../49_Hockey) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +[50_Horserace](../50_Horserace) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️ +[51_Hurkle](../51_Hurkle) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ [52_Kinema](../52_Kinema) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[53_King](../53_King) | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +[53_King](../53_King) | ✅ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️ [54_Letter](../54_Letter) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[55_Life](../55_Life) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[56_Life_for_Two](../56_Life_for_Two) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ -[57_Literature_Quiz](../57_Literature_Quiz) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[58_Love](../58_Love) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[55_Life](../55_Life) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[56_Life_for_Two](../56_Life_for_Two) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[57_Literature_Quiz](../57_Literature_Quiz) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +[58_Love](../58_Love) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ [59_Lunar_LEM_Rocket](../59_Lunar_LEM_Rocket) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️ [60_Mastermind](../60_Mastermind) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ [61_Math_Dice](../61_Math_Dice) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[62_Mugwump](../62_Mugwump) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[63_Name](../63_Name) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[64_Nicomachus](../64_Nicomachus) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[62_Mugwump](../62_Mugwump) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +[63_Name](../63_Name) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[64_Nicomachus](../64_Nicomachus) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ [65_Nim](../65_Nim) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ [66_Number](../66_Number) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ -[67_One_Check](../67_One_Check) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[68_Orbit](../68_Orbit) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[69_Pizza](../69_Pizza) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[70_Poetry](../70_Poetry) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[71_Poker](../71_Poker) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ -[72_Queen](../72_Queen) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[67_One_Check](../67_One_Check) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[68_Orbit](../68_Orbit) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[69_Pizza](../69_Pizza) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[70_Poetry](../70_Poetry) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[71_Poker](../71_Poker) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ +[72_Queen](../72_Queen) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ [73_Reverse](../73_Reverse) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ -[74_Rock_Scissors_Paper](../74_Rock_Scissors_Paper) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[75_Roulette](../75_Roulette) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[76_Russian_Roulette](../76_Russian_Roulette) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[77_Salvo](../77_Salvo) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[78_Sine_Wave](../78_Sine_Wave) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[74_Rock_Scissors_Paper](../74_Rock_Scissors_Paper) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[75_Roulette](../75_Roulette) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +[76_Russian_Roulette](../76_Russian_Roulette) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[77_Salvo](../77_Salvo) | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +[78_Sine_Wave](../78_Sine_Wave) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ [79_Slalom](../79_Slalom) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ [80_Slots](../80_Slots) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[81_Splat](../81_Splat) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +[81_Splat](../81_Splat) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ [82_Stars](../82_Stars) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ [83_Stock_Market](../83_Stock_Market) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[84_Super_Star_Trek](../84_Super_Star_Trek) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[85_Synonym](../85_Synonym) | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[86_Target](../86_Target) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +[84_Super_Star_Trek](../84_Super_Star_Trek) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️ +[85_Synonym](../85_Synonym) | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[86_Target](../86_Target) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ [87_3-D_Plot](../87_3-D_Plot) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ [88_3-D_Tic-Tac-Toe](../88_3-D_Tic-Tac-Toe) | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ [89_Tic-Tac-Toe](../89_Tic-Tac-Toe) | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ -[90_Tower](../90_Tower) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[91_Train](../91_Train) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[92_Trap](../92_Trap) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[93_23_Matches](../93_23_Matches) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +[90_Tower](../90_Tower) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +[91_Train](../91_Train) | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[92_Trap](../92_Trap) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +[93_23_Matches](../93_23_Matches) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ [94_War](../94_War) | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ [95_Weekday](../95_Weekday) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +[96_Word](../96_Word) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ ------------------------------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- -Sum of 95 | 63 | 80 | 95 | 7 | 2 | 60 | 92 | 49 | 20 | 6 +Sum of 96 | 79 | 83 | 96 | 9 | 16 | 75 | 95 | 51 | 58 | 7 diff --git a/00_Utilities/find-missing-implementations.js b/00_Utilities/find-missing-implementations.js index 61d849feb..a458f190e 100644 --- a/00_Utilities/find-missing-implementations.js +++ b/00_Utilities/find-missing-implementations.js @@ -16,10 +16,13 @@ const languages = [ { name: "csharp", extension: "cs" }, { name: "java", extension: "java" }, { name: "javascript", extension: "html" }, + { name: "kotlin", extension: "kt" }, + { name: "lua", extension: "lua" }, { name: "pascal", extension: "pas" }, { name: "perl", extension: "pl" }, { name: "python", extension: "py" }, { name: "ruby", extension: "rb" }, + { name: "rust", extension: "rs" }, { name: "vbnet", extension: "vb" }, ]; diff --git a/00_Utilities/find-unimplemented.js b/00_Utilities/find-unimplemented.js index e048d9ce2..fb88fdbe2 100644 --- a/00_Utilities/find-unimplemented.js +++ b/00_Utilities/find-unimplemented.js @@ -17,11 +17,14 @@ let languages = [ { name: "csharp", extension: "cs" }, { name: "java", extension: "java" }, { name: "javascript", extension: "html" }, + { name: "kotlin", extension: "kt" }, + { name: "lua", extension: "lua" }, { name: "pascal", extension: "pas" }, { name: "perl", extension: "pl" }, { name: "python", extension: "py" }, { name: "ruby", extension: "rb" }, { name: "vbnet", extension: "vb" }, + { name: "rust", extension: "rs" }, ]; const getFilesRecursive = async (path, extension) => { From a56a42f52b611bdb6d9a5c6cd7bfc0b1e7b67e75 Mon Sep 17 00:00:00 2001 From: Aldrin Misquitta Date: Tue, 24 Sep 2024 15:02:21 +0400 Subject: [PATCH 333/377] Fixes the type check failures for python implementations, boxing.py and Stock_Market.py --- 15_Boxing/python/boxing.py | 4 ++-- 83_Stock_Market/python/Stock_Market.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/15_Boxing/python/boxing.py b/15_Boxing/python/boxing.py index 9d8c87d58..907f645c7 100755 --- a/15_Boxing/python/boxing.py +++ b/15_Boxing/python/boxing.py @@ -3,7 +3,7 @@ import random from dataclasses import dataclass from pathlib import Path -from typing import Dict, Literal, NamedTuple, Tuple +from typing import Dict, Literal, NamedTuple, Tuple, cast class PunchProfile(NamedTuple): @@ -70,7 +70,7 @@ def read_punch_profiles(filepath: Path) -> Dict[Literal[1, 2, 3, 4], PunchProfil with open(filepath) as f: punch_profile_dict = json.load(f) return { - int(key): PunchProfile(**value) + cast(Literal[1, 2, 3, 4], int(key)): PunchProfile(**value) for key, value in punch_profile_dict.items() } diff --git a/83_Stock_Market/python/Stock_Market.py b/83_Stock_Market/python/Stock_Market.py index 38d8442a1..6ad3f8d1a 100644 --- a/83_Stock_Market/python/Stock_Market.py +++ b/83_Stock_Market/python/Stock_Market.py @@ -34,7 +34,7 @@ def total_assets(self) -> float: return self.cash_assets + self.stock_assets def _generate_day_change(self) -> None: - self.changes = [] + self.changes: List[float] = [] self.changes.extend( round(random.uniform(-5, 5), 2) for _ in range(len(self.data)) ) From 89b5f6d81d4387d23118f9e4497184889e4e04ef Mon Sep 17 00:00:00 2001 From: Aldrin Misquitta Date: Thu, 31 Oct 2024 14:53:36 +0400 Subject: [PATCH 334/377] Java implementation of Bullfight --- 17_Bullfight/java/Bullfight.java | 466 +++++++++++++++++++++++++++++++ README.md | 2 +- 2 files changed, 467 insertions(+), 1 deletion(-) create mode 100644 17_Bullfight/java/Bullfight.java diff --git a/17_Bullfight/java/Bullfight.java b/17_Bullfight/java/Bullfight.java new file mode 100644 index 000000000..16fe299c0 --- /dev/null +++ b/17_Bullfight/java/Bullfight.java @@ -0,0 +1,466 @@ +import java.util.Random; +import java.util.Scanner; + +/** + * BULLFIGHT + *

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + */ +public class Bullfight { + + private static final int MAX_PASSES_BEFORE_CHARGE = 3; + + public static void main(String[] args) { + printHeader(); + + Scanner scanner = new Scanner(System.in); + System.out.print("\n\n"); + + var instructionsChoice = readInstructionsChoice(scanner); + if (instructionsChoice) { + printInstructions(); + } + + Random random = new Random(); + + //initialize the game with default values + GameState gameState = new GameState(); + + //Randomly select a bull grade + int randomGrade = (int) (random.nextFloat() * BullGrade.values().length + 1); + var bullGrade = BullGrade.fromValue(randomGrade); + + printBullGradeInfo(bullGrade); + + System.out.println(); + + //D[1] in the original + gameState.picadoresDamage = firstStage("PICADO", "RES", bullGrade, random); + + //D[2] in the original + gameState.toreadoresDamage = firstStage("TOREAD", "ORES", bullGrade, random); + + boolean done = false; //controls the main game loop + + while (!done) { + + gameState.passNumber++; + System.out.printf("\n\nPASS NUMBER %d \n", gameState.passNumber); + + if (gameState.passNumber < MAX_PASSES_BEFORE_CHARGE) { + System.out.println("THE BULL IS CHARGING AT YOU! YOU ARE THE MATADOR--"); + System.out.print("DO YOU WANT TO KILL THE BULL? "); + } else { + System.out.print("HERE COMES THE BULL. TRY FOR A KILL? "); + } + + BooleanAnswer yesOrNo = readYesOrNo(scanner); + if (yesOrNo.equals(BooleanAnswer.YES)) { + gameState = attemptKillBull(bullGrade, random, gameState, scanner); + done = true; + } else { + int capeMove; + if (gameState.passNumber < MAX_PASSES_BEFORE_CHARGE) { + capeMove = readCapeMove("WHAT MOVE DO YOU MAKE WITH THE CAPE", scanner); + } else { + capeMove = readCapeMove("CAPE MOVE", scanner); + } + + //handle cape move + gameState = handleCapeMove(capeMove, random, scanner, bullGrade, gameState); + + if (gameState.matadorStatus.equals(MatadorStatus.DEFEATED) || gameState.matadorStatus.equals(MatadorStatus.DEAD)) { + done = true; + } + } + + } + + crowdReaction(gameState, bullGrade, random); + + System.out.println("\nADIOS\n\n"); + } + + private static void printBullGradeInfo(BullGrade bullGrade) { + System.out.println("\n\nYOU HAVE DRAWN A " + bullGrade.name() + " BULL."); + if (bullGrade.equals(BullGrade.AWFUL)) { + System.out.println("YOU'RE LUCKY."); + } else if (bullGrade.equals(BullGrade.SUPERB)) { + System.out.println("GOOD LUCK. YOU'LL NEED IT."); + } + } + + private static void crowdReaction(GameState gameState, BullGrade bullGrade, Random random) { + System.out.println("\n\n"); + if (!gameState.matadorStatus.equals(MatadorStatus.DEFEATED)) { + if (!gameState.matadorStatus.equals(MatadorStatus.INJURED)) { + if (gameState.bullStatus.equals(BullStatus.DEAD)) { + System.out.println("THE CROWD CHEERS!"); + } + } else { + System.out.println("THE CROWD CHEERS WILDLY!"); + } + + System.out.println("\nTHE CROWD AWARDS YOU"); + var crowdReactionScore = calculateCrowdReactionScore(gameState, bullGrade, random); + if (crowdReactionScore < 2.4) { + System.out.println("NOTHING AT ALL."); + } else if (crowdReactionScore < 4.9) { + System.out.println("ONE EAR OF THE BULL."); + } else if (crowdReactionScore < 7.4) { + System.out.println("BOTH EARS OF THE BULL!"); + System.out.println("OLE!"); + } else { + System.out.println("OLE! YOU ARE 'MUY HOMBRE'!! OLE! OLE!"); + } + + } else { + System.out.println("THE CROWD BOOS FOR TEN MINUTES. IF YOU EVER DARE TO SHOW"); + System.out.println("YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--"); + System.out.println("UNLESS THE BULL DOES FIRST."); + } + } + + private static GameState handleCapeMove(int capeMove, Random random, Scanner scanner, BullGrade bullGrade, GameState gameState) { + double m; + if (capeMove == 0) { + m = 3; + } else if (capeMove == 1) { + m = 2; + } else { + //capeMove == 2 + m = 0.5; + } + gameState.capeMovesCumulative += m; + + double f = (6 - bullGrade.getValue() + m / 10) * random.nextFloat() / ((gameState.picadoresDamage + gameState.toreadoresDamage + gameState.passNumber / 10d) * 5); + if (f >= 0.51) { + System.out.println("THE BULL HAS GORED YOU!"); + gameState = stateAfterGoring(random, scanner, gameState, bullGrade); + } + return gameState; + } + + private static GameState stateAfterGoring(Random random, Scanner scanner, GameState gameState, BullGrade bullGrade) { + GameState newGameState = gameState.newCopy(); + if (random.nextBoolean()) { + System.out.println("YOU ARE DEAD."); + newGameState.matadorStatus = MatadorStatus.DEAD; + } else { + System.out.println("YOU ARE STILL ALIVE."); + newGameState = readAndHandleForfeitDecision(random, scanner, newGameState, bullGrade); + } + return newGameState; + } + + /** + * Calculate the crowd's reaction score based on the game state plus some randomness. + * (FNC in the original code on line 1390) + */ + private static double calculateCrowdReactionScore(GameState gameState, BullGrade bullGrade, Random random) { + return calculateGameScore(gameState, bullGrade) * random.nextFloat(); + } + + /** + * Calculates the ame score based on the current state and the selected bull grade. + * (FND in the original code on line 1395) + */ + private static double calculateGameScore(GameState gameState, BullGrade bullGrade) { + return (4.5 + gameState.capeMovesCumulative / 6 - (gameState.picadoresDamage + gameState.toreadoresDamage) * 2.5 + 4 * gameState.matadorStatus.getValue() + 2 * gameState.bullStatus.getValue() - Math.pow(gameState.passNumber, 2) / 120f - bullGrade.getValue()); + } + + private static int readInt(String prompt, Scanner scanner) { + System.out.print(prompt); + while (true) { + System.out.print("? "); + String input = scanner.nextLine(); + try { + return Integer.parseInt(input); + } catch (NumberFormatException e) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); + } + } + } + + private static int readCapeMove(String initialPrompt, Scanner scanner) { + String prompt = initialPrompt; + while (true) { + int capeMove = readInt(prompt, scanner); + if (capeMove <= 0 || capeMove > 3) { + System.out.println("DON'T PANIC, YOU IDIOT! PUT DOWN A CORRECT NUMBER"); + prompt = ""; + } else { + return capeMove; + } + } + } + + private static BooleanAnswer readYesOrNo(Scanner scanner) { + while (true) { + String answer = scanner.nextLine(); + if (answer.equalsIgnoreCase("YES")) { + return BooleanAnswer.YES; + } else if (answer.equalsIgnoreCase("NO")) { + return BooleanAnswer.NO; + } else { + System.out.println("INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'."); + } + } + } + + private static void printInstructions() { + System.out.print("HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.\n"); + System.out.print("HERE IS YOUR BIG CHANCE TO KILL A BULL.\n\n"); + System.out.print("ON EACH PASS OF THE BULL, YOU MAY TRY\n"); + System.out.print("0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)\n"); + System.out.print("1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE\n"); + System.out.print("2 - ORDINARY SWIRL OF THE CAPE.\n\n"); + System.out.print("INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL\n"); + System.out.print("ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).\n"); + System.out.print("BUT IF I WERE YOU,\n"); + System.out.print("I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.\n\n"); + System.out.print("THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE\n"); + System.out.print("(POSTHUMOUSLY IF NECESSARY).\n"); + System.out.print("THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.\n\n"); + System.out.print("THE BETTER THE JOB THE PICADORES AND TOREADORES DO,\n"); + System.out.print("THE BETTER YOUR CHANCES ARE.\n\n"); + } + + private static void printHeader() { + System.out.println(" BULL"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); + } + + /** + * Random number 1 or 2 + * FNA in the original + */ + private static int randomNumber1or2(Random random) { + return (int) (random.nextFloat() * 2 + 1); + } + + private static double firstStage(String horseType, String suffix, BullGrade bullGrade, Random random) { + double b = ((3d / bullGrade.getValue()) * random.nextFloat()); + double c; + + if (b < 0.37) { + c = 0.5; + } else if (b < 0.5) { + c = 0.4; + } else if (b < 0.63) { + c = 0.3; + } else if (b < 0.87) { + c = 0.2; + } else { + c = 0.1; + } + + int t = (int) (10 * c + 0.2); + + System.out.println("THE " + horseType + suffix + " DID A " + getPerformanceRating(t) + " JOB."); + + if (t >= 4) { + if (t == 5) { + if (!horseType.equals("TOREAD")) { + System.out.println(" " + randomNumber1or2(random) + " OF THE HORSES OF THE " + horseType + suffix + " KILLED."); + } + System.out.println(" " + randomNumber1or2(random) + " OF THE " + horseType + suffix + " KILLED."); + + } else { + if (random.nextBoolean()) { + System.out.println("ONE OF THE " + horseType + " " + suffix + " WAS KILLED."); + } else { + System.out.println("NO " + horseType + " " + suffix + " WERE KILLED."); + } + } + } + + System.out.println(); + return c; + } + + public static String getPerformanceRating(int t) { + switch (t) { + case 1: + return "SUPERB"; + case 2: + return "GOOD"; + case 3: + return "FAIR"; + case 4: + return "POOR"; + default: + return "AWFUL"; + } + } + + private static GameState attemptKillBull(BullGrade bullGrade, Random random, GameState gameState, Scanner scanner) { + GameState newGameState = gameState.newCopy(); + System.out.println("\nIT IS THE MOMENT OF TRUTH.\n"); + + int h = readInt("HOW DO YOU TRY TO KILL THE BULL", scanner); + if (h == 4 || h == 5) { + var K = (6 - bullGrade.getValue()) * 10 * random.nextFloat() / ((gameState.picadoresDamage + gameState.toreadoresDamage) * 5 * gameState.passNumber); + if (h == 4) { + if (K > 0.8) { + System.out.println("THE BULL HAS GORED YOU!"); + newGameState = stateAfterGoring(random, scanner, newGameState, bullGrade); + } else { + System.out.println("YOU KILLED THE BULL!"); + newGameState.bullStatus = BullStatus.DEAD; + return newGameState;//game over + } + } else { + if (K > 0.2) { + System.out.println("THE BULL HAS GORED YOU!"); + newGameState = stateAfterGoring(random, scanner, newGameState, bullGrade); + } else { + System.out.println("YOU KILLED THE BULL!"); + newGameState.bullStatus = BullStatus.DEAD; + return newGameState;//game over + } + } + + } else { + System.out.println("YOU PANICKED. THE BULL GORED YOU."); + if (random.nextBoolean()) { + System.out.println("YOU ARE DEAD."); + newGameState.matadorStatus = MatadorStatus.DEAD; + return newGameState; + } else { + return readAndHandleForfeitDecision(random, scanner, newGameState, bullGrade); + } + + } + + return newGameState; + } + + private static GameState readAndHandleForfeitDecision(Random random, Scanner scanner, GameState gameState, BullGrade bullGrade) { + GameState newGameState = gameState.newCopy(); + + System.out.print("\nDO YOU RUN FROM THE RING? "); + BooleanAnswer yesOrNo = readYesOrNo(scanner); + if (yesOrNo == BooleanAnswer.NO) { + System.out.println("\n\nYOU ARE BRAVE. STUPID, BUT BRAVE."); + if (random.nextBoolean()) { + newGameState.matadorStatus = MatadorStatus.INJURED; + return newGameState; + } else { + System.out.println("YOU ARE GORED AGAIN!"); + return stateAfterGoring(random, scanner, newGameState, bullGrade); + } + } else { + System.out.println("COWARD"); + newGameState.matadorStatus = MatadorStatus.DEFEATED; + return newGameState; + + } + } + + private static boolean readInstructionsChoice(Scanner scan) { + System.out.print("DO YOU WANT INSTRUCTIONS? "); + + String choice = scan.nextLine(); + return !choice.equalsIgnoreCase("NO"); + } + + + private enum BooleanAnswer { + YES, NO + } + + private enum BullGrade { + SUPERB(1), + GOOD(2), + FAIR(3), + POOR(4), + AWFUL(5); + + private final int value; + + BullGrade(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static BullGrade fromValue(int value) { + for (BullGrade grade : BullGrade.values()) { + if (grade.getValue() == value) { + return grade; + } + } + throw new IllegalArgumentException("Invalid value: " + value); + } + + } + + /** + * Represents the game state. + */ + private static class GameState { + private MatadorStatus matadorStatus; //D[4] in the original + private BullStatus bullStatus; //D[5] in the original + private double picadoresDamage; //D[1] in the original + private double toreadoresDamage; //D[2] in the original + private int passNumber; //D[3] in the original + private double capeMovesCumulative; //L in the original + + public GameState() { + picadoresDamage = 0; + toreadoresDamage = 0; + passNumber = 0; + matadorStatus = MatadorStatus.ALIVE; + bullStatus = BullStatus.ALIVE; + capeMovesCumulative = 1; + } + + public GameState newCopy() { + GameState newState = new GameState(); + newState.matadorStatus = this.matadorStatus; + newState.bullStatus = this.bullStatus; + newState.picadoresDamage = this.picadoresDamage; + newState.toreadoresDamage = this.toreadoresDamage; + newState.passNumber = this.passNumber; + newState.capeMovesCumulative = this.capeMovesCumulative; + return newState; + } + } + + private enum MatadorStatus { + ALIVE(1), + INJURED(2), + DEAD(1.5), + DEFEATED(0); + + private final double value; + + MatadorStatus(double value) { + this.value = value; + } + + public double getValue() { + return value; + } + } + + private enum BullStatus { + ALIVE(1), + DEAD(2); + + private final double value; + + BullStatus(double value) { + this.value = value; + } + + public double getValue() { + return value; + } + } + +} + diff --git a/README.md b/README.md index f714bc89b..17b828ff0 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 14_Bowling | x | x | x | | | x | x | | | x | | 15_Boxing | x | x | x | | | x | x | | | x | | 16_Bug | x | x | x | | | | x | x | | x | -| 17_Bullfight | x | | x | x | | | x | | | x | +| 17_Bullfight | x | x | x | x | | | x | | | x | | 18_Bullseye | x | x | x | | | x | x | | x | x | | 19_Bunny | x | x | x | | | x | x | x | | x | | 20_Buzzword | x | x | x | | x | x | x | x | x | x | From 929308e84f66473ab8f84b8800681595597e3a77 Mon Sep 17 00:00:00 2001 From: Aldrin Misquitta Date: Sat, 16 Nov 2024 10:15:16 +0400 Subject: [PATCH 335/377] Java implementation of Horserace --- 50_Horserace/java/Horserace.java | 313 +++++++++++++++++++++++++++++++ README.md | 2 +- 2 files changed, 314 insertions(+), 1 deletion(-) create mode 100644 50_Horserace/java/Horserace.java diff --git a/50_Horserace/java/Horserace.java b/50_Horserace/java/Horserace.java new file mode 100644 index 000000000..9a5a7651b --- /dev/null +++ b/50_Horserace/java/Horserace.java @@ -0,0 +1,313 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Scanner; + +/** + * HORSERACE + *

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 DCV);< diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.exe b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.exe deleted file mode 100644 index 6314b08fa8c3c97038ce9b28c45c606b2377360a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19456 zcmeHv3wTr4mF|`;8Q}*K#7aznatxxlA%MYz7;J)sC9*|iFn$0@NMvElSQA@P^#GHm zjftRxIaRNRN!v`n-V6h6;m&Ov@|YAzo60x=^GM>5mkI5JPWm|1N$NfZOq*8sU;7*x z*@1Ls?%eO*`%MnnXRW>V+H0-7_TFnhbe!sYx>+`3OplaGF?JY`9-DZ7{A&os6Q&=X zz@8cZQt@G(`=#RgR)0hag@c>J-gc?U8wdoW(k7o2js+xtKys|9liGvLzIg=&xmHc| z*Du{O@XudcB&X9`zdj)MBmeySrMq7j@b=w55pcoo7X-X*_c_2*AKte6$AJI*wcF$` z0UmvS+3t4)JT0qmvB=l@n_5YBx+OJE#+tvF!z#X*+mxmau^B8cYl6f+1xl$(-8&u7 zEO48S0O47Tt;SVqWWk-dx2XTngeq?EDlOgUpJ%!~RuqM%hx#fuE0wrlMGCLRga%nLVr zqh7|ollBdWaM!5E2G#RaHdZnYMKwsIdj(R)V`D5iFQhVxHa4P=bUKhS9vjIEN5a%W z!YA;JkjFEafZ7C~uPq2h@)7GqBE74SG9KGUEXgSRFOKp=!B3|!cJabQ#?Ij33B#3@ zjP(*u5ASkYjl8SgYIb)ytVM2QrMh+NdHlUnE??n^sCB~;8g?m5?hMAbJfIv+rBcqa zle{ZxmE7_PF2BZQW6JVwF^c0alzQ&JcSJbk+v*@n;_^8zAA>D#K!|C5k|*k*G><2^ z(KInDWeG?myBGDPQMF;8yw(Vt-zVie&vKLVSf+Hcf1}k%=1Sn&Donh>yL9r~Jl+GV zra|zfUR|`{Xb~F0R{Pt7`yKp{M(zMy3rm7lQF zqynFv%)3LYBKM4z2K(agah`xvm1FQ5Pgv$GKrKPoe-k8+@y|cOi`VeaY8U}EZ;_9? zvNJt3rhe?&^(UzHgCDIA`%2I+KSW8&^4ACg8EqvLTA!p^qucvwD;c8W|AzK{Za$e# z4tV;;kGA(k^v^Zgdp`_;<{!-@HKW=q?3Gs8kcpc8Z+OSj81aP?5Iw3aUXiM z#Fdf=^lJVsJDIZFLq3rEQWh_e;|^=7?zzdRaKi9Ll^R}5(;cL>;CvcTQeQUy8I`H;1g z#eR)S_mY4B3d@q2(}2dendVv%4e}Z;8x~f=gt8YnrYq<2Z)D44*bf1_N%~w>)8m8} zYnmkG_AJ41kf?bYb%s)`Qol;nfBj=Bm2Q6*5q<^&Pt;qjTrSv!H6&$Oinr{rT6ZR6 zW~lodaXk+%qE#3kUBTGH$95(=o=;hf=skJ(@aC45mdn5H`9qd`s^{YL>{k={d$Lc? zxstLd(@;LJ{oQP||MTNgr{kwTO!c zj@{f@es?UtvqR^M<#cvr)kO_c&c{#dcAk%BAJ4(~wZN`svI*6~r95>E(~@uh1Fibu zsXTscHkVz)d=A7Vhk1N>`j&Ai%MYRYj53Jb4yon5?2Ph=$ZWK>aye=ZVGPz#Xv~PO zGP-Uq4T1r+YX{M_4*8h9N11NV?oSl%$v!*hZLAYunWc4YU%c|R;$!6kEY(PQbVJu#VWOSG&K*@ zj2M@WpKFU~jUo@;%H{FoM9qUmZrKjE9h>c%)5jBp4o}}&?2`MG?;7B}6IJRuaH6V+ zy7zcCx`7rk#G9Kbm}>L4%~~WDOq#?tOyc%()Kw>OIhQY%ouv?20{!tg`c+4_aBYFl9N1 zdb}c36e-}cjabGJi<1^ViLeSTzab)X%JMj|#)nhU^=c`GY$=ydD>v&&DFX26RE<$9 zn)c)!Agbmrrg~VnF^0-%4Ba94H(EDvxy{;01F046uz7lwpTX_jw4Ok;<_degy}`cD zuEn*tX}f{lM@iWwL_4c z?s8bmcO*?aigaYuIAZ77uh3+(r7Te}bR+yL5Bxcma?6T3>>&vKE*25FkJgb~uB{^} z^GMgyzT|U7<}loleSAc;TaGR%;fJxP)AMlk&P!h~xGRRj*>372_Y$76n4uH&=mdB+ zmiIi&V$`(32OXwolP=j=wBnN9#u5GHyUbj!E8-QWBGWO(biAty1gOPuB(08JdgF12 zQO5@Jou+5|sAs+jVfOFqgpXXQm(%T46+eNMc5o-WZ-pk|#Afo~Llj?BznpL^DWM_c z+>wf9$6wA$)3aZ3mL=skQaNtoXdaq!h0l2rYZ!)}&h*GFaFDyJ+1lt% z_;fD$b+@|1{A>}ApEB`^*S1b~$!KUVfAu1w8GOBU!m5OR0mojiqMw^q48SkE>mdxj zc#n>sNRld$`}p=NA{HX<+Gq2M9@7_(qUAIeo}iI}Uf;qK9kY4-mlt@~ox_6@X?*1> zd&Dpr#*9k2yIRa{`9yAQ-ZRyx~?g+&|#YG~pvM5{8@Le(I4f-KAr?Xs$RTC~wlRp~)xCB5E7O5lEQ|1wO#ANhP)M}3oqGrVGJsp zkl8&T7aU*67}jmmj+r3rJQ-Vc!tex0$e_)ZT^Jo`kRL$FhYB<>_izej7tg5-cd85} z#PIW6+Jk=_bxH;tOXB73>H=!t$7^IE%o%O{m}%Q zx>a-oP>j3{gm>eur zI@HYgvXe?X(7|8rPLKTbJn3Afkb3!CY%{ui>t87+#i)yxU<+YIH=jkR(k`qO2ZOgM zf1hgoJm@HEF$E3(G>KZ+m-?OQVZ%Rw0rB7;0Vqol*{1=H8$OS>?hwx2H2IFeU)aaP zEa4OE#Ci@_-@{nT62q)_5EwdmQ^5ux7;+W@*{8NIq5Hp>=Wrf6t7VD3C|2*DbIkPp zwT0Nh74hs>P2acY@I-#6JCT2icNJP)6|Y8%3Zik@(;yuz4`btM@#g1cn!9qcW3 zo>l!6$DZo*#__+l{NsFTGPOhH>0I{r zps?NNqWT?YWBJOTVIl_kWq@>pNBWP)mpuq(#G!MsamrLUoWk8}@OCrEiU9=D#Z3-e zz8q7vXyb-fSblk6O7ikRO3d=!GsoaS)dt9;qwwuG#v)>3{Q;7)NFv*JbiAI?Sd#9= zwTGT)*m%Je@0B0HMh1LJff$nGj=*I0(q~}J_sE+6fgHyvupGVk73$0c;qfE|eHyvg z&VGSFm*Lm*R8AZ4-=XRW!%0v`?FmCKFdD2U3@>TeVYHI*2a*&^UZk2Q^g7afl`a>| znhScDTQ8-FxRWR-N)u7hZH9#@Oe-|394nzsz1*_F6Di9(v|`9l4?}1f?zED$S8U|+ z%h-pbskD|X;qhi`IV^C~xd^3hgihLzy0Jim7@|xGVh}>8l(KvPfvFSmRMtaJLZ3~$ z3*&LG86pg{3*lYj!szEFLbVGNxR{HLxN?>{FJXBL2V|A-Fs8tni^YgHTAY>|xcnX} zNbqXOtzdg@;l6j~{@om46}_=2kNb*HwHkYiuxOkUn{B5#Whq2XPVxnWn^infEvb1U z<((3$Vb#4L@iO3LPBSm-;YVN)9!Q^wOxaac7f#68Y0_apl_Wif*8>n%(6 zo;ghY37;QkHUZHc)rj*LT>-2LXU-hb_0s*43p90o@(fZx8Li4Mpc6jA1=H1$ z0V5L%70}oqnS@9*@m?09clHTgZfgzi+DU525J9vbevGt=xwCT@+1U+ixvbW}-l`Gz z2sIY0$bj|a-jwAQ$i)7cW*y|=nt>;rL#9XJ5nK?FQWq)3Shb}rD}iG3k&h5%Oz>>w zd72pVH>~||7T^8?`Ru;lGZ&YOWk~EHNI*Y=xtI(`)aYxB&Btc5l4tj6@m9JTZ!Pg7 zJ7Cs?E&1^yG_RQHE9qbgVZ~XzE%ORhZhssXc6ID8AUcYIdefw|j^aWyFdaE<< zRg7u9d1(R3XDU8C#aj(XnXBvc{Y&7A;;DB5voLpJ;r@zfsg(>b~fZvq`02O7oQ!?cHVB={dIh93Gf znGHi6@_8~OZHDRSyW=Cd&b%Jf{W_|gFg!C`4c(5ef+vBRj{dUH6#p9%)K%~e5S~N$ zVqMd|qLxjGYy-#CNCe__{k-R2B%aq#zd&FFIIPl)-le^<^|E0zxZ{1s6NYs_Xv%gO z>VerW^-8!K?2}FymLZD)i-HPZhr!kFm^t967>HpoK$7)B<%L*5ykIIyZC%qQ0Z<2* zVB}zvM%PSc58~7kLlH_aOvO1VHEWWQJpB4NdS4RnqR-BhE$JmAiLl{fXdXTIuc>Rlxl;=-fK zj4dvJ@sdNAZHnfZo&}6w7;{%n7WXrWx|Z| zS-XXQ(xp7Hy9CX?_)oR!ryoy7~Kl}+7XID#Q z2-KCG++L3ANzgVNq}Z_Je+3@Hfrx@0?h4@REODAg z{6oP}>`PF3S~*V*k*5t7J%+cemz!B1<@tiekf z|JxcouED1?_^1XuG}x@cRT`|+8)f$|j!N!#;{pCAV_$3Xl(qM@O^%{I$ zt9MGP_f-u(sKF1la#b3Rk}efHq`|LiFr>i^8oWb;Khxko&HhKUd|F<~nEaPksU@8n ztaPjSH}6WuYea#y3@iX}+2<`9du}Zwy^OL;Z{;4To+~^X56D zVOs8MT6sE;-xh7OlfhX^h3Ntf+NP=WVGWKc{)^epa@>nK56kr{lNfZ2d~4|5O^RE+!~O49ZkNF$|`IZ^}}KBHYwoS zDz*6no1?8%5Q&EUfz47h7?j$Afz6Egn!J%{y1{Ga-8Ju4iLa?~N_Vemkht9;t!!9b zoJ-{rlD*1#x8!J`ca^=?A>C=Oc2Z$gtPLt)Vo&SDM{69YHM9}^=sCz zzExW7TraJ1*48=i&dtpwA#+tBt~#m4ZNJ;;kX);!dhV1~u5r89tf%_b_SLJMwUSWH zsL0{8yFn;XRXA%uBPexJ{rWY+m^x`CBufo7xvJ@~#=crwQ&aC+1KDe&70!BTO|7(g zO}#)J&Kl=x2Q-leaIEJ}XsJ!Jkc^d1r(0Mh+PdE5cEcm-Ywbhw4+l>?snFxKKTq}r0vq`t*mvyhqp>A&>|AO!i|0w zHmtWhs1d8|RU#s+ZGfL3`7ZdI6riKntY&;7cAar8jL3Lha}sBi|3^_{jXM9v*6&`Z z()Vg`Y&jFbvNH9VQ7`kko($5RelqKmJ(&-` zj-Ku@dTiIR^?LS`?aCNkq?g7@e+E6>Mk*s)NH5l~k35-t@B3N#f)v9 z!PvVP++B ze`nWEW>kOcx$SSAd;9Hwp|(^l-PjQEg(Dm7n>XVN*2u<4Fcxm|Z4CQD$atH4+nQr| zZR}XQXk)Ff&F78yu2S(4?Iy^e2WE*xGI10rX=zi- zX2?L^NcpPTdh3QNJMr|7p%HOlG)?ScFN~($Lv@u=G?$P!G=@gR;W4x-s*E3uuiD}g z@{FTsHA0?wG)?dojiS{HJ_$6qQ)^qj;41~K#sHf3y)?zJDEUa_tzj|)v7EJ0J(ad4 z*cNRkhf+N5#6-~O4?g%{^Cq~EUBHJl!tQXi$?CET-O4E1Jwo?TCaqrO8y-bd`Pg!; z-#XN9u)87At%F{Xw{}3K_#XYofLhmtvpEZ7rqgn-L&V1p@|nv{RPRqP$~5Hp<4MHc>NlQ*|1pWnyL2E3sdl3*gpxbX>9%8Vz6fA zTVQq~H6Vb1GDLzaF=J~>X8n?-G}(d8Og?uwitePeb_Rw-k} z&K%~9=CO%C(=)>h`Kc_ocspH))F3 zq<;ouR1ZUjy&_>hUW}hC;SqwmEFH_jxYUi;vGJP#je2Gb>qFU%7#jt8R9KO}PrGouL(I7gFYvjf@1^waSQ(>hWvTqq4L<NVgNmveDwDRW1sZiD3h;~1dMso_V{b&id-NV=$y5*ibebLQr!AYLkSX4T%xvh=nlE+ik(XkSL*y`inKy#Zfj6LrRP*Ke@atrHe z_My*$+pr%RThbH^ZDVYvMvwZ!?fwAz2|Ij9_C!LyCVvYCY^y4qb`GSlzBL@&>b!c% zI|bZLv2fTIh+fsore2HcX$l6!UwPia+I{U97mTf|s%=3gVZbOqjfuKLo5(EhQqOmYep=dp(bsH|LTiImRE@nIJVLcIFtEa`^MwNUW zKDL4=QI9ti^3W`0qc0t*0lgrYcFG-ux~Ts7Fr%{Meu6&hyhA&@L<3|m2lZ6 zZ_@*+|3sTrR&^+oT=EvY>Jdg@ERhYOv&g1Jqx=y>(1FmXcT*e6Dl_zJCDixgH-=Ba zN{k293i!Jv>_d&sjGUs5W^c$pw>>g>Pe*aQp|6d$Re3`g!@eqQmi?G$?qKkN zSZJl@FJ~Yc#+-kbO4j+q(U`ZbApqB4Y9$Q~0d=Z3kIe3sVz}e)ebR^Y5%?R1wdRHIQPMXx4`ou54a`5s80tB%&t)@4%nh zlmfQ_T5x$rdg&7FVI<<|1We%Kp%r*HVB}`pBN81jeFsJGHC%b!YE$7k;2b!?caWNa z)0LPWmt#@jbV;@d=`rARkN+qV={f}XGSVT?>0Un{pIZ|hzxlJ}8jkM>*d-0ew*-v- zrkUDBuvo*bfb{+ z(~tprC13)H=z9VGh(vw#Az=Az6(<8RCAQ?%zMJ8(oWXmCHNY+oUb{r3;_4EStSxUg>Pf7ibDL<7<>AUvTGcn` z9JjEA)$*W(eV>g%i?6vR?B9YN&t_j_q%gDC*@3FGZFc*%_}cI-4&KXVdn2yEmf!=v z@N6mOw>Q!DZQ1M=Z(GDSTbe&2r*i)FwN%a@WmDz+k;b8V<@~hYkojnLe3XJttpT-r z-(&ms?mM{e(7xop{(S@chV~8bE8Sndzh?i2{f+xu_lNd(?C;#aYyaN;2lpS^-|_9v yZ}0l{@VCteiVo~OaQHy-K;MD>0|N&j2*L^h_}*Y_+-QxE}rUlGLuO0$5d^rAEYJGv~ez)E#@L9l{dqsHD_EV0KLyHOK+ zud&2}y+jkSMPvJZ=gthQ#FBse-v9ePGY^+DbLZT1&;8wV&n z{F*dTghdA`S~hidE?2g?e>8`~n&V_3=MZv@DT3q9@I?AAAs`_jAs`_jAs`_jAs`_j zAs`_jAs`_jAs`{}zXXAo!kqrE>OOui9TEZ(0ulle0ulle0ulle0ulle0ulle0ulle z0{=G<;9mdVD2G%E2>}TK2>}TK2>}TK2>}TK2>}TK2>}TK2>}U#Pa|M)*hSWg9{yvW zKMNqlP1^$Azn9}be_fh-awe5HF5ieT6#rAkcZ>KhUh70|I$ zNK}A7S42Fg*%vVN~jVKyb-D^HTSGA=l40G{UcgD4Suz z%AjQS@BvnQd<%Ej2_H}P0Sx*0z^I5YWvB2kpK#b4kG~-%$`9`=qXJ@lLc*0kk&*rp zVK@`9AX_Px>BlgLh>ij9QLq@nE)@pl2=Iw%uZ#)q6y8C}Kq9O;V}@_2Pjob^2T?X3 z9|?P+CP8(`6*c&Hn~Mzd=NlSM(7K)!_4+uUPN|HFi3#ybQ|WZU8nsrXO-RWr-B`cC z#NqxUM?w{j;NZ3|c zPG)V)errVMM%Jc+e;CBcZOf5=z%|EZmGUo7is+sl?wE5K+39|n8G03RP4rdikTuS-EA%Ltd#a;_D%pa~!)@PPiBNQ9CKgPp?VLQ)<=8N_|PLC2=Kr8|G0_$is&6 zFqU!MWxRjqIRB97$WWhdei7k;AwkM$KcDc>knjLyL=?4`@F29u=*R%Skid{)Uo87# zn#ib#ps0Z8XtcLtpYo-A;KBosf zGD0J|d`t$H|NcwL2S!Bs1t>c~A2(N4w^>5nRt4@Ez?y8C>YL-#%5+t-CIPsJaYl$s zh)>HBZJzjyDK3jE<}syfZCZjMk2&K}X;TultPN4RvWQF9WT?{8GC$z8qk=BPo-W(H7|%^66YfS=4B~5QjW7)P1?4&hUe#f*-61{x4J> z?+U-bgw|Zt7VWYEdk@Ij;D8)fNO2&m4LVSa_$U2QiOW;*F?|a8FhX z_ms*UHTs`4e;R@!p8Qi5bR-{G6YYfjo)KqcR9lcs`pdX~-0%G(Sk^&aB9?7Y2dwYs zvNJRp8ofr9rs=0nWMelOR~)0sNEXL5#c|+zQWOrmBmAlVwPWSQfLpK3Q0X-}XjOWZ zR-c_kRL{DLF78U@CmG1z#QLmjfQRE3>a*3~sLxgqzD+2rjB6j^tBmk%PXosAfEZgdLi{nJC4S@2%Jz@;i&Vz=1o2p!eU`Vg zPiTlgKLG*G)Q?&K6Pl-V2j-X)G0f{D?sFQl2@K!bzsN@T8`>wTwCKBH`-q8D(zwzW z!$4(ZR7gZrNK7|na7YkeZW;H{`i0tuWS@L*%^cG?8kF=$R$U|&PR7VYjI->CtwTmXW77uG^^LOT?rouSo z13L|g_^6rw#YRi>MaRHCeK3IyPWH4 z>J>!24W+6nq#9A2stRIAMtKX4E5mpch$)B6+!4#?W&f8{^$-&Tp2OhbB{xP4Y1pNg zn94zjS?wlDcKVAPH-YCEc=)^wV|aaBz%v@6M;GVSN|18`F?`uQ1UXN9MLC8syoT+B zR3&BiN6c+V{-uqWDiAR(jX3TxB=fm<_)Dr##862)mKDn$`xl-##NN5Sk6o#Ri$7t_iuz$ONvvi5O}nx3%(Sqg_tqL zsdgCf@cQgS%n9hc9(kEC4NoJc0h)O{VtF}d5YrDan3D?S`dN_Eqge7;#H<0&5b*G| zb3x$g2YvXwE+K~UI$E69Wr1fvvHjdd4CSt2xtHZk2uzN=AX)Mg+$B60uu}gi+;vJ& zICXESaLUL`%S_HxICXJH=&Epva7EA|W*4ow67c-|I})jbU%3(P@*2zj{S(%hMZ(%>nfNs}}TIdpnLqbz4! z86a@fx~>9;rl70@`V_5Nl^Cr`QiovZgEI7Wb8q1ey-`vsXe%mdUl(`R7E~rscc4U+ zbRpV`bO!aHGPtkmi}F)~mIc>}ZG`!V{Z2QzkJ0rmI-< zsD7>pb}<}-1l~>!V`LbU%PX63)H4}|X1L}p=M~PvkoHet#(Rd>h*^S|YQ-(cFotix zhB17uMmBt^I!Hyi%9wqYL2MLY56=u#XC$awxC^;jAfD{?`{Fz-5ktQTs{s4v^DvZX z!u|H2wQ1g@V$VCo0YKbUXQ~^~vb|70-vW)cprsnXKW^y%R>OqprfYOM zOa{=rn1$9B?4Xul2a%bY4A`__4qVa4t&{quCq*y*U1g+3`(N9b|B6|4Ou%UsZ4g5L z1WY9dau=0m+4Z}w@M6Bco?sQh#XYVaVyHE3D{f8o5ktKW^+Ul+cx*fICig zO%55j#P3N_@BQpzDXD9GBh5qR8v?>%&0g-UUT$*vlif#4pxA}XRW$KhEs*J=m zOr3$5n8pG+wri(U27a)Pz^`d`^Xb~PJGZjMf>W)QpD-!W#l=t;S^@g`Y4U}!A?0U5 zuIJw>TZt~pzFJil%Ei|KUsqm`j}A0fqvs0y4YQ6-aX7~;%>(h|e^Q~dIVZN|Hi(6x zq@_WV6fUf8je~LBVwRO?+tyH90lA^`M?UYq>wJnhZb7$Q+(%I9()o3}oBNvXN_Dtm zTa1=3%@~A$3LG^Vj*8DbFtl{_G#?b0lHBwRSuzA5^eoUQpnmxoBR@QiS=+S#~2~U84Wnj z0#8ABE9ycR89EOQ83`U9U?r9G>@1|J`hlKNC8>CR=6G~UH5Np*34GfTeTo6EHi@?Y z14bSVrI5?d&f<7Rg&3MKH3LRwY$P9#n3h;LNM_!VbW0LaZDS>(7&T)0fd}iMNJBBH zh+$q9F(o*sAy%0T+Yy()RNCYmWjZ}E@$zicr9t0wuUP3bz_%UpXzo&;$?Jodil!Vl z0Ku%db&Vi->9BCMR?FoMdNcg_ktH=z({}K2H({-J5E3#ok~GQWmnkzYchZ7y#}(FI z&hi)D9KW41(P7S{dL33^Rt1{d|`?{+=oT^ zc35!=F0mhep{hyHX6iDN^ooX2jTCr)QwNblq7niU0ulle0ulle0ulle0ulle0ulle z0ulle0{^`T(EPuf0bSp8=8q%NW{jd)3ajJGE(~o z__+l7xAJ#)@@ekt;pE=jrKOW^K#M>pcOM_W=I;Ihfp~G)z^3~2EXby{1arJg>Pu@0 zex30`|7ec;j>CIR68a``e^Ex4nT;1w#A?-9&Kf~pnVybUuE!v6mR&)97C{y&xQ{=YB1a*w?bPpeK-t90s; z7x6XCjPK2P;=O;eL?gWSuY&OH0Fi#Ueh`tR*Q9IuX)=-(cpG09-r1++YIBx00TnoI z0zNuu#Od^jo}S7;RjOL4N=wU3pl=a|+BCN1xZa#K`)424AjtCWCaT3>oWDZ={nxFH5aV zQlYkaoH`*%)iQ*`O{PPqVjbdG-U1$BYQ2h;gA5~|@%QIyaj`6o4N~)Y%2}FvBpeuO z`l;Fd&d8$|OEXuv7WsQYw=kO>;9iT5VYmT8ThxPSxf$6(7Jb|kI;wTq zX@n!`7z``|7#7waCUt51@=lOH}H_dZhNa zjOpI27~jk6+LqPVDCF;rd;}~C8u3_|eh!NrEPX`*8yUyTvns|$EO#8_wk7?IEz1;) z;L9drb`tm631wSt;lzxD^8A#Iv}bLu#6~)^>sqXy6Cvv;f@mWJ-}8A9mLf*p$g4JI zYaI!^#G|2j!dXWWbiKF~)EQrwR3}ttq(9Yx4}vd(9|GBvKSBTk;TDJxgb<7ng3um; z+69%5bRxT?_F&7I*t}-garU9%uFU1wayB;k$dmkOgpBv66gLWSz39_&Sr`t-25%-SBu z#e$EnZwuGoLO;4T<@M*v*5a@03)kOP;;&l?*X!%@*ZqX+G(q0eQr9h5J#yS@fj>&P zru>cI4f}EBnN`O?4>~M)!in$diL60>FhA~J@7NqXJ>y*PFA<%cy*p(i`f(t{@UrCs zY{Jo=2wOg1GiFnQN~OsVRQU&GAfHV~=`zIrXUf3r>vLt`^Zm!lKyCeFWk~tYl);7a z`dk_KeE+dB)D$Y9HDtrwI9A!9`hR;F5>)zx6#M2v84Slv;`nAb%hUF=W#sj8XSSw* zEb$PU1TL+at^EN1Qo!VKN+q9lyLR^Nn)`QZXKygP^Y-^fYw`B(+|IsubcZ+>Z$7%4 zk57OP?!~Kgngpc=13a}V-TMQ5Xo#7u#d|~)U zd?Dig;tN^a-|&Ut`=~EO{3m_kbRJ9Qo5&YE5XRWX75N&V@gdm{(eE)<%V)leA7k_A z@j(0&qil@wqtrs}sFlgu%)ZL_JTKnM{mY`WvUMrScvV6wxja|=^GZ{t$0w?kE^Qsj zPQ)>OFdLuiQ#3kigZ$W@FJpbwm5)s*%Dse@*;Cd;CPy5`PryUQc`1Fg$vUNTTb8aH z`1o{nSUMU*&u8hpWzHC#e{AeR^2yhZXM7!HeljEUZN+1paCKi;c$O*wFDysAj}6To zW-#6$*FdfYW#t)P2&-o$@nwl~ z6q?WYFnLC-Y+;Zez^?llrlB!daT?Msmhm(K59uo7Cb4U8*iTh94pYDS~M~(D{sigl161sDr_qiO*P`Ki0zD)LdQ$BhUI! z%h=qs95|Phj6Gw(XHYM`n3SgSsPc0t8arFFvK|Eb>rvL?I*in7l?j;{dX**v6I~qQ zSi3IcufXaxxES9gt`66V>xr7A{-6av)`bi{9o0)ymd^Aq^+MxOt~|%RLFh!~GO{$! zpIK6dD3sT5K0z2XL|ifN){pawV|=Q+m*7|NvgNHT8(P{SPj|#ULx>mSEi5e@fToeD zxuq5Kr*hDk9d!$P;qjt**Irhym1HKevdpH0aebIdmr7GpV93vn4>CS$SvRaJr{HcxGy#-8Bu&C{#l zVfcEaIe!YPM^{#lR2IJdnld}C3cS3LM=a@4R-XT-X?3|dKW8axDz`K(2RUD|F={)5 zSRNG_UhRw9qctaomoT(vcuA!$MUzAgkL;7$@^F^6oNz7bXZ8V}wFNv!K~FX5N;Y?y z&4x`d<>KoE@xu_3=)QvPm(+<^AA50+PcJX1XVDO1OpK{M$0B~WLD~XP|AVM@T- z2-SrKp*I5QO64ItBYTNMNJOAHQfCCRFR~#e0{J3pGt@rF-_ZQ%8pGBa^P?6mC`%d> zM1oRZ6d~jLqS}a~d(yZ)l!oq8d2pYVhvr2oh|5BVkQw$*9yYvvahwHgocj6p zLO-8Ei%2-iq0Y%xiEg5P9+MAoEe(r=v^1mEd-1Div{qxVRK{@ahq)1O#g{{P8zTGT zWi&wf_-Yl)) zFG9#y5D)d!Cz<@6+&YwxJ}|6?9i4?EgDcO zF@?^>dIYKxST`z^mE#_;a@6CfwSB7meFZ)BT4$ys^+E4hI`XHqo+IOIna+{uHJwaHmJs^+TSZ85gPwN77(6ECJh-HVf;au!ofSz35vENo<1PEJ06%Bmni!U6LZ4n^0AI4g_x4sk3kwM()U z(pl`os9jR~CcV)94D|A_F@|HIw0Ds&-&U-_1>Il|bQofG3YaZmWf13`z)Y)Eua!OKI~EL@Y_~(pZvirLo-0^!h877itoc99NeooC5STu#9B<{~j!oZ^Xxo{miG^l;Q(?C@sk)e8?6J@gW;(E3`Xv zl#vcY8*+e;p1^Fbq}&NAou0QFI^%664IZwvt;}TUN^FIf!`sR*#{XAanZweQ*b1M9 zx0TDlVGjDFf5uim*5*j((sn|6m9~?OOs5h%5%D@G;ALnhjewW;KYp&u~L2NnISIyXU$N6(oVo}R_0xXt{m zhPC$({p@I#wo$R4&1ctqoo6wAWrRNE!#Vv}##2(~d>TtOZc^Z$c$D^|VtXe&O4lRh zg?co|%fn_d1Oet^-}#+j_iO-;C)U>kP5wk{POS!pe zElWJSp}FH01=d0k0*KcVyq3mhW1dpRM%98;{3W7&IxClFAQe+ z(R{&`hE~i^ID;C_qiIZ<%lJy>zMF*h5^7JWIFyw?sI&S7e%Tv?RMBtXbCG?r)wIsZ zPkym61ruScEbG+#=8;5ok_wN}m5JCEqgVfhsjZ@|r{|!5gB0jS?dBx(Gwh$3zh(N$ zncW-1c%C89d<#v&f_x3t!Dsv}8_S7f5OJ<1`drFS^htzeB+HBA=-DUv;2Z(VQT2HY z2~uMOa>>D%_gEWX$$JjrY0Kvx7!YR4Xmy5Oo5zp_f`*rr6Pp7;erYWD{H$0z`qXpw zdQ7L1=j_ecHNO`l5(RKaS?HNIEkx0rO~kJuW&D@J`Gc`Ar4#*mAoMfDu8Dx1_}o{V zC&V`3g`&%42jy7-eWo+olxT;=lLKH;d=9>k%@fEb__S8cCdQ&X=E!3>bhDsRS(Gg< z6Q5)0{~wO;DV=B!hU0s(hqg>dj{6lnhU55P2VSOOna+N!Or=KbV)05vvvQUm$CoZ= z9Lo6kpD3qj`&7JsFb;L#K`s2r&toqo1lj^SYc(ZhwLV@F6 zgnvif8IGSmRvu5GEgu!i(+pKeZMiYRS18X(qY`_>GZ0mp8nwlru=>dXPwDo^r!hy5 z@Znl3ZyofXw>7cNkPO2%Q^@kq5ttk`zvH?t%hTtzv+K; z%>AH%{0YgX`fBkJpTp;2#pcr|f!)DI{Jt1$V`_%hhMi&5em=eL=PA>%#2>w9*StT9 zg{-{@rTx+0@kydxi+glLjHwKU7{6xuVcdXtYQs^29n@?>rN(|B1X|Z?j!*?{xDfOs zeko1|lTc|DtS6)mo{4IVGqV%0*TmtIeu|gH@3W%kThEy6rVLAa)ahOXvVBXlvX=6) zK(nk#vF}oVS3Jzc6Rh1&#JN~@!!}K0gVO%%E#i=EvH$8Nl)a%NB5@d&{ldq}UdmD7 zY4hh`U^sltj};;>8Ac*B-YkuS0`+hd;h(|57HbP~$QE%JA^11KqO^Z2jfH3j_B5fw zVTgq@+G!!;4DEpTZ(lC|$9x_y>*M8jL|q(3_-D#*Xa^$=%3j(ReyZ#>o1&0749i}C zxn&{Z#IhGpD8Eqobh(=f_Ro>? z$8ipU+WvloTbNsTo3e8IYgK*y=)nh-=^zHqGLBs``=v7Rd^8i_?KzC4`-w}%Gu#4% z=?JS4s^b|0`Nwh4v2^(KoPq0#X>oCxDE|nVn7@Y&pBJ9Jfr-jU`(3Gx(>3|G#zGmh z$f4mFggymLo6)-{<8Cw<)NN#%Dv$Z?BdmNH9Yw&e6_=6ctIMwG`O|flu8R@PlkPzd zo(`(fNoq+m9j?UZOoSO*pyhnkL}~s+<%vRPE5j2cYxKIrOMMyj8_zL^H|Ovb`mD?h zda6l#s%bt5cg<}Ccrwmgh?B9nx~#mlm<;O5TVQTzjQVVaMo-UFY0txYJd{!(RIvy$ ztu3!+F$hoX%gBvN{#%+EiE~$~7wT_l?o4u0Am?k6VD7Y+j#&A5Ck@O=wbIhR=(hOA*gQgeKszG%MInam#Rh z55dtOZU?S!Avg(fl(%6h*29J4I#PZ{mL3JS`E|)>NcRx&9ZJPpBJLhSD8(C>@Y^FU z3n7e;w<~zV%ke^78bUb5m$j@s1a&FuK)6x5TL=*>A9=xTC}E4bBU|VLTQM9r(X+f2 ztX^$d{g1anC4OYT_729=n%N&c?-T1?%vYphy=`>kIC@ZnteuB6u{41?u=_BZXE<4l zd;GeJd`J`Q-DqrTX+qsUVQ1}%xg0_OrNvsx5ZoZyB$w{3LRw)h#bJoMr3u*_+3ly+ zQl2rrt(o4mmQs`1E5DW!3VF*QPgqMC(h|znD1%iRlbY~DpWc5#{U+h|2b0bFQu0G< z*mZC*Mq*z4`jUtlzjwbL^#0gh4P&NXmA~jq<(~t67eimR=3*=#;%$*=TGP_n>~m`^ zqOKN9t}&BKy5g}g@|PFejaYv~+oJ3=FBIDswPQLLsTlt;>I%MMpJNo3nW4^Od6HQL zFnr3g@p&Y!#iL|A#XsB4!8iil9xEs9gUCT3A3*t&O;P(cT(hBeO|~A1Kz1Xp-%$Ib z_Dt(I;ywvSoHs?Fw&R3AZ7~!f41t~z2P0qc8F5>N5v}=nkom$sZEWH|$wx=XN_;du z`&A&G{BVTqLqAM?A^BGFy%93r2a_DKTk^FLvJziQ{YNnK%NUCy54zS0*JA%Nsnm5P zren!^lc(?;IG8=vhA%@tbeQpkQwYyMsedW;s2An?cwZtupH)BxpWdvbj*I&helItb zRpb%-6FikS=udb)D!<70>GdL3-LO$pE>P%4PYUHCT>u3~l=hkA!=`22D7I-t8I!^` zc+%s}QbXqAc0B;~P5DxN|MlSa-Y@G!>YBNdA$7uM28N z=D15T#Q7xYB(7`S6LcaTI>_G7K{3FBJa;RVZ0!JmBx*91S=dgkPf}*Ghcvn`=1spD zB!6uUp>pgkHHRGG}GtxEHV^ zx~54Ys-FD@h_Dmq0TWsy5=SQlxG63S;SSO$K!F`!Yd9yrG6@x127Bu=wdrgF0^i4q zytK#1k3A;Awf z=|WgX;tpYe=XC~h(SINwqPaf=tdoW7B3u*J&v5OHbSmt@QpktwJes?6Wu>-_eU>(E z6{o1-wqnz*bVZ*jhaXRF@T`BMuQ_fX0?bxA@orC51SM#RznDb_^AHW^Q z_->iqA7is9J7WFz&{waVmKiM=-SRu5@x#8|{EfxQ)~hmmU~Pu+T{YXb_|NWZUfbp< zPaU6K!*a9d!FlbKW6q_nTalbmbJA^&>kgn4@`U~MmN^s|?dm9-_05aT{;SUpJ(l#y zKG*1e>z+G$_qztnRx`e13lh5>Zk1A%JKk$XmRC}AsD7Dzg}TYv9ZlTLt^_;^#Gb@z zB(L`Jg*O{#KAEvP&sb%7z`Eh#l;jp`2}&kYzVxW&N1>J5r)3>hol?Ka`zfY|7bdj?!$F0QLg+i{d2>J2%)2RoRH=X-u>tO@-+pceU z?fHR5wdPN#<*{+eZOr@YR3yInx5_LWtUCVm@btrl4=Wd1)cfs(^}e^$nxyw_RCFi( z>j(Hf92&erKFvMh`0`lKtfm<+*T$MeEIP0uXM4TvL!FoWGO=;D;gxsb88|D)GyX<#*MM652M1&iMK}*j9J6joTa)`pey_ zv9)(K-8ucLmvW`@mh;)e14;ZK_nyd~xb?HwUbbt=aZefF_1-tun@tFtH+#;Bxp4eP7ljE%yBbQg-djvil ziyR7hRIOJJ{Hu5NtUK|YOxw(T?uoiX`ssgf+Sl~jt-A9@_QwEXD&t!lW&ENbtXBU4 zOB-#h!C7~V=2VXhs%o~V;qE!VShUY* zy(`1jrm%dwAIx6gg^xp-74ka^#+*IS>s98tKi|A}^A6s7R8@Xvd5=B4%yxSgg~j!O z{jFf_$a%8onypXYWVO0j_tbUUR`;FzUR`|M;qj6c16;n>RrO7UA7}E+?=Jn-!gA2g z^SA$;KTG|h!Ski{H;syHyeIc?vYTJSEi*W7A>)gQIFk@w`TG3d#y9HSXx1vD{bA?) zSJ!@Z`PDS1wlhtSyW@A6%x}bp?btiu+Ti$B6+*TxNSpC^c;ukbwXIGqycf18MfOrV zp5q!}Axt5ET|>7rvZB|M)-#gUFZm{HY1E{?0sGdO46pWmO23_zE&`WWV5pGaYPqCl z;oF)mPsRWA)2kX4MjYE*tJadWmPe!eZ{FAHhi`zLxq|q{TU4Igqs4~T9iEyPZyk1M z+u2QsKwE_*>)nd%b*= z9!pVY+ZkVB?%m6Q2d38D`t9lYoud;n5;{b0c~Rwlm7RZ-TR!ix#XgR!R+sWEziVW) zqe<%|jrX_FaZiH3?vc9wjx3?6>w=4u>kcd9()Tl2!sl9rfq>om$>g?+>d* zsW~-_QWJCL6&cRxM=>OT29!*%=pTdndqC4 zFxMvM+wdoauUI8Txi%uj@YRer&nw z?Md@mbq40IX>{|CxK%%N+B6MwS0?Y`uO|~8+qXGo_t0%ZW!0(gszi5NyPZN8Urt;FtIhcur$uSV?m{tXsg zk8D1n{<|f$Q6HA9yz!%x>DL*IrTl<>cD`WBdImUN4Hujpmch;5T+YU}DclPMCpW0Z}ef#>L zec80K#d+}@&{QWje zSQPRy?PkULs9N7m)~x#_vTOb9`3_Yt^o@D8Hkkypv<&_dHLEJFV~@iuI2MByaG76V1l{ban1`KlwkoHM~jH>#?ra z%AM_eW$lj@xV5#vF~;u<8DH$Res(J>y=|R#KDo(P$f{bwx6W54zaF-4`TpR72YNaB zbLL;p)NPYDY0_+;bFo}T^-57UyS-g>e&F$*GlpIMBX)^z9r)6!%nky-IkkJ{t`?zo z-}QaF>j!1a^u|-4oS89X?T;Zx?>N77Zh>*M1LEiPv zyxt}ybka9>I5G3levE4w-_Gqv9cQ*~GT}j7&9!b>HRt`jDO0^@p1hV?p-((trk5kf zZD4%gSnLW+-mv0QtFo#2*M_&7zw@%!{)vaXw3^*Ixm!`S+t7^`3KjATO`ffa*Y4h^ zzJ0c8KZol3e(E?;w(I&+V&=<1K<*yAPQIf57Brs8mta~jrW)7XVPucbq_#I{ae*2bgcjlcK zfB0QD#msxXgKZ|BadKPXW4__Lx_y%7_S+7Be~;xGQ@O8$wcC>5)Y~EDj_z}~8&l|Y zzI?uS*uKJC$6rTE<=3x_C+qcF|FI|d6UkpHU7~xINbuUS+|7ssLz zMKfLbwM2z{vZ<%_4V7!TUtC76TXpX8)8B4x%zOW?d*J$SlJ;!+eZrrZ{x_j=yt>*h zsCUr&pB?>o$IZTfMti!=e$C4R{yqmrbe%S;qBX_`b6NfBn=I&_W;wlPM2((v`@2-K z-aFmLZ(Yo3_nx;dY+4uk;tqZj#^iO`d-?XIxZqo_w104;rYzn4aP!Oqed@U0dFyoi zx72Bm_n^OId}B@&9$4fV*8N8Pc72jxHL=o;dobdq>*(Y6&kfz%qe>6>aVxYXg}hSE z+l^N1>tB2BKKhqt=bHK)*lu5Rr|zxgv5te=Yb#HIU3F!AU03|DbJEfgJCEM)y06dc zpq$>lT^)SKEllw0aohcpVmSJlX^c-cJoV4ll{=;z9gnY9SlzmT*|n;p6c=U=nYu+$ z`{}AOZ}1yqHXiEZQgf$SPC~SKV)ZutV#W-tVHz;nV#|R29c@?C<~n#6VEoL+L#uA; zqnvFH*FF*-wNQ3q!R2?eqdYCfp4c3+=IO6LhqV3%^C)I76Yf@+YHhP%`;X(>PphIj zcy(<|&RO5al};VH&>`oD!;h)3Q>I^lL+7VIS5B*ZZ_L(&BNwiJ<^N-?z`TcTr%ar7 z{gmVB{bymP=!1caGGbR`kKj&DH%A<<`eyc)R|S=-z4-Y^@7>#0SLpq!+8MMX#+UZ? z#Kr3m<7A=XgGNqt%|7n6>Jm3@hey9E&YGMCy_amla~Z}r%(<}kv=ixleVX0x>ZjS$ zs8W+_zqB|qZr#whgeDdTZ~cJ1kxePzpPolOev-qjo>~3umJM_5j5qaY|K_o6bK}Qt zb1MZtehln3F}}Wa>KE-@*lu*2T?Y<-^}XUki;3qO^bOv1ss5Q^T`k|gqQ0XU$(ymM z@xIr-6Q|Xz_VD?h^>=(WwtQu*h$&i%Nl^NID(O5JBo*g`Pfye}J&PfpYLL@R z;Gr^x3Gv?Gd4e>B2>g4|IF8=U#?l}TO_m)UDscIBIO_=75Ht#u>LMCc3EBxX8MHI# z3eYZ~KZ5oEy#d+_^fssp^f71x=yT9SP`GnW4Jt>zzy1C$-vl%n*A+o~gVOW)R8V>c z0;Nj@CBDI+eQ^CXs1|ezs19^GXb$LV(7vGiL32T=oC*Z~eI>8~oKrb*yLcaQhQN0a zartNmbdTPjL41{Qz5{`dgEs6ocNEkL*T+EN61Y>Ktw7I!dV`(@^%t(wK+oZNALtd( zL!gDA7eTLsUIx7ZdJFU>=sn@ONVu*JJ#HhuCMeyn2YLt89rOVxt&`$6M)}d8ln=G< z%;ix)O98C@{^R1o|B) zx-V`m=vvUtpx=XT0o?|=6O`(IH|P=2J)jtVa0fxj4i1BwLBI8&q#t1xiEI3EbrHy) z0dmd}fez%IPZav*V+hTzvBZKm3Y4TLTNcyLK$|m6KUzpXN=Q%Flzt2-u|L_eS9NQS-W!Z^2*jJA~k`@=0D7 zP)diq^Q(fwhv(M;#T1Xpp>mxR@Fcq?doe5*Y%8DSbO)vK^Z=~~+7lF02zE_4(KYEc z1Hl^t2;XxEaY$@ve~HMKv?iZbQ9fi?kc z2ig=AHbGmi@;iY-cjgaWK#?cyyUZT|+5!}|O1~q`p9bmy`YkAYQ2u(*wxAx!95VCi zIi5FYS5RNjL{LA_3{Zbi9VqID`9HG9iMR$v`D;MKK(~X2gPsLNzmk6&G!nEn$`u7# z7c>Txo<~CGd=)6!1>w*TAs_ts;}i(Ns1)4hY9i3l2K5POIP4uS=I5W$^88t)_^DjP zPvsKjD=n$0?Xnl-;uf{Ne3BO@FLs!L&lG2f%dY~8Hl0t{&~;r< zWW($i%_V;-uFHc`J)`?&^$ZB0NT@ z3fuNZxPU{on73__Wf-n~0GD1}tUL3+4gbN5Xub}6f4H0Pb;{b#?2)hv;B2Yu9 zir`HKEFBU85&{we5&{we5&{we1_)r7h53<;Mhu+4XRIn#**8<08tW3Piw()ptF`Is zL=9dw8k>WkZDpqEV$*dw30i&A43%D!qt4Q1_Ex&MIJ>#E@NjjF#e4s?v8wdM7Vfd^ zEm+D#jV_Dc2Ftz(fb~Co697X#d=o%CtT+X}D2N$`CPAC2%S_TM8b&ozgsE_)@X_hi z>GAYE06MO6ZEU!NzKNxk)M*onb%SC!*XdPSeRfuCe6}VnF*Y54Ol4)NTAQIxb93d? zx$2Ke;maqM(_fwA;vO5X$%xH$a}^4ep4P&>DWyiHACn-a{ZJ3mFkPcd_&72uT{Ro+G&_jWe$vO)*?6CSja4z=N)3K`m!{0f z%pzuSPuT*T$3OPzHpBQH z?RIU@v*Dd#!BNZJzBb;pBk3!@E~7QCwKt~LN_>@E_6epnn8YaLy@F?T-jL+DdCleM zcVox=d|>X7Ijw3IE;~Bl^q)uTWFL*knh)cf`}Mdb)ux6A7*#S&FX-!Meg5Q=(UX1| zu+Hi2VaLFgsgL<}!-mkakS`aT&*74lo909)GMoPrrFk!g-CWmd7-u6$hlGHHfP{dA zfP{dAfP{dAfP{dAfP{dAz^4(Q`G4>K)cij;DYskEOrp3bpY!chU)-^qCdSB(1Xp%%`2T&*3DWLbE);unX7L%KJe6WMcB7r zT{~0Zr;5GzYPPHY=hp)0hlW(_%6ySOSPQ_j%6wW2@DbJmW?&s)t+W;(ASDqA0SN&K z0SN&K0SN&K0SN&K0SN&Kff590{@?50KmW%r0G&D^S;uDm|H^a!pZ{0S`IB|RQ~zQ- zO3(AxV)APEykC5Ww6XA@pZ4q0L6qkCYq4h(b77?t@MdfAB~WETiW=YROUTSj)nKk( z8SjYN$MfKO?s)x?Ix2zo@m5FtAu&EHQ>zbDY0|Q_Nb%wR068`eE99~VW8%8Zn>KRr zSJ(EM-ioc0yacaXdhq(eeLLO?=5LO?=5 zLO?=5LO?=5LO?>`{{jO4q5c1f>I{05Y8vLH_-a>XTJbu7EROd7SK#=4|04Zx|3AIF zH(k?@J{jYenVzMg-vF3$_BMDiFleYv5GHxzJB8`J1$5Bw3dDov$;SBIBYsYdZ@+8w z8dVy7F1@r)pLwS+=Uo@V#C`LRaURI##imO)c};w|dqw~C53AP-(Qj+Ce6Y_MnQ6^1 z^$vH9P5vdkqrsEr&tHBg>LYLBv%9xcomuyJ#IU=~_IG_Uyz-#DwLWz!%I>8!zc{f& zTKaH&HyaQ56@TO1q>TfJ@5}E_?aBDQ{O(k2?PtH+=5Z{+mzE`HA3h!UscJq^z@1Na zC=r zxBvgHxxe^~yrMAo7x%)Ope*zqpJ5gGxqmV~%r3kQKv}F1cs}zjs}JV=-jHwGh33`0 zdZx}kb1X3A(6V>j@b8cGyFYAwhjuU3gGZWOTz%)z!rp&>-rt$YoBaL7OAbp-XDs|( zcjnB()5H6G??1?L&*ER~T3>2b?o}opNH@TOhC+U2iqD)!K}Z{GsKXQd`RD@_y6uL98T0RGiA0Q%0a6()+-n48Nv{!`L{ssv?Hq$CZ49?X#k!Jc$jTuAVcJ_FWEGpr8z3?Iq(60cj3F;8-;ZTY(ZxS zrr~UFK3!nX0aGe2F)u@vu1Qef<%zi(y&@5t@wM4_iK14Kgy5hgrNs;#9E!hL8-slQ z&iaI?3%z5TjvffK4npt!ru`51*l*_lIbH1VU0r;0fy;&L4v=Nhz{1y}o`pNUuiL=P z)XdTn8|Ue}x>OGwmw{EDEWH+I;&*i)v%I75TZAy1ijYC?0}lZ&(i>Y?Hn5;?>5AXe zRgehbpgs4(!Pa4H@r`-f*FkAXk1z!KHn9mdAW#*o6s~Iv*T-;8dp5*xU~dsNh0uG^ z2^;MD=K`^~5X*i$z+*%8fMud6b+Sf>*Ihz>Tbmrn!MA{8QZ%~aGO1abrtF&DrO(SK z!^(ITK_MTxC!y@FfqNh2-#jv-*Pi!|!#l ztvFscqR+9rM_so(GdRpq+aDj15KlF)kf`_A%|+MwU3)tX$=W^M=1i|;musxGE>-KR_1s~hULZ2g0tg#Xc<`3|O1nj8~4=fECe)r;ZXX9sa%~s(%)r`+${Ii!1{c8Wx^;XSZ zL)`9NzN-(g+ctj2+zH{6XI8Ht+6Uh`!HZiJ^69mznFV?rX;GoWMzfqF%?buYA351m z|5a4r*IlZ)Za<25&<z63wk z`ib$~uQl+uFuTLU#=BTA-lufEK5^VZbiN9&kD+6Ju?3%=@dcPIDct+4R<&j2D)|jN7rwV(LeLM7^im48a98v{>JJu7WoBUL3u?(8(#Sh z-)~~_943TMDAP(m$9D0lyFP2qB~}~LWnqy0o-1e4&N$oIUu%Fhe-F~HL%G&_T0K}f z?$8zQUF*s`f4BI^>BDO#{p=a~qU`v~udT4Za4_Qw+}gSMA4U4N=^ier+WCQ2n~m1) zv|QPNtM>L_nMjvC{o(H!-<&P4rAW_-hsR(O=vaGJ&WR|6)#`fA#c9)Zuc z>}b{dQM1OqXCM86zSH`I@r~Jke#N$TJv@7LeYz-1>wR(4rE!bRa(7JZa(L{56Xtu+ z#sj@bzkz)=7j`_fuj%n=d+vUHcjopt^1JI5M@HWp)qlV@Rz-`!N8dDoy_}u0XL9r9 zvzi@nYr3~;?SkAtFWQG+ogbFIe&g(uTYYD7+e{~1r zJF)C$eEK$D_crgxBMZzj)flj+*UW#XqgG&y|dO>?h^O7ktR9kNhXpVg;Hv-gqT!yoKm zeEzDN?Hb)yc(}biv+&HrZ*KhIm>lXj?@{B;KP){oY|ADL+O5E=kdNI{@!`xKzmDk{ zQ9eAWk?V*>!;`XJ&L2K%PP2lUFXhMQ;QMln&w6r-i}9-gW2e{O-Zb0e@p_MZ2zJIo&}Y-v9@zK{0O+ZlgZ2z$@7$YLTl&y+#?dw1Gv%X-)>O5aI(tZ;2~B2rtp#5j zKgxH2-u7B#vrP{?ET^46^wMPELYuhRQ@6a`s5kNcWAw$n$ML-(#`oIuyWd?q^yH40 z?R~w9(dD1^Tvh*B*81>@jc%#a&#Znn8QUewIJw`?dZ?%;>l&i$;ZOvftWo2x%4A(Odm&V1uM<(Z?PHYx7qoZ@nk7=Vjw&4A)4UqSo@l~t7rLAk(Uej&g z1-o{6cldhf+C5ztckCZuzTK5|D>BGO{@uOjc}Aq4rFmex9o_3K8_~3jW?nPrD;1Bm z*|@lj{MMW09*w(9arzE^{BQ12pUv~>LTfdsf4AD=n0^@%iTy^6%MWvW_xv}{;Rju+ z`PQ0)auhMX+o`(WSFK;Mp<8_I>C0*k*?g_f^Df`*9lLss$GgJWI($Q#3kW3rX54J4 zc=hn>s~5~yPARh4;?~n*;aj`FC979@u5>KyB)8(ciJ~tjqflqKC7!WYLEYU=6l`D0^hf5Z=5t!cPSG$pi(|MSn)HP%jO@aAaQAWO`9QW)RW8-pEe zx88MJI>tNLT^B7smHJEFgDX6*tXlfZVY{RN_=8=HPqFn#(uHncakZCJ?cx_V;$`k> zZ;w>>!k!`TV>IhmKfcRxZyDdT5hvSfp0+y^l4oUBICep~rZE#A{8HKEx2UO4`#<<` zZWewQA58k4+p?xo>+4$QuRB~^T`ktiKeAoF%=q{oX%ilYFW$V_2YVp$7+*nX|G>rr z*NzT9mz?%%=7?p}cfMI_wDR~jHK*q~j_MjW58r8Id|wBfHvaa!*{-n(7hbp3bbjhm zxBp$|xvf@3d30RU@rbKEzS)Q|phBLozuq#3BBNa$WwX9{vDtt1*`ddh9@*y_-EZA< zNAG^uY&mWqWtqt0!`S_|VVd^Jz$SIsw} z{*_(r)5GgE8vkgvx#{mAkJ6^Dp8N1_xgq$b8RKj5)_7aX6(_tyw={jfbiO-+ezvj62jIZ}f?VkP_Yig8l!S#%sx=iLVCvQetW816a8`~LI-+XBu z{7VPYFKe|;1Fm(9-fPRLxz2aSZMyuX!?j)YYLo2Z@~DJ@%2=l+@uSCJk-(IG?=@0vPL`G({t?) zuG?w0;o;5AjVC*EoLMO4Yi!bd-K@9<;mSMH>kL@uwafm8Dl30mG3Hp^TM<16z8hzU zbsA&hTYkd)hhb*lOtbc}KezgZ^LRyg(3$#8jx|1Au6*5=!`j4S4TZ_O=YK$(=BrEp z!#`j{LdVOp8?%r8Hn7VB#n*jbRA2n#x{3IHGUGebL-%s{`QHb=b$D|#$FZ7a&8dy+ zUN7qruw%oi5thmHoncF?At>bcqkIl0$NxX}t^^*+t^XfUR1$8BBu!G3vP-1UVkuiv z6dK!ztj!D}GKqFY8--Thq*Yv6xLvJMDb>Ac*Gk$@N*DG2ooBe$?ccqf_kE|g``-6F zpMITL&Yb6YzB6W?bAI3N_m}YDM8%$YO|{3@AGmiRY^D9R)9QEqUE^G47QlKZ)6Y6r zJvCqB(zM4-&0$Y&DY~0BM{PB-bGWBBwJOeb^2+fDon`vXJsMtn?77#%o42y|4AZvV zqV?uk#&%BYqTOBH5(b(3RFIM+xjg)_3DIKCnFc)uUhUao#zn6s$%-Dc%IGV6-9 z!^LW1#t3$qs;1hdZ&31tdbLbHg)&EpKF-ODi$!WEC_Pa_Z-JPq&n%XP!w zBB53b8fFa=*GN==+j!j+-|i2$@%kyg4NC*40fGgAH!%qKXlD`0#bb!W^YHb|Y?Gj0SGWZ~bpl;z;cXJ&wRv1)JQdoX1(FJ4))^)Z6JgIVm(AQL=i+KL=8j}gj63mR|s{8(GXS;E)eq} zmO-RL=u5)upv83_E1|7{kmw8N3ZV}%5dznJbb{6gf)5c7kqVIwaTuZ$;x`K^28obvWE0{Y;LkTUUdR^SVz?Nh`VJNDk^WB+pa@U| zC;}7#iU37`B0v%NItbwT|5vF02Up5$eq<;I{P%oAun3>;?=5lv0$xd+@wH13kIG#t-E1vA^JNw0t!@OBp8@39l1Fd`$gj zxZc(WwsrTp`Fv+1i6=XPB$LkUQ9TCJBJ%{?X#UBry#z^ z(f{6>ggNKuh97y;Mb+=X$kki=vS0l}{@vlryAwSXA?b1ek}oWAzQ(p$fzl~T_Wj*6 z7U=YrJ(XfUA=l}OzWbxff?S)oPsq7-hA_uriKq1*8hb{pio4-<%k{x6?8J@DIgM62 zi&sooJ56`qRI?P|V$Q(*7O2T9j*#~#w6wWZt>C77T(dakt_gb&`;qp(&HK5Da31+g zztY>ARa1)gcT0+YCdX=+;gJ<~c0*)}wvxSA>?xb1HBNsYe*;MGpgQ=_<-MFx`2YlOuZq#!nd@%Ynz79M}`gZEVJyPng1#?wszEyGV;mbsy119{#uMA}BzpSx z^$2_(SVxcfmoOyS1IL5!cVWhcHHNnP@}JySX}f<6o^M~fz~+6Vx(QMpIH_KeREI&T znQnqBdH#dROe6X(?P0Z zCiNvD^^+mhBU&(j=c4n4Ak|}&>Mu$4&ZPQ%JVzz*zasS)AoaB(^~HG$#|KktX2Wx9 z1;_`_f_n`RAazH=H3s3@1AY$vA+T;?Hju*$@Os2>nYo{lzxi;Ur#w79>bc-Wzdd>_K$RxU(!>i!|Q$e z{-&wi3-__EvIttNt#pEXc}IQa1$expw(=3&$2s*TXg}3gN@HOw-6#SS0g3=cfFeK< zpa@U|C;}7#iU37`2mze`|7ZRGA*tV?0Dz8;ww~T7BVFB&_WyIjJh?ufPym=3fXL(9 zaR8R#g#_4euD*S91_gnz#=U?oJZNt}j&}gtAA|yd?BI}4=!m`U@!VVtIeBuSs33kV z_PWPf0O4!JVNO3$4yLJp;@!_;eBS$jw>$2K$FmpvZM^n;x&V&ne=VObYJXaqpZ~n? zHqFm}-rturKTql}{a4T9lluG8eE;Wtw`sor^S;N1z_DYA_mRvz_+~=D&92t{m-k=F z>b+#|`0aONUiv$0wFnlLefWvy`~S#q`R|hN7q#y(DSv>}_n4GtKQ_x#e}~l9n({P0?;9;@o(5@M3CidA zyuUu>bC@@-jr0f%FSz0I%trh9+1uL&Yz59L=5v@q;B7SUIjSInRp7C<+W}xOF&SXsZ@cXZw=w@i9YVN9BwTmGufb9jB?!FD23`kly`WWq*O2f#CJqEH z1O)cU?#T1_SNI+ONp43+UI*rMe9GrYg>(85q6VTD3(gNB6e1IXZWIBE07ZZzKoOt_ zPy{Ff6ak9BzmLGz)Bg*#>uvJ?ZYuN{_E*ns)0{QU zS>sx+q#E_)={RQ{{leX{C9!DEhV5}#0e#FI4~ef_a;&*VO7PLt*|mq4D3RHNPm(_oU^;-@*q zcI`OUX@BedVn^M0N6q+`@{0fdDhVBdB0v$K2v7tl0u%v?07ZZzKoOt_Py{Ff|J?|D zz5G9y)4~4#-^%~1AZa-#(8Y%WKUy4FPGe7+@68G2`-cQOa=b&hKKLC_hCW8nM;6G{ zOrHrM!FJPuXwp zQ-5X*&ady2aLn$%dPyK;9ppKOGv1Sj`;3?KfPD{QUgLrK!1!yJBeVz$_Qs#{Nx^(> zBr_JS0WpT@XV`XM3`H{crI^==;}0FO@(lI~-AbJJ* z^ZYnm3$7*+IBy%?Y<@4Z};dxy}-Y69L^h0^n7SK>@mwo zul4GVtIxMTcsF8>&4?{8h8O;@>sdItQ}z1&6Zz5Z|l#;-U_vcg`|tkYP1 zn-&oNQRFfGyrYC!^zb$LXJjHs1MD4v!>iI5fhL2Ap<$4nTVvoLE`wi}Ad2QMO zEz6?~oo&6v1X5-7TXzlsUVx}I+oay`q+agd%A=jsV}dkKo&^^wEb-pqt@$#ChTLn^ zUw%vLCr$IS$5iW|40^QNZA9#3ZlCq(2wgY8{pxLk(w9Bqx7c{fn&_Smbt;rUw0BqX z%i&%%v(4E?yOa^q9fkXu4qW*1mn)%bms*!@9?n{S;pFRO!*VN2Qr?#H7uQ}AI?z{W86@RBLHolWL8Yqo4DL`X%+7bivcs9QPaW^y0wRxsS?s zM|0RQdp-L4SJcEPt;?HQA7nc9d2jz3g#PMzd{Pf(QcwCAYm7^3!SK_~Q_XY6Tf|>}fyrzWf zuVPx&S{{av=qIhTVfdi?-Hav`% zWo4+a-Ez~3AmamC4L!*7{g>dnj3utGel)fGy~c#)eg>0O`E`?J8}3|?@KYN7^iuI0 zm)_?p5F*u1lX~luYNx-IcReZJlhnJOw004x$33a125If0;g_TX@ zBkp&y(Xp-}9PQhrc*SU?c>{^Mar1jy)YZWpNz^qZNNXaHdT$J#hR-8n z;E?)LJ4~04J$|-q<@c=0QOVbbMpzxcIpk`*i}c6$LlClHuCu>f%Yw9a7O9s<3bWs| z;NsZAJgw^50F&yF=%Fvx`^G7$dN$7sjXLpQeW0Wp)L*c|=ds4B%kY0(mps18yR!N7 zydzQ9toc^n4F7B1lcM&DB=saAt-_q3Ub2|j)R8@^Lx4C%=Mh3A6$)RyS&~R$~C)Da5FJea(+>=bJ?nG zm!wMIT)$P#$8S~3u>pS1;isW(U0=A~zpdNvYx}GMPZzxQy%t)$oVyNMxYR@2pjC$! zro94KLSpXY@lqj#>*EMr!H>gu@KcXq9A>)#{qcA=p~dT`x1j|JDCz?Rj5VO`3#}ov z;3Fe|%X`!hT9`f}MQA;tRfaYI+JVr9LCbJUWI|xBD(1MB!tE*uTr)^Q z3A|(=^dYPud?4C+tkG~=&>Qv((Xkd%Iy_zjk2OI^^#ME~+Up@5hUY3FoLxAgu6xh;+EEFA3LcaJv$2*FYrU#~~!3{!uT8y>MF}+KCXE(ANoCTsNr* zzXk%=PkI9_AKG{bSy;cqb(C1pT0vl5tPiw&h(D^U)XtGjf<9*O;mL#+d+_8#`>7Al zWq7O!LJ5Dk=tdEs2>fjkfS+#oo)*Jj*Jz@#o2MH)B7_^@rsKwQv&L!hAdZi}C!gaM z?#&Mg3FNs2@xr|c{Qtc}f`a_{?4S@Ij?e+X7@5e4dHieM|6P!(9FOk}6Pt3u#S27Wei3$_XZj5)j|0{l5L8HyjJ8%2O3KoOt_Py{Ff6ak6= zMSvne5ugbC6%oMmHm>OB|Ng<@o`L>8>`+h42!?e8wx5ua+|dtERO-Kx6# z?B&JfeRQ{MSbbV{&(=DJpeLtUk$#&Jr5I*iz=y62 zFu2hFC;}7#iU37`B0v$K2v7tl0u%v?z_&!;E6x9XIKG}?fqZsgh_`1TB;kGhL)amV zWS=K`KEU|4`9Ic1;|+7t@CH;W^piaB=omi0kL=$a4bR&%*th+d{%p?AYSSl6Gn(l- z&>4#(w!QFNrtw3#pyG!8V9vmdw&S?gb{s%KLl|G6d@<_~*=@W8HV-Hi9akg%1TAUK$WwxZU%lIj=JCShKOGS6nf z&>_|RGM%D=?R}z_B?@dud}w@WoKULMZ~TDtdW7nkevboqul63w$(!k=oRX~+S9ot; zqx1e#tM(l*`cRd|!+ztWy!nk5c)zSIk*&w_y3XUv%sg~+WZ;qq(J~pAHD0C{4dR6q zs}9`<+&oL%@9u+GHTfgeBX+GYv(o2H6R!xkHK;Vl_|D#4x5`v}Ck+E0A~T-M-Tum} zf8O+ww`tM%)`Jf&OLCmMdPMgQE!W{KtkS9530zKQyf5p$NcA?Px(HHT7->y)QvDdI z&UWu)jPs~giKB)&m&|MqYkoYkbBX@F?ZWbG~zjkVJ;~Ujx@LaIM{eC)pp!b;j zT;E>_gFpevZ;bN9Slz_Y7cJVLvR)#q#MlIq(?b)uxYHBy}@ zsUDY9XDe#mDXCw=SzG*hnR_(6_Skc;g*R_y?HQ(RyG85GvyAPW)-_C4)==;P#G#nNs?S1 zf25z&$VIEF&6BRkb(h<^?!>N>%QV~{BSflWt#`)b^-*RV` zwDcT1?An-$we`bhb{^n$DiJUy)q#-eJ1pTd!xEnwE7XB_D zGq`9xc6A>bS>>*{ZAe1R6!~7Oc}wP9tiGVL{kwvFt;TWiok6M#E78XLjW*?MP0g$4 zuh5zDvw0Vnv0^^!^s3C$dYRHMu5v{p6@B% z;t|=0YTc_`BJx8)tI-+v`?Aiq2tEtoZ;(}Uy!n0399N$sj9_~hSm;GdbO#r~v^kIze~lVf(a z&LV@gr*?n7?$r_l+)wJx$AssCdX3(GhR4e7H?9|a*!FO^)XlrmC3DNqORa_P4N@I& z!YDi*_qwc2e7uDOZ(21c%ly7TW0LIIUDgTJH&V1E-gsz%=!n$cg;d`wY9E*z%y}5C ze$%8DrF_ffk<#oqy_(zA{7EWDSEptq*{$28IK*ZiXr&DC`KAo$Cuw1He$;nU@+HI1 zYb}bNcK)(Ef2E_v8s~nx$1YeSMC!})!VHh6QnQN_GN{o$zFO;yOG84Rg^>r%2lf)H z@iVxQJS8wF0ih6>m%_ZFyY-1zR|3xN*39^2Onmei`9p^H8qW?Jur+CbQGV8AO_)25 z#{IH-$TVJh8st6M{N?5petNHYoF-1-y%+9{V@}wtxP`Odr26s-W<0edyQHq8`RVeR z71ibke)8$J!g+_KYRR3efmgLvRPPN1O_>qi@01>6N=Dc2Nj!JQ?09b1#t)h2uaq5F z`?Iml+it6GH_O0xB&qKMsSgaPE|Jt1fK<0js++Vh!MMcCE3BG&?zCq4#**qa)tipB zh*uwConKzFY(eyPnfgrljVARG+sceLP z?1x@KN9FuBrBt^3?CRe9rs!2-RmSy4HH*SCtSUG=5F*vPlInIz^{%9TRHVK^q&{(^ zdS+4k#K|(>FJJaK%VNG?x}4u*?C@Qe)*F52qU>?5M>I39FEMHL^`6c*P`kA0#Tjxx zhhEHh+q)mPn3I=tb9A==!Mz02t;M%Z&Lo#Pk4_siXJ&oB$DqGVVUF+1J`GLG@ALvoFH*ffsZSEAf67L<*k*|*hJVL?BW8By=gD0wc=y#p zULBb`@`&V^S%*S~NL%W?--OW2nYdpwKQgJS(yCy)%KS_DG8K0Fu7+9m9wj+xOUB)I zNB6N(ou3MOFtY`Leo!-n{TP~f>=9P|WPD{v`KIC1DRppi|JDR=8{rK8-M8dUK z;hJm>ti^WJ5&5+7gnXgJYqfKr#jk^(6eL_LMF_8^~9uxv=g0msob-^9=z^ec&1=yiF#ApaB z2p5R?5Lo-$uK6v3+dgn&mC$0{Z@b?2Q>`!7_qJ<$v6eR*f(47%9c$dw!DC1P9*59| zz#3jgzYG07)$e-1b@eI;x={ou0u%v?07ZZzKoR&H0{A*=w&?l)!JLTS#Q$GI`!5UE zd3eLulX%1V@juf3w;v4d_s?+qU0w0Db5e}+v~xDcWU@>1stOl49?Fc1yD2rXG%C*J z^US^L=lh`$ zxIb`lJ8ou7KMrUOAm4(Y5J2F5!0qk0nf<>b>G&+YO%b37Py{Ff6ak6=MSvne5ugZA z1SkR&fxj;Tc-s9H^8bM$o<82bbAHqM<2n9i$QHAZM-&c=HKU z*puvLSUcL=v1jPv8ay^~y72rP+!@U1NVVCd+AC7c1F6=VRC7bB!6Vf`k!k=$t+gf9 zP>^aYZ;Zk`jW26+NHtKT8d_4#E2(ykRGUMpc_q~pkZNN|wHBlrH&JU|Ni{d5njlim z5~+5QRI^Fy{XnYqA@x=u)e@3wT12f?A@$-Q^*ou`9e-~eo#}nPTMrlCs5x9|_q@^j zWj~%eJuX2r@!ptG^Fo)0fcFEb=LxCipH#a+>Y*|geicFE%a_0BpjA+7B)#$axu(uL zcF1|8Z8+ST&+lyZZuyN<<>Vd$q@FCKo-w2vjqlr}0Ose%J^)j(A!?=98rgsX{@5|awQm-je z?-o+eCsL0voSG)_ejxQGBlUhD^*nKa10>Z!cGOPddaBn{KyS%{`m4~IK^qF8J{VH= z5b+S%5T_s>K}e{=a}YKVfe=X$`4CkQxW=h0a0i?~ub2d_)DX}wf{xM+G?wjp%XY1$ zpW+|aUmXoP%0JRueo1GEYpQ;#wQR4K+EHuysmAhCeWgAeJKZP(6ak6=MSvne5ugZA z1SkR&0g3=cfFkhUgn$Gbte5EZ|2~nyYA zm`RBt0bA(FKZnC-cRX}9R4)kh^7IZM_YL?TEG z2<_E%5zV{LCl2g%A*1JtvAm1hJ|54jhrGrFj9;_y{#UwF+);VAx%c~ax_z?bF6WnS zvSm5>dI2d{_q|z%5amPMUbMMBWbNzqQsHY<6$4J^_3rWne1Rz+;@|W3rhEwQRtuTJ zP6vyn_e??kT1&e+=#(sg-%G-pHT-UMka49c%CZ(JMc5g1-@ z!{wQc_Vcs1w++||J_p#dS{p*RmLT-HJ`A4K;_w(yAD9h$R^uC(?trZkfW{yI>p)Zr zT!MdvoAEWc6LoMbf96vyD*l8t^$Nrv1-elLC;}7#iU37`B0v$K2v7tl0u+J&C;~YD zKUehm{~%AkABW3j`*8RiZ@zy>u+Rwrp?`-5(5~xm&*>{+;RS3^zLeQO&WTDOr+?~q zIemW~JB-KSvfB?Sl*{39g89&wv=%@q^nJk80_Z-=MzYzw=c^|@x0=hG*=Vm}4iOM!(#W>0UyE!_p6zBmK!*p7xZr8q&)Abx5XZ$U3eMeT+3P$ z@m4YOL~b%dlwZGk`pjOp+`=LxUDwU*YkH<=(#+`|2vNVmjIaz>`vcO1;;QxmQ)*uRp%g;ea>zuvp^1x4REw)#Q&Nl9J6jyj}UZeB=Q>*qJF#1rH#!EVl5UJl_-As)0 zq8G21T`}q(Q`%>8#m~*1zE>INo!GSC`IxNHHG&CucSKNrJ>}Ow{4sbCLey_C%ly7T zW0LIIUDgTJH&V1E-gs#3MTq(hhMM?Jv*Blp=WsNx6=~>8-kJ2m0wMQF`1?h9_l}3d zLmE=|MM`)|pOsZF+nvib+U%UZyPJHE{)*2bKSuoqn`)1*KXC6t*h>3rr`7NJyT-Z9 zEI`QD7UO4~tDc&#acSD)rsl9Gw-nt?o1?ZG**V!2mA70@TK0K})kJn0I`pxj+F)tqT;r|sbyc6)&zXl(^BNsjz z_MzVwN)$q50)gKNT2b-gQ(o=~=)2~+>{~wkXn5{GXA1H@VbX!gz zXY+Y{PcAO@gK_61yzXFV};fB|=0%orn*t7bX%|wI#kK*EE&z>KQ>=yXe0~M_Z7YVKg^p8PWqpS|3#twAOFeR|5NQh3u+er z=I4*K|ICpD2D1Hwu@3-7mURA)b^nK$`G2xu%ZPnidae$;&)e}h4as&_wR=3jV|ruA zlPk3+1n!OhJ-UA(KL4EVUjewkW)O6v2v7tl0u%v?07ZZzKoOt_Py{Ff6oLO<1n~TS zw&>^ooZt@We?0FORqnst`w!>l@rLuwc=4G%;%cnlEy>(zbLGmIiT~JETK%G=>SEZT3B7LEH@r}JnPl+4 z%K;E#{@Z);M;rkB9$^ju{>=H&^#nkHZWIBE07ZZzKoOt_Py{Ff6ak6=Mc_Y&z*oxu z^ZmFX5o|9{AGT*;V2HO+1t7|GfOa0h{I+!fCC-=u3 z0+!i!cuhCtCx;IWzfK;>$zlI|yf1q(;l4TnW4`?yT5w0$SP=OAz-@P!C}%R~u#C;- zVGe^3QaGXCV1<6&&@5&@GB7qiCM$UCGn?5Ucu)p)mOI6aDXVH@rw8ZJ1=+RnDOTah zIczM5j>jMn!}$EcF>tw_k?dej1UrxuJcsXxU*CQ_a)igTjT!&9;{lsCG#}P*Dn`Sx zh^r;pC3PLmPnXZEs5U?FlTW`D&O0nsOYU3^ysE9DdT%H~Lyd61DLuxNjIQ02cjT~ z>BHQfe!N+xFkOB}o@L44Fek1jGEP{H^Eb&X(550np z%K2?dsciY#)xG&m(W}I&jO&kT7KLY6Rd9A7G==F`tSR$g;kr$+$ybvccA3~eyMA${ z=_;dYx8jnC#y9jD?;<2O4v&XQ`9~IQSJiyjFW!VyysGFLYnv^ zgcdR5RcgH1>&5*spY!;dLX?`~>625F#g1Qpd&|>&tROcm;W$F|u!zMHUl7%)s`%tR zuVDjIPkz2;^;~AZDg|8*W_I=3pr%pwq{YC*zV}w?d*`~d6*te*(E8}`y(vOPOuvbq z4^4+XW*Oi$7cdz9KTvmnFWcq}TIJuFqDu+xN8d z9j3cvXM%5N)7FG#=~|06HHnv}Bjm~SlU?VhBk?|ZRmzZKnqfw_cc`h{UNuAEV!YSV zr<0bX?)iYwF{a<+rcMp&nU4zRKmKP8Q!l( z%Jn4v#U6dT_8Z*K^4hcmT9!u}I@@}S38c#Ex9%J;5}_Q%!|s8u)|Tx{MnvXk?U-IV z>_Bdxh?2LzNR?=reB5-sLFVEy`1~>BJ(}+sK77j59e(L6Hbt&bTFt04%8SmJ5D zhsK@}tKx3B-Ew_!3p;URb55g`&f*ml)=tx%H`Oc!AtiI%?`X;7*Wx>4FV&qJHaJ&G zeN~Owvm&Y59fqp0Uh}v&TT>B=n}Pc+P?J|2A@5OWX>+Su!A<$NW^u}06ZRhVBkg^g z_j42ByD6XPS9*K1YD&@mZb|XaYRuH!(wf?@hZ{JLzyOLK#fIjn@YC zQ?d(vGpOc|JQN$5e*F{=kJIfoJ4OD3m9F!Lvimj%OI$LiF7WDUdM7t082`pZ!u0@4 zTw2P)v}o4g>?NAc{#&%P@ASGjHb1kg_@kEHM#G)gkKB(?+9cdhnP)R#=#c7unNCr` z_C8U|5(Ty+J~X~GPAJvsH-12RJ$#=s{T>JKUhO@UlQ+{#Ipyc&QH!S?`~( zxmzis+z zF$b61{WK@=^PXvCOusc&U55YTy5#Xy-j&Vc{Aaw@8ML5UJ7e@-N293+rk>YTMd&!Q zU)GWHzLhgqBIPUv=LsH5n&w|IGYZhJa<~5IeKn9 zC7WRaGJ1 zjcS!RYM67$%;vD>$0IwJ=zrg7Q;6hdu|fN5rzSVPQEf(O40FCe9X`-|%zdu*nkhH- z^>dS%=wKQZ;^pNUm{ez%Sy*U37yf>y;QfZ~lN*Z0IPpymS7dy?Hhm0pzNrPnPdATG z-l){?d1J|;C+7Kv?{*d9l#zVxy3mRi@lr_rsA9;)BmD`;i*Ck}l&Vedx*UFAqtXQDen1_(91U`@5m!y7(m)yQl z)?D?ceGjx(v+OLd4$-(c{7R3WgAC)xdWqh!FJik$A&I@TLa%~q#ln$?D2RX(_XHAT$r<{ z_T6UXJu>TxwZp|~V#Ww|nX0DRrEgI3ggFhf-^c)!p@Nho$>s4!`Z55!; zxvlF?>^iwj!~HQr=b3)#@1EX2_q|)Rf%4Livr->=6@0ukRY|Ywp7b{XUI%ZMk4Gqi z*{?#GqeLI)=NIHbdJ4SB*8BZcYA4kKjz_N zje+MXQfBf7HB>x;?;uhS#T8TW@vSn*82NFzty9Rj@+%+Kd*929oAU8Y=~?BAYhKoA zF5Eu|p}R~!rToiLgI1q1i8RR9$@R2o={a`TwJ{ZI>xa$kJizNzqO<6|z?+!AkAv6N zm#j0`y;;)u+xHRt9x=bG7q|J$EF0~ofXZj5e%>2)wId$yWTRtULpa*EN%7j@ybKkI0@ukc zb@B!hb>rsuwy3LY}BBn+ji`p&tq^=eB(`9rP9i_4M@2L7}svGb9M zQsf@SgQwx+ix@bh{?rcB>AO!?Woi_2IspLKdw=4rlzHSB%znq1-cyq69hFT3h3Qkp--_{N8P z8_yd7E~k0Er+AA;WFM+^uX2gV4<+Y-6v2DU62F>NbG-R|&K|R6b2<+iW<6;g@0|3Q z(6E^TwJ!cb4`@pl+^LpV6z)p!e)~klmT@OcXZ8tX%aWPUlS$x#xc& za~_rQlWym~Gc^0-S`BH;eyiQw?x~uE-YGv?y0*u)3mZ?4l^N99T&imEqoK9K)A*&Z zuA+;NZ)L0E{0rIzS51~Ze5?3iua94Ol?Tu9Wn$NWEJIgYGbOx+g!>h%`-Kk(4w07* zIaBz2ch&OC8IHw~$t}|}EazPtm}#;Lp*ecE-_!U9T^6;Dtv0zo`QYch{BJS)oh$pa z&cStgkU>yt&>W?8X|V@ASn`j&b?o0AzpOBP$v~KQGvgJg9I`3S9>1OEzx4I0jAstv zj}_|_yrsr(SNowjSwb=xp`Y~ee!Y}BIc8_;EHYSoYWHjfW6h|?vzv<-tf*XaAZFRT z7F!2|mH^KO)_v}LOn5G+*XZqMc&yxh<9fk|Z4ZY_-MkxJGPnG^)Y=M!teNpvT&g;| z)7W;_gCVB#=DgRC;U?BDY0_O@{`9BCr(FBG!hRD*;qkcFWo_c)EhKo;syUzcyv}02 zUwVhP=F1!!a<5T;`7N!VG|kT*Q>}k8=+SPs5wVlGeb&RefCh7X6N~$QuTZUhw0qU0 zHTs=bgXw3q z`c0Esl=3Z?M@qBf^lENb^CzhsU7ebdWVddU;t-p8Y~YD+{>e?_=q<+i>}czH7TZ6K;2HyB!C&8zA6t+SZTp zdaUsEFa#O_fwxG61h}0KEgTkeUlH0UxQ}124k29kh4X^jsp3Lz8~h0|n+o*9;|=c6 zUjTnx%-bG$TRS_JioB7IAp;mGWq#G&gmm2f8M7p zkB`T*7yE5IoJW5H`}c!m8siSv9pc>BpXNBE5BHX7sgs!-byI$XZk^vRTF3T#9eSOU zcWbLQdESOJ-$9zkAk9C$FvI7eQnQN_GN{o$zFO;yOG84Rg^>r%2lf)H@iVxQJS8wF zfqZ?Fbe)2@h7I5iFt)wlzkLqy=Rp+$Z*Vy(z%5)_3h?IxE(;m|!BogQ{s=)giU37` zB0v$K2v7tl0u%v?07ZZz@V|rrp8wAkz5d^a6A0#iKwS3>^yIR6pucY`1RzQcz^Jyh zfYi3N07y~%x@p23UAhOe77!B3;d=5zxGdp8;rahKxlzoTfEQ>J0)FNF3;TCw)(i|k zvt}>__S4=6uNmO{O*`M+8Sebq`oVVS+pYt^`?ePo?i;Tu;BoN&KDVZT3nY@}62DcB zkd&)HnoA^IqewN!YZL>XUL5#3_fh%oXbwAOuSZ}1ikcXub$L_kgG{GB@9kgn?KrKZ z98^-yC@EK8)SOIGZi}e7o21--Qcl0TEB?HwhDAq68t+`zI6WX?#di{{ABmdd zNy^<6H78Tn44?0px&Ne`OoXUNGM9mRXsPL9bMa!Wv2|YB1@T5l zslt;B)l-0IL&|j%b*@7VcqS}yv7pJ3DL$vObX`@u>hsn+2VB<)z@`sznh%in8ESng*qS(RTmS+?QM z1qnZ;(N8ZG&vEH}t^y%at{|xN1`Pl z)oxob^WQIP)k!r6Da?3Z*0hsq6B^)r)ggpyj|ky)PAed~U`|UrFC4h$0=SDn@*q$G zfc_PpcP|+1U*UO=27=8WalH8h{y)z<9Ug1vdGCeWpK`q`;jxZv8>R+M$-|zDOZK;3sHFEzBcrpN6 z$K3xo$fXN??gYfSe_{X5zvlDBV2pnypWm(pz1l8qJguXp1zUV!xeJL z)C=gZi@%jex~O@`qRu;uT3b)* z&HkGv@`f82y@q?$&7?Ac+pxn!M_n%IF?^wHMr_5d zp)(hqFW4t{xcn*PXG!^@qV^ys<)4!3I@V}hJNybj~FlX+b)<}t7khCZM{VIGrU9>YF>__0;YV?CJ1 z=E7sr@Yq`BF&Q|Y<0FRH8 zlZUZj#^KG?X7l)-d=9=RgT~9Tpxw*#<-?e5$JYt`4n4y|xbU1j)JeqW*q`ZRiMpe% z3|9gm|8>LX-?lN{iP-x9-^ZBRiwQARgvVI$7(NbrvELs@M;-;~Jf3u2O4PN}NNXFB z@cq^IFn;D5-u`)(rFczpOte<;jrdXGC2yi&Te3nx7f2jd9U+-nXLB z#HH&Gw(fmj^lV*eJ!yccT1hKEw)J7vuI%26$!p$`>Pfy;-hfm$OS&#a%HJT(bCRx$ zlICYf`BJ31N>bhkX?~it7Ak3enzUA?8>54)nRu2PIGz{uZsMdo@2R)N9;97(8RJ~b zS`+bBG4n)jGI`A+QXUGa&XtsRL#kgT<>!#DpOWfVNp+;8yc<$Jji`AtqUOJl^8ZM6 zpQJSdN%fqf<`a_U5x*6mkd*&N>N`VPvxt-@7~+P1rz79U-WuMwXdCaw>fB9{>zrN` z&Y4$o!foS&eq1!&B?!!@N%=XXJVDa@2Wc&6Qr;$M{*5&ME9$&GOihUNp`>{x()>PY z?Kx5%DJd_AG;d|WTxWk-=Sr$eCFLWL<|RpMp^7@+P3rSRTH}OzDK0IB~raTX-#@ky*(*!gw*$l zls`o3mqyC>A@x-w^(Vx2w^`yV&Rowq`oYzBw#)0CpVuga2vw9e4Zh8EZB^MckBT0dyFK^p*VKD7Ax zW6<)TErk}=WCeGj4TJUpwDX~T1T8FH3tmDifPYQUE`nAZjx8SAuFx)lRuY_v4u_AE+gyHFDEoH@#SRMbfsFT`Y5WJlnC*G!I=CIn#@F4t1HQk0 z?97X7wGfr!q1T)3Zr?G8RWtA0Yt_m;S?Sm1=H%;qqF(nB^|}bY?uHcPpVrvx4%em7 z1#=q&m}UVspaT4va>6g98%2O3KoOt_Py{Ff6ak6=MSvne5ugbCWe~t~H80WE{|n|s zv=#sR3U&W<+vffU+vffza1J1=MYz?0x&LLDjKbXiSMNVK7>3U;tm%h~5ehl%*6{ip zOkX|3f>+1@uYEE+CVYKY<~6uhA0Wik3BThu&kQeG`7PlJ@-Ps-;Yuq $zeiFYF)3f0)IXAxuT9EdCgqQk@|;O|p`HM&mCAbUOtuug zUm>ZUfwb-;DX*K9KT68$CgmZL^3O>5sHD6oQoa+Zeu$JeNUAR(L(X-Ijnqcz+{Q+!IqdL_5c2!S;U()x>}x>r(OHz~iGRIf~`D<$P&lll#i^5RA9 zH$bYFw=l!k<6qYMkm_?teWSmX&oikmoK#0ks&69I;gR|^koquSevS)-aJ^Ev{+R>| zp?Iy)1_Ey^;Nx_Kb}+QS)xmWH1z-)r+*gGb79It|p@k6OwMPg6UW^<8Z40y=x#XB5 zPQpL`JNOY+4ug}Y8%2O3KoOt_Py{Ff6oJ1X0$(ZrALh-)y!$XO-dD)~w{!n-ool>x z%-aQQR)(vbi2eT4;g+#AmC zk7M%tVhFtSLbySmfkKZz%$pY;vpC}mh_BzjbZmWqD}ejqYj%6F-^Od_2h_pi86J54 zH+7hFKA3sYsiU37`B0v$K z2v7tl0u%v?07ZZz@Yh8E&;N(E@&7$T{YM7zMn?DtkA$i6NI#Be=*U2wkvb!_HGKkM zuBr(>{*uuD@~@{O1NkMNC~#f+osYkbwcQllMHzKs*z?hC{XJmPB!-##F!KdMJ;HO< zuf1>V(S*0!_I>+uIoRm_Ywmk!`+2vm8C+=JH=74;1Xvm&^d9({$Dq=73@vTPFzeT2 z07r&EI0io<1`Ig#KZ*cFfFeK%B*x3;7BeE$Cra{K@GxFR}rIt)dCB0v$K2v7tl0u%v?07ZZzKoOt_Pz3&G z5Ww^Q*=_m%iNf+U8#0%zqob{-H_Av?*Db_rF4xU7$Y+$k8y3FvINp3l{cjAq0WlA}ZtxxG1w246 z(BA%j-M~H+mInNz{DbGPCWHiq`Ui5jpb$`% z4n%i&z6I(GkBU*IUvA?B&pGy#JN%6n9kKZSMWPoo=5jxy$*bn`~K5zFt7e z)qQW)fu|#(_oJw5ACP*Ji@HVvsh1?F_u~(Yhk4PvyGKKI1%J;qbSxciw|)NGUWKC` z)q4-Pw&w6070>T(Lj8E~F=vV2eGscAf24ZEt`%lh`n+l46#=&fmF5`V*}LmjnTqcu z@R0jfwHZWROF`BQpRY#B^(6kq9(}v^8{E(G+Oz{&mPZ>p+j@%$q{`~I?i?@@A<|k3 z5;O34`z*#*#mkspQhB8?rUzd_kUT^#>&2l;!3|sOh;&~IsP|6l=}qdjPwI_N>J|U3 zJljdVx<&2nPU`7R>WNP30WWIL_Gjbq=Z|yYvi}EtgMPc7cS*f)U{;9uvibuG-8ZDg z%}dfqH95EmAyUtFQG2of)objKdcc#`;vuc2Kw6{7A1(-4;_F9t7d(qm2!3kNQq#re z;>B8H>%6oJ;*E|{g(nxPr$i!D$n>j}pL9F_ouQesag%iyi;{k~ zs{5-s2#MO$TMf*cSmI(qlOt1nPG{-5s+j#Uy|h$oX9h*>tT#nu5K z(%Lyo4DfhTcRnUO7u0L?_A@+IZohH8;KR0u!=-NCjV_s6eqL&A1wyUN@9)MXm&f_P zHoa;cDI;06YFiIYr{vmOeLBB%-0*rq?TL&~gh*@Wkk(uv^|B|ec|=-^hqQJMX{{Sl zZ+y~PHy5Yl_icWw>%7cu7t)pFW(PFH6&Ne$Wmy?2Y`5HWBFOlFRs$3VC-vGVt&MaE z%+pxn`sznh%in8ESng*qS(RTmS+?QM1qnZ;(N8ZG&vEH}4n8lW-uQOK1T1FA}_;aOD<|xs}IeBr>sPt~Dr_bzl%PlNI(skX; zzNTl2Ce57gfzTDE-=@|@?=8$78vVUb9y^e;;r*D!(JD&g4WB&Rlsy~OZZ!gbIrt7_ zi8oXw$19EdprsI7ExxVM>%tSKvbZO!^hc#03_cT^whj7;x;6u8?IBvjVNLa>V=dy< zhgj#A*DPBQy2MBjGP!`+$xAj;@3(tiI~ht7+k4j;?cT-1nRM zDt)&#a&T$k!GwPtpJI3rq5WV~!V6k6Kcs#b7QKCW4ua@T~thy6%<-{$??L|Eg)%X}>HVs*dp z0l^{i(jjLGpYN_(emTRjI5N3qdWPk^YXdV)b|I9{j8}SlvuaAw{%%R}&*WGQGd!}w z&TfcI(N?k-i#=tNw8jY`3uZq3<=PClnCri}vQO(AT$cwK1f>SeQCgQ4d(eX=|Hxa% z{@wA*3d5HSM2NJ8LlJYGSfFyqrZ{{2cAo#z*Q+v~IfOq}tW)ro8oyobhvH-j$zX&U z;C!thgzKro+5%Q!q}g6)6`lg`79_xHudvJ^fT=ptfK~-sSOyTNw>=J**Gx@;_VI-4 zqMsiRE+v`q4BN(ouR~@$Skhv~!;j9L6Fuf z=mpo$qOMuMAAnF%A2=rX99BYG1Cb7oNx=GTF9<6DYcJf_huae&GNGRnw3YCf543!U zcnDc#=nIhwx3eJ*LzF_?hNy$UhNLVAZHOf3X9lew%q{XE0^xQv#43n%h$g|^xMBT;ey#O&i@UJPjl_|^)rpk8`nm9 z1cn#faCv5<{rv3hZ3DIf_%zr4`8ta<*B+&&c>3hjWU=Gd-`?^xA1lZWOE?a5OLsh{ z{?OUKZ0AMg;Mkmqz*SU?c>{^Mar1jy)YZvCjnHZM`#ECZkor?QOqY*6ezt7o_pHiM$=8QQSRKDP}~n5PKECmnrmNds+f_aw%}y=#QtjYz#-HTB5joq)mk4}ESa$}sU#hb%LqvyWR8a_Ae!VhMPAxFscTXE)k z&e0F9#;siwL1 z?@b{;2#HLV_(ac#ro$eyjPzQs?zsAV`-68Q=Gctb@?v=554+CAA1;7(6&dKu5?@u) z>-i?vXDi(8d)oO9(_OMN!8f#NYr?X0two!f#LLqW@?`qSuJhB8cptqgWymqjFr(W$ z)KqS-nxSwp-fQX8NlQ}qd_d?J)9-Oprv~-RM+a^ml3H*3)MSeB|1>vTom{ZVB>uFcyg2pM+9{r-== zFM+FRYyaOlks+x}NjN2?XwFbVp-H2JQf}j^PP5J_g$S9aA_`@?dNW1nW~xiZkd(M) zGH0GL-NgU9);T9}-Rr#nn|J!{{pso1d#`7$^{nq&d!N1cTF>*WYOgi*m`qj7va261 zbpPP9aCzu%SZVcxZ8nC6(bRsr<{J;&sKe{egH2Phsi2b2ji#W?-moVT>| z-T5d>GUt5``+s-dyEhgjup5g2ivWuNivWuNivWuNi+~6LGXEd+Pt5H<})Y#axuSx$tCJmhc2%>_75xfYYU$AHuKx3@|u*X9%nTuD!bMP2H^6t^W=;hdM zOBluTuCf!Fay{E}kDT#0oHEj-;MZ3v{Z{wET1aW_d!)5DePT)K)u_(lMXA4bNxpAz z%;V+E4pS2Hth%+6sSfFLDb*o7VkW~x;hCAs;kL3r^z3Zd@lEBd`x*~zZvUO@(#0%4`>ww9-*Tk2hd`6*I?xo@Q?VP10E+;N0E+;N0E+;N0E+;N0E+;N0E+;N z0D1pc6~F(F9_lvA+1=jB+Q`&UKQKI;phJEBgO`&7x+ySRCU7FdeCfN-(camCBzG0Z zosSj?Gwz+pT70|&<3oUeC#37>e?)y%;`%CKh$^WsAUdJZ>uXHi8?!83G43_^CPKEp z65M@!;6BlZcyg4uApAdrNnbH0?J$>0Hs{Zn1jNR~@FImiy!ZefyiP_%`UFJ5-DSLx z$PrtQ#_St?u^wq+J?#EMj~`ioJ94pOv-n*9P#-}wFMuD!5AX@`iwqkCO zK;Hj<`X}uFBLwgOAZ%#-Z)9X>V$#>l*tntTf2@!n&KD*$p54C&Bd=r#U5W224#O9~ zjXz(=_Y3DwG>GI} zza{50K9(O4hK1qv;*7DlZliC>e->=05>_!dD%nC8Nvr}capr~13`8&|ycm8A^4m0w zRp1wZ+GBWFvhNoojEyGBhcQeCW{^@}$il-`2wEP*_ovIW;U~;WX*hH$qh)l1oRg9- zj_-h`q3&i)K_I<8AjYEBn|`46a5idL7ZO$a$}VUHnUN0 zE@&HQJBaAZ#d*m_d>e>2s;?@eM8^iH!$s!HI*9%@V*Sg->+k0yGtr-LqQ3>|kYSQw zDFKBW^rBBxFK}f8AbZaeIa0r8F7HLvURRasl8aw7mNE3Vb4?A}7S~>BWKO`$&u<_z`}= zq@R>A{zf6641-}A3?m+FlCdW$OO3X9xQq-liuQ9W)JKpXro@FT8NdB-o?&9*{BR96 zEQ4HwXQ)2&Xqm1k!;6;D6zv?Ow3g-*@B*ljMhMmleIEM`$SY4}IkbKUwvk+0l6q8t_XJXpBFCatuU5TV**9y-QEsLv-=rDEK-88XevClqBW@9`gS4X! z)mt8NR!XEDo$0YP(+xP9qb&qOQT}kh2H9!;5y&r+Hy0m&#!vzI5@`GQ_5DWbGpFS@ z5!WxNPnPx>=_%4KGBy!5?i-t>r8>?k;66ca2?SfxZUu~0Pg*X6v1$gLm6W(hCu7G& z=5xQ3kujRKm|=RuzaQC1J)|tS9HiUn&R<-Ue?3MugZSY>O+%8A=qxHh^#Aj{LUFnV zPLb>B7A>3TXhic6z0cO4>;Hw`&R^**xt~84>#d10$z_JndyFUA=}X%$xwc|>h=L>d z`hHHXr;+q}!reTQClK-iX+Mzmi}E+8$K;v~q2+bPJ^9P~Hy3G=?Q_)18ckn>SCx4-TY~b8@}Z>n^b><3|RQ(#So5v_VuxoBB2^ zrDb*k_L96oF;NlpCzi^P+p;K+s`yxj$)Y~+G$4A9Lq1El=Tk=dO!>Tk%P-V%m_pyj$gRyfH0& zC%2C-GZIXxGJ5_q))?Co{R)nIYFwWrvkke#K**dlK_}+6od{;BfNh-J4u9@yXF325N z5OA?}5P$S5BlSu54YT@hbu$~WeZ(na+?)^4dbxW~1zq%<&veaJ88g&(*1Pz#mS$n5 zRpabGx$}4CKEKZ}>UgN-asrNZ->Chf$$=3vE7!f*JuLU!jMG6+G~=5*7%;9dbm9$+ z^Ez7I@>%7B_^$?6+9xQ;RV`TCTHihO;gt?epSmr3HR<6Y5({C}a8h2?`_(=}I}Hiw zaqYnH2RIYEG?7n`R&saL{(f_pf=UJw|G+7ZP zw^BxZ+rts5uWK}G8D;=&@A*C3+Yh)IW4PGiQf?=2g<-CPCr0`EdxfVwciymjw^b;^ z41^UnmlK_B-b%+$W~x=Rfi<`XS1bW2R}q{!`^|2(#W zv@rzIXuUcS16<6q`#Sw&*R=6v&c_Eei(341H;pAr6noE5Eiie#3s&v8fpR&U&NTlu zS#I5OMJvtoxwi}#ah+`|d-OW3d$x5O^?u0%{SjN(k;qjKJ0250L=f?InDwrJ5m#ky zttx$*IOZXD@q{<38xHMAWtajgSLr2qH}k@?#5(N{x8r(ul2==%tA4YknRVf=idpi( z12C@Ssn7ohZdNCQ{bznWRIz3JyN3tTw%;g?o$qq)XwU0>ujwA11=7a`&~_&J9aCsK zW$L?`)8Fd5eiWv-j1jo%X{?Fw?!3`_zt)^L)wmBGr}c*Ji+i~LvHz6ISF*S07&@&s zsCksNj#oErQw#5z-7LrA_o0UiDeu#&r;G0H-aPH$+m&6nC@d{9jFYKO9FUYVSTn;p zbD5eSd_vQD6T&pKlG0P;<|gm$S)lcQ5n{0ZZN7v2uOQ4>-L4+c5+dx{`X2hwjM^P&FQuwit2%BOFi zUP$!ua2a&3&C4>6Le+jw(d|`L^8XQt>zB&SP>~CoP`f_vPTG^hD>oN+D_V6-ZGB}} z!ThVGXMG<(n7}Z$7&Basr<{s>#O|xx+AppRSE@TxXS4qD$+Q$%mkBBHq5YQitbmVk zdcEbHODkU5XVXf9<0kq?RJu-!|NWAt^Yt}O5j*o&mG2$0l3@e}q`cY10WA+C9(j@w z|MJL{tu-od3g0{KwYfFnRE+C{R_8EWm~+6I%enNZJm9(JzzU7WCMg~KDz6yD< zW=-p9K6{(od(-g_!_1}n>FaBc@cL+@+2^$eSL5#XtI64IS`40@dn<9z_LC2}y>~Or zBHG@=uic)%jAL?FsGi&N?N~`#c!=e4uI0bmke{=w^`FN`JV)DMEqB0vt!zK}s*b^> zYbrm?EW2%xaC%NkUikSf3!Cm8)*Qc=xCe4M#$$5ly|(aZ@vGCgj!)Xu&9}GiGFZE~ zPB^vhc2&;C_A{i9(Il;3%exepUU$95X(d#RQ(fC*X0?NIyG4Ro<4@l&HCorUAh*tZ zI_??L`qM0??U+26wr7RzHZ1>|$RddU; z+=>!XKa9$<9e=Ld28$eq2{s{e50Y;+n^rgQzQxVqdEbs*b%oX&s`%i!tJmC!J`oua z!D>raP0jP=D&Gk(a(R28Tt#9@bkWqDfC z$F;Y0n_s>@xj3}!RP!acZ`jlF=AEfJ{ZSC_A_ zv&W6srgN_toY%KHzF+gjJ@q@Ayn9a_9@8NWF*bTp{e~5F{zc`!;l5T?)-}Uz`^;M1 z{O$SSd%Sg~M^9+3{NYm)!(5=iC#1aP(8OFg_aXzFT?c)|}L*y8hKaS^1dd z;G=;t)o*aODNlbt8@*(!LtLVAW{YaxX;18W z#p90JPt#4Ruih70YwTN;k(J`SbcJdU$MMjwA8BuTmrimvW~chLb;y^CJ7q9!^2k%= zk&rFtgow-aB6SjVI$?4>;sF?+W>XBcyWHa@kc!YPxjV*t-4DZ^ufipmN$N z&M7VW3p15BRNS}Pem=0%yfN!-HH)uRhF2PDXx`Am8b|uO;Lv(NasP)~7M{3fd0{WI(u^alHbf7-?UtGwN?Qy{8Oo%&EC;{-o6mlMVJ|d#jLSW*xe+rNPde0)2Xhc zg{x8VB!BXlFfSbd_r0q6xPvUr#uZUBrwmp4ef3Or=Khs^R}jv3bS~AnkR_ zDjR=f`GrY}4l`$eJJ#(Q3nJI8YyUG7w>%xP|0U!!tn`sPX0*4iyePTO0qL2HK zcktg#nbbV&faRgWAQfC=}vjGuO=S#uW)-%x@DEl)NRij-!F3EK%(E7jkoR%KndQ#~y%%dUdA9^dY%T#>%Qttm@aOiis!am}%Cd353Q z{J{&%?t2#%4>P}H^7=aBu?!;RF(tyi)7EL~-+6SXYv_Ye{)NraL3-2WpVe+T^Kj-W z4xTrr(ef_#s@duvb1U*HmNE)e8XR-TgKt5(^kHSTJkEbdE8=6 z)v%+x+Bdt0vO;OS8U@YrHni|xrrqo0y$^jXT-vXZzj30KkLt?ty$n9N{x`%JQl$5n zUg;N7gr{3~Y|*KEr*Fr)wV`r%;{D=u9Y(AV$(*+$VV>%g5R*}YDvOy@+(*RZEjwDG z!!YSoZdGK_)ZM!b?mrB(xF0oH>q%PBbTv)C+VRm758X-&m-9wk9V^mr`-+FZ;`}`I z%<~gE-FGzaxuDweQDO6k>-%X=^&cN|xh_NcnAT%ydEL5=Te$V~?X*q8#O!a!YJExN z##LQTIho|Gvq!6Md2wsqDT-NBD{{0vr=2RuRoYYb0QW09Jj`-A&UZTOJnL+I=4hq& z-CcGj1rDZlE6tWo4!SU^#hc1K?_=;ihsrICYwJ@ZV|nbi;VmizH?^al?G4r2D>q>5 z&Zr*pwkGda;M=q(DX&(TkkUeJL8SA={4@Cq70$Vpv9|5|%2}_@y8c!z@X05{hQeG4 zmop{R+{E(fQWMXd)n|@w6qNL>T{SanRFAibb{AKlU0)l3?+inU++?Bh4OfGLhi3B2 zFPwPSbp3iI-&M=@)a47CTE3lo=|~yFykQsyT|zf9pBT~#y7*uw2>b8w-nJeOE)&K3 zyRlE^5-gjE;vSJX1+tIf&b$Qqf<*JBqWM#j)&l3;L1dfHFiH3sXBL3B244cM3Z4e8 z2EH6zU3{z$o{3{a@GNlrTr=qIBvMZZNHnL3=M3zVdRl^G*wAe+-T`Z=qe@v96ygt7`O#E^h=5Zj{wI{A`=BZ6$A4%ivr)5ZO>Rm9xaYXnurYG_gM^9>B6Lyo^Hrvh>~#ry`|9{ege8AsQ^)xoR4CFO{| z>tj9*=f5rojiBXlz==Lh!AUu-z)8Jrz)3k|42r(L<2xGmNjV&F(nhi=LynB=w&2R( z9l#3#P&^Kjk=YT0c`bM;=p9JSh+&3-grI*mK3GX-TravP2a4u_o2p^_fC53KIIaeT z0CaBv6Ao&Q0Z%|m18oEqf-ZtQaK0K`5<_ewbWy>e4aa#BOKcCyJA!llu}|WORbk%) zJRU@1irL}9@&HLThzaBuKApsk>*pmw-8T|tvU8$jfpiQQNPSOi!ESOi!ESOi!ESOi!ESOi!E z{?!PO_sVbiI`=UWMF99`{r^jReNPrQ#IO^2m&XgOj}M%E+r;=q@a#m6#!ZJ!=R4-(s_UL_Op*d}AX zy^WZ=K@Uv@@?GPg*k(K+Dk1_gK}Z4k97Y=@&TdQM~~?MCwo!$pn} zd=R-I+}{t*1Bgu~u}3VSb@rxu5!*+sXs)+CC3=x@;7(;MWQ5GGG@tCB))9#2{IQN2 znqQaND*shm+^OD9bbn<)8}C2GAk#{#kHhi%;kr=sZXt{ns6wX(H)j zam2t#KOsNvvqdjFH3+e;1^S768H}YE7|C>GEEzxM6t(X(M7m_dk^%81vZ0pvS|DvD zw#jQLHpJH7n645a=iKNyYOma%WR}=flX6{TK94U2#!TrRtsk)t(Z}TbnzMKuUnCuj zjjV$qU){(O2eNI)dJilo@s+gl%Ym$IZtiP@f1mBEzdf$4m7LLM-1_o5*4vR@M7#dn z#`UvJ_A#mlZ6jG?M6uZO`CLEAxv%kQh=p?lEJ)iW*RUN~B!msBFa(BHAaV`AYfal8 z{fC zyZ)24|Nif^|JKI1<#J>qh9{&49?drP(y;t}R7r`!>|O6Ps}0;j#`JzM>%|IVJl)t5 zx$C#4YAf%(-#cfXrJbo@B&Q9j!!%Je5qE=B%Q^$A2<-X|6IHC)1!!f@pWF~H>@qqR8#sX?B(;K?P zQLsn*6BP{ef6b0P8^0}FPP0>6%w5|ytGm=Ol-W4QYp?!>3$rZhf&xYf`)Hq8@#L8F z_U`RydFxsounFF^`Evi3VM#Y;4qj7q)#6y{$ua#`4G8vp(djPMBR95P{Ba-Bj+)mg zHJ1A(y|>kSRK6tshSilllWyO6s^M_&LofX+BYY;|S<{2a<=kZahjKSoDfdq~%FI8d zF|AnJBB#u2$JzAvv+I6MSo`m@vuEw+Kc)rT*f8DU)3K7{T~9B5`doj?Hg!B(jv)P} zmR~+mebEt%gg*I3JN#@uv>B*#Za~G77doCzyZ9ejI0nAz@C?S~ILY(u&bpmGRjTpk zjM<*Pb$3-Z9nvr{UAD)|qbqOJ+s6zet)2Z_(e+`-?YGnSdCt_c zz1K{0I%hhLoS0R}+T*kK`2Sn>_$_?Nbu@e8hSl9Pra7GtaE>2m=%!eCd}~W(VfCoq zcizn2q7j+kaw7u8;5A<4bGbA4Pv>xUK9DJv$qAe3O3G?*o!2A5-4h z@5bxnI$hSJbTP}%zN?RK9{BRe+U-Yc=c$j$U!pj~@L7p^?fL=u4hG_K4BZuWjoX}X zJo{8e(=@{yb_%n8vEQB1#J1vAk4pdEo}R_`=jNCl{>r}Sl>L+uZ4ormQMi$_nb+%FVJ}m;Yt~O}7^bo9`^V9GyKY*4TQ}-uMs9+vpZsyf zo+mf$h%s9^CUa9u<<^~5ALDx&Yqwwdc-^hHy@MTluYRJt``4Tk$$JX$%&7pwVlHPv zal6MWydKRP=hDVGNXK~A&ohIf->sQBC(~fsig%o{Oos8Ja*9hsjAY+WUXb2nzkaOQ z)%DsMR~L*{Ii2i3`+@bWj4dBw|4rrYzH9Qb=Y~7mFYj!g=JdeA!TfHy+oNtddW(H8 z%XL5c_wD{@Md{Zqe75-9G0a`LEoLF+BGPGj-}eKM zPs=O0x>7T}a9hiio4H%`U`l&z@8UGHZsqU zhi}vp+kdi8Z2!skd|&MMh79?xPxf&;q~G_+K5lt*PLS+7VV``fCi`Sg^(Bsp-*?fx ztZ2TLq-o-OZ=5F^UcZtsmBu^)R|kI%t^@uG+z|XVIEFv-9(*WxEjX#C4m=PXmq!w& zh3KTwG_WR^IGYbn?7J6&Hv?Y=-U1w#9HRif0i4)*7l6a5dQu5EvEMES?+AViyc0O4 zI2kTD@-SN9NMne-zZ$qMxH`BVIQFUiKYRdC`+eB(GktL03>@uGvINI|k~KK-2SEI= z5q|(?V<8@&6)~XgK*au^*!^=czwu{w{}yP=*S7x>yZ^6k{)xSRAmkT-4uYyd z@`lg}#BMACECMV7ECMV7ECMV7ECMV7ECMV7|49gt_sO6i7XQyDkS7QeMnyMX96-tX zd~@;oN)PgZ0vlfE=!REjW)a?ltMFn?*XNUvZh<`i*x+DZj88~ZRG4UuC0U;?!(f>` zFD4G*m*^Tx^3E;F*BmPyhbfUV$y!fZ@E`xtb-!e-B#|TKxyXDjkF1rHtO2biAQKtr zidSjI9NY@>)l|nh;-%L?i0c*P#}6mE3{v_)^$Um!L>qWK3yM^RiQ zL_r{t5G9SpnpOcXQYgw#RQMg0%P@xc)`GR|IED=XiSXv*j}TSlNP!umMAj6yq;fhk zB-T?M0fmvo9r8hWF$p4BD<$}qWJXX~E2@*7j104c9?Q`>L^0n2qL3#l+$TCfl8@LU z45D&{RQDi!$bfgq_y8UZKww4@9mS7C*e3FchW3LcIMK!ZE4dh6KvWF+j`Wo)WXRgt zk5u1!^9iaK$)=2N2{QO{Le|nMVNZh|E75YzXt_jBUcAspQmUxj=i<6Wcp+97B1rND zAs9I6H`R$tD@k zIHu!F8RM)R>115E$cV-Ti33Rbi|B?pUtjd42GT5Xo?z=D^KEQNtSo{X!L^}`1Obvx z+E4Hyb$*QxNhfU=)&ECqh<>EaqIJYy<6)*GOUD4l8`?x{7mUQmM&e@!@$o?M@dEL& zwfMM7d`#BXll(HYPx0+od@L_Mj>oac9zYR$_~rzi$R=iVpOj%r<&(tMV}rm-X=08(MCLMFQ9#J;A)*V442ARc| zZ4$snDH7K_Vx~q%Lqs%Q+mgM&D1kTtA~_=03Aw(>H#!;gu;^HZnMIGA&}&VW=8NV@ zvPssd|3qaZvCkxVek>A6V=#Vbffs7-fgCu_F0K%GS2w9^xcGN%t@sAug?6?C5iSQz)_&36ziunJAD%}WWSGx)R7oF+%27l=S}DOF zFq22ib-=HK4813|pndxpLCHOV$dmhbE|s^$x9R36Lu4bNiMo1#v_Pb-T<9#>zP_K4 zn2WWv3}Ua*7voSAvykZPBJ){af=LYuNx`+w+7kR{*%HL#df;;U?Kt#X%Ox72X^Vd= zl)a)iYkE*cXD#3ExB6BX8r}Ql#ti9W&Y5G9hRe~q8P_b*_T2cU6Ph|rx>P&tQ_qRj zP8SSn0*v-|T9!~9B(itma&GS%{Yovi!&1Mq`lep(TAB?meU=(}c#Zalvu|FF3~POe zwM}4S*s(F}*cf*I{up)>=zT41{J{AOXJ1(4;nJ-0oB8nt6OTDhyRY2KGqq6mgIPp! z85_f{?CjrLgD>scdNzg~8^dn8)BjKmJ0J4gl;1@d!pr|SGb(??0O2Mb*ZEy-4v$I> z@mqJ7w`lv|E8ci798KiDzZUP`6%$Wdn^QJ+9veIFpNX9(t?lQfzU2D&evCb7Z93Ul zd~7Vff9IP1#$Ky0t&IS?rvHCC7T*gcqsAm7I|L1as!e~7~iPClQ{0w?+QfJF0|qIpr057QweRvX=x zK@Q7wX-qyXaI)rG7kn+aDfoJDYjCnw+XcKB9K({X(dL66!*L`yS*yJn{5<#$@XO#= z!LNb811D>+F>T4*0w-(k?|^p$zY9**+CKm{27d@n=4~H=6aC3NhG@P>G>=5|C-XX3 z7EL!d$dR3qVtIm-Xud~;&(}CviRFialX8ZM^N~p!(HxFwZinP+g>!)*vT-3N3$6|> z53T`@Pv}e!a4gv-deYd0SSn5N!*XsK>#z^_Af%gv4+kFrPUehouD*SuxfRiz%h&Bg z{Yem~G5sXt;IG<;I;cGApzXu!7p=z?Wr*e?L~|UZ9x_gbfyg!naxK9L5(iJR?)|S~;Y~*8|5-e|Or(7s6HleXm+|l}LS_LvY6Ivo_7$;?y+35g z92^(>9^mmH$y)gu$Tf_S_w}0j-o5|0X8v32;L_t`FaroJ*+;}!>V~bIOFH(g&XM^=^6h2#RB|$nz6ZA z1Xu)E1Xu)E1Xu)E1Xu)E1Xu)E1Xu)E1Xu(b3jy-}ulw!y|CrdwKYRi}Tr>+MIWFR; z)hj?|=gIbEEI&tkX9sfjN0v>>XEzoB76BFk76BFk76BFk76BFk76BFk76BFk7J=_0 z@E7y{5q`puzcv4_%a91xSg$TtBc>DaMT7K86VM}EZ zU=d&uU=d&uU=d&uU=d&uU=d&uU=d&u_}@d|FW&!Sh5T^7FyV_O0FCwj-za7O@AU@T zA{GG_0Tuxk0Tuxk0Tuxk0Tuxk0Tuxk0TzKDg8+H|_ZQp$4>R}n^Y)n#6%*!dF zCqdXFc!7LBAJ#KAY9ex#p}AIFQ1i3;^GGBPwV>1$?e>>cGF8sqI3 z5!lz%J6IqN_st72)yH|n8L&{2@g;r(+A>_mcOp~Izw{g6f)MZ#{E7U?VD8YUh-f|{ zsKYWqQ%N8U1b0-jMGydUag5|@5-0)NR1i!HXiS75#J@kaGeAse+mUvnAnZd!cmZKP z)^?^ewsAblkYTJP(V^YMVdQCy>*0tUAj+>rkDYPc6+ZA~7(1Gm#4<wXc%}Z z>rkJUOOG9KtU~jSM112xO2M?=p`tkI;#x^OX4m?BqBz^5aom~a^P+VQLYrimVSGWf zpD+OS65?GN5(pATPtz12K#QqbGHe7|!i!z7F)5=+KKEH>LR^ zpev#*@F(&ckEs;)ebdmWIN0QeLX#^`5nLlDBi6dRo2C+TRRxYR4U9WLk3031%*Y=oM z?V#Llkzm&N)Avh_*0n9jturU_0gIt5mos@VZ%xLo7s7c)4!>D7^B5=-xYVS|YE@A8 zUM_*V-g(I*Zix|*+gSC6QHyslzw|NR(eF~2$5BDh5y6b!8+Se&SLHDwKN|5S9En`@ zu;Ve|Lj)0Thgt6m7;#nR)~eE{iDMpe7f*Pjy5Z1{RE8;_a+O|!cQY?MORUrWa67Jd zCwaAHy6QJunpqd_s+c7oJU|&ZI+OAe!Zfs!(o^K-ChzU!t~YJLeXEqSO0AUEEIpKS zcuucz2xL+ST)3Rd?CJxx?>BF;oDkcrq?RzQKCxZgFYXsn>n67{m|Tg*Q!#^Yq#dR z4^Qctp1?4>soX_n>#O;1`&oAF+V0iD&VuR7rmwesXlk@5cB1^-1+AV1GtBE@M88g| zdj=V|{3%`eqn+`Xk0)^Tv&E;IbHC0=A@BQ96^DOO5 z1tU2XVOP{kHk)7Dnseo(MvygPhfFmla`Wp{<4X+-DlO*RexrJ8YhXxOm9N0<>B1Ia z+5NnnED^8cyeX0MS8L+7aih_+K1+^l`g?KuX7(lJ#avKyOis3u6^y*k%eK0i)XQ4& zc#i$d`bl^@j_NKdbD#cs}Q~xr_Xb@(ynipvPnckqbGSypY*u($iok zZ%&(OK`(!~>U(;k))k(nYj(cVu%}84bDhem<(E%XUv$JGp-;Zi4nLa@Z3gO`8&I+2 zg^p*_F8)UrB5+Iv)lWOcIi*E^VW#qiiu->r9$ldc(XT*br(@B^A?pPE*{>F4J#vk^ ztNL6ep!tw>+P@a1%F5wJITd4{%dy!zy3gAe!nz1Eqp+AYHVV6&sW`O(^W>SOYkC=M}vR-#_J9^*NZU$NO`dEHWy_1@Abd7qo;iBggYB!x)*sV!vR-1VP1*g}3I>lgdo8BJ_^F5I|2N%b0H$J|EHA}*&WTdu-I z-?GU-Q^&nSPhFb#GNO9J)B$aLw(_00J;tk|yg{_y#llU9+w74w03f_8#IYobGGT%P9dEyuE z$$h%c{xmk@wtvB=DgpT!wnjA`lmsv!ZU=dmAg)*ZhFP`?qgi_I|*O z$r@@y`rW&|V&hND!!@`zlm-zwrbM`R+B!}BJC6=^4Sf*GzpyzvNN>9Qv)V0Z9?o3F zxr10+D3iGrWvoH;MHtF&6SYWnz;UKtj7D;VYl0*-MxlO{H) zDmr|_U#DBf;j7bDzKB}#Dy@0kVolYsqr2KSyN9-h(t0%tn&oY1;lE6~*U5X|j?-5G z&sAK`IKT1&f%Eejy$ze$G1cXr2P>b=(k$6gB)9AF?cKUd4e`55%Nyo*d$7)3u9-<) z<@(CU>u$a69qib9^%LFQzvi4s-cx{JRtkejc?*i$JznAUXx=!NHqJph#9x`N%N) zsodRnOX1H{QXRr0X5zV$-p8|BE4)7QAR=J6)zg*f!pwH#dGC1P zH=c}pJ>ZbzyerE1J&MA!IhVt2Wq;_|*|6iA^s{~+kUaUA^3HxYULV)#vL>aAS$_6i zeZ-WrB63|GobL8&$DOiGlX*UgTYWq7E2LG7y@*d+E zkEhVDsAouAm&hn(`KV*NA8)FfTb|`sl#u#iRF>`dbKN#r5metxS;7E!Cg_sT%rLPx_}P zt0ep991QT;H~TQd45at*$wK8Dt_B4U&E%I~IPtFO`t?e_tCsDl%NI7ad^`8jkuvy; zr`OxH{C6Ajb9S|MdEseh^?FHyZ+Kk6C67mrhL4Y5UE5_1#(g{pzxz85{nm1cMrhjN z-wI`~=*^lQRMA<>xBIQW6^2Ilez`G&VNz(lwdUKN89R()%36lr?AYY$;o|GO-&-o4 z+?;O`mR^}#vy@>f>F?lmxqTacAG^I)InJk|Y*lCZ-R32$hx^PsAGTw2aHQH2Jnx$S zMC#SL8P_b*_T2cU6Ph|rx>P&tQ_qRjP8SSn0*v-|T9!~9gjj!6zuWspzfz0su+;CY zzNuHcmS%%XpQVN#UZeft?3-63!&)C=m{r!KysiSrE?PbAciP}SG14V);+%y^PQ5?A zeri6m#HiDdE}8g!tD(Oiwy)B4m6dL1Z#CYrc$?~Ur@Yx$6OZ~=xIHM{vPx&_w&(DP zN6S0CHqi5A{}2_X?5B)qi=dH?!i}8Gyk6%Ddzs2zvwmWO`x=$I8zy+Rb?4??p8j3a zH>yqFePjIVG24zT$lY%Cv1*kdThd-A?J*hGYJHuCO?K`U^DVurMsY4-oKiXN z>V&%eyIPDFDtPX^tQS7()?|gO@?K9f3)KZtMVeZ<43mHtE-q)9<0Kp1#JsuA=Yzu^ zMa|lnUi2ZS$(FKpYU%O4=Xm(8Mhr$Ox7ev33xD^eZFvN%sx2`fqhJ z8?k-FDPv8B88w`gSM`3i&(Kao0(x9KFg(J!yUwB~tC}}^X8$C7S#H+j`>m%VMkJN% zTPM4(-{v!xj(hY!?frR{=`T%IM9Hm`QQ!7(MC$7r&036SdLNI@RnlSxxC<@zRAd?6 zTUc=QgTsvj-8t?0^xYA3Z(lcztAr+`Uis!WgA2!Y-#ANu41cwO;k9#4)# zilcAG?Xb|RS*ejaA?V{pufezn&7;q|3;JZ~eVXg!9yO@!?8mf#8yluOd^%QgyzA-3 zPoL{g*{04gecVWS<>M9azs*?r^zG9Ni9Q}KgYLC?S>{ow+RrJvy{bz7KLYVwOyy>% z$OTQPT_1NR?aASln~S>@tvaT*zA~&}{?*d6zKJb`DQ|XhK+6M(N1i0azdUkf zYmLgA!uO7QZEj6C72`Ug)j8bK74Aw5L6HcwWU6r%3J?1H5&NcU&=(X4dW_?cruZh%9x)(6NuV^)Mo=N>B8bF{ ztOkDvYTg0gl0YAjuP68(QU<6$_DOt5l|Fxr57{s_WFcfOf~rBXh~3x@WC|Jv+JO6@ zJ9sAa3c$C0f5EUB}!1IpbVJ6wzFMyX27>j?O_ZVJ0 zkK}TVi3-MCI@bns{sQmMs{%&z1+jkN+>yfAKz@|Bu^|>3U}Zo=Y$R+Gyhji9cBktS zoJL~T$W-6NSl`6R#JI1wKR?pjE=nNuz-okeP&k^VPpXOz^p{#mlF^M9&hr!SJ}azG zN(hJuWVi;_Zf-7aZq}|YZtmu;ZZ1x)?py2I4_PDK2Y0FU>_M5g+9~f#`3KK0(b(!K%`@h?Wa6TI0WHr>z-r3sRqc2{pv8ghBm1G!sy!bNAP`qDr8OB#% z$cq=!w0=rBP0xWbG7L@84CIr1{gle_{>+6uk&&cDM3Qw8{gft@X7xqBiw)B- z_tvn?s)lJ}zf2?Rd7ule&;G0Wo_~?{Wqt3yNE`Y^eGI+_)tC8Iea#!BxqeljV#Bnr z@~JdPa~J0$eQt?AZo@R>BYlq~n$}a47R(C?z#1UU1ah8W^L2UMQK48>Ef>3j61u z)7-z#_pU*jB%k;iuw>fM`r<`bhX`A;K8xs@f*t^VG))s1UBf=Pitm6(<2B58RfNGo zahmA5!Usl@51+Y6nFsgan;`Ou(o95YVqFfFH%!BAhvaiaACi2&_&!&kuP;gKtHdGK zxGTQ<;X56X(HASz0r~92^?_lii&98=8^z~Iy7;^%x{%hz6{kIKm?mJb?hE?k<7pD= zPy{x}=P$r{qJu2a!Ixo^ZY%;U0xSY7 z0xSY70#YGB-v3p_@BgERx{Y#nw|BBOGBxxu(hm#|C(oH3l#woOkxFq^h(&-!fJJ~sfJJ~sfJJ~sfJJ~sfJJ~sfJJ~sKxzcY`~MHH|L0?N zp6?gVpNN$Jjc)&61D&6@liof|TKkg5wqumm&Qe-?Wohjcq_tO(*1n{%?MAdQ*Tv2u@X;vG!g^cO_V%CclnCp?&KKro^DNo^g=dO!>Tk%P- zV%m_pyj$gRyfH0&C%2C-GZIXxGJ5_qzGc}Gxq{=K8rLUIZIM4kGc{~+E4PP}AN>A% zZs)udtq-LwZRIhw)Yx_{2WY+Ay{CdMdd_FMW~+=D>O1RQ{8>x0Fw?4W_MhDOJ9D4k zm)?$|j+VE4R{0?QtHG7_2?}ym3)Z&QcTatIr9;!FZp&UxdUz-cb8d}oPcs0MiCoV4 zJ=@z4xEW)(*x^!cCvSyeu7f8=`TKi?r#yGwuzR;vsPuL>iPUZ+qd@m)?U2;vYMmax zF5Y?1D!<=*S+4tw?8u_J){n+NUdJ$(s9edsbz$Z_uQx2g;ZRM9m-Fo_Q&iTCzb9xk! zi?8z#O|xx+AppRSE@TxXS4qD$+Q$%mkBBHq5YQi#P$0Q4^>=F-nq2mrF}N7G&pXe ze?+D0wD{jIX*yqD;}o$oe^vS3AuFY~uRCW(%DeQaJm9(JzzU7WCMg~KDz6yD< zW=-p9K6{(od(-g_!_1}n>FaBc@cL+@+2^$eSL5#XtI64IS`40@dn<9z_LC2}y>~Or zA~#ar;n!}@U&b-HD^$pqg`H=$dP z7f03)o;&cs@ssm^;a=>UdO>S~-GR$JDw93rKfUiEy*;qB{(hzz(tdN3eKXCe%cRLU zI{96!mXzO_pz*^0;Eqa-_h|=~yKcuilg9Q7G!bjOxSZNnryY-N=ayX^c(qBI>UFgxnl=af*}FbSo-MsU9Smo* zZ0);r_5We?8J zIO5gOE0STP^$V0u??dh5>hcwK_PFudbnX>{^ZHiD_iMhmr+#OXckijgV>+Z|!tWQ> zgmO8AI@6;kG*|xcDT!e&P`MY55t(!D2|qac zDOwmGjdtIyymM<#>Qi0+>YuE9%yO^})fns6xSYY=rab-qZ1j@Z_9ZKIxoM?`U(M0k zaj`i4O_^}U!?Qgd@mxpczVDAnT7MGK`Yn25N%Z@^-wA2`Nl5FTLRx=GjqSJS-{p@; zTK_?f?e9lgKR)9Ika6IaRW|;}@(Ys`9cIoB=Ux2mUYCha^j13r7R$6tts5PM-$7~p z^E9^q2WkB}NbASPf%^L?(pR`OW$B8ksg)_NITkLDE}Wh}c!Ak{@1o*i=9f%fUzgrL z&oo-z#a=aA{bLU1^X{HgnW(LL^zevOnFANzT=BCSn6x8y=7Gld&-0(|cSn)lUwWlq zND-cH-LXZd?wxGUjofZvyYFRFrvRCx<|kjQ`MHZ8*2<11<1g1{U{$ih;4>P}R0gyb z$|j}uP|AL?^J3B^C&LMuK{l$=`{$WX%bTRFtlC@IcekzMmHR5*T@UCNrC+!3+2V7@ zFn8s)n1%RJO{e;O-;Yl|EwAM2O3n1bZ7oxhA1QHPj`q!tJ-#d<-B8U%X6g~gl*R50 zqh>|gv9EaeE6&eT&pbb&(|t$to(rli9~Cx#xW1p}RR8fYm+La5_q#Keme;M@xP@C! z-%i^kOw67Y?7T>!v%tHJXVtyU!i*D&e!cM=_V4n~;+G;Hzr&@VJD?AscK99b4H^dW21)!@5Wf`P^Ic)t9{FMC($E)$ z8vJy8%OAzpz9@(v3W@&-5A4T-=72ImrgHEhL40ChKM?yD!HMsQOq`SWpRnsC@|*Fs zABu~RA$}+t`k=7;h98P=`Jf>FHi#bz>VpE`8Nc>H!LS>P0E+;N0E+;N0E+;N!2fXs z$o#*Sc>TX$G+!@5pf`aZsRtkbdT_bVk7^kGPai(~@hDes3qU-=|CLVw4W@|_fj5c# z!?wN?v2BKdp^tzk^a+ZH3gj`wFZ++G|HqXpYL_>j$H{iKzFj`iK0X0(PC!~l>^Og1 z+i1n?KNbNN0Tuxk0Tuxk0Tuxk0Tuxk0Tuxk0Tux%5%`Pu{}7&Ebi>zwhQ9xE8@~Uy z6xZ@?e*k~-{{6Shm9lB97>fXl0E+;N0E+;N0E+;N0E+;N0E+;N0E+;NfEWSt{{I8) z|APe~evyIUyclZyk2=h;c0k6Ld^>21H3Pn|W|HtPza6+l3;7ZJiTuc5F1-9lBNjjm zX3;g3uowZ{QOOqT@dq)AbX~zY*wd1Y_(vzZqd>#3<~1H`re&BUAD{ZL_d`Q?0bwL+ z0F7g>$_!E>G3I5MKgO6RG46+xb+)vOo;2qDa2XlqXL_svUx|a1NQ`+I=8rMvNnU&8 zO`@{SG_ON_S}XnU_XctvQ8A!MAk{-8!E@R<4A6lb#x-ujp>*oziaV49jI`+CUO4OG= z=?52?KlTGj$1+}qVC^FFN32zm&P6)G(?#Y>JjuF?8l;uL=eM-Be~oR^*Vwky(%K*w zqTO6hWp?#}+V`8cSk4JL{8!eWVJyb4OFJy=d6A0UwY5|wV9LFcI|EpQm@_cE5bK-=E=)jtd8-$zOZ?v^3++*GUs($$Lbz% z5=_Zw7-?<7rM2~LY@0c0Z9xBBwspbOhe|W8YKzL{daLvDo;i1Xc5d{`UZEMzu~Sl) zbon&SXyqi_45alzBdx7oWBbTyY}-F+eP>8(Bj|(&Bra#undZMH%dK0kXr*~R_m<%z zuCr}rk6x#B&$e!(-Yo=XJi< zbPvx0>1_$6^@$;^uM25y1f}(1A+65|r9lK2rbM`R+B!}BJC6=^4Sf*GzpyzvNN>9Q zv)V0Z9?o3Fxg)(VrxzSj-lU05s)`QZ@Ym^{xw^&m(?C7rc&F;Z2 zF_hM;QP3=JLks_9+PzNR`_RY2rTrTD8z)-%sIDB}%ixpiFN3A`@$#Q;b11D1yp1Kn z?@qj5oUX%&^&y$_RwT?*of2X)N>F7nbBgF;cwaw13 zBJJ(+;B>cFJMNTin#}V_-0ItrUs0W?wshBs7ZHO;JZ{gg{`c7ulILYlyYyP&5Z zDX&fETaif#ZDoRtZm9+hNY&7{deT2VStZ#&=U{-(zS)PRw>i|J*W0!HcN_9^cC~hS z;b~^|dP#zBcwE6Hk4KJ%kB?tn+hq+Fg~x-qoPIkF{nm1cMrhjN-wI`~=*^lQRMA<> zxBIQW6^2Ilez`FN@vw&yxmxpW&x{?$F=Z`7Z+2{Q^>FcZ-tR3HPj1dP2}`fctywC) zZx8dINO@W}N&C6>4HH`fYJU=%Mz-CU@J-WyS;DpE4A1T zOa0F3n|iftX*Rg@S!(FvHQFD}zIin=to0#=k=A!wW7~R5>x)fVoAAc=+1A)T(Hh$~ z*+A+GD>_$6iy7c9wAfRTWq5C4!PO5AHx6{?wCmG%N6@`}-7v1C^`R%NuPJGLNJ;B^ zNm?IBjqTe=0GnSfXLfNw%L9o=o+QM-JaT1gjmn$C_l|pQZcR89<2s?$xgoe$sZ(EU z0mr&;)PB+AzzCU@>)z}hmV0i->7XZ?@l75K7*`lN@diFdG`3Hmm#90Q5dGF5`sNdj zdlTICF$hyZwV-(f#cPmNe3t25LST0)R@@-j@LU9H!2CQtju=sVcoD&HL;cUHiZsopTx%cd-m1D274>9gNEKEolzk2XMhfZh^_KF zoWF>DQ@m5!fdWB~aoo@zo7iFt@jjOZz7bRix(J$sbD5C;+AjM8@)O(aJ)|s9f9%_V zRQfQC2Y5V)*lF8AFAtE!UYpozUjz|5ZHbNc*S6W2&^NQM$UeIUc^lejXTWBABgh@^ zCVRk3K$fWUTXx#@Hrl}8Ya8u+l+SJ~0xSY70xSY70xSY70xSY70xSZJkAN(S{8rpP zQS`sRAOG+Fr<}%bC0ink0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N!2fLo$os$UxBdUc z#71H*KJN<`03sg%$WvYqn{++^lg0ASCBE{6yqE}nq@NJ0&&hi2AE`rEu^&QNve*XO za)}PSc)k$FKe~P`as3O#^@mI9r+yIqqN9C;3DN%o9CXEcsE|o=Y(Wk52=NKxhoet? zc=6O8;74QfBl~-Zq@7qFK(>SR?Tq0C^97`p!jKrAU!YHTRDfSNX|fLnA_jvG4#WNZ z0>Xaym@pRWxK*s<^*`zu6-iYJij52q@`>Tfe{-Kmu7MPC!@-tP-(C_bl-vw_{w3p1 z;*+#pQ;{C?{-DQ?$63<%8^t!wE1yy6^jn$D<{+J7SnA-_j}4 zFD52xf)6h;jvo^h8NrJb{&2m_#d=*8>y=!uS1^3Yio?wMd_%E+0cMil6>qF9BwJ>^ zZlWKSAKhm^@*XO=UM*hKYki{$F??UhWCUV={&BA*4@Wc)EJ#Q7@l0fU@xEzW-e zHr8aSs4488$@y`xKPG%U{f5gh*4;$MxhRyJf1xhob76B#j=N}x)5YcLXo`;8i_@>c z_M6B(LHXp{Nh}&ej(>rHIpOL6i|E@PSdwF&xZR@+MaMJ6oCn)z(vDv+2T0^%Ay04_ zr7b$P61R60$|Lw&!H}KE$BOf{=ZfSPB0s6`wYdI7=taueB*w9ixc(O6{&@o5e55{W zald6LijH51+wmGU-2}fbz@Nz7730@Qtj~E9(fLkLhUjB2?%%m$ZY^n-IR6P0M#>?6 zdkEhoPCpI3h@LaW$49%1(l3eo^}RU%Cb6C?#JGYAK?Xx)ViKE}WNZWoVmp#;8QU>vMsL}A40;%wh>XV4*iz7o znGu#KBqBAbX&`k{NKFf=Y2jYez^&7m)HKkF7828t)JY-Nw9txPlA4w@riIot@aKNt z-fNvXb2KxyK{D!s!P`7P8J6s7YG(YJolx7!8(6X2Q8g~HblMegU|oB+!6%cxfn zrL%dd4R;&#nc-g+y2|AFPATsvgw9^!cY&1WtsJkUMU@t z&Vwj_#=lPJeC!gNPCfL7^v{-bo{)RJ$ZruU}QtB~mbD2UB>!HdW6DePYt30UztQuoTrPwjGM`}( zK{{?1dBsr9h~kVQKHont@_0hzT`F|lDRSQ|diAQb8}*3Kc;6R(E|YYxllI~sk>gT4 zGu&HHR^F?TF6sG+$n!dh_d1xMe!MDrbw8AY;lC{M{j%s$OzPF0B9{fi_h!+nCnde5 zQXe*p9KRv@eznxwn8^Eu**2e1xi66W{fq7U^QB(TlJrNRx0L^@B9EuVj`2)j(tEzt z;|oQu_lO)H3|RbS!uLzCClHBqpQQgPelz|PNFPP$ye#}*C;IR_e&s-pV0M|#Q&M-&s)%Qrn?#X2v(dIMBaCc z{@pF%pOkXB80F0HF|n5qN;#K_-F^o0BK{G`m+4)G2R`2~bS;v2S1-2j9~1eU4?RH< zI**F{Uyyv;MPBdVJ=3`lbTZr;;pa&yhkCqcy}n1n->39yJdwv^f`0;hvL4JTvguwX z;b#l~b3rFW=Y*uZW1>GV%l%5Ze_7IRlyrKfzT77C&650HlKYIjInInR=l7sxV@^R~ z&~ZKweaoLwmuJjv{tlyUGXjOqVrPs3EOxf+aS8)tV>=vY4ChIOaR#!J7YsV6K;|k5 z;C6ce@^uO;5E}*(*UWtU3gUe3!VsPUGlFBzjAE1slcWR}*Qj{V2^t9_ zbmt6b6Y@tKyer6aiWY$kTqa5&e=&Z7lsw0oi~O9gRG3WjEBSz{$ovJ9JXpKaan_jv z%g-OH%XgLpoP413k?NehfORd4KR*Uh*vNZkhrmFvpwOAIDCmqM=ve-kQ#XbmNF4bG zoWepYDU(gXc~0RBr_Q+`FAwnod1F=iV;~qD7B~g-^73cw42(JX`9%;)5dQ*IB(bnC zfBn-WqU{c<5_u~)tB~dZO6cqaoH09mtI4r&4wB7xW(5lz2r$1BR0N$WM#5XUA?LA* zg1|lpB4c{RJ4wI;Gj3%`Fynv|UKDUDZVQqGx#r*wlVOCl4);1h8=w=g1F#ElFJLcV zKVTg2EZ{KU6~Ixz+W;~<4-fz>0jvg80r)NW9zYT>2H;xn-GB!G`v8vv4g#J7OaNX3 z90NdYC{br2pct?c5Ck*;HUYW;Lx7tBI{|kA_5dCR8~_{wya+e~cmu$)ngb{TtOL{m zIstuv5x@?>F2G*Ee!w{3S-@eyD}bYbw*dtZcL1;iuo_SW2m?9*J%A)&3~&cvH{b!l zKEUIEgMjA%6M%eFfI`4RKrvt?AP8sxYyxxxh5$DMb^`7K>;XIsH~@GGa0u`s;0VAu z1N;Hz1Bw78fOUX6KpUVBFap>C*af&3uoti&@GRgk;3(j2KmlyYJU{@j1h5)V1qcJU zrn3i-1dIXh0PF@l0N4k39B>fu9AEC*af&3uoti&Fb;SYa2W6k;B7zw zYT7(N0I&qG8c+oY13CabfHA-wfZc!x0Q&$30nY&@0Iva#0rFv_3jqrO#ekK7AfN%T z3D6C=8L$&@7hn(IVZZ^vQ-DK&7Xe2AZvfcYodcK;C<2rK)&c4OZGcWdA7BKq1F#El zFJLcVKVTg2EZ{KU6~Ixz+kgW2PxAl)z!Jb}KouYi=m7Kpl7KP59e~|{2LSs3j{^<@ zo&!t(UIQEh6rurJ2v`XS0vZ6D0NsEgz|DZ2fV%*D01pEW0GHwX9KEMcI2VfWAUcg?!e!w{3S-@eyD}bYbw*j!?&OAT>umrFgPz4AB zIsiR@Bw!412Vghg0l+@MLBMl>3BYTBV}N|L(ZzrupaHN6&xu);1$48z}tWV_>1!Z z0l*T#>FcxvPD|jl1Wrrfv;3>Y`8inQaR9_9xl;)Q;f-e2w~{A zJ5HpnC*B=N40mPiahcid?j%0+WuJoV0<((81KeL?`YQz zk$9{R-i_}D~$HwnIYy#)^=+2y5n@S^6IXI9Q?vF)!uuUAFAT%=B zz<1TaH@BwXuO%9Gm;K zAW0v~vE1?yNiRo~1M*av1SE`)KCkMzWhuJnOAp_hj3uM-Q7b!^ljwz()AlIp#7(jI zATiWI*1Jn3-zErSH~}S=3ZeDwtg&xmBBJyW8SbM9ciucL9aySl6uKX0 zMKv~;_{9ikYf30N*x%a~>4If2Ctp~agP0#N_^r{t1PCJ0UfRzm~T)`Ybr z7;Plq{}Xd(=Kb)B(KOJ)4f2_CdW>oG@%RvyCeP3e-*Jf|>XCAS5+z`O>jWT{Z4>kdWy9D^(b@7J3 zx?WhpcvsJ;mr?S;ydn|myVXMS%6D5KJ>{KacQy45)p%{_y93JAza^2RStVVJ!|}RE zxUr^5!l-Ubv6(P@C+csWnGbW;d|0<4-7!~2l;h!y4M~li> z20xN=4PZQ9%9XxISHxEPcTuuy*G5`mQr zv#u}Nzok1GDZOfmY0b#fGU2IUp34)O_{i31S1h^CYH6zZgDPGna_)m&)^f}hAx+In z_^oVPPD8MbCmp|(w#3%0Zmc(O%b?r3YirkT!5K^1*?% zYu%sDSB3BAurA0=?>*}1XWyeLQqR67bmhb73SGkky*HpehDElDhW-zf&Ug*h5O&A5 zMu+>7Fu{GXWNcEPs{-)HK05`ekiKh$zHpICpXFNooLrTgbVOR=&!U%yNHI|5eT4sR zb@7giJ!!i-3+bxTf)3TY&P&q6`ZN?-m}tJ&DSc|VG%dc>Clkji-eRF?VX+&|dJjn1 z{&1Wo33DhF=A>jo7e79V1nm!Jt)y3UxtpiUJ4{pp&Pz1Yobl0^ zZs(7OFfaW7>Kt-D=6-b^xfs9S>s)fKdE_?C3BQ}UWX>b+UIQN#y^Vu_O+nnR#XRmN z%<0B49~{EGYzO?UPh!ru9=`#r(ev1e=c*{?wKwA#@m|ClushJ9?rz3hbr0swKZChj zgn6JBI)k)2ufv=!-WLPE65-weZr5te@qP;P!Y#PBBklFbqZRYZ2-^wga&H^f1=Jzj zHsFxX-U`rjCFaQokbf;`M7%p1Fn0_Zu&By>=&zs#`GSX=(aY{cm^#F*TZj2*c(f%* zdnMvNyB7W=(z)Z)n7i)6JT<()m7r}W_}B}4$2FKIN1S`X=cWxP!!3{r!W;vB3~_^v znEM_=81T}z5%b-k?Eup24kHcZy#sPP2p$W;Ul??S!Pfz#-&v0Qz}sHnCvL!eI^sM9 z*|#D79^`Qtaz2E-li;}<^v(kmqkr@^_`VtPoB+KI$nyyD??c%AD4Q37-+}VFi|-Nl zaqydubYH}XN*~H+2hx3@3VDLAJCN@FCh(8vf~z6t2;|lY*(1(tkj(?&?HJPPMBLSo z-$KOihI|(yuM)%?LwW24KYQ_f1o4j{@11zR1G0Gy{LVxAJHTT%crC=c3CL~}^FV%Y zLr#I~@g6+%p^SDyR(&Y9V~D>J`5wf5Khk>xbRGhP>!Fw6^Et@oS@6(_cteQ)BGSJZ z=^g|vD?$4N(%J#}1R&FUsXLHUAb~Q+yXO%8VesMr_bliwz`G&HtQhwyggXZPII;!# zpezC?mj;x@T~|PUpk*KUpNH};0&Wj<^Et@qVWhDT@t*@vkAt30=*J%D&vTR$=;=h9 zw?WUd$ZrI6ClPNYeFHpp016TJ*Z|Upe2yT$w-M$Qz|F|lL3(w_Z#Q(S5NXYa zjE2^OHozhLeg%2-A-^KXW`beyy9D_iMBH_i;0gM+1T@|Z{Ell-o``oZWE=$kUdZAI zcus=Pod_Fl!5wsuQRhI<+sJb#WVIjV6hvP0@w^)FBA%Z@8YM_?59Coy-jVM@l+7zB z*L;-w4(O=^euI!@9m=o|FoAcQP{*G_xcSr@JRgGY6d~`u(31wd+XR{pkbcmD2Fw{k z*mWqA1CUu;C&HjS+mOecYe5&}auDTq2=Nc1491bhQN$Zshwz9q4|EoQt{`a54?-WC zkuPMl332Cx|5p%hKKR^$aD6Dt$074Qz#W8)I#6CmkY6XtWCZf-LtY)=eLi&UD9Ygt z(7g^}3n8C92zLbas{?5TAfzuK= zErHV#I4yzqQvz?#h2JtOGX;7!z=5;iv!02)iJfNB(fJ|#oIFG+gHOhLBYalgqwu+S z{|5Xj-q*n2;r&(kV7!mQkK%nZ{3hP#!cXFT4g4ze48Mx^$KXrxeqq$!-+_d$@CSLnTGA`6w$FKz&J7a25q>Mfm7$Nr`y%*&ygx7bzbem%cot;AmpKbQBYr1y-3dk}s$-_L~~&iiHXH+c`i$L0MAN%tN2)qMUT z{C3`NgD=bb0{F7LUnlw9E%9H1U(ELxi@ctOAI;~yPJ0i9?L8{x{IrC7Ug)_+p6?TU zqwo=v`*os6k8H5%yefM1Xh@z#U+xxtxCea!=Kn*X_YuMWMCck8{g^HKa+~n;vgH4W z$Y()|q%U%KUFiH7`W8&TUi9@gp>MO$_kGc$SB3vFxxa)y0OQRSJvv|H_JpK!j_CW+ zpbhu3=+XUBF1L#uZ&m&!{w(2pv*^oZLjR*uKCcTObJ53O{4sd�FBXKc9ZM81pA_h!5W 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%0AvRy$oHGxuh0oJ6?CqG&-7nig1K?f!kes>U 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 diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.exe b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.exe deleted file mode 100644 index 34d54fafcf76a08ced987b41d97b78f22bc91908..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82432 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©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 ^#oy%2Zxs~^I&{;?jt^P`{3{IY)TI(Ifx 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

Rk789 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%0A_uZ9v|$ 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 diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.pdb b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.pdb deleted file mode 100644 index bba54022198e04476009f05f737eb09ae6f86ecd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 856064 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 z%0A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
3TN#e}o?)37hu3 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 LJ_-C^NZ|hfzA&(S

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + */ +public class Horserace { + + private static final String[] horseNames = { + "JOE MAW", + "L.B.J.", + "MR.WASHBURN", + "MISS KAREN", + "JOLLY", + "HORSE", + "JELLY DO NOT", + "MIDNIGHT" + }; + public static final int MAX_DISTANCE = 28; + public static final int NUM_HORSES = 8; + + public static void main(String[] args) { + printHeader(); + + Scanner scanner = new Scanner(System.in); + Random random = new Random(); + + printHelp(scanner); + + List betNames = readBetNames(scanner); + + boolean donePlaying = false; + while (!donePlaying) { + + int[] odds = generateOdds(random); + int sumOdds = Arrays.stream(odds).sum(); + printOdds(sumOdds, odds); + + Map bets = takeBets(scanner, betNames); + + var horsePositions = runRace(horseNames.length, sumOdds, odds, random); + + printRaceResults(horsePositions, bets, sumOdds, odds); + + donePlaying = readDonePlaying(scanner); + } + } + + private static int[] generateOdds(Random random) { + int[] odds = new int[NUM_HORSES]; + for (int i = 0; i < NUM_HORSES; i++) { + odds[i] = (int) (10 * random.nextFloat() + 1); + } + return odds; + } + + private static void printOdds(int R, int[] D) { + System.out.printf("%n%-28s%-14s%-14s%n%n", "HORSE", "NUMBER", "ODDS"); + for (int n = 0; n < horseNames.length; n++) { + System.out.printf("%-28s% -14d%.6f :1%n", horseNames[n], n + 1, ((float) R / D[n])); + } + } + + private static boolean readDonePlaying(Scanner scan) { + System.out.println("DO YOU WANT TO BET ON THE NEXT RACE ?"); + System.out.print("YES OR NO? "); + String choice = scan.nextLine(); + return !choice.equalsIgnoreCase("YES"); + } + + /** + * Simulate the race run, returning the final positions of the horses. + */ + private static int[] runRace(int numberOfHorses, int sumOdds, int[] odds, Random random) { + int[] positionChange = new int[numberOfHorses]; + + System.out.println(); + System.out.println("1 2 3 4 5 6 7 8"); + + int totalDistance = 0; + int[] currentPositions = new int[NUM_HORSES]; + int[] horsePositions = new int[NUM_HORSES]; + + while (totalDistance < MAX_DISTANCE) { + System.out.println("XXXXSTARTXXXX"); + + for (int i = 0; i < numberOfHorses; i++) { + horsePositions[i] = i + 1; + positionChange[i] = calculatePositionChanges(sumOdds, odds[i], random); + currentPositions[i] += positionChange[i]; + } + + sortHorsePositionsBasedOnCurrent(currentPositions, horsePositions); + + totalDistance = currentPositions[horsePositions[7] - 1]; + + boolean raceFinished = false; + int i = 0; + while (i < NUM_HORSES && !raceFinished) { + int distanceToNextHorse = currentPositions[(horsePositions[i] - 1)] - (i < 1 ? 0 : currentPositions[(horsePositions[i - 1] - 1)]); + if (distanceToNextHorse != 0) { + int a = 0; + while (a < distanceToNextHorse && !raceFinished) { + System.out.println(); + if (currentPositions[horsePositions[i] - 1] >= MAX_DISTANCE) { + raceFinished = true; + } + a++; + } + } + + if (!raceFinished) { + System.out.print(" " + horsePositions[i] + " "); // Print horse number + } + i++; + } + + if (!raceFinished) { + //Print additional empty lines + for (int a = 0; a < MAX_DISTANCE - totalDistance; a++) { + System.out.println(); + } + } + + System.out.println("XXXXFINISHXXXX"); + System.out.println("\n"); + System.out.println("---------------------------------------------"); + System.out.println("\n"); + } + + return horsePositions; + } + + /** + * Sorts the horsePositions array in place, based on the currentPositions of the horses. + * (bubble sort) + */ + private static void sortHorsePositionsBasedOnCurrent(int[] currentPositions, int[] horsePositions) { + for (int l = 0; l < NUM_HORSES; l++) { + int i = 0; + /* + uses a do-while instead of a for loop here, because in BASIC + a FOR I=1 TO 0 causes at least one execution of the loop + */ + do { + if (currentPositions[horsePositions[i] - 1] >= currentPositions[horsePositions[i + 1] - 1]) { + int h = horsePositions[i]; + horsePositions[i] = horsePositions[i + 1]; + horsePositions[i + 1] = h; + } + i++; + } while (i < (7 - l)); + } + } + + private static int calculatePositionChanges(int r, int d, Random random) { + int positionChange = (int) (100 * random.nextFloat() + 1); + + if (positionChange < 10) { + positionChange = 1; + } else { + int s = (int) ((float) r / d + 0.5); + if (positionChange < (s + 17)) { + positionChange = 2; + } else if (positionChange < s + 37) { + positionChange = 3; + } else if (positionChange < s + 57) { + positionChange = 4; + } else if (positionChange < s + 77) { + positionChange = 5; + } else if (positionChange < s + 92) { + positionChange = 6; + } else { + positionChange = 7; + } + } + + return positionChange; + } + + private static void printRaceResults(int[] m, Map bets, int r, int[] d) { + System.out.println("THE RACE RESULTS ARE:"); + int z9 = 1; + for (int i = 7; i >= 0; i--) { + int f = m[i]; + System.out.println(); + System.out.println(z9 + " PLACE HORSE NO. " + f + " AT " + (r / d[f - 1]) + ":1"); + z9++; + } + bets.forEach((betName, bet) -> { + if (bet.horseNumber == m[7]) { + int n = bet.horseNumber; + System.out.println(); + System.out.printf("%s WINS $ %.2f %n", bet.betName, ((float) r / d[n]) * bet.amount); + } + }); + } + + private static Map takeBets(Scanner scanner, List betNames) { + Map bets = new HashMap<>(); + System.out.println("--------------------------------------------------"); + System.out.println("PLACE YOUR BETS...HORSE # THEN AMOUNT"); + for (String betName : betNames) { + boolean validInput = false; + while (!validInput) { + int horseNumber = readInt(betName, scanner);//Q in the original + double betAmount = readDouble("?", scanner); //P in the original + if (betAmount < 1 || betAmount > 100000) { + System.out.println(" YOU CAN'T DO THAT!"); + } else { + bets.put(betName, new Bet(betName, horseNumber, betAmount)); + validInput = true; + } + } + } + + return bets; + } + + private static void printHelp(Scanner scanner) { + System.out.print("DO YOU WANT DIRECTIONS"); + + String directions = readChoice(scanner); + + if (!directions.equalsIgnoreCase("NO")) { + System.out.println("UP TO 10 MAY PLAY. A TABLE OF ODDS WILL BE PRINTED. YOU"); + System.out.println("MAY BET ANY + AMOUNT UNDER 100000 ON ONE HORSE."); + System.out.println("DURING THE RACE, A HORSE WILL BE SHOWN BY ITS"); + System.out.println("NUMBER. THE HORSES RACE DOWN THE PAPER!"); + System.out.println(); + } + } + + private static String readChoice(Scanner scanner) { + System.out.print("? "); + return scanner.nextLine(); + } + + private static int readInt(String prompt, Scanner scanner) { + System.out.print(prompt); + while (true) { + System.out.print("? "); + String input = scanner.nextLine(); + try { + return Integer.parseInt(input); + } catch (NumberFormatException e) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); + } + } + } + + private static double readDouble(String prompt, Scanner scanner) { + System.out.print(prompt); + while (true) { + System.out.print("? "); + String input = scanner.nextLine(); + try { + return Double.parseDouble(input); + } catch (NumberFormatException e) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); + } + } + } + + private static List readBetNames(Scanner scanner) { + int c = readInt("HOW MANY WANT TO BET ", scanner); + System.out.println("WHEN ? APPEARS,TYPE NAME"); + List names = new ArrayList<>(); + for (int i = 1; i <= c; i++) { + System.out.print("? "); + names.add(scanner.nextLine()); + } + + return names; + } + + private static void printHeader() { + System.out.println(" HORSERACE"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); + System.out.println("\n\n"); + System.out.println("WELCOME TO SOUTH PORTLAND HIGH RACETRACK"); + System.out.println(" ...OWNED BY LAURIE CHEVALIER"); + } + + private static class Bet { + String betName; + int horseNumber; + double amount; + + public Bet(String betName, int horseNumber, double amount) { + this.betName = betName; + this.horseNumber = horseNumber; + this.amount = amount; + } + + @Override + public String toString() { + return "Bet{" + + "betName='" + betName + '\'' + + ", horseNumber=" + horseNumber + + ", amount=" + amount + + '}'; + } + } +} + diff --git a/README.md b/README.md index 17b828ff0..1ba366b81 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 47_Hi-Lo | x | | x | x | x | x | x | x | x | x | | 48_High_IQ | x | x | x | | | | x | | | x | | 49_Hockey | x | | x | | | | x | | | x | -| 50_Horserace | x | | x | | | | | | x | x | +| 50_Horserace | x | x | x | | | | | | x | x | | 51_Hurkle | x | x | x | | | x | x | x | x | x | | 52_Kinema | x | x | x | | | x | x | x | | x | | 53_King | x | | x | | | | x | | x | x | From 8dd95146090313929fc50b322aa876951b9bcff8 Mon Sep 17 00:00:00 2001 From: MirceaMazi Date: Tue, 7 Jan 2025 18:53:23 +0200 Subject: [PATCH 336/377] Fixed small grammar errors at the beginning and end of the game in the js file --- 05_Bagels/javascript/bagels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/05_Bagels/javascript/bagels.js b/05_Bagels/javascript/bagels.js index 5a62a751a..c0d519e2b 100644 --- a/05_Bagels/javascript/bagels.js +++ b/05_Bagels/javascript/bagels.js @@ -84,7 +84,7 @@ async function main() } while (j >= 1) ; } print("\n"); - print("O.K. I HAVE A NUMBER IN MIND.\n"); + print("OK. I HAVE A NUMBER IN MIND.\n"); for (i = 1; i <= 20; i++) { while (1) { print("GUESS #" + i); @@ -142,7 +142,7 @@ async function main() print("\n"); } else { print("OH WELL.\n"); - print("THAT'S A TWENTY GUESS. MY NUMBER WAS " + a[1] + a[2] + a[3]); + print("THAT'S YOUR TWENTIETH GUESS. MY NUMBER WAS " + a[1] + a[2] + a[3]); } y++; print("PLAY AGAIN (YES OR NO)"); From d494079613f3ff5ea9edc66c3183f1c1a12a2cb3 Mon Sep 17 00:00:00 2001 From: P Marques <13932504-psmbrs@users.noreply.gitlab.com> Date: Mon, 17 Feb 2025 16:17:05 -0300 Subject: [PATCH 337/377] initial --- 45_Hello/rust/Cargo.toml | 6 + 45_Hello/rust/src/main.rs | 247 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 253 insertions(+) create mode 100644 45_Hello/rust/Cargo.toml create mode 100644 45_Hello/rust/src/main.rs diff --git a/45_Hello/rust/Cargo.toml b/45_Hello/rust/Cargo.toml new file mode 100644 index 000000000..7d75412a6 --- /dev/null +++ b/45_Hello/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/45_Hello/rust/src/main.rs b/45_Hello/rust/src/main.rs new file mode 100644 index 000000000..310c5db32 --- /dev/null +++ b/45_Hello/rust/src/main.rs @@ -0,0 +1,247 @@ +/** HELLO GAME BY DAVID AHL + * https://github.com/coding-horror/basic-computer-games/blob/main/45_Hello/hello.bas + * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). + * No additional features or improvements were added. As a faithful translation, + * many of the code here are done in an unrecommended way by today's standards. + * 17/02/25 +*/ + +use std::io::Write; + +fn main() { + // 2 PRINT TAB(33);"HELLO" + // 4 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + // 6 PRINT: PRINT: PRINT + print!( + "{}{}\n{}{}\n\n\n\n", + " ".repeat(33), + "HELLO", + " ".repeat(15), + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + ); + + let mut input = String::new(); + + //10 PRINT "HELLO. MY NAME IS CREATIVE COMPUTER." + //20 PRINT: PRINT: INPUT "WHAT'S YOUR NAME";N$: PRINT + print!("HELLO. MY NAME IS CREATIVE COMPUTER.\n\nWHAT'S YOUR NAME? "); + let _ = std::io::stdout().flush().unwrap(); + input.clear(); + std::io::stdin().read_line(&mut input).unwrap(); + let n = input.trim().to_uppercase(); + + //30 PRINT "HI THERE, ";N$;", ARE YOU ENJOYING YOURSELF HERE"; + //40 INPUT B$: PRINT + print!("\nHI THERE, {n}, ARE YOU ENJOYING YOURSELF HERE? "); + loop { + let _ = std::io::stdout().flush().unwrap(); + input.clear(); + std::io::stdin().read_line(&mut input).unwrap(); + let b = input.trim().to_uppercase(); + + //50 IF B$="YES" THEN 70 + if b == "YES" { + //70 PRINT "I'M GLAD TO HEAR THAT, ";N$;".": PRINT + //75 GOTO 100 + println!("\nI'M GLAD TO HEAR THAT, {n}."); + break; + } + //55 IF B$="NO" THEN 80 + else if b == "NO" { + //80 PRINT "OH, I'M SORRY TO HEAR THAT, ";N$;". MAYBE WE CAN" + //85 PRINT "BRIGHTEN UP YOUR VISIT A BIT." + println!("\nOH, I'M SORRY TO HEAR THAT, {n}. MAYBE WE CAN\n{}", + "BRIGHTEN UP YOUR VISIT A BIT." + ); + break; + } + else { + //60 PRINT N$;", I DON'T UNDERSTAND YOUR ANSWER OF '";B$;"'." + //65 PRINT "PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE";: GOTO 40 + print!("\n{n}, I DON'T UNDERSTAND YOUR ANSWER OF '{b}'.\n{}", + "PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE? " + ); + } + } + + //100 PRINT + //105 PRINT "SAY, ";N$;", I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT" + //110 PRINT "THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO" + //120 PRINT "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)"; + //125 INPUT C$ + //126 PRINT + print!("\nSAY, {n}, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\n{}\n{}", + "THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO", + "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)? " + ); + 'outer: loop { + let _ = std::io::stdout().flush().unwrap(); + input.clear(); + std::io::stdin().read_line(&mut input).unwrap(); + let c = input.trim().to_uppercase(); + + //130 IF C$="SEX" THEN 200 + if c == "SEX" { + loop { + //200 INPUT "IS YOUR PROBLEM TOO MUCH OR TOO LITTLE";D$: PRINT + print!("\nIS YOUR PROBLEM TOO MUCH OR TOO LITTLE? "); + let _ = std::io::stdout().flush().unwrap(); + input.clear(); + std::io::stdin().read_line(&mut input).unwrap(); + let d = input.trim().to_uppercase(); + + //210 IF D$="TOO MUCH" THEN 220 + if d == "TOO MUCH" { + //220 PRINT "YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!" + //225 PRINT "IF IT BOTHERS YOU, ";N$;", TAKE A COLD SHOWER." + //228 GOTO 250 + println!("\nYOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!\n{}", + format!("IF IT BOTHERS YOU, {n}, TAKE A COLD SHOWER.") + ); + break; + } + //212 IF D$="TOO LITTLE" THEN 230 + else if d == "TOO LITTLE" { + //230 PRINT "WHY ARE YOU HERE IN SUFFERN, ";N$;"? YOU SHOULD BE" + //235 PRINT "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME" + //240 PRINT "REAL ACTION." + //250 PRINT + println!("\nWHY ARE YOU HERE IN SUFFERN, {n}? YOU SHOULD BE\n{}\n{}", + "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH", + "SOME REAL ACTION." + ); + break; + } + else { + //215 PRINT "DON'T GET ALL SHOOK, ";N$;", JUST ANSWER THE QUESTION" + //217 INPUT "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT";D$:GOTO 210 + println!("\nDON'T GET ALL SHOOK, {n}, JUST ANSWER THE QUESTION\n{}", + "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT? " + ); + } + } + } + //132 IF C$="HEALTH" THEN 180 + else if c == "HEALTH" { + //180 PRINT "MY ADVICE TO YOU ";N$;" IS:" + //185 PRINT " 1. TAKE TWO ASPRIN" + //188 PRINT " 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)" + //190 PRINT " 3. GO TO BED (ALONE)" + //195 GOTO 250 + println!("\nMY ADVICE TO YOU {n} IS:\n{}\n{}\n{}", + " 1. TAKE TWO ASPRIN", + " 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)", + " 3. GO TO BED (ALONE)" + ); + } + //134 IF C$="MONEY" THEN 160 + else if c == "MONEY" { + //160 PRINT "SORRY, ";N$;", I'M BROKE TOO. WHY DON'T YOU SELL" + //162 PRINT "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING" + //164 PRINT "SO YOU WON'T NEED SO MUCH MONEY?" + //170 GOTO 250 + println!("\nSORRY, {n}, I'M BROKE TOO. WHY DON'T YOU SELL\n{}\n{}", + "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING", + "SO YOU WON'T NEED SO MUCH MONEY? " + ); + } + //136 IF C$="JOB" THEN 145 + else if c == "JOB" { + //145 PRINT "I CAN SYMPATHIZE WITH YOU ";N$;". I HAVE TO WORK" + //148 PRINT "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES" + //150 PRINT "REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, ";N$;"," + //153 PRINT "IS TO OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN." + //155 GOTO 250 + println!("\nI CAN SYMPATHIZE WITH YOU {n}. I HAVE TO WORK\n{}\n{}\n{}", + "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES", + format!("REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, {n}"), + "IS TO OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN." + ); + } + else { + //138 PRINT "OH, ";N$;", YOUR ANSWER OF ";C$;" IS GREEK TO ME." + //140 GOTO 250 + println!("\nOH, {n}, YOUR ANSWER OF {c} IS GREEK TO ME."); + } + + loop { + //255 PRINT "ANY MORE PROBLEMS YOU WANT SOLVED, ";N$; + //260 INPUT E$: PRINT + print!("\nANY MORE PROBLEMS YOU WANT SOLVED, {n}? "); + let _ = std::io::stdout().flush().unwrap(); + input.clear(); + std::io::stdin().read_line(&mut input).unwrap(); + let e = input.trim().to_uppercase(); + + //270 IF E$="YES" THEN 280 + if e == "YES" { + //280 PRINT "WHAT KIND (SEX, MONEY, HEALTH, JOB)"; + //282 GOTO 125 + print!("\nWHAT KIND (SEX, MONEY, HEALTH, JOB)? "); + continue 'outer; + } + //273 IF E$="NO" THEN 300 + else if e == "NO" { + break 'outer; + } + else { + //275 PRINT "JUST A SIMPLE 'YES' OR 'NO' PLEASE, ";N$;"." + //277 GOTO 255 + println!("\nJUST A SIMPLE 'YES' OR 'NO' PLEASE, {n}."); + } + } + } + //300 PRINT + //302 PRINT "THAT WILL BE $5.00 FOR THE ADVICE, ";N$;"." + //305 PRINT "PLEASE LEAVE THE MONEY ON THE TERMINAL." + println!("\nTHAT WILL BE $5.00 FOR THE ADVICE, {n}.\n{}", + "PLEASE LEAVE THE MONEY ON THE TERMINAL." + ); + //307 FOR I=1 TO 2000: NEXT I + //310 PRINT: PRINT: PRINT + loop { + //315 PRINT "DID YOU LEAVE THE MONEY"; + //320 INPUT G$: PRINT + print!("\nDID YOU LEAVE THE MONEY? "); + let _ = std::io::stdout().flush().unwrap(); + input.clear(); + std::io::stdin().read_line(&mut input).unwrap(); + let g = input.trim().to_uppercase(); + + //325 IF G$="YES" THEN 350 + if g == "YES" { + //350 PRINT "HEY, ";N$;"??? YOU LEFT NO MONEY AT ALL!" + //355 PRINT "YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING." + //360 PRINT:PRINT "WHAT A RIP OFF, ";N$;"!!!":PRINT + //365 GOTO 385 + println!("\nHEY, {n}??? YOU LEFT NO MONEY AT ALL!\n{}\n{}", + "YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.", + format!("WHAT A RIP OFF, {n}!!!\n\nTAKE A WALK, {n}") + ); + break; + } + //330 IF G$="NO" THEN 370 + else if g == "NO" { + //370 PRINT "THAT'S HONEST, ";N$;", BUT HOW DO YOU EXPECT" + //375 PRINT "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS" + //380 PRINT "DON'T PAY THEIR BILLS?" + //385 PRINT:PRINT "TAKE A WALK, ";N$;".":PRINT:PRINT:GOTO 999 + println!("\nTHAT'S HONEST, {n}, BUT HOW DO YOU EXPECT\n{}\n{}", + "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS", + format!("DON'T PAY THEIR BILLS?\n\nTAKE A WALK, {n}") + ); + break; + } + else { + //335 PRINT "YOUR ANSWER OF '";G$;"' CONFUSES ME, ";N$;"." + //340 PRINT "PLEASE RESPOND WITH 'YES' OR 'NO'.": GOTO 315 + println!("YOUR ANSWER OF '{g}' CONFUSES ME, {n}.\n{}", + "PLEASE RESPOND WITH 'YES' OR 'NO'." + ); + } + } + + //390 PRINT "NICE MEETING YOU, ";N$;", HAVE A NICE DAY." -> unreachable + //400 REM + //999 END +} From 5d3ae5b282b381c02f5c1414f2bd64b4757dabff Mon Sep 17 00:00:00 2001 From: P Marques <13932504-psmbrs@users.noreply.gitlab.com> Date: Mon, 17 Feb 2025 16:33:18 -0300 Subject: [PATCH 338/377] name game initial rust implementation --- 63_Name/rust/Cargo.toml | 6 ++ 63_Name/rust/src/main.rs | 116 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 63_Name/rust/Cargo.toml create mode 100644 63_Name/rust/src/main.rs diff --git a/63_Name/rust/Cargo.toml b/63_Name/rust/Cargo.toml new file mode 100644 index 000000000..7d75412a6 --- /dev/null +++ b/63_Name/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/63_Name/rust/src/main.rs b/63_Name/rust/src/main.rs new file mode 100644 index 000000000..0f45f63bd --- /dev/null +++ b/63_Name/rust/src/main.rs @@ -0,0 +1,116 @@ +/** NAME GAME BY DAVID AHL + * https://github.com/coding-horror/basic-computer-games/blob/main/45_Hello/hello.bas + * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). + * No additional features or improvements were added. As a faithful translation, + * many of the code here are done in an unrecommended way by today's standards. + * 17/02/25 +*/ + +use std::io::Write; + +fn main() { + let mut input = String::new(); + + //1 PRINT TAB(34);"NAME" + //2 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + //3 PRINT: PRINT: PRINT + print!("{}{}\n{}{}\n\n\n\n", + " ".repeat(34), + "NAME", + " ".repeat(15), + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + ); + + //5 DIM B$(40) + let mut b = [0; 40]; + + //10 PRINT "HELLO.": PRINT "MY NAME IS CREATIVE COMPUTER." + //20 PRINT "WHAT'S YOUR NAME (FIRST AND LAST";: INPUT A$: L=LEN(A$) + print!("{}\n{}\n{}", + "HELLO.", + "MY NAME IS CREATIVE COMPUTER.", + "WHAT'S YOUR NAME (FIRST AND LAST)? " + ); + + let _ = std::io::stdout().flush().unwrap(); + std::io::stdin().read_line(&mut input).unwrap(); + let a = input.trim().to_uppercase(); + let l = a.len(); + + //30 PRINT: PRINT "THANK YOU, "; + print!("\nTHANK YOU, "); + + //40 FOR I=1 TO L: B$(I)=MID$(A$,I,1): NEXT I + for i in 1..=l { + b[i-1] = a.chars().nth(i-1).unwrap() as u8; + } + + //50 FOR I=L TO 1 STEP -1: PRINT B$(I);: NEXT I + for i in (1..=l).rev() { + print!("{}", b[i-1] as char); + } + + //60 PRINT ".": PRINT "OOPS! I GUESS I GOT IT BACKWARDS. A SMART" + //70 PRINT "COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!": PRINT + //80 PRINT "BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER." + //90 PRINT "LET'S PUT THEM IN ORDER LIKE THIS: "; + print!("{}\n{}\n{}\n\n{}\n{}", + ".", + "OOPS! I GUESS I GOT IT BACKWARDS. A SMART", + "COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!", + "BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.", + "LET'S PUT THEM IN ORDER LIKE THIS: " + ); + + //100 FOR J=2 TO L: I=J-1: T$=B$(J) + let mut i; + let mut t; + for j in 2..=l { + i = j - 1; + t = b[j-1]; + loop { + //110 IF T$>B$(I) THEN 130 + if i == 0 || t > b[i-1] { + //130 B$(I+1)=T$: NEXT J + b[i] = t; + break; + } else { + //120 B$(I+1)=B$(I): I=I-1: IF I>0 THEN 110 + b[i] = b[i-1]; + i = i - 1; + } + } + } + + //140 FOR I=1 TO L: PRINT B$(I);: NEXT I: PRINT: PRINT + for i in 1..=l { + print!("{}", b[i-1] as char); + } + print!("\n\n"); + + //150 PRINT "DON'T YOU LIKE THAT BETTER";: INPUT D$ + print!("DON'T YOU LIKE THAT BETTER? "); + + let _ = std::io::stdout().flush().unwrap(); + input.clear(); + std::io::stdin().read_line(&mut input).unwrap(); + let d = input.trim().to_uppercase(); + + //160 IF D$="YES" THEN 180 + if d == "YES" || d == "Y" { + //180 PRINT: PRINT "I KNEW YOU'D AGREE!!" + print!("\nI KNEW YOU'D AGREE!!"); + } + else { + //170 PRINT: PRINT "I'M SORRY YOU DON'T LIKE IT THAT WAY.": GOTO 200 + print!("\nI'M SORRY YOU DON'T LIKE IT THAT WAY."); + } + + print!("\n\n{}{}.\n{}\n", + "I REALLY ENJOYED MEETING YOU ", + a, + "HAVE A NICE DAY!" + ); + + //999 END +} From 44b4e636613a5475a1e2e6831e17603cce0a64c5 Mon Sep 17 00:00:00 2001 From: P Marques <13932504-psmbrs@users.noreply.gitlab.com> Date: Mon, 17 Feb 2025 16:37:25 -0300 Subject: [PATCH 339/377] name game initial rust implementation --- 63_Name/rust/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/63_Name/rust/src/main.rs b/63_Name/rust/src/main.rs index 0f45f63bd..1a1f631a7 100644 --- a/63_Name/rust/src/main.rs +++ b/63_Name/rust/src/main.rs @@ -1,5 +1,5 @@ -/** NAME GAME BY DAVID AHL - * https://github.com/coding-horror/basic-computer-games/blob/main/45_Hello/hello.bas +/** NAME GAME BY GEOFFREY CHASE + * https://github.com/coding-horror/basic-computer-games/blob/main/63_Name/name.bas * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). * No additional features or improvements were added. As a faithful translation, * many of the code here are done in an unrecommended way by today's standards. From 96afc1cfcea3a5d11dcc07cf3098c068a0b291f1 Mon Sep 17 00:00:00 2001 From: P Marques <13932504-psmbrs@users.noreply.gitlab.com> Date: Mon, 17 Feb 2025 17:18:35 -0300 Subject: [PATCH 340/377] bunny game initial rust implementation --- 19_Bunny/rust/Cargo.toml | 6 ++ 19_Bunny/rust/src/main.rs | 114 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 19_Bunny/rust/Cargo.toml create mode 100644 19_Bunny/rust/src/main.rs diff --git a/19_Bunny/rust/Cargo.toml b/19_Bunny/rust/Cargo.toml new file mode 100644 index 000000000..7d75412a6 --- /dev/null +++ b/19_Bunny/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/19_Bunny/rust/src/main.rs b/19_Bunny/rust/src/main.rs new file mode 100644 index 000000000..4eb9b7316 --- /dev/null +++ b/19_Bunny/rust/src/main.rs @@ -0,0 +1,114 @@ +/** BUNNY GAME + * https://github.com/coding-horror/basic-computer-games/tree/main/19_Bunny + * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). + * No additional features or improvements were added. As a faithful translation, + * many of the code here are done in an unrecommended way by today's standards. + * 17/02/25 +*/ + +//290 DATA 2,21,14,14,25 +//300 DATA 1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1 +//310 DATA 1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1 +//320 DATA 5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1 +//330 DATA 9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1 +//340 DATA 13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1 +//350 DATA 19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1 +//360 DATA 8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1 +//370 DATA 4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1 +//380 DATA 2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1 +//390 DATA 14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1 +//400 DATA 14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1 +//410 DATA 12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1 +//420 DATA 10,11,17,18,22,22,24,24,29,29,-1 +//430 DATA 22,23,26,29,-1,27,29,-1,28,29,-1,4096 + +// 4096 is the end of file +// -1 is the end of line +const DATA: [i32;233] = [ + 2,21,14,14,25, + 1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1, + 1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1, + 5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1, + 9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1, + 13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1, + 19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1, + 8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1, + 4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1, + 2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1, + 14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1, + 14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1, + 12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1, + 10,11,17,18,22,22,24,24,29,29,-1, + 22,23,26,29,-1,27,29,-1,28,29,-1,4096, +]; + +fn main() { + let mut col = 0; + + //10 PRINT TAB(33);"BUNNY" + //20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + //30 PRINT: PRINT: PRINT + //100 REM "BUNNY" FROM DAVID AHL'S 'BASIC COMPUTER GAMES' + print!("{}{}\n{}{}\n", + " ".repeat(33), + "BUNNY", + " ".repeat(15), + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + ); + + //120 FOR I=0 TO 4: READ B(I): NEXT I + let mut b = [0;5]; + for i in 0..=4 { + b[i] = DATA[col]; + col = col + 1; + } + + //130 GOSUB 260 + //260 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I + for _ in 1..=6 { + println!(); + } + //270 RETURN + + //140 L=64: REM ASCII LETTER CODE... + let l = 64; + let mut prev = 0; + loop { + //170 READ X: IF X<0 THEN 160 + let x = DATA[col]; + col = col + 1; + if x < 0 { + //160 PRINT + println!(); + prev = 0; + continue; + } + //175 IF X>128 THEN 240 + else if x > 128 { + //240 GOSUB 260: GOTO 450 + for _ in 1..=6 { + println!(); + } + break; + } + else { + //180 PRINT TAB(X);: READ Y + print!("{}", " ".repeat((x - prev) as usize)); // verificar + prev = x; + let y = DATA[col]; + col = col + 1; + //190 FOR I=X TO Y: J=I-5*INT(I/5) + for i in x..=y { + let j = i - 5 * (i / 5); + //200 PRINT CHR$(L+B(J)); + print!("{}", (l + b[j as usize]) as u8 as char); + prev = prev + 1; + //210 NEXT I + + } + //220 GOTO 170 + } + } + //450 END +} + From ed068bda69850aa7b5a7bae6c70534bea901a935 Mon Sep 17 00:00:00 2001 From: P Marques <13932504-psmbrs@users.noreply.gitlab.com> Date: Mon, 17 Feb 2025 23:09:23 -0300 Subject: [PATCH 341/377] kinema game initial rust implementation --- 52_Kinema/rust/Cargo.toml | 7 +++ 52_Kinema/rust/src/main.rs | 107 +++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 52_Kinema/rust/Cargo.toml create mode 100644 52_Kinema/rust/src/main.rs diff --git a/52_Kinema/rust/Cargo.toml b/52_Kinema/rust/Cargo.toml new file mode 100644 index 000000000..3a87396aa --- /dev/null +++ b/52_Kinema/rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +[dependencies] +rand = "0.9.0" \ No newline at end of file diff --git a/52_Kinema/rust/src/main.rs b/52_Kinema/rust/src/main.rs new file mode 100644 index 000000000..3b6e0321c --- /dev/null +++ b/52_Kinema/rust/src/main.rs @@ -0,0 +1,107 @@ +use std::io::Write; +use rand::Rng; + +/** KINEMA BY RICHARD PAV + * https://github.com/coding-horror/basic-computer-games/blob/main/52_Kinema/kinema.bas + * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). + * As a faithful translation, many of the code here are done in an unrecommended way by + * today's standards. + * + * ATTENTION: The original code has mathematical imprecision and uses simplifications + * instead of the real formulation, which could lead to incorrect results. I have solved + * this issue, but kept the old lines. To compile the original version, just uncomment the + * code with the OLD label and comment the lines with the NEW label. + * example: gravity is now 9.81 instead of 10 + * 17/02/25 +*/ + +fn subroutine(a: f64, q: &mut i32) { + std::io::stdout().flush().unwrap(); + //500 INPUT G + let mut input = String::new(); + let g; + loop { + std::io::stdin().read_line(&mut input).unwrap(); + match input.trim().parse::() { + Ok(e) => { g = e; break; }, + Err(_) => { print!("\nINVALID. TRY AGAIN: "); continue; }, + }; + } + //502 IF ABS((G-A)/A)<.15 THEN 510 + if f64::abs((g-a)/a) < 0.15 { + //510 PRINT "CLOSE ENOUGH." + print!("CLOSE ENOUGH."); + //511 Q=Q+1 + *q = *q + 1; + } + else { + //504 PRINT "NOT EVEN CLOSE...." + print!("NOT EVEN CLOSE..."); + //506 GOTO 512 + } + //512 PRINT "CORRECT ANSWER IS ";A + print!("\nCORRECT ANSWER IS {a:.2}\n"); + //520 PRINT + //530 RETURN +} + +fn main() { + let mut rng = rand::rng(); + + //10 PRINT TAB(33);"KINEMA" + //20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + //30 PRINT: PRINT: PRINT + //100 PRINT + //105 PRINT + print!("{}KINEMA\n{}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n\n", + " ".repeat(33), + " ".repeat(15) + ); + loop { + //106 Q=0 + let mut q = 0; + //110 V=5+INT(35*RND(1)) + let v: f64 = 5.0 + 35.0 * rng.random_range(0.0..1.0); + //111 PRINT "A BALL IS THROWN UPWARDS AT";V;"METERS PER SECOND." + //112 PRINT + print!("\nA BALL IS THROWN UPWARDS AT {v:.2} METERS PER SECOND.\n"); + //115 A=.05*V^2 + //let a = 0.05 * v.powf(2.0); // OLD + let mut a = v.powf(2.0) / (2.0 * 9.81); // NEW + //116 PRINT "HOW HIGH WILL IT GO (IN METERS)"; + print!("\nHOW HIGH WILL IT GO (IN METERS)? "); + + //117 GOSUB 500 + subroutine(a, &mut q); + + //120 A=V/5 + //a = v / 5.0; // OLD + a = 2.0 * v / 9.81; // NEW + //122 PRINT "HOW LONG UNTIL IT RETURNS (IN SECONDS)"; + print!("\nHOW LONG UNTIL IT RETURNS (IN SECONDS)? "); + //124 GOSUB 500 + subroutine(a, &mut q); + + //130 T=1+INT(2*V*RND(1))/10 + let t = 1.0 + (2.0 * v * rng.random_range(0.0..1.0) / 10.0); + //132 A=V-10*T + a = v + (-9.81 * t); + //134 PRINT "WHAT WILL ITS VELOCITY BE AFTER";T;"SECONDS"; + print!("\nWHAT WILL ITS VELOCITY BE AFTER {t:.2} SECONDS? "); + + //136 GOSUB 500 + subroutine(a, &mut q); + + //140 PRINT + //150 PRINT Q;"RIGHT OUT OF 3."; + print!("\n{q} RIGHT OUT OF 3.\n"); + //160 IF Q<2 THEN 100 + if q < 2 { + continue; + } + //170 PRINT " NOT BAD." + //print!(" NOT BAD."); + //180 GOTO 100 + } + //999 END +} \ No newline at end of file From 3d677c985455c67a13cc96bb7b9c2156eea55ecb Mon Sep 17 00:00:00 2001 From: P Marques <13932504-psmbrs@users.noreply.gitlab.com> Date: Mon, 17 Feb 2025 23:13:55 -0300 Subject: [PATCH 342/377] kinema game initial rust implementation --- 52_Kinema/rust/src/main.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/52_Kinema/rust/src/main.rs b/52_Kinema/rust/src/main.rs index 3b6e0321c..9ce5c29ed 100644 --- a/52_Kinema/rust/src/main.rs +++ b/52_Kinema/rust/src/main.rs @@ -1,6 +1,3 @@ -use std::io::Write; -use rand::Rng; - /** KINEMA BY RICHARD PAV * https://github.com/coding-horror/basic-computer-games/blob/main/52_Kinema/kinema.bas * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). @@ -11,10 +8,20 @@ use rand::Rng; * instead of the real formulation, which could lead to incorrect results. I have solved * this issue, but kept the old lines. To compile the original version, just uncomment the * code with the OLD label and comment the lines with the NEW label. - * example: gravity is now 9.81 instead of 10 + * example: gravity is now 9.81 instead of 10; Inputs and outputs are now float not integers... + * + * FORMULATION + * A BALL IS THROWN UPWARDS AT 9,36 METERS PER SECOND. + * HOW HIGH WILL IT GO (IN METERS)? (9,36 ^2) / (2 * 9,81) = 4,465321101 + * HOW LONG UNTIL IT RETURNS (IN SECONDS)? 2*(9,36 / 9,81) = 1,908256881 + * WHAT WILL ITS VELOCITY BE AFTER 1,09 SECONDS? 9,36- 9,81 * 1,09 = −1,3329 + * * 17/02/25 */ +use std::io::Write; +use rand::Rng; + fn subroutine(a: f64, q: &mut i32) { std::io::stdout().flush().unwrap(); //500 INPUT G @@ -104,4 +111,4 @@ fn main() { //180 GOTO 100 } //999 END -} \ No newline at end of file +} From e60957ad7e06c23d17da1cade88ce45cf08c5202 Mon Sep 17 00:00:00 2001 From: marquesrs <80490672+marquesrs@users.noreply.github.com> Date: Sun, 23 Feb 2025 15:08:18 -0300 Subject: [PATCH 343/377] init --- 13_Bounce/rust/Cargo.lock | 7 ++ 13_Bounce/rust/Cargo.toml | 6 ++ 13_Bounce/rust/src/main.rs | 160 +++++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 13_Bounce/rust/Cargo.lock create mode 100644 13_Bounce/rust/Cargo.toml create mode 100644 13_Bounce/rust/src/main.rs diff --git a/13_Bounce/rust/Cargo.lock b/13_Bounce/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/13_Bounce/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/13_Bounce/rust/Cargo.toml b/13_Bounce/rust/Cargo.toml new file mode 100644 index 000000000..7d75412a6 --- /dev/null +++ b/13_Bounce/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/13_Bounce/rust/src/main.rs b/13_Bounce/rust/src/main.rs new file mode 100644 index 000000000..0028aaaf7 --- /dev/null +++ b/13_Bounce/rust/src/main.rs @@ -0,0 +1,160 @@ +use std::io::Write; + +fn input(msg: &str) -> String { + print!("{}", msg); + let _ =std::io::stdout().flush().unwrap(); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + return input.trim().to_uppercase(); +} + +fn main() { + //10 PRINT TAB(33);"BOUNCE" + //20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + //30 PRINT:PRINT:PRINT + print!("{}{}\n{}{}\n\n\n", + " ".repeat(33), + "BOUNCE", + " ".repeat(15), + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + ); + + //90 DIM T(20) + let mut t: Vec = Vec::with_capacity(20); + + //100 PRINT "THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY" + //110 PRINT "OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF" + //120 PRINT "ELASTICITY OF THE BALL. PLEASE USE A DECIMAL FRACTION" + //130 PRINT "COEFFICIENCY (LESS THAN 1)." + //131 PRINT + //132 PRINT "YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN" + //133 PRINT "'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY)." + //134 PRINT + print!("{}\n{}\n{}\n{}\n\n{}\n{}\n\n", + "THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY", + "OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF", + "ELASTICITY OF THE BALL. PLEASE USE A DECIMAL FRACTION", + "COEFFICIENCY (LESS THAN 1).", + "YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN", + "'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).", + ); + + loop { + //135 INPUT "TIME INCREMENT (SEC)";S2 + let s2 = input("TIME INCREMENT (SEC): ").parse::().unwrap(); + + //140 PRINT + println!(); + + //150 INPUT "VELOCITY (FPS)";V + let v = input("VELOCITY (FPS): ").parse::().unwrap(); + + //160 PRINT + println!(); + + //170 INPUT "COEFFICIENT";C + let c = input("COEFFICIENT: ").parse::().unwrap(); + + //180 PRINT + //182 PRINT "FEET" + //184 PRINT + print!("\nFEET\n"); + + //186 S1=INT(70/(V/(16*S2))) + let s1 = ( + 70.0 / (v / (16.0 * s2) ) + ) as i32; + + //190 FOR I=1 TO S1 + for i in 1..=s1 { + //200 T(I)=V*C^(I-1)/16 + t.push(v * c.powf(i as f32 - 1.0) / 16.0); + //210 NEXT I + } + + let mut l = 0.0; + + //220 FOR H=INT(-16*(V/32)^2+V^2/32+.5) TO 0 STEP -.5 + let mut h = ((-16.0*(v/32.0).powf(2.0)) +(v.powf(2.0)/32.0) + 0.5).floor(); + while h >= 0.0 { + //221 IF INT(H)<>H THEN 225 + if h.floor() != h { + //225 L=0 + l = 0.0; + } + else { + //222 PRINT H; + println!("{}", h); + //225 L=0 + l = 0.0; + } + + //230 FOR I=1 TO S1 + for i in 1..=s1 { + let mut t2 = 0.0; + //240 FOR T=0 TO T(I) STEP S2 + while t2 <= t[(i - 1) as usize] { + //245 L=L+S2 + l = l + s2; + + //250 IF ABS(H-(.5*(-32)*T^2+V*C^(I-1)*T))>.25 THEN 270 + let condition = h - (0.5 * (-32.0) * t2.powf(2.0) + v * c.powf((i-1) as f32) * t2); + if condition >= 0.25{ + continue; + } + //260 PRINT TAB(L/S2);"0"; + print!("{}0", " ".repeat((l/s2) as usize)); + + //270 NEXT T + t2 = t2 + s2; + } + + //275 T=T(I+1)/2 + t2 = t[i as usize] / 2.0; + + //276 IF -16*T^2+V*C^(I-1)*T Date: Sun, 2 Mar 2025 10:20:33 -0300 Subject: [PATCH 344/377] bounce game initial rust implementation --- 13_Bounce/rust/src/main.rs | 10 ++++------ README.md | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/13_Bounce/rust/src/main.rs b/13_Bounce/rust/src/main.rs index 0028aaaf7..1490ca878 100644 --- a/13_Bounce/rust/src/main.rs +++ b/13_Bounce/rust/src/main.rs @@ -61,9 +61,7 @@ fn main() { print!("\nFEET\n"); //186 S1=INT(70/(V/(16*S2))) - let s1 = ( - 70.0 / (v / (16.0 * s2) ) - ) as i32; + let s1 = (70.0 / (v / (16.0 * s2))).floor() as i32; // verified //190 FOR I=1 TO S1 for i in 1..=s1 { @@ -75,10 +73,10 @@ fn main() { let mut l = 0.0; //220 FOR H=INT(-16*(V/32)^2+V^2/32+.5) TO 0 STEP -.5 - let mut h = ((-16.0*(v/32.0).powf(2.0)) +(v.powf(2.0)/32.0) + 0.5).floor(); - while h >= 0.0 { + let mut h = (-16.0 * (v / 32.0).powi(2) + (v.powi(2)) / 32.0 + 0.5).floor() as i32; // verified + while h >= 0 { //221 IF INT(H)<>H THEN 225 - if h.floor() != h { + if h != h { //225 L=0 l = 0.0; } diff --git a/README.md b/README.md index 1ba366b81..d7a19ef83 100644 --- a/README.md +++ b/README.md @@ -89,20 +89,20 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 09_Battle | x | x | x | | | | x | | x | x | | 10_Blackjack | x | x | x | | | | x | x | x | x | | 11_Bombardment | x | x | x | | | x | x | x | x | x | -| 12_Bombs_Away | x | x | x | | x | x | x | | | x | -| 13_Bounce | x | x | x | | | x | x | x | | x | +| 12_Bombs_Away | x | x | x | | x | x | x | | x | x | +| 13_Bounce | x | x | x | | | x | x | x | x | x | | 14_Bowling | x | x | x | | | x | x | | | x | | 15_Boxing | x | x | x | | | x | x | | | x | | 16_Bug | x | x | x | | | | x | x | | x | | 17_Bullfight | x | x | x | x | | | x | | | x | | 18_Bullseye | x | x | x | | | x | x | | x | x | -| 19_Bunny | x | x | x | | | x | x | x | | x | +| 19_Bunny | x | x | x | | | x | x | x | x | x | | 20_Buzzword | x | x | x | | x | x | x | x | x | x | | 21_Calendar | x | x | x | | | x | x | x | x | x | | 22_Change | x | x | x | | | x | x | | x | x | | 23_Checkers | x | | x | | | x | x | x | | x | | 24_Chemist | x | x | x | | | x | x | | x | x | -| 25_Chief | x | x | x | | x | x | x | x | | x | +| 25_Chief | x | x | x | | x | x | x | x | x | x | | 26_Chomp | x | x | x | | | x | x | | | x | | 27_Civil_War | x | x | x | | | | x | | | x | | 28_Combat | x | x | x | | | x | x | | | x | @@ -120,33 +120,33 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 40_Gomoko | x | x | x | | | x | x | | | x | | 41_Guess | x | x | x | | | x | x | x | x | x | | 42_Gunner | x | x | x | | | x | x | | | x | -| 43_Hammurabi | x | x | x | | | | x | | | x | +| 43_Hammurabi | x | x | x | | | | x | | x | x | | 44_Hangman | x | x | x | | | x | x | x | | x | -| 45_Hello | x | x | x | | x | x | x | x | | x | +| 45_Hello | x | x | x | | x | x | x | x | x | x | | 46_Hexapawn | x | | | | | | x | | | x | | 47_Hi-Lo | x | | x | x | x | x | x | x | x | x | | 48_High_IQ | x | x | x | | | | x | | | x | | 49_Hockey | x | | x | | | | x | | | x | | 50_Horserace | x | x | x | | | | | | x | x | | 51_Hurkle | x | x | x | | | x | x | x | x | x | -| 52_Kinema | x | x | x | | | x | x | x | | x | +| 52_Kinema | x | x | x | | | x | x | x | x | x | | 53_King | x | | x | | | | x | | x | x | | 54_Letter | x | x | x | | | x | x | x | x | x | | 55_Life | x | x | x | | | x | x | x | x | x | | 56_Life_for_Two | x | x | x | | | x | x | | | x | | 57_Literature_Quiz | x | x | x | | | x | x | | x | x | -| 58_Love | x | x | x | | | x | x | x | | x | +| 58_Love | x | x | x | | | x | x | x | x | x | | 59_Lunar_LEM_Rocket | x | | x | | | | x | | x | x | | 60_Mastermind | x | x | x | | | x | x | | x | x | | 61_Math_Dice | x | x | x | | | x | x | x | x | x | | 62_Mugwump | x | x | x | | | x | x | | x | x | -| 63_Name | x | x | x | x | | x | x | x | | x | +| 63_Name | x | x | x | x | | x | x | x | x | x | | 64_Nicomachus | x | x | x | | | x | x | | x | x | | 65_Nim | x | | x | | | | x | x | x | x | | 66_Number | x | x | x | | | x | x | | x | x | | 67_One_Check | x | x | x | | | x | x | | | x | | 68_Orbit | x | x | x | | | x | x | x | x | x | -| 69_Pizza | x | x | x | | | x | x | x | | x | +| 69_Pizza | x | x | x | | | x | x | x | x | x | | 70_Poetry | x | x | x | | | x | x | x | | x | | 71_Poker | x | x | x | | | | | | | x | | 72_Queen | x | | x | | | x | x | | x | x | @@ -154,7 +154,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 74_Rock_Scissors_Paper | x | x | x | x | | x | x | x | x | x | | 75_Roulette | x | x | x | | | x | x | | x | x | | 76_Russian_Roulette | x | x | x | x | | x | x | x | x | x | -| 77_Salvo | x | | x | | | | x | | | x | +| 77_Salvo | x | | x | | | | x | | x | x | | 78_Sine_Wave | x | x | x | x | | x | x | x | x | x | | 79_Slalom | x | | x | | | | x | | | x | | 80_Slots | x | x | x | | | x | x | x | | x | @@ -162,7 +162,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 82_Stars | x | x | x | | | x | x | x | x | x | | 83_Stock_Market | x | x | x | | | | x | | | x | | 84_Super_Star_Trek | x | x | x | | | | x | | x | x | -| 85_Synonym | x | x | x | | | x | x | x | | x | +| 85_Synonym | x | x | x | | | x | x | x | x | x | | 86_Target | x | x | x | | | x | x | | | x | | 87_3-D_Plot | x | x | x | | | x | x | x | | x | | 88_3-D_Tic-Tac-Toe | x | | x | | | | x | | | x | From 847c9eeca1bc68de23eff7d1b5e237b48748ae64 Mon Sep 17 00:00:00 2001 From: marquesrs <80490672+marquesrs@users.noreply.github.com> Date: Mon, 3 Mar 2025 01:26:31 -0300 Subject: [PATCH 345/377] bounce game initial rust implementation --- 13_Bounce/rust/src/main.rs | 49 +++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/13_Bounce/rust/src/main.rs b/13_Bounce/rust/src/main.rs index 1490ca878..32fc6ea78 100644 --- a/13_Bounce/rust/src/main.rs +++ b/13_Bounce/rust/src/main.rs @@ -58,60 +58,58 @@ fn main() { //180 PRINT //182 PRINT "FEET" //184 PRINT - print!("\nFEET\n"); + print!("\nFEET\n\n"); - //186 S1=INT(70/(V/(16*S2))) - let s1 = (70.0 / (v / (16.0 * s2))).floor() as i32; // verified + //186 S1=INT(70/(V/(16*S2))) // verified + let s1 = (70.0 / (v/(16.0*s2))) as i32; //190 FOR I=1 TO S1 for i in 1..=s1 { //200 T(I)=V*C^(I-1)/16 - t.push(v * c.powf(i as f32 - 1.0) / 16.0); + t.push(v * c.powf(i as f32 - 1.0) / 16.0); // verified //210 NEXT I } let mut l = 0.0; //220 FOR H=INT(-16*(V/32)^2+V^2/32+.5) TO 0 STEP -.5 - let mut h = (-16.0 * (v / 32.0).powi(2) + (v.powi(2)) / 32.0 + 0.5).floor() as i32; // verified - while h >= 0 { + let mut h = (-16.0 * (v / 32.0).powi(2) + (v.powi(2)) / 32.0 + 0.5).floor(); + while h >= 0.0 { //221 IF INT(H)<>H THEN 225 - if h != h { - //225 L=0 - l = 0.0; - } - else { + if h.floor() == h { //222 PRINT H; - println!("{}", h); - //225 L=0 - l = 0.0; + print!("{}", h); } + //225 L=0 + l = 0.0; //230 FOR I=1 TO S1 for i in 1..=s1 { - let mut t2 = 0.0; + let mut T = 0.0; //240 FOR T=0 TO T(I) STEP S2 - while t2 <= t[(i - 1) as usize] { + while T <= t[(i - 1) as usize] { //245 L=L+S2 l = l + s2; //250 IF ABS(H-(.5*(-32)*T^2+V*C^(I-1)*T))>.25 THEN 270 - let condition = h - (0.5 * (-32.0) * t2.powf(2.0) + v * c.powf((i-1) as f32) * t2); - if condition >= 0.25{ + let condition = h - (0.5 * (-32.0) * T.powf(2.0) + v * c.powf((i-1) as f32) * T); + if condition.abs() >= 0.25{ + T = T + s2; continue; } //260 PRINT TAB(L/S2);"0"; - print!("{}0", " ".repeat((l/s2) as usize)); + print!("{}{}", " ".repeat((l / s2) as usize), T); //270 NEXT T - t2 = t2 + s2; + T = T + s2; } //275 T=T(I+1)/2 - t2 = t[i as usize] / 2.0; + if i as usize == t.len() { break; } + T = t[i as usize] / 2.0; //276 IF -16*T^2+V*C^(I-1)*T Date: Mon, 3 Mar 2025 02:11:30 -0300 Subject: [PATCH 346/377] bounce game initial rust implementation --- 13_Bounce/rust/src/main.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/13_Bounce/rust/src/main.rs b/13_Bounce/rust/src/main.rs index 32fc6ea78..d287b89e8 100644 --- a/13_Bounce/rust/src/main.rs +++ b/13_Bounce/rust/src/main.rs @@ -71,6 +71,7 @@ fn main() { } let mut l = 0.0; + let mut l_expected = l; //220 FOR H=INT(-16*(V/32)^2+V^2/32+.5) TO 0 STEP -.5 let mut h = (-16.0 * (v / 32.0).powi(2) + (v.powi(2)) / 32.0 + 0.5).floor(); @@ -82,7 +83,7 @@ fn main() { } //225 L=0 l = 0.0; - + l_expected = l; //230 FOR I=1 TO S1 for i in 1..=s1 { let mut T = 0.0; @@ -90,16 +91,20 @@ fn main() { while T <= t[(i - 1) as usize] { //245 L=L+S2 l = l + s2; - + l_expected = l_expected + s2; + //250 IF ABS(H-(.5*(-32)*T^2+V*C^(I-1)*T))>.25 THEN 270 let condition = h - (0.5 * (-32.0) * T.powf(2.0) + v * c.powf((i-1) as f32) * T); if condition.abs() >= 0.25{ T = T + s2; continue; } + // TABS ARE NOT SPACES, BUT A TERMINAL POSITION //260 PRINT TAB(L/S2);"0"; - print!("{}{}", " ".repeat((l / s2) as usize), T); - + let spaces = ((l / s2).floor()-1.0) as usize; + print!("{}0", " ".repeat(spaces)); + l = l - spaces as f32; + //270 NEXT T T = T + s2; } @@ -128,7 +133,7 @@ fn main() { print!(" "); //320 FOR I=1 TO INT(L+1)/S2+1 - for _ in 1..=((l+1.0) / s2 + 1.0) as i32 { + for _ in 1..=((l_expected+1.0) / s2 + 1.0) as i32 { //330 PRINT "."; print!("."); //340 NEXT I @@ -139,7 +144,7 @@ fn main() { print!("\n 0"); //360 FOR I=1 TO INT(L+.9995) - for i in 1..=((l + 0.9995) as i32) { + for i in 1..=((l_expected + 0.9995) as i32) { //380 PRINT TAB(INT(I/S2));I; print!("{}{}", " ".repeat((i as f32 / s2) as usize), i); //390 NEXT I @@ -148,7 +153,7 @@ fn main() { //400 PRINT //410 PRINT TAB(INT(L+1)/(2*S2)-2);"SECONDS" //420 PRINT - let tabs = ((l+1.0) / (2.0 * s2) - 2.0) as usize; + let tabs = ((l_expected+1.0) / (2.0 * s2) - 2.0) as usize; println!("\n{}SECONDS\n", " ".repeat(tabs)); //430 GOTO 135 From 617bdc1e9f760560ebd5dcc5308425a7a59505ba Mon Sep 17 00:00:00 2001 From: marquesrs <80490672+marquesrs@users.noreply.github.com> Date: Mon, 3 Mar 2025 03:15:38 -0300 Subject: [PATCH 347/377] bounce game initial rust implementation --- 13_Bounce/rust/src/main.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/13_Bounce/rust/src/main.rs b/13_Bounce/rust/src/main.rs index d287b89e8..f69b2d920 100644 --- a/13_Bounce/rust/src/main.rs +++ b/13_Bounce/rust/src/main.rs @@ -40,20 +40,23 @@ fn main() { ); loop { - //135 INPUT "TIME INCREMENT (SEC)";S2 - let s2 = input("TIME INCREMENT (SEC): ").parse::().unwrap(); + //135 INPUT "TIME INCREMENT (SEC)";S2 + //let s2 = input("TIME INCREMENT (SEC): ").parse::().unwrap(); + let s2 = 0.1f32; //140 PRINT println!(); //150 INPUT "VELOCITY (FPS)";V - let v = input("VELOCITY (FPS): ").parse::().unwrap(); + //let v = input("VELOCITY (FPS): ").parse::().unwrap(); + let v = 20.0f32; //160 PRINT println!(); //170 INPUT "COEFFICIENT";C - let c = input("COEFFICIENT: ").parse::().unwrap(); + //let c = input("COEFFICIENT: ").parse::().unwrap(); + let c = 0.5f32; //180 PRINT //182 PRINT "FEET" @@ -157,6 +160,7 @@ fn main() { println!("\n{}SECONDS\n", " ".repeat(tabs)); //430 GOTO 135 + break; } //440 END } \ No newline at end of file From 4f46b2f7eb484c18f447a711320fbfd5e25d3818 Mon Sep 17 00:00:00 2001 From: marquesrs <80490672+marquesrs@users.noreply.github.com> Date: Mon, 3 Mar 2025 03:49:00 -0300 Subject: [PATCH 348/377] bounce game initial rust implementation --- 13_Bounce/rust/src/main.rs | 77 +++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/13_Bounce/rust/src/main.rs b/13_Bounce/rust/src/main.rs index f69b2d920..99050227d 100644 --- a/13_Bounce/rust/src/main.rs +++ b/13_Bounce/rust/src/main.rs @@ -1,3 +1,11 @@ +/** BOUNCE GAME + * https://github.com/coding-horror/basic-computer-games/blob/main/13_Bounce/bounce.bas + * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). + * No additional features or improvements were added. As a faithful translation, + * many of the code here are done in an unrecommended way by today's standards. + * 03/03/25 +*/ + use std::io::Write; fn input(msg: &str) -> String { @@ -41,22 +49,22 @@ fn main() { loop { //135 INPUT "TIME INCREMENT (SEC)";S2 - //let s2 = input("TIME INCREMENT (SEC): ").parse::().unwrap(); - let s2 = 0.1f32; + let s2 = input("TIME INCREMENT (SEC): ").parse::().unwrap(); + //let s2 = 0.2f32; //140 PRINT println!(); //150 INPUT "VELOCITY (FPS)";V - //let v = input("VELOCITY (FPS): ").parse::().unwrap(); - let v = 20.0f32; + let v = input("VELOCITY (FPS): ").parse::().unwrap(); + //let v = 20.0f32; //160 PRINT println!(); //170 INPUT "COEFFICIENT";C - //let c = input("COEFFICIENT: ").parse::().unwrap(); - let c = 0.5f32; + let c = input("COEFFICIENT: ").parse::().unwrap(); + //let c = 0.6f32; //180 PRINT //182 PRINT "FEET" @@ -74,56 +82,57 @@ fn main() { } let mut l = 0.0; - let mut l_expected = l; //220 FOR H=INT(-16*(V/32)^2+V^2/32+.5) TO 0 STEP -.5 let mut h = (-16.0 * (v / 32.0).powi(2) + (v.powi(2)) / 32.0 + 0.5).floor(); while h >= 0.0 { + let mut line_content = String::new(); //221 IF INT(H)<>H THEN 225 if h.floor() == h { //222 PRINT H; - print!("{}", h); + line_content.push_str(h.to_string().as_str()); + line_content.push(' '); } //225 L=0 l = 0.0; - l_expected = l; //230 FOR I=1 TO S1 for i in 1..=s1 { - let mut T = 0.0; + let mut t_val = 0.0; //240 FOR T=0 TO T(I) STEP S2 - while T <= t[(i - 1) as usize] { + while t_val <= t[(i - 1) as usize] { //245 L=L+S2 l = l + s2; - l_expected = l_expected + s2; //250 IF ABS(H-(.5*(-32)*T^2+V*C^(I-1)*T))>.25 THEN 270 - let condition = h - (0.5 * (-32.0) * T.powf(2.0) + v * c.powf((i-1) as f32) * T); + let condition = h - (0.5 * (-32.0) * t_val.powf(2.0) + v * c.powf((i-1) as f32) * t_val); if condition.abs() >= 0.25{ - T = T + s2; + t_val = t_val + s2; continue; } // TABS ARE NOT SPACES, BUT A TERMINAL POSITION //260 PRINT TAB(L/S2);"0"; - let spaces = ((l / s2).floor()-1.0) as usize; - print!("{}0", " ".repeat(spaces)); - l = l - spaces as f32; + let spaces = ((l / s2) - 1.0) as usize; + while line_content.len() < spaces { + line_content.push(' '); + } + line_content.push('0'); //270 NEXT T - T = T + s2; + t_val = t_val + s2; } //275 T=T(I+1)/2 if i as usize == t.len() { break; } - T = t[i as usize] / 2.0; + t_val = t[i as usize] / 2.0; //276 IF -16*T^2+V*C^(I-1)*T Date: Mon, 3 Mar 2025 11:35:22 -0300 Subject: [PATCH 349/377] 3D plot game initial rust implementation --- 87_3-D_Plot/rust/Cargo.lock | 7 ++++ 87_3-D_Plot/rust/Cargo.toml | 6 ++++ 87_3-D_Plot/rust/src/main.rs | 68 ++++++++++++++++++++++++++++++++++++ README.md | 2 +- 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 87_3-D_Plot/rust/Cargo.lock create mode 100644 87_3-D_Plot/rust/Cargo.toml create mode 100644 87_3-D_Plot/rust/src/main.rs diff --git a/87_3-D_Plot/rust/Cargo.lock b/87_3-D_Plot/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/87_3-D_Plot/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/87_3-D_Plot/rust/Cargo.toml b/87_3-D_Plot/rust/Cargo.toml new file mode 100644 index 000000000..7d75412a6 --- /dev/null +++ b/87_3-D_Plot/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/87_3-D_Plot/rust/src/main.rs b/87_3-D_Plot/rust/src/main.rs new file mode 100644 index 000000000..ebd66dfa2 --- /dev/null +++ b/87_3-D_Plot/rust/src/main.rs @@ -0,0 +1,68 @@ +/** 3D Plot GAME + * https://github.com/coding-horror/basic-computer-games/blob/main/87_3-D_Plot/3dplot.bas + * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). + * No additional features or improvements were added. As a faithful translation, + * many of the code here are done in an unrecommended way by today's standards. + * 03/03/25 +*/ + +fn main() { + //1 PRINT TAB(32);"3D PLOT" + //2 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + //3 PRINT:PRINT:PRINT + print!("{}", + format!("{}{}\n{}{}\n\n\n\n", + " ".repeat(31), + "3D PLOT", + " ".repeat(14), + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + ) + ); + + //5 DEF FNA(Z)=30*EXP(-Z*Z/100) + let fna = |z: f32| {30.0 * f32::exp(-z*z/100.0)}; + + //100 PRINT + println!(); + + let mut line_content = String::new(); + //110 FOR X=-30 TO 30 STEP 1.5 + let mut x = -30.0; + while x <= 30.0 { + //120 L=0 + let mut l = 0; + + //130 Y1=5*INT(SQR(900-X*X)/5) + let y1 = 5.0 * (f32::sqrt(900.0-x*x)/5.0).floor(); + + //140 FOR Y=Y1 TO -Y1 STEP -5 + let mut y = y1; + while y >= -y1 { + //150 Z=INT(25+FNA(SQR(X*X+Y*Y))-.7*Y) + let z = (25.0 + fna(f32::sqrt(x*x+y*y))-0.7*y) as i32; + + //160 IF Z<=L THEN 190 + if z <= l { + y = y - 5.0; + continue; + } + //170 L=Z + l = z; + //180 PRINT TAB(Z);"*"; + while (line_content.len() as i32) < (z-1) { + line_content += " "; + } + line_content += "*"; + //190 NEXT Y + y = y - 5.0; + } + print!("{}", line_content); + line_content.clear(); + + //200 PRINT + println!(); + //210 NEXT X + x = x + 1.5; + } + //300 END +} \ No newline at end of file diff --git a/README.md b/README.md index d7a19ef83..b74523106 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 84_Super_Star_Trek | x | x | x | | | | x | | x | x | | 85_Synonym | x | x | x | | | x | x | x | x | x | | 86_Target | x | x | x | | | x | x | | | x | -| 87_3-D_Plot | x | x | x | | | x | x | x | | x | +| 87_3-D_Plot | x | x | x | | | x | x | x | x | x | | 88_3-D_Tic-Tac-Toe | x | | x | | | | x | | | x | | 89_Tic-Tac-Toe | x | x | x | x | | x | x | | x | x | | 90_Tower | x | x | x | | | x | x | | x | x | From 5983497c6cfdf9b55f58f8e6744f08af69efb2ad Mon Sep 17 00:00:00 2001 From: marquesrs <80490672+marquesrs@users.noreply.github.com> Date: Mon, 3 Mar 2025 12:12:58 -0300 Subject: [PATCH 350/377] depth charge game initial rust implementation --- 31_Depth_Charge/rust/Cargo.lock | 7 ++ 31_Depth_Charge/rust/Cargo.toml | 6 ++ 31_Depth_Charge/rust/src/main.rs | 132 +++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 31_Depth_Charge/rust/Cargo.lock create mode 100644 31_Depth_Charge/rust/Cargo.toml create mode 100644 31_Depth_Charge/rust/src/main.rs diff --git a/31_Depth_Charge/rust/Cargo.lock b/31_Depth_Charge/rust/Cargo.lock new file mode 100644 index 000000000..b21cc6a2d --- /dev/null +++ b/31_Depth_Charge/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "rust" +version = "0.1.0" diff --git a/31_Depth_Charge/rust/Cargo.toml b/31_Depth_Charge/rust/Cargo.toml new file mode 100644 index 000000000..7d75412a6 --- /dev/null +++ b/31_Depth_Charge/rust/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/31_Depth_Charge/rust/src/main.rs b/31_Depth_Charge/rust/src/main.rs new file mode 100644 index 000000000..3c51c3485 --- /dev/null +++ b/31_Depth_Charge/rust/src/main.rs @@ -0,0 +1,132 @@ +use std::io::Write; + +/** DEPTH CHARGE GAME + * https://github.com/marquesrs/basic-computer-games/blob/main/31_Depth_Charge/depthcharge.bas + * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). + * No additional features or improvements were added. As a faithful translation, + * many of the code here are done in an unrecommended way by today's standards. + * 03/03/25 +*/ + +fn input(msg: &str) -> String { + print!("{}", msg); + let _ =std::io::stdout().flush().unwrap(); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + return input.trim().to_uppercase(); +} + +fn main() { + // 2 PRINT TAB(30);"DEPTH CHARGE" + // 4 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + // 6 PRINT: PRINT: PRINT + print!("{}", format!("{}{}\n{}{}\n\n\n\n", + " ".repeat(29), + "DEPTH CHARGE", + " ".repeat(14), + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + )); + + // 20 INPUT "DIMENSION OF SEARCH AREA";G: PRINT + let mut g = input("DIMENSION OF SEARCH AREA"); + + // 30 N=INT(LOG(G)/LOG(2))+1 + let mut n = INT(LOG(G)/LOG(2)) + 1; + + // 40 PRINT "YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER" + // 50 PRINT "AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR" + // 60 PRINT "MISSION IS TO DESTROY IT. YOU HAVE";N;"SHOTS." + // 70 PRINT "SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A" + // 80 PRINT "TRIO OF NUMBERS -- THE FIRST TWO ARE THE" + // 90 PRINT "SURFACE COORDINATES; THE THIRD IS THE DEPTH." + // 100 PRINT : PRINT "GOOD LUCK !": PRINT + print!("{}", format!("{}{}{}{}{}{}{}{}{}", + "YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\n", + "AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR\n", + "MISSION IS TO DESTROY IT. YOU HAVE", + n, + "SHOTS.\n", + "SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A\n", + "TRIO OF NUMBERS -- THE FIRST TWO ARE THE\n", + "SURFACE COORDINATES; THE THIRD IS THE DEPTH.\n", + "\nGOOD LUCK !\n" + )); + + 'main: loop { + // 110 A=INT(G*RND(1)) : B=INT(G*RND(1)) : C=INT(G*RND(1)) + let mut a = INT(G*RND(1)); + let mut b = INT(G*RND(1)); + let mut c = INT(G*RND(1)); + + // 120 FOR D=1 TO N : PRINT : PRINT "TRIAL #";D; : INPUT X,Y,Z + let mut x; + let mut y; + let mut z; + for d in 1..=n { + print!("\nTRIAL #{}", d); + x = input("X: "); + y = input("X: "); + z = input("X: "); + // 130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300 + if i32::abs(x-a) + i32::abs(y-b) + i32::abs(z-c) == 0 { + // 300 PRINT : PRINT "B O O M ! ! YOU FOUND IT IN";D;"TRIES!" + // 400 PRINT : PRINT: INPUT "ANOTHER GAME (Y OR N)";A$ + print!("{}", format!("{}{}{}{}{}", + "\n", + "B O O M ! ! YOU FOUND IT IN", + d, + "TRIES!\n", + "\n\n" + )); + let a = input("ANOTHER GAME (Y OR N): "); + // 410 IF A$="Y" THEN 100 + if a == "Y" { + continue 'main; + } + else { + // 420 PRINT "OK. HOPE YOU ENJOYED YOURSELF." : GOTO 600 + print!("OK. HOPE YOU ENJOYED YOURSELF."); + break 'main; + } + } + + // 140 GOSUB 500 : PRINT : NEXT D + subroutine(x, y, z, a, b, c); + println!(); + } + // 200 PRINT : PRINT "YOU HAVE BEEN TORPEDOED! ABANDON SHIP!" + // 210 PRINT "THE SUBMARINE WAS AT";A;",";B;",";C : GOTO 400 + print!("{}", format!("{}{}{}{}{}{}{}", + "\nYOU HAVE BEEN TORPEDOED! ABANDON SHIP!\n", + "THE SUBMARINE WAS AT ", + a, + ",", + b, + ",", + c + )); + } + // 600 END +} + +// 500 PRINT "SONAR REPORTS SHOT WAS "; +// 510 IF Y>B THEN PRINT "NORTH"; +// 520 IF YA THEN PRINT "EAST"; +// 540 IF XB OR X<>A THEN PRINT " AND"; +// 560 IF Z>C THEN PRINT " TOO LOW." +// 570 IF Zb { print!("NORTH"); }; + if ya { print!("EAST"); }; + if xc { print!(" TOO LOW."); }; + if z Date: Mon, 3 Mar 2025 12:52:49 -0300 Subject: [PATCH 351/377] depth charge game initial rust implementation --- 31_Depth_Charge/rust/Cargo.lock | 236 +++++++++++++++++++++++++++++++ 31_Depth_Charge/rust/Cargo.toml | 1 + 31_Depth_Charge/rust/src/main.rs | 76 ++++++---- 3 files changed, 282 insertions(+), 31 deletions(-) diff --git a/31_Depth_Charge/rust/Cargo.lock b/31_Depth_Charge/rust/Cargo.lock index b21cc6a2d..8be5f5fa6 100644 --- a/31_Depth_Charge/rust/Cargo.lock +++ b/31_Depth_Charge/rust/Cargo.lock @@ -2,6 +2,242 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi", + "windows-targets", +] + +[[package]] +name = "libc" +version = "0.2.170" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy 0.7.35", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha", + "rand_core", + "zerocopy 0.8.21", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + [[package]] name = "rust" version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "syn" +version = "2.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe" + +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf01143b2dd5d134f11f545cf9f1431b13b749695cb33bcce051e7568f99478" +dependencies = [ + "zerocopy-derive 0.8.21", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712c8386f4f4299382c9abee219bee7084f78fb939d88b6840fcc1320d5f6da2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/31_Depth_Charge/rust/Cargo.toml b/31_Depth_Charge/rust/Cargo.toml index 7d75412a6..3a87396aa 100644 --- a/31_Depth_Charge/rust/Cargo.toml +++ b/31_Depth_Charge/rust/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] +rand = "0.9.0" \ No newline at end of file diff --git a/31_Depth_Charge/rust/src/main.rs b/31_Depth_Charge/rust/src/main.rs index 3c51c3485..f8269de08 100644 --- a/31_Depth_Charge/rust/src/main.rs +++ b/31_Depth_Charge/rust/src/main.rs @@ -1,5 +1,7 @@ use std::io::Write; +use rand::Rng; + /** DEPTH CHARGE GAME * https://github.com/marquesrs/basic-computer-games/blob/main/31_Depth_Charge/depthcharge.bas * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). @@ -28,10 +30,10 @@ fn main() { )); // 20 INPUT "DIMENSION OF SEARCH AREA";G: PRINT - let mut g = input("DIMENSION OF SEARCH AREA"); + let g = input("DIMENSION OF SEARCH AREA: ").parse::().unwrap(); // 30 N=INT(LOG(G)/LOG(2))+1 - let mut n = INT(LOG(G)/LOG(2)) + 1; + let n = (f32::ln(g as f32) / f32::ln(2.0) + 1.0) as i32; // 40 PRINT "YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER" // 50 PRINT "AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR" @@ -40,54 +42,50 @@ fn main() { // 80 PRINT "TRIO OF NUMBERS -- THE FIRST TWO ARE THE" // 90 PRINT "SURFACE COORDINATES; THE THIRD IS THE DEPTH." // 100 PRINT : PRINT "GOOD LUCK !": PRINT - print!("{}", format!("{}{}{}{}{}{}{}{}{}", - "YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\n", - "AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR\n", - "MISSION IS TO DESTROY IT. YOU HAVE", + let a = (g * rand::rng().random_range(0..=1)) as i32; + let b = (g * rand::rng().random_range(0..=1)) as i32; + let c = (g * rand::rng().random_range(0..=1)) as i32; + print!("{}", format!("{}{}{}{}{}{}{}{}{}{}{}", + "\nYOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER\n", + "AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR\n", + "MISSION IS TO DESTROY IT. YOU HAVE ", n, - "SHOTS.\n", + " SHOTS.\n", "SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A\n", "TRIO OF NUMBERS -- THE FIRST TWO ARE THE\n", "SURFACE COORDINATES; THE THIRD IS THE DEPTH.\n", + format!("EXAMPLE FOR DIMENSION {}: ", g), + format!("{}, {}, {}", a, b, c), "\nGOOD LUCK !\n" )); 'main: loop { // 110 A=INT(G*RND(1)) : B=INT(G*RND(1)) : C=INT(G*RND(1)) - let mut a = INT(G*RND(1)); - let mut b = INT(G*RND(1)); - let mut c = INT(G*RND(1)); - + let a = (g * rand::rng().random_range(0..=1)) as i32; + let b = (g * rand::rng().random_range(0..=1)) as i32; + let c = (g * rand::rng().random_range(0..=1)) as i32; // 120 FOR D=1 TO N : PRINT : PRINT "TRIAL #";D; : INPUT X,Y,Z let mut x; let mut y; let mut z; for d in 1..=n { - print!("\nTRIAL #{}", d); - x = input("X: "); - y = input("X: "); - z = input("X: "); + print!("\nTRIAL #{}\n", d); + x = input("X: ").parse::().unwrap(); + y = input("Y: ").parse::().unwrap(); + z = input("Z: ").parse::().unwrap(); // 130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300 if i32::abs(x-a) + i32::abs(y-b) + i32::abs(z-c) == 0 { // 300 PRINT : PRINT "B O O M ! ! YOU FOUND IT IN";D;"TRIES!" - // 400 PRINT : PRINT: INPUT "ANOTHER GAME (Y OR N)";A$ print!("{}", format!("{}{}{}{}{}", "\n", - "B O O M ! ! YOU FOUND IT IN", + "B O O M ! ! YOU FOUND IT IN ", d, - "TRIES!\n", - "\n\n" + " TRIES!\n", + "\n" )); - let a = input("ANOTHER GAME (Y OR N): "); - // 410 IF A$="Y" THEN 100 - if a == "Y" { - continue 'main; - } - else { - // 420 PRINT "OK. HOPE YOU ENJOYED YOURSELF." : GOTO 600 - print!("OK. HOPE YOU ENJOYED YOURSELF."); - break 'main; - } + // 400 PRINT : PRINT: INPUT "ANOTHER GAME (Y OR N)";A$ + if replay() { continue 'main; } + else { break 'main; } } // 140 GOSUB 500 : PRINT : NEXT D @@ -96,15 +94,18 @@ fn main() { } // 200 PRINT : PRINT "YOU HAVE BEEN TORPEDOED! ABANDON SHIP!" // 210 PRINT "THE SUBMARINE WAS AT";A;",";B;",";C : GOTO 400 - print!("{}", format!("{}{}{}{}{}{}{}", + print!("{}", format!("{}{}{}{}{}{}{}{}", "\nYOU HAVE BEEN TORPEDOED! ABANDON SHIP!\n", "THE SUBMARINE WAS AT ", a, ",", b, ",", - c + c, + "\n" )); + + replay(); } // 600 END } @@ -130,3 +131,16 @@ fn subroutine(x: i32, y: i32, z:i32, a:i32, b:i32, c:i32) { if z bool { + let r = input("ANOTHER GAME (Y OR N): "); + // 410 IF A$="Y" THEN 100 + if r == "Y" { + return true; + } + else { + // 420 PRINT "OK. HOPE YOU ENJOYED YOURSELF." : GOTO 600 + println!("OK. HOPE YOU ENJOYED YOURSELF."); + return false; + } +} \ No newline at end of file From cef657426af1675eb3ab172bec7627a395208df5 Mon Sep 17 00:00:00 2001 From: marquesrs <80490672+marquesrs@users.noreply.github.com> Date: Mon, 3 Mar 2025 12:54:20 -0300 Subject: [PATCH 352/377] depth charge game initial rust implementation --- 31_Depth_Charge/rust/src/main.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/31_Depth_Charge/rust/src/main.rs b/31_Depth_Charge/rust/src/main.rs index f8269de08..f997fda36 100644 --- a/31_Depth_Charge/rust/src/main.rs +++ b/31_Depth_Charge/rust/src/main.rs @@ -1,7 +1,3 @@ -use std::io::Write; - -use rand::Rng; - /** DEPTH CHARGE GAME * https://github.com/marquesrs/basic-computer-games/blob/main/31_Depth_Charge/depthcharge.bas * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). @@ -10,6 +6,9 @@ use rand::Rng; * 03/03/25 */ +use std::io::Write; +use rand::Rng; + fn input(msg: &str) -> String { print!("{}", msg); let _ =std::io::stdout().flush().unwrap(); From f7472afbd11e320ce4df31bef4b3942a14352b65 Mon Sep 17 00:00:00 2001 From: marquesrs <80490672+marquesrs@users.noreply.github.com> Date: Tue, 4 Mar 2025 12:00:58 -0300 Subject: [PATCH 353/377] init --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d7a19ef83..20754fb17 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 28_Combat | x | x | x | | | x | x | | | x | | 29_Craps | x | x | x | | x | x | x | x | x | x | | 30_Cube | x | x | x | | | | x | x | x | x | -| 31_Depth_Charge | x | x | x | | | x | x | x | | x | +| 31_Depth_Charge | x | x | x | | | x | x | x | x | x | | 32_Diamond | x | x | x | x | | x | x | x | x | x | | 33_Dice | x | x | x | | x | x | x | x | x | x | | 34_Digits | x | x | x | | | x | x | | | x | @@ -150,7 +150,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 70_Poetry | x | x | x | | | x | x | x | | x | | 71_Poker | x | x | x | | | | | | | x | | 72_Queen | x | | x | | | x | x | | x | x | -| 73_Reverse | x | x | x | | | x | x | x | | x | +| 73_Reverse | x | x | x | | | x | x | x | x | x | | 74_Rock_Scissors_Paper | x | x | x | x | | x | x | x | x | x | | 75_Roulette | x | x | x | | | x | x | | x | x | | 76_Russian_Roulette | x | x | x | x | | x | x | x | x | x | From dce839e4ced233447e42e13186403a5799edd8b2 Mon Sep 17 00:00:00 2001 From: marquesrs <80490672+marquesrs@users.noreply.github.com> Date: Tue, 4 Mar 2025 12:01:23 -0300 Subject: [PATCH 354/377] reverse game initial rust implementation --- 73_Reverse/rust/Cargo.lock | 243 ++++++++++++++++++++++++++++++++++++ 73_Reverse/rust/Cargo.toml | 7 ++ 73_Reverse/rust/src/main.rs | 190 ++++++++++++++++++++++++++++ 3 files changed, 440 insertions(+) create mode 100644 73_Reverse/rust/Cargo.lock create mode 100644 73_Reverse/rust/Cargo.toml create mode 100644 73_Reverse/rust/src/main.rs diff --git a/73_Reverse/rust/Cargo.lock b/73_Reverse/rust/Cargo.lock new file mode 100644 index 000000000..0da17814e --- /dev/null +++ b/73_Reverse/rust/Cargo.lock @@ -0,0 +1,243 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi", + "windows-targets", +] + +[[package]] +name = "libc" +version = "0.2.170" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy 0.7.35", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha", + "rand_core", + "zerocopy 0.8.21", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rust" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "syn" +version = "2.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf01143b2dd5d134f11f545cf9f1431b13b749695cb33bcce051e7568f99478" +dependencies = [ + "zerocopy-derive 0.8.21", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712c8386f4f4299382c9abee219bee7084f78fb939d88b6840fcc1320d5f6da2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/73_Reverse/rust/Cargo.toml b/73_Reverse/rust/Cargo.toml new file mode 100644 index 000000000..3a87396aa --- /dev/null +++ b/73_Reverse/rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +[dependencies] +rand = "0.9.0" \ No newline at end of file diff --git a/73_Reverse/rust/src/main.rs b/73_Reverse/rust/src/main.rs new file mode 100644 index 000000000..f7d12c30a --- /dev/null +++ b/73_Reverse/rust/src/main.rs @@ -0,0 +1,190 @@ +/** REVERSE GAME + * https://github.com/marquesrs/basic-computer-games/blob/main/73_Reverse/reverse.bas + * Direct conversion from BASIC to Rust by Pablo Marques (marquesrs). + * No additional features or improvements were added. As a faithful translation, + * many of the code here are done in an unrecommended way by today's standards. + * 03/03/25 +*/ + +use rand::Rng; +use std::io::Write; + +fn input(msg: &str) -> String { + print!("{}", msg); + let _ =std::io::stdout().flush().unwrap(); + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + return input.trim().to_uppercase(); +} + +fn main() { + // 10 PRINT TAB(32);"REVERSE" + // 20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + // 30 PRINT:PRINT:PRINT + // 100 PRINT "REVERSE -- A GAME OF SKILL": PRINT + print!("{}", format!("{}{}{}{}{}{}{}{}", + " ".repeat(31), + "REVERSE", + "\n", + " ".repeat(14), + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n", + "\n\n\n", + "REVERSE -- A GAME OF SKILL\n", + "\n" + )); + + // 130 DIM A(20) + let mut a = Vec::with_capacity(20); + + // 140 REM *** N=NUMBER OF NUMBERS + // 150 N=9 + let n = 9; + + // 160 PRINT "DO YOU WANT THE RULES"; + // 170 INPUT A$ + let opt = input("DO YOU WANT THE RULES (YES OR NO)? "); + + + if opt == "YES" { + // 190 GOSUB 710 + sub1(n); + } + // 180 IF A$="NO" THEN 210 + 'c : loop { + // 200 REM *** MAKE A RANDOM LIST A(1) TO A(N) + // 210 A(1)=INT((N-1)*RND(1)+2) + a[1-1] = ((n-1) as f32 * rand::rng().random_range(0.0..=1.0) + 2.0) as i32; + + // 220 FOR K=2 TO N + 'a : for k in 2..=n { + // 230 A(K)=INT(N*RND(1)+1) + a[k-1] = (n as f32 * rand::rng().random_range(0.0..=1.0) + 1.0) as i32; + // 240 FOR J=1 TO K-1 + for j in 1..k { + if a[k-1] == a[j-1] { + // 250 IF A(K)=A(J) THEN 230 + continue 'a; + } + // 260 NEXT J: + } + //NEXT K + } + // 280 REM *** PRINT ORIGINAL LIST AND START GAME + // 290 PRINT: PRINT "HERE WE GO ... THE LIST IS:" + print!("\nHERE WE GO ... THE LIST IS: "); + + // 310 T=0 + let mut t = 0; + + 'b : loop { + // 330 PRINT "HOW MANY SHALL I REVERSE"; + // 340 INPUT R + let r = input("HOW MANY SHALL I REVERSE: ").parse::().unwrap(); + + // 350 IF R=0 THEN 520 + if r == 0 { + // 520 PRINT + // 530 PRINT "TRY AGAIN (YES OR NO)"; + // 540 INPUT A$ + let opt = input("\nTRY AGAIN (YES OR NO): "); + // 550 IF A$="YES" THEN 210 + if opt == "YES" { + continue 'c; + } + // 560 PRINT: PRINT "O.K. HOPE YOU HAD FUN!!":GOTO 999 + print!("\nO.K. HOPE YOU HAD FUN!!"); + break 'c; + } + // 360 IF R<=N THEN 390 + if r <= n { + // 390 T=T+1 + t = t + 1; + + // 400 REM *** REVERSE R NUMBERS AND PRINT NEW LIST + // 410 FOR K=1 TO INT(R/2) + for k in 1..=((r/2) as usize) { + // 420 Z=A(K) + let z = a[k-1]; + // 430 A(K)=A(R-K+1) + a[k-1] = a[r-k]; + // 440 A(R-K+1)=Z + a[r-k] = z; + + // 450 NEXT K + } + // 460 GOSUB 610 + sub2(&a, n); + + // 470 REM *** CHECK FOR A WIN + // 480 FOR K=1 TO N + for k in 1..=n { + // 490 IF A(K)<>K THEN 330 + if a[k-1] != k as i32 { + continue 'b; + } + // 500 NEXT K + } + // 510 PRINT "YOU WON IT IN";T;"MOVES!!!":PRINT + print!("{}{}{}", "YOU WON IT IN ", t, " MOVES!!!\n\n"); + + } + // 370 PRINT "OOPS! TOO MANY! I CAN REVERSE AT MOST";N:GOTO 330 + print!("OOPS! TOO MANY! I CAN REVERSE AT MOST {n}"); + + // 320 GOSUB 610 + sub2(&a, n); + } + } + // 999 END +} + +// 600 REM *** SUBROUTINE TO PRINT LIST +fn sub2(a: &Vec, n: usize) { + // 610 PRINT:FOR K=1 TO N:PRINT A(K);:NEXT K + // 650 PRINT:PRINT:RETURN + for k in 1..=n { + print!("{}", a[k-1]); + } + print!("\n\n"); +} + +// 700 REM *** SUBROUTINE TO PRINT THE RULES +fn sub1(n: usize) { + // 710 PRINT:PRINT "THIS IS THE GAME OF 'REVERSE'. TO WIN, ALL YOU HAVE" + // 720 PRINT "TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH";N;")" + // 730 PRINT "IN NUMERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU" + // 740 PRINT "TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO" + // 750 PRINT "REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:" + // 760 PRINT:PRINT "2 3 4 5 1 6 7 8 9" + // 770 PRINT:PRINT "AND YOU REVERSE 4, THE RESULT WILL BE:" + // 780 PRINT:PRINT "5 4 3 2 1 6 7 8 9" + // 790 PRINT:PRINT "NOW IF YOU REVERSE 5, YOU WIN!" + // 800 PRINT:PRINT "1 2 3 4 5 6 7 8 9":PRINT + // 810 PRINT "NO DOUBT YOU WILL LIKE THIS GAME, BUT" + // 820 PRINT "IF YOU WANT TO QUIT, REVERSE 0 (ZERO).":PRINT: RETURN + + print!("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", + "\n", + "THIS IS THE GAME OF 'REVERSE'. TO WIN, ALL YOU HAVE\n", + "TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH ", + n, + ")\n", + "IN NUMERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU\n", + "TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\n", + "REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:\n", + "\n", + "2 3 4 5 1 6 7 8 9\n", + "\n", + "AND YOU REVERSE 4, THE RESULT WILL BE:\n", + "\n", + "5 4 3 2 1 6 7 8 9\n", + "\n", + "NOW IF YOU REVERSE 5, YOU WIN!\n", + "\n", + "1 2 3 4 5 6 7 8 9\n", + "\n", + "NO DOUBT YOU WILL LIKE THIS GAME, BUT\n", + "IF YOU WANT TO QUIT, REVERSE 0 (ZERO).\n", + "\n", + ) +} \ No newline at end of file From 7e35a798d223d7bfb1d307f783e426f8cb58d4b3 Mon Sep 17 00:00:00 2001 From: marquesrs <80490672+marquesrs@users.noreply.github.com> Date: Tue, 4 Mar 2025 14:18:11 -0300 Subject: [PATCH 355/377] reverse game initial rust implementation --- 73_Reverse/rust/src/main.rs | 83 +++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/73_Reverse/rust/src/main.rs b/73_Reverse/rust/src/main.rs index f7d12c30a..8fd06505e 100644 --- a/73_Reverse/rust/src/main.rs +++ b/73_Reverse/rust/src/main.rs @@ -34,7 +34,7 @@ fn main() { )); // 130 DIM A(20) - let mut a = Vec::with_capacity(20); + let mut a = vec![0; 20]; // 140 REM *** N=NUMBER OF NUMBERS // 150 N=9 @@ -45,7 +45,7 @@ fn main() { let opt = input("DO YOU WANT THE RULES (YES OR NO)? "); - if opt == "YES" { + if opt == "YES" || opt == "Y" { // 190 GOSUB 710 sub1(n); } @@ -53,29 +53,40 @@ fn main() { 'c : loop { // 200 REM *** MAKE A RANDOM LIST A(1) TO A(N) // 210 A(1)=INT((N-1)*RND(1)+2) - a[1-1] = ((n-1) as f32 * rand::rng().random_range(0.0..=1.0) + 2.0) as i32; - + // element 0 + a[0] = ((n-1) as f32 * rand::rng().random_range(0.0..=1.0) + 2.0) as i32; + // 220 FOR K=2 TO N - 'a : for k in 2..=n { - // 230 A(K)=INT(N*RND(1)+1) - a[k-1] = (n as f32 * rand::rng().random_range(0.0..=1.0) + 1.0) as i32; - // 240 FOR J=1 TO K-1 - for j in 1..k { - if a[k-1] == a[j-1] { + for k in 2..=n { + 'a : loop { + // element k + // 230 A(K)=INT(N*RND(1)+1) + a[k-1] = (n as f32 * rand::rng().random_range(0.0..=1.0) + 1.0) as i32; + + // element 0 to k-1 + // 240 FOR J=1 TO K-1 + for j in 1..k { // 250 IF A(K)=A(J) THEN 230 - continue 'a; + if a[k-1] == a[j-1] { + continue 'a; + } + // 260 NEXT J: } - // 260 NEXT J: + break; } //NEXT K - } + } + // 280 REM *** PRINT ORIGINAL LIST AND START GAME // 290 PRINT: PRINT "HERE WE GO ... THE LIST IS:" - print!("\nHERE WE GO ... THE LIST IS: "); - + print!("\nHERE WE GO ... THE LIST IS:\n"); + // 310 T=0 let mut t = 0; + // 320 GOSUB 610 + sub2(&a, n); + 'b : loop { // 330 PRINT "HOW MANY SHALL I REVERSE"; // 340 INPUT R @@ -83,17 +94,8 @@ fn main() { // 350 IF R=0 THEN 520 if r == 0 { - // 520 PRINT - // 530 PRINT "TRY AGAIN (YES OR NO)"; - // 540 INPUT A$ - let opt = input("\nTRY AGAIN (YES OR NO): "); - // 550 IF A$="YES" THEN 210 - if opt == "YES" { - continue 'c; - } - // 560 PRINT: PRINT "O.K. HOPE YOU HAD FUN!!":GOTO 999 - print!("\nO.K. HOPE YOU HAD FUN!!"); - break 'c; + if replay() { continue 'c; } + else { break 'c; } } // 360 IF R<=N THEN 390 if r <= n { @@ -127,12 +129,13 @@ fn main() { // 510 PRINT "YOU WON IT IN";T;"MOVES!!!":PRINT print!("{}{}{}", "YOU WON IT IN ", t, " MOVES!!!\n\n"); + if replay() { continue 'c; } + else { break 'c; } + } + else { + // 370 PRINT "OOPS! TOO MANY! I CAN REVERSE AT MOST";N:GOTO 330 + print!("OOPS! TOO MANY! I CAN REVERSE AT MOST {n}"); } - // 370 PRINT "OOPS! TOO MANY! I CAN REVERSE AT MOST";N:GOTO 330 - print!("OOPS! TOO MANY! I CAN REVERSE AT MOST {n}"); - - // 320 GOSUB 610 - sub2(&a, n); } } // 999 END @@ -143,7 +146,7 @@ fn sub2(a: &Vec, n: usize) { // 610 PRINT:FOR K=1 TO N:PRINT A(K);:NEXT K // 650 PRINT:PRINT:RETURN for k in 1..=n { - print!("{}", a[k-1]); + print!("{} ", a[k-1]); } print!("\n\n"); } @@ -187,4 +190,20 @@ fn sub1(n: usize) { "IF YOU WANT TO QUIT, REVERSE 0 (ZERO).\n", "\n", ) +} + +fn replay() -> bool { + // 520 PRINT + // 530 PRINT "TRY AGAIN (YES OR NO)"; + // 540 INPUT A$ + let r = input("\nTRY AGAIN (YES OR NO): "); + // 550 IF A$="YES" THEN 210 + if r == "YES" || r == "Y" { + return true; + } + else { + // 560 PRINT: PRINT "O.K. HOPE YOU HAD FUN!!":GOTO 999 + println!("\nO.K. HOPE YOU HAD FUN!!"); + return false; + } } \ No newline at end of file From 187364df47b047b85e0631541b72db7f6e576f77 Mon Sep 17 00:00:00 2001 From: Brian Wilkins Date: Fri, 14 Mar 2025 10:00:08 -0400 Subject: [PATCH 356/377] Lua representation of flipflop game --- 36_Flip_Flop/lua/flipflop-game.lua | 183 +++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 36_Flip_Flop/lua/flipflop-game.lua diff --git a/36_Flip_Flop/lua/flipflop-game.lua b/36_Flip_Flop/lua/flipflop-game.lua new file mode 100644 index 000000000..d529d1017 --- /dev/null +++ b/36_Flip_Flop/lua/flipflop-game.lua @@ -0,0 +1,183 @@ +--[[ +Game of FlipFlop +=============== + +Based on the original BASIC game of FlipFlop from the 1970s. + +This is a faithful recreation of the classic game, maintaining the original gameplay +while modernizing the implementation for Lua. For example, the original's complex +trigonometric random number generation has been replaced with Lua's math.random, +as modern random number generators are more sophisticated than those available +in 1970s BASIC. + +How to Play: +----------- +The game presents a row of 10 X's. Your goal is to flip all X's to O's. +Enter a number from 1-10 to flip that position. The computer will also make +random moves in response. Special commands: +- Enter 0 to see the current board again +- Enter 11 to quit the game +Try to complete the puzzle in 12 moves or fewer for the best score! + +Strategy Tips: +------------ +- When you make a move, watch how the computer responds. It will often + make a predictable counter-move. +- If you enter the same position twice, the computer will use a different + random pattern for its response. +- Try to work systematically from one end of the board to the other, + rather than making random moves. +- If you get stuck, sometimes starting over (11) is better than continuing + with a poor position. + +Technical Notes: +-------------- +- Written for Lua 5.1 compatibility +- Uses tables for game state management +- Implements original game logic without goto statements +- Preserves the original game's move counting and win conditions +- Maintains the classic text-based interface style + +Original BASIC Version: +-------------------- +The original game used complex trigonometric functions for random number +generation, likely due to limitations in BASIC's random number capabilities: + R=TAN(Q+N/Q-N)-SIN(Q/N)+336*SIN(8*N) + N=R-INT(R) + N=INT(10*N) + +This has been simplified to use Lua's built-in random number generator +while maintaining the same gameplay experience. + +Converted from BASIC to Lua by Brian Wilkins +March 2025 +]]-- + +local function showInstructions() + print(" FLIP FLOP") + print(" CREATIVE COMPUTING") + print(" MORRISTOWN, NEW JERSEY") + print("\n\n") + print("THE OBJECT OF THIS GAME IS TO FLIP ALL THE X'S TO O'S.") + print("WHEN YOU INPUT A NUMBER, THAT NUMBER AND ALL ADJACENT") + print("NUMBERS WILL BE FLIPPED.") + print("\n") + print("INPUT A NUMBER FROM 1 TO 10 TO START THE GAME. TO QUIT") + print("THE GAME AT ANY TIME, TYPE A 0 (ZERO). TO START OVER WITH") + print("A NEW PUZZLE IN THE MIDDLE OF A GAME, TYPE A 11 (ELEVEN).") + print("\n\n") +end + +local function printUpdatedBoard(board) + print("1 2 3 4 5 6 7 8 9 10") + print(table.concat(board, " ")) + print("\n\n") +end + +local function processMove(gameState, position) + -- Check if current position is O + if gameState.board[position] == "O" then + gameState.board[position] = "X" + if position == gameState["lastMove"] then + -- Generate random position using simplified random logic + local R = math.random() -- between 0 and 1 + local N = math.floor(R * 10) + 1 + if gameState.board[N] == "O" then + gameState.board[N] = "X" + else + gameState.board[N] = "O" + end + end + else + gameState.board[position] = "O" + -- Generate another random position + local R = math.random() + local N = math.floor(R * 10) + 1 + if gameState.board[N] == "O" then + gameState.board[N] = "X" + else + gameState.board[N] = "O" + end + end +end + +local function checkWin(gameState) + -- Check if all positions are O's + for i = 1, 10 do + if gameState.board[i] ~= "O" then + return false + end + end + return true +end + +local function initializeGame() + local gameState = { + board = {}, + lastMove = nil, + moves = 0 + } + + -- Initialize board + for i = 1, 10 do + gameState.board[i] = "X" + end + return gameState +end + +local function playGame() + showInstructions() + + local gameState = initializeGame() + local playing = true + + print("HERE IS THE STARTING LINE OF X'S.") + print("\n\n") + printUpdatedBoard(gameState.board) + + while playing do + print("INPUT THE NUMBER") + local N = tonumber(io.read()) + + -- Check if input is valid + if not N or N ~= math.floor(N) then + print("ILLEGAL ENTRY--TRY AGAIN.") + elseif N == 11 then + playing = false + elseif N > 11 then + print("ILLEGAL ENTRY--TRY AGAIN.") + elseif N == 0 then + printUpdatedBoard(gameState.board) + else + -- Process the move + processMove(gameState, N) + gameState["lastMove"] = N + gameState.moves = gameState.moves + 1 + + -- Show the updated board + printUpdatedBoard(gameState.board) + + -- Check for win + if checkWin(gameState) then + if gameState.moves <= 12 then + print(string.format("VERY GOOD. YOU GUESSED IT IN ONLY %d GUESSES.", gameState.moves)) + else + print(string.format("TRY HARDER NEXT TIME. IT TOOK YOU %d GUESSES.", gameState.moves)) + end + + print("DO YOU WANT TO TRY ANOTHER PUZZLE? (Y/N)") + local answer = io.read():upper() + if answer:sub(1,1) == "Y" then + gameState = initializeGame() + print("HERE IS THE STARTING LINE OF X'S.") + print("\n\n") + printUpdatedBoard(gameState.board) + else + playing = false + end + end + end + end +end + +playGame() From 9a695d5b5a3af7fd8c9129d22b46648614961740 Mon Sep 17 00:00:00 2001 From: David Nellis Date: Sun, 6 Apr 2025 11:00:49 -0600 Subject: [PATCH 357/377] Updating broken link to archive.org copy --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c970edde..3b54d4471 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ We’re updating the first million selling computer book, [BASIC Computer Games](https://en.wikipedia.org/wiki/BASIC_Computer_Games), for 2022 and beyond! -- [Read the original book](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf) (pdf) +- [Read the original book](https://archive.org/details/basiccomputergam0000unse) (pdf) - [Play the original games in your browser](https://troypress.com/wp-content/uploads/user/js-basic/index.html) ### Where can we discuss it? From 00d7a10bee6cceb24454a794323cd66a4d5f9b3b Mon Sep 17 00:00:00 2001 From: nrezmerski <108252649+nrezmerski@users.noreply.github.com> Date: Fri, 18 Jul 2025 06:06:12 -0500 Subject: [PATCH 358/377] Create hello.swift --- .../45_Hello/Swift/hello.swift | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 00_Alternate_Languages/45_Hello/Swift/hello.swift diff --git a/00_Alternate_Languages/45_Hello/Swift/hello.swift b/00_Alternate_Languages/45_Hello/Swift/hello.swift new file mode 100644 index 000000000..0d882f755 --- /dev/null +++ b/00_Alternate_Languages/45_Hello/Swift/hello.swift @@ -0,0 +1,157 @@ + +func tab(_ number_Of_Spaces: Int) { + var spaces = "" + + for _ in 1...number_Of_Spaces { + spaces += " " + } + print(spaces, terminator:"") +} + + +func get_Input() -> String { + let input = readLine() + return (input == nil ? "" : input!.uppercased()) +} + + +func main() +{ + var done = false, + answered = false, + maybe_More = false, + paid = false + var reply = "" + var name = "STRANGER" + + tab (33) + print("HELLO") + tab (15) + print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n") + + print("HELLO. MY NAME IS CREATIVE COMPUTER.") + print("WHAT'S YOUR NAME? ") + let input = readLine() + if (input != nil && input != "") { + name = input!.uppercased() + } + + print("\nHI THERE, \(name), ARE YOU ENJOYING YOURSELF HERE?") + + reply = get_Input() + while (reply != "YES" && reply != "NO") { + print("\(name), I DON'T UNDERSTAND YOUR ANSWER OF '\(reply)'.") + print("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE?") + reply = get_Input() + } + + if (reply == "YES") { + print("\nI'M GLAD TO HEAR THAT, \(name).\n") + } + else { + print("\nOH, I'M SORRY TO HEAR THAT, \(name). MAYBE WE CAN " + + "BRIGHTEN UP YOUR VISIT A BIT.\n") + } + + print("SAY, \(name), I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT " + + "THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO " + + "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)?") + + while (!done) { + reply = get_Input() + + if (reply == "JOB") { + print("\nI CAN SYMPATHIZE WITH YOU \(name). I HAVE TO WORK " + + "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES " + + "REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, \(name), IS TO " + + "OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.\n") + } + + else if (reply == "MONEY") { + print("\nSORRY, \(name), I'M BROKE TOO. WHY DON'T YOU SELL " + + "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING " + + "SO YOU WON'T NEED SO MUCH MONEY?\n") + } + + else if (reply == "HEALTH") { + print("\nMY ADVICE TO YOU \(name) IS:") + print(" 1. TAKE TWO ASPRIN") + print(" 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)") + print(" 3. GO TO BED (ALONE)\n") + } + + else if (reply == "SEX") { + print("\nIS YOUR PROBLEM TOO MUCH OR TOO LITTLE?") + + answered = false + while (!answered) { + reply = get_Input() + if (reply == "TOO MUCH") { + print("\nYOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!") + print("IF IT BOTHERS YOU, \(name), TAKE A COLD SHOWER.\n") + answered = true + } + else if (reply == "TOO LITTLE") { + print("\nWHY ARE YOU HERE IN SUFFERN, \(name)? YOU SHOULD BE " + + "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME " + + "REAL ACTION.\n") + answered = true + } + else { + print("\nDON'T GET ALL SHOOK, \(name), JUST ANSWER THE QUESTION " + + "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT?") + } + } + } + + else { // not one of the prescribed categories + print("\nOH, \(name), YOUR ANSWER OF '\(reply)' IS GREEK TO ME.\n") + } + + print("\nANY MORE PROBLEMS YOU WANT SOLVED, \(name)? ") + + maybe_More = true + while (maybe_More) { + reply = get_Input() + if (reply == "NO") { + done = true + maybe_More = false + } + else if (reply == "YES") { + print("\nWHAT KIND (SEX, MONEY, HEALTH, JOB) ") + maybe_More = false + } + else { + print("\nJUST A SIMPLE 'YES' OR 'NO' PLEASE, \(name). ") + } + } // no further questions + } // end of 'not done' loop + + print("\nTHAT WILL BE $5.00 FOR THE ADVICE, \(name).") + print("PLEASE LEAVE THE MONEY ON THE TERMINAL.") + // pause a few seconds + print("\n\n\nDID YOU LEAVE THE MONEY? ") + reply = get_Input() + while (!paid) { + if (reply == "YES") { + print("\nHEY, \(name)??? YOU LEFT NO MONEY AT ALL!") + print("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\n") + print("WHAT A RIP OFF, \(name)!!!\n") + print("TAKE A WALK, \(name).") + paid = true + } + else if (reply == "NO") { + print("THAT'S HONEST, \(name), BUT HOW DO YOU EXPECT " + + "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS " + + "DON'T PAY THEIR BILLS?\n") + print("NICE MEETING YOU, \(name), HAVE A NICE DAY.") + paid = true + } + else { + print("YOUR ANSWER OF '\(reply)' CONFUSES ME, \(name).") + print("PLEASE RESPOND WITH 'YES' OR 'NO'.") + } + } +} + +main() From e2c73ec2781570191878ae5012bd460a63284948 Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Sun, 4 Jan 2026 04:49:50 -0500 Subject: [PATCH 359/377] Fix typo --- 01_Acey_Ducey/python/acey_ducey.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/01_Acey_Ducey/python/acey_ducey.py b/01_Acey_Ducey/python/acey_ducey.py index 75a1eac27..e6dca6f21 100755 --- a/01_Acey_Ducey/python/acey_ducey.py +++ b/01_Acey_Ducey/python/acey_ducey.py @@ -6,7 +6,6 @@ import random - cards = { 2: "2", 3: "3", @@ -28,7 +27,7 @@ def play_game() -> None: cash = 100 while cash > 0: print(f"You now have {cash} dollars\n") - print("Here are you next two cards") + print("Here are your next two cards") round_cards = list(cards.keys()) # gather cards from dictionary card_a = random.choice(round_cards) # choose a card card_b = card_a # clone the first card, so we avoid the same number for the second card From 786eb181b405c22ce663c42deab5e9ed0c64901f Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Sun, 4 Jan 2026 05:00:08 -0500 Subject: [PATCH 360/377] Flake8 errors --- 03_Animal/python/animal.py | 2 +- 07_Basketball/python/basketball.py | 10 +++++----- 17_Bullfight/python/bullfight.py | 2 +- 49_Hockey/python/hockey.py | 22 +++++++++++----------- 59_Lunar_LEM_Rocket/python/lunar.py | 2 +- 64_Nicomachus/python/nicomachus.py | 2 +- 65_Nim/python/Traditional_NIM.py | 6 +++--- 69_Pizza/python/pizza.py | 2 +- 89_Tic-Tac-Toe/python/TicTacToe_Hard.py | 2 +- 9 files changed, 25 insertions(+), 25 deletions(-) diff --git a/03_Animal/python/animal.py b/03_Animal/python/animal.py index 077b93d7f..70754b91c 100644 --- a/03_Animal/python/animal.py +++ b/03_Animal/python/animal.py @@ -131,7 +131,7 @@ def main() -> None: # Main loop of game print_intro() while ( - keep_playing := parse_input( + _keep_playing := parse_input( "Are you thinking of an animal? ", True, root ) == "y" diff --git a/07_Basketball/python/basketball.py b/07_Basketball/python/basketball.py index e3a598628..122185a13 100644 --- a/07_Basketball/python/basketball.py +++ b/07_Basketball/python/basketball.py @@ -139,7 +139,7 @@ def dartmouth_jump_shot(self) -> None: else: print("Shot is off target.") if self.defense / 6 * random.random() > 0.45: - print(f"Rebound to {self.opponent}" + "\n") + print(f"Rebound to {self.opponent}\n") self.opponent_ball() else: print("Dartmouth controls the rebound.") @@ -185,7 +185,7 @@ def dartmouth_non_jump_shot(self) -> None: if 7 / self.defense * random.random() > 0.925: print("Charging foul. Dartmouth loses the ball.\n") else: - print(f"Shot blocked. {self.opponent}" + "'s ball.\n") + print(f"Shot blocked. {self.opponent}'s ball.\n") else: self.foul_shots(1) self.opponent_ball() @@ -270,7 +270,7 @@ def opponent_jumpshot(self) -> None: or self.defense != 6 and random.random() <= 0.5 ): - print(f"Pass back to {self.opponent}" + " guard.\n") + print(f"Pass back to {self.opponent} guard.\n") self.opponent_ball() elif self.defense == 6 and random.random() > 0.75: print("Ball stolen. Easy lay up for Dartmouth.") @@ -310,14 +310,14 @@ def opponent_non_jumpshot(self) -> None: and random.random() <= 0.75 and random.random() <= 0.5 ): - print(f"Pass back to {self.opponent}" + " guard.\n") + print(f"Pass back to {self.opponent} guard.\n") self.opponent_ball() elif self.defense == 6 and random.random() > 0.75: print("Ball stolen. Easy lay up for Dartmouth.") self.add_points(1, 2) self.opponent_ball() else: - print(f"Pass back to {self.opponent}" + " guard\n") + print(f"Pass back to {self.opponent} guard\n") self.opponent_ball() else: print("Dartmouth controls the rebound.\n") diff --git a/17_Bullfight/python/bullfight.py b/17_Bullfight/python/bullfight.py index 32a6ac107..3ee2dfb8e 100644 --- a/17_Bullfight/python/bullfight.py +++ b/17_Bullfight/python/bullfight.py @@ -29,7 +29,7 @@ def determine_player_kills( print(f"THE {player_type}{plural_form} DID A {job_qualities[job_quality]} JOB.") if job_quality >= 4: if job_quality == 5: - if player_was_killed := random.choice([True, False]): + if _player_was_killed := random.choice([True, False]): print(f"ONE OF THE {player_type}{plural_form} WAS KILLED.") else: if player_type != "TOREAD": diff --git a/49_Hockey/python/hockey.py b/49_Hockey/python/hockey.py index c65d889e4..a660cf237 100644 --- a/49_Hockey/python/hockey.py +++ b/49_Hockey/python/hockey.py @@ -127,7 +127,7 @@ def print_header() -> None: def instructions() -> None: - if wants_it := ask_binary( + if _wants_it := ask_binary( "WOULD YOU LIKE THE INSTRUCTIONS? ", "ANSWER YES OR NO!!" ): print() @@ -229,7 +229,7 @@ def team2_action( z1 = 3 elif pass_value == 2: print("IT'S A ' 3 ON 2 '!\n") - print(f"ONLY {team_a.players[3]} AND {team_a.players[4]}" + " ARE BACK.\n") + print(f"ONLY {team_a.players[3]} AND {team_a.players[4]} ARE BACK.\n") print( team_b.players[player_index[j - 2]] + " GIVES OFF TO " @@ -374,7 +374,7 @@ def handle_hit( else: print(f"{team_b.name}: {team_b.score}\t{team_a.name}: {team_a.score}\n") team = team_a if controlling_team == 1 else team_b - print(f"GOAL SCORED BY: {team.players[goal_player]}" + "\n") + print(f"GOAL SCORED BY: {team.players[goal_player]}\n") if goal_assistant1 != 0: if goal_assistant2 != 0: print( @@ -402,16 +402,16 @@ def handle_miss( saving_player = randint(1, 7) if controlling_team == 1: if saving_player == 1: - print(f"KICK SAVE AND A BEAUTY BY {team_b.players[5]}" + "\n") - print(f"CLEARED OUT BY {team_b.players[3]}" + "\n") + print(f"KICK SAVE AND A BEAUTY BY {team_b.players[5]}\n") + print(f"CLEARED OUT BY {team_b.players[3]}\n") remaining_time -= 1 return ("continue", remaining_time) if saving_player == 2: - print(f"WHAT A SPECTACULAR GLOVE SAVE BY {team_b.players[5]}" + "\n") + print(f"WHAT A SPECTACULAR GLOVE SAVE BY {team_b.players[5]}\n") print(f"AND {team_b.players[5]}" + " GOLFS IT INTO THE CROWD\n") return ("break", remaining_time) if saving_player == 3: - print(f"SKATE SAVE ON A LOW STEAMER BY {team_b.players[5]}" + "\n") + print(f"SKATE SAVE ON A LOW STEAMER BY {team_b.players[5]}\n") remaining_time -= 1 return ("continue", remaining_time) if saving_player == 4: @@ -447,20 +447,20 @@ def handle_miss( print("ON THE LOOSE PUCK!\n") return ("break", remaining_time) if saving_player == 3: - print(f"SKATE SAVE BY {team_a.players[5]}" + "\n") + print(f"SKATE SAVE BY {team_a.players[5]}\n") print(team_a.players[5] + " WHACKS THE LOOSE PUCK INTO THE STANDS\n") return ("break", remaining_time) if saving_player == 4: - print(f"STICK SAVE BY {team_a.players[5]}" + " AND HE CLEARS IT OUT HIMSELF\n") + print(f"STICK SAVE BY {team_a.players[5]} AND HE CLEARS IT OUT HIMSELF\n") remaining_time -= 1 return ("continue", remaining_time) if saving_player == 5: - print(f"KICKED OUT BY {team_a.players[5]}" + "\n") + print(f"KICKED OUT BY {team_a.players[5]}\n") print("AND IT REBOUNDS ALL THE WAY TO CENTER ICE\n") remaining_time -= 1 return ("continue", remaining_time) if saving_player == 6: - print(f"GLOVE SAVE {team_a.players[5]}" + " AND HE HANGS ON\n") + print(f"GLOVE SAVE {team_a.players[5]} AND HE HANGS ON\n") return ("break", remaining_time) return ("continue", remaining_time) diff --git a/59_Lunar_LEM_Rocket/python/lunar.py b/59_Lunar_LEM_Rocket/python/lunar.py index 228093e91..112d86012 100644 --- a/59_Lunar_LEM_Rocket/python/lunar.py +++ b/59_Lunar_LEM_Rocket/python/lunar.py @@ -324,7 +324,7 @@ def run_simulation() -> None: return if capsule.velocity > 0 and new_state.velocity < 0: - if landed := handle_flyaway(sim_clock, capsule): + if _landed := handle_flyaway(sim_clock, capsule): process_final_tick(delta_t, sim_clock, capsule) return diff --git a/64_Nicomachus/python/nicomachus.py b/64_Nicomachus/python/nicomachus.py index e5d1c8253..e60acbf66 100644 --- a/64_Nicomachus/python/nicomachus.py +++ b/64_Nicomachus/python/nicomachus.py @@ -43,7 +43,7 @@ def play_game() -> None: print(f"YOUR NUMBER WAS {d}, RIGHT?") - if response := get_yes_or_no(): + if _response := get_yes_or_no(): print("HOW ABOUT THAT!!") else: print("I FEEL YOUR ARITHMETIC IS IN ERROR.") diff --git a/65_Nim/python/Traditional_NIM.py b/65_Nim/python/Traditional_NIM.py index ead90b2d0..b3476509f 100644 --- a/65_Nim/python/Traditional_NIM.py +++ b/65_Nim/python/Traditional_NIM.py @@ -78,14 +78,14 @@ def main() -> None: # Start game loop input("\nPress Enter to start the Game:\n") - end = False + _end = False while True: game.print_pegs() # Players Move command = input("\nYOUR MOVE - Number of PILE, Number of Object? ") game.remove_pegs(command) - if end := game.check_for_win(): + if _end := game.check_for_win(): print("\nPlayer Wins the Game, Congratulations!!") input("\nPress any key to exit") break @@ -96,7 +96,7 @@ def main() -> None: f"\nA.I MOVE - A.I Removed {ai_command[1]} pegs from Pile {ai_command[0]}" ) game.remove_pegs(f"{str(ai_command[0])},{str(ai_command[1])}") - if end := game.check_for_win(): + if _end := game.check_for_win(): print("\nComputer Wins the Game, Better Luck Next Time\n") input("Press any key to exit") break diff --git a/69_Pizza/python/pizza.py b/69_Pizza/python/pizza.py index aa4a01e93..ac68d671f 100644 --- a/69_Pizza/python/pizza.py +++ b/69_Pizza/python/pizza.py @@ -155,7 +155,7 @@ def main() -> None: player_name = print_instructions() - if more_directions := yes_no_prompt("DO YOU NEED MORE DIRECTIONS?"): + if _more_directions := yes_no_prompt("DO YOU NEED MORE DIRECTIONS?"): print_more_directions(player_name) understand = yes_no_prompt("UNDERSTAND?") diff --git a/89_Tic-Tac-Toe/python/TicTacToe_Hard.py b/89_Tic-Tac-Toe/python/TicTacToe_Hard.py index 8b3e50ab9..3a37cc6fe 100644 --- a/89_Tic-Tac-Toe/python/TicTacToe_Hard.py +++ b/89_Tic-Tac-Toe/python/TicTacToe_Hard.py @@ -171,7 +171,7 @@ def display(game: TicTacToe) -> None: if game.board[i][game.dim_sz - 1] == "blur": line1 = line1 + " \n" else: - line1 = f"{line1} {game.board[i][game.dim_sz - 1]}" + " \n" + line1 = f"{line1} {game.board[i][game.dim_sz - 1]} \n" print(line1, "\n\n") From 5b8973521938979a37ce8456dae35754b7658d90 Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Sun, 4 Jan 2026 05:09:20 -0500 Subject: [PATCH 361/377] Remove missed error; remove underscored-unused variables --- 03_Animal/python/animal.py | 2 +- 17_Bullfight/python/bullfight.py | 2 +- 49_Hockey/python/hockey.py | 4 ++-- 59_Lunar_LEM_Rocket/python/lunar.py | 2 +- 64_Nicomachus/python/nicomachus.py | 2 +- 65_Nim/python/Traditional_NIM.py | 2 +- 69_Pizza/python/pizza.py | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/03_Animal/python/animal.py b/03_Animal/python/animal.py index 70754b91c..1c29f2faf 100644 --- a/03_Animal/python/animal.py +++ b/03_Animal/python/animal.py @@ -131,7 +131,7 @@ def main() -> None: # Main loop of game print_intro() while ( - _keep_playing := parse_input( + parse_input( "Are you thinking of an animal? ", True, root ) == "y" diff --git a/17_Bullfight/python/bullfight.py b/17_Bullfight/python/bullfight.py index 3ee2dfb8e..cfe3ed7ed 100644 --- a/17_Bullfight/python/bullfight.py +++ b/17_Bullfight/python/bullfight.py @@ -29,7 +29,7 @@ def determine_player_kills( print(f"THE {player_type}{plural_form} DID A {job_qualities[job_quality]} JOB.") if job_quality >= 4: if job_quality == 5: - if _player_was_killed := random.choice([True, False]): + if random.choice([True, False]): print(f"ONE OF THE {player_type}{plural_form} WAS KILLED.") else: if player_type != "TOREAD": diff --git a/49_Hockey/python/hockey.py b/49_Hockey/python/hockey.py index a660cf237..7b1e1ecf6 100644 --- a/49_Hockey/python/hockey.py +++ b/49_Hockey/python/hockey.py @@ -127,7 +127,7 @@ def print_header() -> None: def instructions() -> None: - if _wants_it := ask_binary( + if ask_binary( "WOULD YOU LIKE THE INSTRUCTIONS? ", "ANSWER YES OR NO!!" ): print() @@ -408,7 +408,7 @@ def handle_miss( return ("continue", remaining_time) if saving_player == 2: print(f"WHAT A SPECTACULAR GLOVE SAVE BY {team_b.players[5]}\n") - print(f"AND {team_b.players[5]}" + " GOLFS IT INTO THE CROWD\n") + print(f"AND {team_b.players[5]} GOLFS IT INTO THE CROWD\n") return ("break", remaining_time) if saving_player == 3: print(f"SKATE SAVE ON A LOW STEAMER BY {team_b.players[5]}\n") diff --git a/59_Lunar_LEM_Rocket/python/lunar.py b/59_Lunar_LEM_Rocket/python/lunar.py index 112d86012..b65e0fa54 100644 --- a/59_Lunar_LEM_Rocket/python/lunar.py +++ b/59_Lunar_LEM_Rocket/python/lunar.py @@ -324,7 +324,7 @@ def run_simulation() -> None: return if capsule.velocity > 0 and new_state.velocity < 0: - if _landed := handle_flyaway(sim_clock, capsule): + if handle_flyaway(sim_clock, capsule): process_final_tick(delta_t, sim_clock, capsule) return diff --git a/64_Nicomachus/python/nicomachus.py b/64_Nicomachus/python/nicomachus.py index e60acbf66..1485d4a1c 100644 --- a/64_Nicomachus/python/nicomachus.py +++ b/64_Nicomachus/python/nicomachus.py @@ -43,7 +43,7 @@ def play_game() -> None: print(f"YOUR NUMBER WAS {d}, RIGHT?") - if _response := get_yes_or_no(): + if get_yes_or_no(): print("HOW ABOUT THAT!!") else: print("I FEEL YOUR ARITHMETIC IS IN ERROR.") diff --git a/65_Nim/python/Traditional_NIM.py b/65_Nim/python/Traditional_NIM.py index b3476509f..89c376464 100644 --- a/65_Nim/python/Traditional_NIM.py +++ b/65_Nim/python/Traditional_NIM.py @@ -96,7 +96,7 @@ def main() -> None: f"\nA.I MOVE - A.I Removed {ai_command[1]} pegs from Pile {ai_command[0]}" ) game.remove_pegs(f"{str(ai_command[0])},{str(ai_command[1])}") - if _end := game.check_for_win(): + if game.check_for_win(): print("\nComputer Wins the Game, Better Luck Next Time\n") input("Press any key to exit") break diff --git a/69_Pizza/python/pizza.py b/69_Pizza/python/pizza.py index ac68d671f..33bd60b6c 100644 --- a/69_Pizza/python/pizza.py +++ b/69_Pizza/python/pizza.py @@ -155,7 +155,7 @@ def main() -> None: player_name = print_instructions() - if _more_directions := yes_no_prompt("DO YOU NEED MORE DIRECTIONS?"): + if yes_no_prompt("DO YOU NEED MORE DIRECTIONS?"): print_more_directions(player_name) understand = yes_no_prompt("UNDERSTAND?") From b1585bab9b0a9361c2c47cad4f81593a68e1db6d Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Sun, 4 Jan 2026 05:10:38 -0500 Subject: [PATCH 362/377] Remove unused variable --- 65_Nim/python/Traditional_NIM.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/65_Nim/python/Traditional_NIM.py b/65_Nim/python/Traditional_NIM.py index 89c376464..655e5d85c 100644 --- a/65_Nim/python/Traditional_NIM.py +++ b/65_Nim/python/Traditional_NIM.py @@ -78,14 +78,14 @@ def main() -> None: # Start game loop input("\nPress Enter to start the Game:\n") - _end = False + while True: game.print_pegs() # Players Move command = input("\nYOUR MOVE - Number of PILE, Number of Object? ") game.remove_pegs(command) - if _end := game.check_for_win(): + if game.check_for_win(): print("\nPlayer Wins the Game, Congratulations!!") input("\nPress any key to exit") break From 888f4a43305cc82440ea11c690dfd49e68e6458a Mon Sep 17 00:00:00 2001 From: Brian Wignall Date: Sun, 4 Jan 2026 05:14:15 -0500 Subject: [PATCH 363/377] Run `black` on queen.py to fix Flake8 formatting complaint --- 72_Queen/python/queen.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/72_Queen/python/queen.py b/72_Queen/python/queen.py index 285174c49..327c43f6e 100755 --- a/72_Queen/python/queen.py +++ b/72_Queen/python/queen.py @@ -117,9 +117,9 @@ def num_to_loc(num: int) -> Tuple[int, int]: ) # These are the places that the computer will always try to move into. -COMPUTER_PREF_MOVES: Final[ - FrozenSet[Tuple[int, int]] -] = COMPUTER_SAFE_SPOTS | frozenset([WIN_LOC]) +COMPUTER_PREF_MOVES: Final[FrozenSet[Tuple[int, int]]] = ( + COMPUTER_SAFE_SPOTS | frozenset([WIN_LOC]) +) # These are the locations (not including the win location) from which either player can # force a win (but the computer will always choose one of the COMPUTER_PREF_MOVES). @@ -171,10 +171,10 @@ def get_move(current_loc: Optional[Tuple[int, int]]) -> Tuple[int, int]: "WHERE WOULD YOU LIKE TO START? " ) elif ( - (new_row == row and new_col < col) # move left - or (new_col == col and new_row > row) # move down - or (new_row - row == col - new_col) # move diag left and down - ) and (not FIX_BOARD_BUG or (new_col >= 0 and new_row < 8)): + (new_row == row and new_col < col) # move left + or (new_col == col and new_row > row) # move down + or (new_row - row == col - new_col) # move diag left and down + ) and (not FIX_BOARD_BUG or (new_col >= 0 and new_row < 8)): return new_row, new_col else: prompt = "Y O U C H E A T . . . TRY AGAIN? " From 507ade94bb45ece7ee0373c4933d8647e54d5289 Mon Sep 17 00:00:00 2001 From: Uncle Scientist Date: Fri, 13 Feb 2026 08:24:06 -0500 Subject: [PATCH 364/377] Add Rust port of 42_Gunner --- 42_Gunner/rust/Cargo.lock | 411 +++++++++++++++++++++++++++++++++++++ 42_Gunner/rust/Cargo.toml | 7 + 42_Gunner/rust/src/main.rs | 161 +++++++++++++++ 3 files changed, 579 insertions(+) create mode 100644 42_Gunner/rust/Cargo.lock create mode 100644 42_Gunner/rust/Cargo.toml create mode 100644 42_Gunner/rust/src/main.rs diff --git a/42_Gunner/rust/Cargo.lock b/42_Gunner/rust/Cargo.lock new file mode 100644 index 000000000..1bc05f192 --- /dev/null +++ b/42_Gunner/rust/Cargo.lock @@ -0,0 +1,411 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core", + "wasip2", + "wasip3", +] + +[[package]] +name = "gunner" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "chacha20", + "getrandom", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "syn" +version = "2.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/42_Gunner/rust/Cargo.toml b/42_Gunner/rust/Cargo.toml new file mode 100644 index 000000000..cfc8f092c --- /dev/null +++ b/42_Gunner/rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "gunner" +version = "0.1.0" +edition = "2024" + +[dependencies] +rand = "0.10.0" diff --git a/42_Gunner/rust/src/main.rs b/42_Gunner/rust/src/main.rs new file mode 100644 index 000000000..1f4547d53 --- /dev/null +++ b/42_Gunner/rust/src/main.rs @@ -0,0 +1,161 @@ +use rand::{RngExt, rngs::ThreadRng}; +use std::{ + convert::Infallible, + io::{self, BufRead, Write}, + str::FromStr, +}; + +fn main() { + println!("{:>30}GUNNER", ""); + println!("{:>15}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY", ""); + println!("\n\n"); + + println!("You are the officer-in-charge, giving orders to a gun"); + println!("crew, telling them the degrees of elevation you estimate"); + println!("will place a projectile on target. A hit wihtin 100 yards"); + println!("of the target will destroy it.\n"); + + let mut game = GunnerGame::new(); + while game.run() == PlayAgain::Yes { + // do nothing -- just loop around and call game.run() again + } +} + +struct GunnerGame { + gun_range: usize, // each game has different range for the gun. "R" in the basic code + targets_destroyed: isize, // the "Z" counter in basic + total_rounds: isize, // how many rounds were fired across all targets. "S1" in basic + rng: ThreadRng, // our PRNG +} + +impl GunnerGame { + fn new() -> Self { + let mut rng = rand::rng(); + let gun_range = rng.random_range(20_000..=60_000); + + Self { + gun_range, + rng, + targets_destroyed: 0, + total_rounds: 0, + } + } + + fn run(&mut self) -> PlayAgain { + println!("Maximum range of your gun is {} yards.\n", self.gun_range); + + for targets in 0..4 { + if targets > 0 { + // After the first round, we want to let the user know that there's + // another target in sight + println!("\nThe forward observer has sighted more enemy activity..."); + } + + // let the player try to destroy it + let target_destroyed = self.handle_target(); + + if !target_destroyed { + println!("\nBoom !!!! You have just been destroyed by the enemy.\n\n\n"); + println!("Better go back to Fort Sill for refresher training!"); + + println!(); + break; + } else { + self.targets_destroyed += 1; + } + } + + // only display success message if all targets were destroyed + if self.targets_destroyed == 4 { + println!("\n\nTotal rounds expended were: {}", self.total_rounds); + if self.total_rounds <= 18 { + println!("Nice shooting !!"); + } + } + + println!("\n"); + get_input("Try again (Y or N)") + } + + fn handle_target(&mut self) -> bool { + let target_distance = + ((self.gun_range as f32) * (0.1 + 0.8 * self.rng.random::())) as isize; + + println!("Distance to the target is {target_distance} yards.\n\n"); + + // The player gets 5 shots. On the 6th shot we still ask for an elevation, + // but then report that they've been destroyed. + for shots_fired in 1..=6 { + let elevation = loop { + let elevation: f32 = get_input("Elevation"); + + // Let the player know how well they did. + if elevation < 1.0 { + println!("Miniumum elevation is one degree."); + } else if elevation > 89.0 { + println!("Maximum elevation is 89 degrees."); + } else { + break elevation; + } + }; + + // Only allow the player to destroy the target with the first 5 shots. The + // sixth is ignored. + if shots_fired < 6 { + let angle = 2.0 * elevation / 57.3; + let intersection = self.gun_range as f32 * angle.sin(); + let delta = target_distance - (intersection as isize); + + if delta.abs() < 100 { + println!( + "*** Target Destroyed *** {shots_fired} rounds of ammunition expended." + ); + self.total_rounds += shots_fired; + return true; + } else if delta > 100 { + println!("Short of target by {delta} yards."); + } else { + println!("Over target by {} yards.", delta.abs()); + } + } + } + + false + } +} + +#[derive(PartialEq, Eq)] +enum PlayAgain { + Yes, + No, +} + +impl FromStr for PlayAgain { + type Err = Infallible; + + fn from_str(line: &str) -> Result { + if line.to_uppercase() == "Y" { + Ok(Self::Yes) + } else { + Ok(Self::No) + } + } +} + +fn get_input>(prompt: S) -> R { + loop { + print!("{}? ", prompt.as_ref()); + let mut stdout = io::stdout().lock(); + let _ = stdout.flush(); + + let mut buffer = String::new(); + let stdin = std::io::stdin(); + let mut handle = stdin.lock(); + let _ = handle.read_line(&mut buffer); + + if let Ok(result) = buffer.trim().to_string().parse::() { + return result; + } + println!("?Re-enter"); + } +} From 8ace6f60f3bb4fd6747b1aff2d93555ca9d3c01c Mon Sep 17 00:00:00 2001 From: aconconi Date: Tue, 10 Mar 2026 08:55:34 +0100 Subject: [PATCH 365/377] 71_Poker ported to Python --- 71_Poker/python/README.md | 29 +- 71_Poker/python/cards/__init__.py | 11 + 71_Poker/python/cards/card.py | 50 +++ 71_Poker/python/cards/deck.py | 17 + 71_Poker/python/game.py | 405 ++++++++++++++++++++++++ 71_Poker/python/players/__init__.py | 7 + 71_Poker/python/players/dealer.py | 178 +++++++++++ 71_Poker/python/players/human.py | 21 ++ 71_Poker/python/players/player.py | 51 +++ 71_Poker/python/poker.py | 38 +++ 71_Poker/python/pokerhand/__init__.py | 7 + 71_Poker/python/pokerhand/evaluation.py | 206 ++++++++++++ 71_Poker/python/pokerhand/hand.py | 39 +++ 71_Poker/python/pokerhand/rank.py | 31 ++ 14 files changed, 1089 insertions(+), 1 deletion(-) create mode 100644 71_Poker/python/cards/__init__.py create mode 100644 71_Poker/python/cards/card.py create mode 100644 71_Poker/python/cards/deck.py create mode 100644 71_Poker/python/game.py create mode 100644 71_Poker/python/players/__init__.py create mode 100644 71_Poker/python/players/dealer.py create mode 100644 71_Poker/python/players/human.py create mode 100644 71_Poker/python/players/player.py create mode 100644 71_Poker/python/poker.py create mode 100644 71_Poker/python/pokerhand/__init__.py create mode 100644 71_Poker/python/pokerhand/evaluation.py create mode 100644 71_Poker/python/pokerhand/hand.py create mode 100644 71_Poker/python/pokerhand/rank.py diff --git a/71_Poker/python/README.md b/71_Poker/python/README.md index 781945ec4..bc58f0839 100644 --- a/71_Poker/python/README.md +++ b/71_Poker/python/README.md @@ -1,3 +1,30 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Python](https://www.python.org/about/) +Conversion to [Python](https://www.python.org/about/) by Alex Conconi, 2026. + +--- + +### Python porting notes + +#### Known BASIC bugs — fixed + +- **Tie tack unreachable** (BASIC line 3970): The condition + `IF O/3<>INT(O/3) THEN 4090` is logically inverted. It checks if the + tie tack has *not* been sold, and if so, incorrectly jumps to the + "Bust" message. This makes the tie tack sale permanently unreachable + even if the player still owns it. The Python port fixes this to restore + the original intended experience where both assets can be sold. + +#### Known BASIC bugs/quirks — kept faithful + +- **$50 buy-back materialises from nowhere** (BASIC lines 3570/3640): + When the player buys back a pawned item, `C=C+50` adds $50 to the + dealer's stack without deducting from the player. Kept as-is — it + models the dealer/pawnbroker liquidating the physical item. + +- **Yes/No prompts accept anything** (e.g. BASIC lines 3550, 3880): + `LEFT$(J$,1)="Y"` treats every non-"Y" input as "no" with no + re-prompt. The Python port normalises all yes/no prompts to a single + `_read_yes_no` that retries on invalid input (matching the stricter + "Do you wish to continue?" prompt at lines 4120–4150). + diff --git a/71_Poker/python/cards/__init__.py b/71_Poker/python/cards/__init__.py new file mode 100644 index 000000000..956089deb --- /dev/null +++ b/71_Poker/python/cards/__init__.py @@ -0,0 +1,11 @@ +"""Cards package initialization.""" + +from .card import Card, CardRank, CardSuit +from .deck import Deck + +__all__ = [ + "Card", + "CardRank", + "CardSuit", + "Deck", +] diff --git a/71_Poker/python/cards/card.py b/71_Poker/python/cards/card.py new file mode 100644 index 000000000..2491c3430 --- /dev/null +++ b/71_Poker/python/cards/card.py @@ -0,0 +1,50 @@ +"""Card primitives: Suits, Ranks, and the Card class.""" + +from dataclasses import dataclass +from enum import Enum, IntEnum + + +class CardSuit(Enum): + """Enumeration of card suits.""" + + CLUBS = 0 + DIAMONDS = 1 + HEARTS = 2 + SPADES = 3 + + def __str__(self) -> str: + return self.name.capitalize() + + +class CardRank(IntEnum): + """Card ranks from Two (0) to Ace (12).""" + + TWO = 0 + THREE = 1 + FOUR = 2 + FIVE = 3 + SIX = 4 + SEVEN = 5 + EIGHT = 6 + NINE = 7 + TEN = 8 + JACK = 9 + QUEEN = 10 + KING = 11 + ACE = 12 + + def __str__(self) -> str: + if self.value <= 8: # TWO(0) through TEN(8) + return f" {str(self.value + 2)} " + return ("Jack", "Queen", "King", "Ace")[self.value - 9] + + +@dataclass(frozen=True) +class Card: + """A single playing card.""" + + suit: CardSuit + rank: CardRank + + def __str__(self) -> str: + return f"{self.rank} of {self.suit}" diff --git a/71_Poker/python/cards/deck.py b/71_Poker/python/cards/deck.py new file mode 100644 index 000000000..862d33e42 --- /dev/null +++ b/71_Poker/python/cards/deck.py @@ -0,0 +1,17 @@ +"""Deck implementation.""" + +import random + +from .card import Card, CardRank, CardSuit + + +class Deck: # pylint: disable=too-few-public-methods + """Standard 52-card deck, shuffled on creation.""" + + def __init__(self) -> None: + self._cards = [Card(suit, rank) for suit in CardSuit for rank in CardRank] + random.shuffle(self._cards) + + def deal(self) -> Card: + """Remove and return the top card.""" + return self._cards.pop() diff --git a/71_Poker/python/game.py b/71_Poker/python/game.py new file mode 100644 index 000000000..92d97463a --- /dev/null +++ b/71_Poker/python/game.py @@ -0,0 +1,405 @@ +"""Poker game logic — port of the 1978 Creative Computing BASIC original.""" + +import random +from typing import NoReturn + +from cards import Deck +from players import Dealer, Human, Player +from pokerhand import Hand + + +class GameOver(Exception): + """Raised when the game ends (either side busted, player quits, or walks away).""" + + +class PokerGame: # pylint: disable=too-few-public-methods + """Five-card draw poker against the house.""" + + INITIAL_MONEY: int = 200 + ANTE: int = 5 + + human: Human + dealer: Dealer + deck: Deck + pot: int + + def __init__(self) -> None: + """Initialise game state and allocate both sides' starting stack.""" + self.human = Human(PokerGame.INITIAL_MONEY) + self.dealer = Dealer(PokerGame.INITIAL_MONEY) + self.deck: Deck + self.pot = 0 + + # ------------------------------------------------------------------ + # Intro and main loop + # ------------------------------------------------------------------ + + def run(self) -> None: + """Execute the primary game loop until a GameOver exception occurs.""" + self._display_intro() + while True: + self._play_round() + + # ------------------------------------------------------------------ + # Round + # ------------------------------------------------------------------ + + def _play_round(self) -> None: + """Deal one complete round: ante, bet, draw, bet, showdown.""" + print() + + # Reset per-round state + self.deck = Deck() + + # --- Ante --- + if self.dealer.money <= self.ANTE: + self._dealer_goes_bust() + + print(f"The ante is ${self.ANTE}. I will deal:\n") + + if self.human.money <= self.ANTE: + self._human_try_raise_funds(self.ANTE) + + self.pot += self.ANTE * 2 + self.human.pay_ante(self.ANTE) + self.dealer.pay_ante(self.ANTE) + + # --- Deal --- + self.human.receive_new_hand(Hand([self.deck.deal() for _ in range(5)])) + self.dealer.receive_new_hand(Hand([self.deck.deal() for _ in range(5)])) + + print("Your hand:") + print(self.human.hand) + print() + + # --- Opening bet --- + dealer_action = self.dealer.get_opening_action() + if self.dealer.money < self.dealer.bet: + self._dealer_try_raise_funds() + + if dealer_action == Player.Action.CHECK: + print("I check.") + else: + print(f"I'll open with $ {self.dealer.bet}") + + if not self._conduct_betting_round(post_draw=False): + return + + # --- Draw --- + print() + self._player_discard_draw() + draw_count = self.dealer.discard_and_draw(self.deck) + print( + f"\nI am taking {draw_count} card{'s' if draw_count != 1 else ''}" + ) + + # --- Post-draw bet --- + self.dealer.decide_postdraw_bet() + if not self._conduct_betting_round(post_draw=True): + return + + # --- Showdown --- + self._showdown() + + # ------------------------------------------------------------------ + # Player draw + # ------------------------------------------------------------------ + + def _player_discard_draw(self) -> None: + """Ask the player how many cards to replace, then deal replacements.""" + count = self._read_int( + "Now we draw -- how many cards do you want? ", + low=0, + high=3, + too_high_msg="You can't draw more than three cards.", + ) + + if count == 0: + return + + print("What are their numbers:") + for _ in range(count): + pos = self._read_int("", low=1, high=5) + self.human.replace_card(pos - 1, self.deck.deal()) + + print("Your new hand:") + print(self.human.hand) + + # ------------------------------------------------------------------ + # Betting round + # ------------------------------------------------------------------ + + def _conduct_betting_round(self, post_draw: bool) -> bool: + """ + Executes a betting round. + Returns True if the betting phase completed (hand continues). + Returns False if a player folded (hand ends). + """ + while True: + human_action = self._get_human_action() + + match human_action: + case Player.Action.FOLD: + # Human fold always ends betting loop (hand ends) + self._settle_bets() + self._award_pot(dealer_wins=True) + return False + + case Player.Action.CALL: + # Human call always ends betting loop (proceed to next phase) + self._settle_bets() + return True + + case Player.Action.CHECK: + # Pre-draw: human check ends human's turn. + # Post-draw: dealer gets a chance to bet/check back. + if not post_draw or self._handle_human_post_draw_check(): + return True + # If dealer bet, we fall through and loop for human response + + case Player.Action.RAISE: + if self._handle_human_raise(): + return True + # If dealer re-raised, we fall through and loop for human response + + case _: + raise ValueError(f"Unknown player action: {human_action}") + + def _handle_human_post_draw_check(self) -> bool: + """Process dealer response to human check. Returns True if phase ends.""" + dealer_action = self.dealer.get_check_response() + if self.dealer.money < self.dealer.bet: + self._dealer_try_raise_funds() + + if dealer_action == Player.Action.CHECK: + print("I'll check.") + self._settle_bets() + return True + + print(f"I'll bet $ {self.dealer.bet}") + return False + + def _handle_human_raise(self) -> bool: + """Process dealer response to human raise. Returns True if phase ends.""" + dealer_action = self.dealer.get_raise_response(self.human.bet) + if self.dealer.money < self.dealer.bet: + self._dealer_try_raise_funds() + + match dealer_action: + case Player.Action.FOLD: + print("I fold.") + self._settle_bets() + self._award_pot(dealer_wins=False) + return True # Round ends + + case Player.Action.CALL: + print("I'll see you.") + self._settle_bets() + return True + + case Player.Action.RAISE: + raise_amount = self.dealer.bet - self.human.bet + print(f"I'll see you, and raise you {raise_amount}") + return False + + case _: + raise ValueError(f"Unknown dealer action: {dealer_action}") + + def _get_human_action(self) -> Player.Action: + """Prompt user for a bet and return the resulting Action.""" + while True: + print() + raw = input("What is your bet? ").strip() + + try: + bet = float(raw) + except ValueError: + continue + + # Fractional bet: only .5 is valid, and only as a check + if bet != int(bet): + if self.dealer.bet == 0 and self.human.bet == 0 and bet == 0.5: + return Player.Action.CHECK + print("No small change, please.") + continue + + amount = int(bet) + + if amount == 0: + return Player.Action.FOLD + + if self.human.bet + amount > self.human.money: + self._human_try_raise_funds(self.human.bet + amount) + continue + + if self.human.bet + amount < self.dealer.bet: + print("If you can't see my bet, then fold.") + continue + + self.human.bet += amount + + if self.human.bet == self.dealer.bet: + return Player.Action.CALL + return Player.Action.RAISE + + def _dealer_try_raise_funds(self) -> None: + """Attempt to raise funds for the dealer. Raises GameOver if failed.""" + if not self.human.has_watch: + if self._read_yes_no( + "Would you like to buy back your watch for $50? " + ): + self.dealer.money += 50 + self.human.has_watch = True + if self.dealer.money >= self.dealer.bet: + return + + if not self.human.has_tack: + if self._read_yes_no( + "Would you like to buy back your tie tack for $50? " + ): + self.dealer.money += 50 + self.human.has_tack = True + if self.dealer.money >= self.dealer.bet: + return + + self._dealer_goes_bust() + + def _dealer_goes_bust(self) -> NoReturn: + """Inform the player and terminate the game.""" + print("I'm busted. Congratulations!") + raise GameOver + + def _human_try_raise_funds(self, target_money: int) -> None: + """Offer the player's assets for cash. Raises GameOver if short of target.""" + print("\nYou can't bet with what you haven't got.") + + if self.human.has_watch: + if self._read_yes_no("Would you like to sell your watch? "): + if self._chance(3): + print("That's a pretty crummy watch - I'll give you $25.") + self.human.money += 25 + else: + print("I'll give you $75 for it.") + self.human.money += 75 + self.human.has_watch = False + if self.human.money >= target_money: + return + + if self.human.has_tack: + if self._read_yes_no("Will you part with that diamond tie tack? "): + if self._chance(4): + print("It's paste. $25.") + self.human.money += 25 + else: + print("You are now $100 richer.") + self.human.money += 100 + self.human.has_tack = False + if self.human.money >= target_money: + return + + print("Your wad is shot. So long, sucker!") + raise GameOver + + def _settle_bets(self) -> None: + """Move both sides' committed chips into the pot.""" + self.pot += self.human.settle_bet() + self.pot += self.dealer.settle_bet() + + # ------------------------------------------------------------------ + # Showdown + # ------------------------------------------------------------------ + + def _showdown(self) -> None: + """Reveal hands, compare scores, and award the pot.""" + print("\nNow we compare hands:") + + print("My hand:") + print(self.dealer.hand) + dealer_hand_eval = self.dealer.hand.evaluate() + + player_hand_eval = self.human.hand.evaluate() + + print(f"\nYou have {player_hand_eval}") + print(f"And I have {dealer_hand_eval}") + + if dealer_hand_eval == player_hand_eval: + print("The hand is drawn.") + print(f"All ${self.pot} remains in the pot.") + else: + self._award_pot(dealer_wins=dealer_hand_eval > player_hand_eval) + + def _award_pot(self, dealer_wins: bool) -> None: + """Announce the winner, award the pot, and prompt to continue.""" + if dealer_wins: + print("I win.") + self.dealer.win_pot(self.pot) + else: + print("You win.") + self.human.win_pot(self.pot) + print( + f"Now I have $ {self.dealer.money} and you have $ {self.human.money}" + ) + if not self._read_yes_no("Do you wish to continue? "): + raise GameOver + self.pot = 0 # Reset pot after awarding it + + # ------------------------------------------------------------------ + # Helpers + # ------------------------------------------------------------------ + + # pylint: disable=too-many-arguments + def _read_int( + self, + prompt: str, + *, + low: int | None = None, + high: int | None = None, + too_low_msg: str | None = None, + too_high_msg: str | None = None, + ) -> int: + """Read and validate an integer within an optional range.""" + while True: + raw = input(prompt).strip() + if not raw: + continue + try: + val = int(raw) + except ValueError: + continue + + if low is not None and val < low: + if too_low_msg: + print(too_low_msg) + continue + + if high is not None and val > high: + if too_high_msg: + print(too_high_msg) + continue + + return val + + def _read_yes_no(self, prompt: str) -> bool: + """Read yes/no response. Returns True for yes, False for no.""" + while True: + response = input(prompt).strip().lower() + if response in ["y", "yes"]: + return True + if response in ["n", "no"]: + return False + print("Answer yes or no, please.") + + def _chance(self, n: int) -> bool: + """Return True with probability n/10.""" + return random.random() < n / 10 + + def _display_intro(self) -> None: + """Print the welcome banner.""" + print(" POKER") + print(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n") + print( + f"Welcome to the casino. We each have ${PokerGame.INITIAL_MONEY}." + ) + print("I will open the betting before the draw; you open after.") + print("To fold bet 0; to check bet .5.") + print("Enough talk -- let's get down to business.") diff --git a/71_Poker/python/players/__init__.py b/71_Poker/python/players/__init__.py new file mode 100644 index 000000000..866e40a52 --- /dev/null +++ b/71_Poker/python/players/__init__.py @@ -0,0 +1,7 @@ +"""Players package initialization.""" + +from .dealer import Dealer +from .human import Human +from .player import Player + +__all__ = ["Player", "Human", "Dealer"] diff --git a/71_Poker/python/players/dealer.py b/71_Poker/python/players/dealer.py new file mode 100644 index 000000000..0467f4add --- /dev/null +++ b/71_Poker/python/players/dealer.py @@ -0,0 +1,178 @@ +"""Dealer state and decision-making logic.""" + +import random +from enum import Enum, auto + +from cards import Deck +from pokerhand import Hand, HandEvaluation, HandRank + +from .player import Player + + +class Dealer(Player): + """Dealer state: bankroll, strategy, and per-round betting.""" + + class Strategy(Enum): + """The dealer's play style for the current round, set during the opening.""" + + NORMAL = auto() + WEAK = auto() + BLUFFING = auto() + + strategy: Strategy + bet_base: int + was_bluffing: bool + hand_is_weak: bool + bluff_discard_count: int | None + + def receive_new_hand(self, hand: Hand) -> None: + """Reset per-round state and receive a new hand.""" + super().receive_new_hand(hand) + self.strategy = Dealer.Strategy.NORMAL + self.bet_base = 0 + self.was_bluffing = False + self.hand_is_weak = False + self.bluff_discard_count = None + + def decide_postdraw_bet(self) -> None: + """Update bluffing state, evaluate hand and set betting tier.""" + self.was_bluffing = self.strategy == Dealer.Strategy.BLUFFING + + result = self.hand.evaluate() + rank = result.hand_rank + self.bet = 0 + self.hand_is_weak = self._is_hand_weak(result, is_redeal=True) + + if self.was_bluffing: + self.bet_base = 28 + elif self.hand_is_weak: + self.bet_base = 1 + elif rank < HandRank.THREE_OF_A_KIND: + self.bet_base = 2 + if self._chance(1): + self.bet_base = 19 + elif rank <= HandRank.FLUSH: # THREE_OF_A_KIND, STRAIGHT, FLUSH + self.bet_base = 19 + if self._chance(1): + self.bet_base = 11 + else: # FULL_HOUSE, FOUR_OF_A_KIND + self.bet_base = 2 + + def _is_hand_weak(self, result: HandEvaluation, is_redeal: bool) -> bool: + """Check whether the hand qualifies as 'weak'.""" + # Original logic: IF Z>5 THEN Weak. + # HandRank 1-4 are Schmaltz, Partial Straight, Pair, Two-Pair. + if result.hand_rank < HandRank.THREE_OF_A_KIND: + # Partial Straight is only weak on re-evaluation + if result.hand_rank == HandRank.PARTIAL_STRAIGHT: + return is_redeal + return True + return False + + def get_opening_action(self) -> Player.Action: + """Evaluate hand and set the dealer's pre-draw opening bet and strategy.""" + result = self.hand.evaluate() + + if self._is_hand_weak(result, is_redeal=False): + strat, base, discard, action = self._decide_weak_opening() + else: + strat, base, discard, action = self._decide_normal_opening(result) + + self.strategy = strat + self.bet_base = base + self.bluff_discard_count = discard + + if action == Player.Action.RAISE: + self.bet = self.bet_base + random.randint(0, 9) + else: + self.bet = 0 + + return action + + def _decide_weak_opening( + self, + ) -> tuple[Strategy, int, int | None, Player.Action]: + """Pure logic for weak-hand opening decisions.""" + if self._chance(8): + return Dealer.Strategy.BLUFFING, 23, 2, Player.Action.RAISE + if self._chance(8): + return Dealer.Strategy.BLUFFING, 23, 1, Player.Action.RAISE + if self._chance(9): + return Dealer.Strategy.WEAK, 1, None, Player.Action.CHECK + return Dealer.Strategy.BLUFFING, 23, 0, Player.Action.RAISE + + def _decide_normal_opening( + self, result: HandEvaluation + ) -> tuple[Strategy, int, int | None, Player.Action]: + """Pure logic for normal-hand opening decisions.""" + rank = result.hand_rank + if rank < HandRank.THREE_OF_A_KIND: + if self._chance(8): + return Dealer.Strategy.NORMAL, 0, None, Player.Action.CHECK + return Dealer.Strategy.BLUFFING, 23, None, Player.Action.RAISE + + # Strong hand (THREE_OF_A_KIND and above) + if rank > HandRank.FULL_HOUSE: # FOUR_OF_A_KIND + base = 2 if self._chance(9) else 35 + else: + base = 35 + return Dealer.Strategy.NORMAL, base, None, Player.Action.RAISE + + def discard_and_draw(self, deck: Deck) -> int: + """Evaluate hand and replace the dealer's discard cards.""" + if self.bluff_discard_count is not None: + count = self.bluff_discard_count + if count == 0: + return 0 + ranked = sorted(range(5), key=lambda i: self.hand[i].rank.value) + for i in ranked[:count]: + self.replace_card(i, deck.deal()) + return count + + result = self.hand.evaluate() + for i in result.discard_indices: + self.replace_card(i, deck.deal()) + return len(result.discard_indices) + + def get_check_response(self) -> Player.Action: + """Respond to a player's check. Returns the dealer's action.""" + if not self.was_bluffing and self.hand_is_weak: + return Player.Action.CHECK + + self.bet = self.bet_base + random.randint(0, 9) + return Player.Action.RAISE + + def get_raise_response(self, player_paid: int) -> Player.Action: + """Respond to a player's raise. Returns the dealer's action.""" + if self.bet_base != 1: + if player_paid > 3 * self.bet_base: + if self.bet_base == 2 and self._chance(1): + return self._raise(player_paid) + return self._call(player_paid) + return self._raise(player_paid) + + if player_paid > 5: + return Player.Action.FOLD + + if player_paid > 3: + return self._call(player_paid) + + return self._raise(player_paid) + + def _call(self, player_paid: int) -> Player.Action: + """Dealer calls the player's bet.""" + self.bet = player_paid + return Player.Action.CALL + + def _raise(self, player_paid: int) -> Player.Action: + """Raise the player's bet.""" + raise_amount = player_paid - self.bet + random.randint(0, 9) + if raise_amount <= 0: + return self._call(player_paid) + + self.bet = player_paid + raise_amount + return Player.Action.RAISE + + def _chance(self, n: int) -> bool: + """Return True with probability n/10.""" + return random.random() < n / 10 diff --git a/71_Poker/python/players/human.py b/71_Poker/python/players/human.py new file mode 100644 index 000000000..b496e1ceb --- /dev/null +++ b/71_Poker/python/players/human.py @@ -0,0 +1,21 @@ +"""Human player state and behavior.""" + +from .player import Player + + +class Human(Player): + """ + The human player in the game. + + Note: As a state container, this class has no logic methods; + decision-making is provided by the user via the game controller. + """ + + has_watch: bool + has_tack: bool + + def __init__(self, money: int) -> None: + """Initialize the human player with starting assets.""" + super().__init__(money) + self.has_watch = True + self.has_tack = True diff --git a/71_Poker/python/players/player.py b/71_Poker/python/players/player.py new file mode 100644 index 000000000..e5925641d --- /dev/null +++ b/71_Poker/python/players/player.py @@ -0,0 +1,51 @@ +"""Base Player class for both Human and Dealer.""" + +from enum import Enum, auto + +from cards import Card +from pokerhand import Hand + + +class Player: + """Base class representing a participant in the poker game.""" + + money: int + bet: int + hand: Hand + + class Action(Enum): + """Standard actions a player can take.""" + + FOLD = auto() + CHECK = auto() + CALL = auto() + RAISE = auto() + + def __init__(self, money: int) -> None: + """Initialize the player with a starting bankroll.""" + self.money = money + self.bet = 0 + + def receive_new_hand(self, hand: Hand) -> None: + """Reset per-round state and receive a new hand.""" + self.bet = 0 + self.hand = hand + + def pay_ante(self, amount: int) -> None: + """Pay the ante.""" + self.money -= amount + + def win_pot(self, amount: int) -> None: + """Add the pot to the player's money.""" + self.money += amount + + def settle_bet(self) -> int: + """Move the current bet out of the player's money. Returns the bet amount.""" + amount = self.bet + self.money -= amount + self.bet = 0 + return amount + + def replace_card(self, index: int, card: Card) -> None: + """Replace a card in the player's hand.""" + self.hand[index] = card diff --git a/71_Poker/python/poker.py b/71_Poker/python/poker.py new file mode 100644 index 000000000..f027432bf --- /dev/null +++ b/71_Poker/python/poker.py @@ -0,0 +1,38 @@ +""" +From: BASIC Computer Games (1978) +Edited by David H. Ahl + +You and the computer are opponents in this game of draw poker. +At the start of the game, each player is given $200. The game +ends when either player runs out of money, although if you go +broke the computer will offer to buy back your wristwatch or +diamond tie tack. + +The computer opens the betting before the draw; you open the +betting after the draw. If you don't have a hand that's worth +anything and you want to fold, bet 0. Prior to the draw, to +check the draw, you may bet .5. Of course, if the computer has +made a bet, you must match it in order to draw or, if you have +a good hand, you may raise the bet at any time. + +The author is A. Christopher Hall of Trinity College, +Hartford, Connecticut. + + +Python port by Alex Conconi, 2026. +""" + +from game import GameOver, PokerGame + + +def main() -> None: + """Entry point for the poker game application.""" + game = PokerGame() + try: + game.run() + except GameOver: + pass + + +if __name__ == "__main__": + main() diff --git a/71_Poker/python/pokerhand/__init__.py b/71_Poker/python/pokerhand/__init__.py new file mode 100644 index 000000000..3de94bf24 --- /dev/null +++ b/71_Poker/python/pokerhand/__init__.py @@ -0,0 +1,7 @@ +"""Hand package initialization.""" + +from .evaluation import HandEvaluation +from .hand import Hand +from .rank import HandRank + +__all__ = ["Hand", "HandEvaluation", "HandRank"] diff --git a/71_Poker/python/pokerhand/evaluation.py b/71_Poker/python/pokerhand/evaluation.py new file mode 100644 index 000000000..c2e33fdbf --- /dev/null +++ b/71_Poker/python/pokerhand/evaluation.py @@ -0,0 +1,206 @@ +"""Hand evaluation logic.""" + +from collections import Counter +from collections.abc import Callable +from typing import TYPE_CHECKING + +from cards.card import Card, CardRank + +from .rank import HandRank + +if TYPE_CHECKING: + from .hand import Hand + + +class HandEvaluation: + """ + Evaluator and Result container for a poker hand. + + When initialized with a Hand, it immediately performs the evaluation + and stores the resulting rank, high card, and recommended discards. + """ + + hand_rank: HandRank + high_card: Card + discard_indices: list[int] + + def __init__(self, hand: "Hand"): + """Perform evaluation of the provided hand.""" + self.discard_indices = [] + self._evaluate(hand) + + def __str__(self) -> str: + rank = self.hand_rank + card = self.high_card + + match rank: + case HandRank.SCHMALTZ | HandRank.PARTIAL_STRAIGHT: + return f"{rank}, {card.rank} high" + case ( + HandRank.PAIR + | HandRank.TWO_PAIR + | HandRank.THREE_OF_A_KIND + | HandRank.FULL_HOUSE + | HandRank.FOUR_OF_A_KIND + ): + return f"{rank} {card.rank}'s" + case HandRank.STRAIGHT: + return f"{rank}, {card.rank} high" + case HandRank.FLUSH: + return f"{rank} {card.suit}" + case _: + return f"{rank} {card.rank}" + + def __lt__(self, other: "HandEvaluation") -> bool: + return (self.hand_rank, self.high_card.rank.value) < ( + other.hand_rank, + other.high_card.rank.value, + ) + + def __eq__(self, other: object) -> bool: + # this object could be compared to any other object with == + if not isinstance(other, HandEvaluation): + return NotImplemented + return (self.hand_rank, self.high_card.rank.value) == ( + other.hand_rank, + other.high_card.rank.value, + ) + + class _EvaluationContext: # pylint: disable=too-few-public-methods + """Intermediate calculations for hand evaluation.""" + + def __init__(self, hand: "Hand"): + self.cards = hand.cards + self.rank_indexed = sorted( + enumerate(self.cards), key=lambda item: item[1].rank.value + ) + + # Frequency analysis + rank_counts = Counter(c.rank for c in self.cards) + sorted_groups = sorted( + rank_counts.items(), + key=lambda rc: (rc[1], rc[0].value), + reverse=True, + ) + self.freq_pattern = tuple(count for _, count in sorted_groups) + self.ranks_by_freq = [rank for rank, _ in sorted_groups] + self.sorted_ranks: list[CardRank] = [ + c.rank for _, c in self.rank_indexed + ] + + def _evaluate(self, hand: "Hand") -> None: + """Internal algorithm to determine hand strength.""" + ctx = self._EvaluationContext(hand) + + checks: list[Callable[[HandEvaluation._EvaluationContext], bool]] = [ + self._check_four_of_a_kind, + self._check_full_house, + self._check_flush, + self._check_straight, + self._check_three_of_a_kind, + self._check_two_pair, + self._check_pair, + self._check_partial_straight, + self._check_schmaltz, + ] + + for check in checks: + if check(ctx): + break + + def _check_four_of_a_kind(self, ctx: _EvaluationContext) -> bool: + if ctx.freq_pattern != (4, 1): + return False + self.hand_rank = HandRank.FOUR_OF_A_KIND + self.high_card = next( + c + for _, c in reversed(ctx.rank_indexed) + if c.rank == ctx.ranks_by_freq[0] + ) + return True + + def _check_full_house(self, ctx: _EvaluationContext) -> bool: + if ctx.freq_pattern != (3, 2): + return False + self.hand_rank = HandRank.FULL_HOUSE + self.high_card = next( + c + for _, c in reversed(ctx.rank_indexed) + if c.rank == ctx.ranks_by_freq[0] + ) + return True + + def _check_flush(self, ctx: _EvaluationContext) -> bool: + if len({c.suit for c in ctx.cards}) != 1: + return False + self.hand_rank = HandRank.FLUSH + self.high_card = max(ctx.cards, key=lambda c: c.rank) + return True + + def _check_straight(self, ctx: _EvaluationContext) -> bool: + if ( + len(set(ctx.sorted_ranks)) == 5 + and ctx.sorted_ranks[4].value - ctx.sorted_ranks[0].value == 4 + ): + self.hand_rank = HandRank.STRAIGHT + self.high_card = ctx.rank_indexed[4][1] + return True + return False + + def _check_three_of_a_kind(self, ctx: _EvaluationContext) -> bool: + if ctx.freq_pattern != (3, 1, 1): + return False + self.hand_rank = HandRank.THREE_OF_A_KIND + self.high_card = next( + c + for _, c in reversed(ctx.rank_indexed) + if c.rank == ctx.ranks_by_freq[0] + ) + self.discard_indices = [idx for idx, _ in ctx.rank_indexed[0:3]] + return True + + def _check_two_pair(self, ctx: _EvaluationContext) -> bool: + if ctx.freq_pattern != (2, 2, 1): + return False + self.hand_rank = HandRank.TWO_PAIR + self.high_card = next( + c + for _, c in reversed(ctx.rank_indexed) + if c.rank == ctx.ranks_by_freq[0] + ) + keep = {ctx.ranks_by_freq[0], ctx.ranks_by_freq[1]} + self.discard_indices = [ + i for i, c in enumerate(ctx.cards) if c.rank not in keep + ] + return True + + def _check_pair(self, ctx: _EvaluationContext) -> bool: + if ctx.freq_pattern != (2, 1, 1, 1): + return False + self.hand_rank = HandRank.PAIR + self.high_card = next( + c + for _, c in reversed(ctx.rank_indexed) + if c.rank == ctx.ranks_by_freq[0] + ) + self.discard_indices = [idx for idx, _ in ctx.rank_indexed[0:3]] + return True + + def _check_partial_straight(self, ctx: _EvaluationContext) -> bool: + if ctx.sorted_ranks[3].value - ctx.sorted_ranks[0].value == 3: + self.hand_rank = HandRank.PARTIAL_STRAIGHT + self.high_card = ctx.rank_indexed[3][1] + self.discard_indices = [ctx.rank_indexed[4][0]] + return True + if ctx.sorted_ranks[4].value - ctx.sorted_ranks[1].value == 3: + self.hand_rank = HandRank.PARTIAL_STRAIGHT + self.high_card = ctx.rank_indexed[4][1] + self.discard_indices = [ctx.rank_indexed[0][0]] + return True + return False + + def _check_schmaltz(self, ctx: _EvaluationContext) -> bool: + self.hand_rank = HandRank.SCHMALTZ + self.high_card = ctx.rank_indexed[4][1] + self.discard_indices = [idx for idx, _ in ctx.rank_indexed[0:4]] + return True diff --git a/71_Poker/python/pokerhand/hand.py b/71_Poker/python/pokerhand/hand.py new file mode 100644 index 000000000..aef598ace --- /dev/null +++ b/71_Poker/python/pokerhand/hand.py @@ -0,0 +1,39 @@ +"""Hand implementation.""" + +from collections.abc import Iterator + +from cards.card import Card + +from .evaluation import HandEvaluation + + +class Hand: + """A 5-card poker hand that acts as a simple data container.""" + + def __init__(self, cards: list[Card]): + if len(cards) != 5: + raise ValueError("Hand must have exactly 5 cards") + self.cards = list(cards) + + def evaluate(self) -> HandEvaluation: + """Factory method to return a hand evaluation.""" + return HandEvaluation(self) + + def __len__(self) -> int: + return len(self.cards) + + def __iter__(self) -> Iterator[Card]: + return iter(self.cards) + + def __getitem__(self, i: int) -> Card: + return self.cards[i] + + def __setitem__(self, i: int, card: Card) -> None: + self.cards[i] = card + + def __str__(self) -> str: + """Return a multi-line formatted description of the hand.""" + entries = [f"{i} -- {card}" for i, card in enumerate(self.cards, 1)] + lines = [f" {entries[i]:<32}{entries[i + 1]}" for i in range(0, 4, 2)] + lines.append(f" {entries[4]}") + return "\n".join(lines) diff --git a/71_Poker/python/pokerhand/rank.py b/71_Poker/python/pokerhand/rank.py new file mode 100644 index 000000000..181cec0a1 --- /dev/null +++ b/71_Poker/python/pokerhand/rank.py @@ -0,0 +1,31 @@ +"""Hand rank enumeration.""" + +from enum import IntEnum, auto + + +class HandRank(IntEnum): + """Poker hand ranks ordered from weakest to strongest.""" + + SCHMALTZ = auto() + PARTIAL_STRAIGHT = auto() + PAIR = auto() + TWO_PAIR = auto() + THREE_OF_A_KIND = auto() + STRAIGHT = auto() + FLUSH = auto() + FULL_HOUSE = auto() + FOUR_OF_A_KIND = auto() + + def __str__(self) -> str: + """Return the display name of the rank.""" + return { + HandRank.SCHMALTZ: "Schmaltz", + HandRank.PARTIAL_STRAIGHT: "Schmaltz", + HandRank.PAIR: "a pair of", + HandRank.TWO_PAIR: "Two pair", + HandRank.THREE_OF_A_KIND: "Three", + HandRank.STRAIGHT: "Straight", + HandRank.FLUSH: "a flush in", + HandRank.FULL_HOUSE: "Full house", + HandRank.FOUR_OF_A_KIND: "Four", + }[self] From a28e5a0a7dde84af7a54518bd5e2bd3ddaeb8516 Mon Sep 17 00:00:00 2001 From: aconconi Date: Thu, 12 Mar 2026 11:09:29 +0100 Subject: [PATCH 366/377] Fixed discard logic bug in _check_three_of_a_kind and _check_pair --- 71_Poker/python/game.py | 1 - 71_Poker/python/pokerhand/evaluation.py | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/71_Poker/python/game.py b/71_Poker/python/game.py index 92d97463a..68b42331a 100644 --- a/71_Poker/python/game.py +++ b/71_Poker/python/game.py @@ -27,7 +27,6 @@ def __init__(self) -> None: """Initialise game state and allocate both sides' starting stack.""" self.human = Human(PokerGame.INITIAL_MONEY) self.dealer = Dealer(PokerGame.INITIAL_MONEY) - self.deck: Deck self.pot = 0 # ------------------------------------------------------------------ diff --git a/71_Poker/python/pokerhand/evaluation.py b/71_Poker/python/pokerhand/evaluation.py index c2e33fdbf..feedaf0e8 100644 --- a/71_Poker/python/pokerhand/evaluation.py +++ b/71_Poker/python/pokerhand/evaluation.py @@ -1,5 +1,6 @@ """Hand evaluation logic.""" +import functools from collections import Counter from collections.abc import Callable from typing import TYPE_CHECKING @@ -12,6 +13,7 @@ from .hand import Hand +@functools.total_ordering class HandEvaluation: """ Evaluator and Result container for a poker hand. @@ -156,7 +158,8 @@ def _check_three_of_a_kind(self, ctx: _EvaluationContext) -> bool: for _, c in reversed(ctx.rank_indexed) if c.rank == ctx.ranks_by_freq[0] ) - self.discard_indices = [idx for idx, _ in ctx.rank_indexed[0:3]] + keep_rank = ctx.ranks_by_freq[0] + self.discard_indices = [i for i, c in enumerate(ctx.cards) if c.rank != keep_rank] return True def _check_two_pair(self, ctx: _EvaluationContext) -> bool: @@ -183,7 +186,8 @@ def _check_pair(self, ctx: _EvaluationContext) -> bool: for _, c in reversed(ctx.rank_indexed) if c.rank == ctx.ranks_by_freq[0] ) - self.discard_indices = [idx for idx, _ in ctx.rank_indexed[0:3]] + keep_rank = ctx.ranks_by_freq[0] + self.discard_indices = [i for i, c in enumerate(ctx.cards) if c.rank != keep_rank] return True def _check_partial_straight(self, ctx: _EvaluationContext) -> bool: From 22c4ba5bc127c19f8515ce2101c2e09a28a86e4e Mon Sep 17 00:00:00 2001 From: Uncle Scientist Date: Thu, 26 Mar 2026 08:20:29 -0400 Subject: [PATCH 367/377] Add Rust port of 40_Gomoku --- 40_Gomoko/rust/Cargo.lock | 411 +++++++++++++++++++++++++++++++++++++ 40_Gomoko/rust/Cargo.toml | 7 + 40_Gomoko/rust/src/main.rs | 209 +++++++++++++++++++ 3 files changed, 627 insertions(+) create mode 100644 40_Gomoko/rust/Cargo.lock create mode 100644 40_Gomoko/rust/Cargo.toml create mode 100644 40_Gomoko/rust/src/main.rs diff --git a/40_Gomoko/rust/Cargo.lock b/40_Gomoko/rust/Cargo.lock new file mode 100644 index 000000000..7ef3861c9 --- /dev/null +++ b/40_Gomoko/rust/Cargo.lock @@ -0,0 +1,411 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core", + "wasip2", + "wasip3", +] + +[[package]] +name = "gomoku" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" +dependencies = [ + "chacha20", + "getrandom", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/40_Gomoko/rust/Cargo.toml b/40_Gomoko/rust/Cargo.toml new file mode 100644 index 000000000..6874f0e90 --- /dev/null +++ b/40_Gomoko/rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "gomoku" +version = "0.1.0" +edition = "2024" + +[dependencies] +rand = "0.10.0" diff --git a/40_Gomoko/rust/src/main.rs b/40_Gomoko/rust/src/main.rs new file mode 100644 index 000000000..53ec70ae9 --- /dev/null +++ b/40_Gomoko/rust/src/main.rs @@ -0,0 +1,209 @@ +use std::{ + fmt::Display, + io::{BufRead, Write}, +}; + +use rand::prelude::*; + +fn main() { + println!("{:>33}GOMOKU", ""); + println!("{:>15}CREATIVE COMPUTING MORISSTOWN, NEW JERSEY\n\n\n", ""); + + println!("Welcome to the oriental game of Gomoku."); + println!("\nThe game is played on an N by N grid of a size"); + println!("that you specify. During your play, you may cover one grid"); + println!("intersection with a marker. The object of the game is to get"); + println!("5 adjacent markers in a row -- horizontally, vertically, or"); + println!("diagonally. On the board diagram, your moves are marked"); + println!("with a '1' and the computer moves with a '2'."); + println!("\nThe computer does not keep track of who has won."); + println!("To end the game, type -1,-1 for your move.\n"); + + loop { + let size = get_board_size(); + + // Line 210: initialize the game board + let mut game = Gomoku::new(size); + + if !game.play() { + break; + } + } +} + +struct Gomoku { + board: Vec>, + size: isize, +} + +impl Gomoku { + fn new(size: usize) -> Self { + Self { + board: vec![vec![Piece::Empty; size]; size], + size: size as isize, + } + } + + fn get_player_move(&self) -> (isize, isize) { + let mut first_attempt = true; + loop { + if !first_attempt { + println!("Illegal move. Try again..."); + } + first_attempt = false; + let response = prompt_for_input("Your play (I,J)"); + let Some((i, j)) = response.split_once(',') else { + continue; + }; + let Ok(i) = i.trim().parse::() else { + continue; + }; + let Ok(j) = j.trim().parse::() else { + continue; + }; + if i == -1 { + return (-1, -1); + } + if i < 1 || i > self.size || j < 1 || j > self.size { + continue; + } + return (i, j); + } + } + + fn play(&mut self) -> bool { + let mut rng = rand::rng(); + + // Line 300 + println!("\nWe alternate moves. You go first...\n"); + + 'next_move: loop { + println!("{self}"); + + // Line 310 + let (i, j) = self.get_player_move(); + + // Line 320 + if i == -1 { + break; + } + + let pos = self.get(i, j); + + match *pos { + Piece::Empty => *pos = Piece::Human, + Piece::Computer | Piece::Human => { + println!("Square occupied. Try again..."); + continue; + } + } + + // Lines 500-590: The computer tries an intelligent move + for e in -1..=1 { + for f in -1..=1 { + // Line 510: + if e == 0 && f == 0 { + continue; + } + + // Line 540: + let x = i + e; + let y = j + f; + if x < 1 || x > self.size || y < 1 || y > self.size { + continue; + } + + let pos = self.get(x, y); + if *pos == Piece::Human { + let x = i - e; + let y = j - f; + if x < 1 || x > self.size || y < 1 || y > self.size { + continue; + } + let pos = self.get(x, y); + if *pos == Piece::Empty { + *pos = Piece::Computer; + continue 'next_move; + } + } + } + } + + // Lines 600-660: The computer tries a random move + loop { + let x = rng.random_range(1..=self.size as usize) as isize; + let y = rng.random_range(1..=self.size as usize) as isize; + let pos = self.get(x, y); + if *pos == Piece::Empty { + *pos = Piece::Computer; + continue 'next_move; + } + } + } + + // Lines 980-999 + println!("\nThanks for the game!!"); + prompt_for_input("Play again (1 for yes, 0 for no)") == "1" + } + + fn get(&mut self, i: isize, j: isize) -> &mut Piece { + &mut self.board[i as usize - 1][j as usize - 1] + } +} + +impl Display for Gomoku { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for row in &self.board { + for col in row { + write!(f, "{col}")?; + } + writeln!(f)?; + } + Ok(()) + } +} + +#[derive(Clone, Copy, PartialEq)] +enum Piece { + Empty, + Computer, + Human, +} + +impl Display for Piece { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + " {}", + match self { + Piece::Empty => '0', + Piece::Computer => '2', + Piece::Human => '1', + } + ) + } +} + +fn prompt_for_input>(prompt: S) -> String { + print!("{}? ", prompt.as_ref()); + let mut lock = std::io::stdout().lock(); + let _ = lock.flush(); + + let mut buffer = String::new(); + let stdin = std::io::stdin(); + let mut handle = stdin.lock(); + let _ = handle.read_line(&mut buffer); + buffer.trim().to_string() +} + +fn get_board_size() -> usize { + loop { + let buffer = prompt_for_input("What is your board size (min 7/ max 19)"); + if let Ok(val) = buffer.trim().parse::() + && (7..=19).contains(&val) + { + return val; + } + println!("I said, the minimum is 7, the maximum is 19."); + } +} From 48295e460fbdb47231bda4507d217d4356cf76b6 Mon Sep 17 00:00:00 2001 From: Uncle Scientist Date: Fri, 3 Apr 2026 08:25:30 -0400 Subject: [PATCH 368/377] A Rust crate to handle the eccentricities of BASIC input statements --- 00_Common/rust/Cargo.lock | 7 + 00_Common/rust/Cargo.toml | 7 + 00_Common/rust/crates/basic_input/Cargo.toml | 6 + .../rust/crates/basic_input/src/input.rs | 354 ++++++++++++++++++ .../basic_input/src/input/input_state.rs | 77 ++++ .../crates/basic_input/src/input/io_layer.rs | 80 ++++ 00_Common/rust/crates/basic_input/src/lib.rs | 42 +++ .../rust/crates/basic_input/src/parse.rs | 85 +++++ 8 files changed, 658 insertions(+) create mode 100644 00_Common/rust/Cargo.lock create mode 100644 00_Common/rust/Cargo.toml create mode 100644 00_Common/rust/crates/basic_input/Cargo.toml create mode 100644 00_Common/rust/crates/basic_input/src/input.rs create mode 100644 00_Common/rust/crates/basic_input/src/input/input_state.rs create mode 100644 00_Common/rust/crates/basic_input/src/input/io_layer.rs create mode 100644 00_Common/rust/crates/basic_input/src/lib.rs create mode 100644 00_Common/rust/crates/basic_input/src/parse.rs diff --git a/00_Common/rust/Cargo.lock b/00_Common/rust/Cargo.lock new file mode 100644 index 000000000..2c85bc520 --- /dev/null +++ b/00_Common/rust/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "basic_input" +version = "0.1.0" diff --git a/00_Common/rust/Cargo.toml b/00_Common/rust/Cargo.toml new file mode 100644 index 000000000..23c680f4e --- /dev/null +++ b/00_Common/rust/Cargo.toml @@ -0,0 +1,7 @@ +# +# Although there is currently only the `basic_input` crate here, I am anticipating +# more utility crates for rust ports, as well as proc macro crates. +# +[workspace] +resolver = "2" +members = [ "crates/basic_input" ] diff --git a/00_Common/rust/crates/basic_input/Cargo.toml b/00_Common/rust/crates/basic_input/Cargo.toml new file mode 100644 index 000000000..d32bdb628 --- /dev/null +++ b/00_Common/rust/crates/basic_input/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "basic_input" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/00_Common/rust/crates/basic_input/src/input.rs b/00_Common/rust/crates/basic_input/src/input.rs new file mode 100644 index 000000000..0955d8ec4 --- /dev/null +++ b/00_Common/rust/crates/basic_input/src/input.rs @@ -0,0 +1,354 @@ +mod input_state; +mod io_layer; + +use input_state::InputState; +use io_layer::IoLayer; + +/// Main entrypoint for this module. Display a prompt and read one or more values from the user. +/// See [the crate docs](module@crate) +pub fn get_input>(prompt: S) -> BI { + let mut io = IoLayer::get_io(); + get_input_from_io(prompt, &mut io) +} + +// This is the trait that we return to the user, which allows us to have +// a different function for each return type. +// let one_input : f32 = get_input("..."); +// let (x, y) : (f32, f32) = get_input("..."); +// let (a, b, c) : (f32, f32, f32) = get_input("..."); +pub trait BasicInput { + fn from_string>(s: S, state: &mut InputState) -> Result + where + Self: Sized; +} + +// -------------------------------------------------------------------------------- + +impl BasicInput for f32 { + fn from_string>(s: S, state: &mut InputState) -> Result { + state.input_f32s(s, 1)?; + Ok(state.data[0].as_f32()) + } +} + +impl BasicInput for (f32, f32) { + fn from_string>(s: S, state: &mut InputState) -> Result { + state.input_f32s(s, 2)?; + + Ok((state.data[0].as_f32(), state.data[1].as_f32())) + } +} + +impl BasicInput for (f32, f32, f32) { + fn from_string>(s: S, state: &mut InputState) -> Result { + state.input_f32s(s, 3)?; + + Ok(( + state.data[0].as_f32(), + state.data[1].as_f32(), + state.data[2].as_f32(), + )) + } +} + +impl BasicInput for (f32, f32, f32, f32) { + fn from_string>(s: S, state: &mut InputState) -> Result { + state.input_f32s(s, 4)?; + + Ok(( + state.data[0].as_f32(), + state.data[1].as_f32(), + state.data[2].as_f32(), + state.data[3].as_f32(), + )) + } +} + +impl BasicInput for (f32, f32, f32, f32, f32, f32, f32, f32, f32, f32) { + fn from_string>(s: S, state: &mut InputState) -> Result { + state.input_f32s(s, 10)?; + + Ok(( + state.data[0].as_f32(), + state.data[1].as_f32(), + state.data[2].as_f32(), + state.data[3].as_f32(), + state.data[4].as_f32(), + state.data[5].as_f32(), + state.data[6].as_f32(), + state.data[7].as_f32(), + state.data[8].as_f32(), + state.data[9].as_f32(), + )) + } +} + +impl BasicInput for String { + fn from_string>(s: S, state: &mut InputState) -> Result { + state.input_strings(s, 1)?; + Ok(state.data[0].as_string()) + } +} + +impl BasicInput for (String, String) { + fn from_string>(s: S, state: &mut InputState) -> Result { + state.input_strings(s, 2)?; + Ok((state.data[0].as_string(), state.data[1].as_string())) + } +} + +// -------------------------------------------------------------------------------- + +fn get_input_from_io>(prompt: S, io: &mut IoLayer) -> BI { + let mut state = InputState { + io, + data: Vec::new(), + }; + + state.io.raw_output_string(format!("{}? ", prompt.as_ref())); + + loop { + let buffer = state.io.raw_input_string(); + match BI::from_string(buffer, &mut state) { + Ok(result) => return result, + Err(e) => match e { + BasicInputError::ParseFailed => { + state.io.raw_output_string("?REENTER\n"); + state.io.raw_output_string(format!("{}? ", prompt.as_ref())); + state.data.clear(); + } + BasicInputError::MissingInput => { + state.io.raw_output_string("??? "); + } + }, + } + } +} + +#[derive(Debug)] +pub enum BasicInputError { + ParseFailed, + MissingInput, +} + +#[cfg(test)] +mod test { + use crate::input::get_input_from_io; + use crate::input::io_layer::{IoLayer, TextInput, TextOutput}; + use std::collections::VecDeque; + + fn getio() -> IoLayer { + IoLayer { + output: Box::new(WriteTestLayer::new()), + input: Box::new(ReadTestLayer::new()), + } + } + + #[test] + fn test_trait_single_input() { + let mut testio = getio(); + testio.input.set_input_text("2"); + let result: f32 = get_input_from_io("prompt", &mut testio); + assert_eq!(2.0, result); + } + + #[test] + fn test_trait_dual_input() { + let mut testio = getio(); + testio.input.set_input_text("2,3"); + let result: (f32, f32) = get_input_from_io("prompt", &mut testio); + assert_eq!( + "prompt? ".to_string(), + testio.output.get_last_line().unwrap() + ); + assert_eq!(2.0, result.0); + assert_eq!(3.0, result.1); + } + + #[test] + fn test_invalid_input() { + let mut testio = getio(); + testio.input.set_input_text("abc"); + testio.input.set_input_text("2"); + let result: f32 = get_input_from_io("prompt", &mut testio); + assert_eq!( + "prompt? ".to_string(), + testio.output.get_last_line().unwrap() + ); + assert_eq!( + "?REENTER\n".to_string(), + testio.output.get_last_line().unwrap() + ); + assert_eq!(2.0, result); + } + + #[test] + fn test_multiple_invalid_input() { + let mut testio = getio(); + testio.input.set_input_text("abc"); + testio.input.set_input_text("2,a"); + testio.input.set_input_text("2,3"); + let result: (f32, f32) = get_input_from_io("prompt", &mut testio); + assert_eq!( + "prompt? ".to_string(), + testio.output.get_last_line().unwrap() + ); + assert_eq!( + "?REENTER\n".to_string(), + testio.output.get_last_line().unwrap() + ); + assert_eq!( + "prompt? ".to_string(), + testio.output.get_last_line().unwrap() + ); + assert_eq!( + "?REENTER\n".to_string(), + testio.output.get_last_line().unwrap() + ); + assert_eq!( + "prompt? ".to_string(), + testio.output.get_last_line().unwrap() + ); + assert_eq!(2.0, result.0); + assert_eq!(3.0, result.1); + } + + #[test] + fn two_inputs_over_multiple_lines() { + let mut testio = getio(); + testio.input.set_input_text("2"); + testio.input.set_input_text("3"); + let result: (f32, f32) = get_input_from_io("prompt", &mut testio); + assert_eq!( + "prompt? ".to_string(), + testio.output.get_last_line().unwrap() + ); + assert_eq!("??? ".to_string(), testio.output.get_last_line().unwrap()); + assert_eq!(2.0, result.0); + assert_eq!(3.0, result.1); + } + + #[test] + fn test_triple_f32() { + let mut testio = getio(); + testio.input.set_input_text("1, 2, 3"); + let result: (f32, f32, f32) = get_input_from_io("enter 3 numbers", &mut testio); + assert_eq!(1.0, result.0); + assert_eq!(2.0, result.1); + assert_eq!(3.0, result.2); + } + + #[test] + fn test_input_string() { + let mut testio = getio(); + testio.input.set_input_text("hello"); + let result: String = get_input_from_io("String prompt", &mut testio); + assert_eq!("hello".to_string(), result); + } + + #[test] + fn test_two_input_strings() { + let mut testio = getio(); + testio.input.set_input_text("hello, world"); + let result: (String, String) = get_input_from_io("Double string prompt", &mut testio); + assert_eq!("hello".to_string(), result.0); + assert_eq!("world".to_string(), result.1); + } + + #[test] + fn test_four_nums() { + let mut testio = getio(); + testio.input.set_input_text("1, 2, 3, 4"); + let result: (f32, f32, f32, f32) = get_input_from_io("whatever", &mut testio); + assert_eq!(4.0, result.3); + } + + #[test] + fn test_extra_ignored() { + let mut testio = getio(); + testio.input.set_input_text("1, 2, 3, 4"); + let result: (f32, f32) = get_input_from_io("whatever", &mut testio); + assert_eq!(Some("whatever? "), testio.output.get_last_line().as_deref()); + assert_eq!( + Some("?EXTRA IGNORED\n"), + testio.output.get_last_line().as_deref() + ); + assert_eq!(2.0, result.1); + } + + #[test] + fn test_extra_ignored_bad_parse() { + let mut testio = getio(); + testio.input.set_input_text("1, 2, hello"); + let result: (f32, f32) = get_input_from_io("whatever", &mut testio); + assert_eq!(Some("whatever? "), testio.output.get_last_line().as_deref()); + assert_eq!( + Some("?EXTRA IGNORED\n"), + testio.output.get_last_line().as_deref() + ); + assert_eq!(2.0, result.1); + } + + #[test] + fn test_ten_nums() { + let mut testio = getio(); + testio.input.set_input_text("1, 2, 3, 4, 5, 6, 7, 8, 9, 10"); + let result: (f32, f32, f32, f32, f32, f32, f32, f32, f32, f32) = + get_input_from_io("whatever", &mut testio); + assert_eq!(Some("whatever? "), testio.output.get_last_line().as_deref()); + assert_eq!(None, testio.output.get_last_line()); + assert_eq!(10.0, result.9); + } + + // + // Helpers for test i/o + // + pub struct ReadTestLayer { + next_line: VecDeque, + } + + impl ReadTestLayer { + pub fn new() -> Self { + Self { + next_line: VecDeque::new(), + } + } + } + + impl TextInput for ReadTestLayer { + fn read(&mut self) -> String { + if let Some(line) = self.next_line.pop_front() { + println!(">> returning {line}"); + line + } else { + panic!("Test tried to read too much input"); + } + } + + fn set_input_text(&mut self, text: &str) { + self.next_line.push_back(text.to_string()); + } + } + + pub struct WriteTestLayer { + last_items_written: VecDeque, + } + + impl WriteTestLayer { + pub fn new() -> Self { + Self { + last_items_written: VecDeque::new(), + } + } + } + + impl TextOutput for WriteTestLayer { + fn write(&mut self, to_write: &str) { + self.last_items_written.push_back(to_write.into()); + } + + fn get_last_line(&mut self) -> Option { + self.last_items_written.pop_front() + } + } +} diff --git a/00_Common/rust/crates/basic_input/src/input/input_state.rs b/00_Common/rust/crates/basic_input/src/input/input_state.rs new file mode 100644 index 000000000..58c19e88f --- /dev/null +++ b/00_Common/rust/crates/basic_input/src/input/input_state.rs @@ -0,0 +1,77 @@ +use crate::{BasicInputError, input::io_layer::IoLayer}; + +pub struct InputState<'a> { + pub(crate) io: &'a mut IoLayer, + pub(crate) data: Vec, +} + +impl<'a> InputState<'a> { + pub(crate) fn input_f32s>( + &mut self, + s: S, + count: usize, + ) -> Result<(), BasicInputError> { + let vals = crate::parse::parse(s); + + for v in vals { + if self.data.len() >= count { + self.io.raw_output_string("?EXTRA IGNORED\n"); + return Ok(()); + } + + let value = v + .trim() + .parse::() + .map_err(|_| BasicInputError::ParseFailed)?; + self.data.push(Value::Num(value)); + } + + if self.data.len() < count { + return Err(BasicInputError::MissingInput); + } + + Ok(()) + } + + pub(crate) fn input_strings>( + &mut self, + s: S, + count: usize, + ) -> Result<(), BasicInputError> { + let vals = crate::parse::parse(s); + + for v in vals { + let value = v.trim(); + self.data.push(Value::Str(value.to_string())); + } + if self.data.len() < count { + return Err(BasicInputError::MissingInput); + } + if self.data.len() > count { + self.io.raw_output_string("?EXTRA IGNORED\n"); + } + Ok(()) + } +} + +#[derive(Clone, Debug)] +pub enum Value { + Num(f32), + Str(String), +} + +impl Value { + pub(crate) fn as_f32(&self) -> f32 { + match self { + Value::Num(num) => *num, + Value::Str(_) => panic!("tried to extract a number, but Value was a String"), + } + } + + pub(crate) fn as_string(&self) -> String { + match self { + Value::Num(_) => panic!("tried to extract a string, but Value was a Num"), + Value::Str(s) => s.clone(), + } + } +} diff --git a/00_Common/rust/crates/basic_input/src/input/io_layer.rs b/00_Common/rust/crates/basic_input/src/input/io_layer.rs new file mode 100644 index 000000000..5939da31f --- /dev/null +++ b/00_Common/rust/crates/basic_input/src/input/io_layer.rs @@ -0,0 +1,80 @@ +use std::io::{BufRead, StdoutLock, Write}; + +pub struct IoLayer { + pub(super) output: Box, + pub(super) input: Box, +} + +impl IoLayer { + pub(crate) fn get_io() -> Self { + Self { + output: StdoutLayer::new(), + input: StdinLayer::new(), + } + } + + pub(crate) fn raw_output_string>(&mut self, s: S) { + self.output.write(s.as_ref()); + } + + pub(crate) fn raw_input_string(&mut self) -> String { + self.input.read() + } +} + +pub(crate) trait TextOutput { + fn write(&mut self, to_write: &str); + #[cfg(test)] + fn get_last_line(&mut self) -> Option; +} + +pub(crate) trait TextInput { + fn read(&mut self) -> String; + #[cfg(test)] + fn set_input_text(&mut self, text: &str); +} + +struct StdoutLayer<'a> { + stdout: StdoutLock<'a>, +} + +impl<'a> TextOutput for StdoutLayer<'a> { + fn write(&mut self, to_write: &str) { + print!("{to_write}"); + let _ = self.stdout.flush(); + } + + #[cfg(test)] + fn get_last_line(&mut self) -> Option { + unreachable!(); + } +} + +struct StdinLayer; +impl TextInput for StdinLayer { + fn read(&mut self) -> String { + let mut buffer = String::new(); + let stdin = std::io::stdin(); + let mut handle = stdin.lock(); + let _ = handle.read_line(&mut buffer); + buffer + } + + #[cfg(test)] + fn set_input_text(&mut self, _text: &str) { + unreachable!(); + } +} + +impl<'a> StdoutLayer<'a> { + fn new() -> Box { + Box::new(Self { + stdout: std::io::stdout().lock(), + }) + } +} +impl StdinLayer { + fn new() -> Box { + Box::new(Self) + } +} diff --git a/00_Common/rust/crates/basic_input/src/lib.rs b/00_Common/rust/crates/basic_input/src/lib.rs new file mode 100644 index 000000000..8d14d9a5f --- /dev/null +++ b/00_Common/rust/crates/basic_input/src/lib.rs @@ -0,0 +1,42 @@ +//! A library for reading input from a basic program. +//! +//! In BASIC, you can have a statement like +//! ```basic +//! 10 INPUT "PROMPT";A$ +//! ``` +//! This crate emulates this with: +//! ```no_run +//! let a_value: String = basic_input::get_input("PROMPT"); +//! ``` +//! +//! BASIC also allows programmers to read multiple values at a time. For example, to +//! read two numbers, the program will have `INPUT "PROMPT";X1,Y1`. This can be done +//! in Rust with a tuple: +//! ```no_run +//! let (x1, y1): (f32, f32) = basic_input::get_input("Enter coordinates"); +//! ``` +//! The code will automatically re-prompt if the user doesn't enter all the values. +//! +//! Guided by the README.md under 00_Common, we know that there are `INPUT` statements +//! in the various games which ask for +//! +//! * 1 or 2 strings, +//! * 1-4 floating-point numbers, or 10(!) floating-point numbers +//! +//! and there are no other kinds of input required. All of these have been accounted +//! for in the `input` module (see `impl BasicInput for `) but they are easy +//! enough to extend/enhance for different kinds of input. +//! +//! To use this in your Rust code, you can reference the local crate by adding the +//! following line to your `Cargo.toml`: +//! +//! ```toml +//! basic_input = { path = "../../00_Common/rust/crates/basic_input" } +//! ``` +//! +//! (adjust the number of `../` for the depth of your own subdirectory) + +pub mod input; +mod parse; + +pub use input::*; diff --git a/00_Common/rust/crates/basic_input/src/parse.rs b/00_Common/rust/crates/basic_input/src/parse.rs new file mode 100644 index 000000000..fa2ac9eff --- /dev/null +++ b/00_Common/rust/crates/basic_input/src/parse.rs @@ -0,0 +1,85 @@ +pub(crate) fn parse>(buffer: B) -> Vec { + let mut result = Vec::new(); + let mut in_quote = false; + let mut need_comma = false; + + let mut current = String::new(); + for ch in buffer.as_ref().chars() { + match (ch, in_quote) { + (',', false) => { + result.push(current.trim().to_string()); + current.clear(); + } + ('"', true) => { + need_comma = true; + result.push(current.trim().to_string()); + current.clear(); + } + ('"', false) => { + in_quote = true; + } + + (',', true) if need_comma => { + need_comma = false; + in_quote = false; + } + (',', true) => current.push(ch), + + _ => { + current.push(ch); + } + } + } + if !current.is_empty() { + result.push(current.trim().to_string()); + } + + result +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parse_single_value() { + let result = parse("123"); + assert_eq!("123".to_string(), result[0]); + assert_eq!(1, result.len()); + } + + #[test] + fn parse_two_values() { + let result = parse("123, 456"); + assert_eq!("123".to_string(), result[0]); + assert_eq!("456".to_string(), result[1]); + assert_eq!(2, result.len()); + } + + #[test] + fn parse_quoted_value() { + let result = parse("123, \"456,789\", 10"); + assert_eq!("123".to_string(), result[0]); + assert_eq!("456,789".to_string(), result[1]); + assert_eq!("10".to_string(), result[2]); + assert_eq!(3, result.len()); + } + + #[test] + fn parse_missing_closing_quote() { + let result = parse("123, \"456,789, 10"); + assert_eq!("123".to_string(), result[0]); + assert_eq!("456,789, 10".to_string(), result[1]); + assert_eq!(2, result.len()); + } + + #[test] + fn parse_quoted_value_twice() { + let result = parse("123, \"456,789\", 10, 11"); + assert_eq!("123".to_string(), result[0]); + assert_eq!("456,789".to_string(), result[1]); + assert_eq!("10".to_string(), result[2]); + assert_eq!("11".to_string(), result[3]); + assert_eq!(4, result.len()); + } +} From 96d5c3d2cb9bb6380e1e71454a275bb38bc60541 Mon Sep 17 00:00:00 2001 From: aconconi Date: Mon, 27 Apr 2026 11:48:48 +0200 Subject: [PATCH 369/377] Fix dealer weak-hand logic and schmaltz discard count to match original BASIC --- 71_Poker/python/players/dealer.py | 16 ++-- 71_Poker/python/pokerhand/evaluation.py | 97 +++++++++++++------------ 2 files changed, 59 insertions(+), 54 deletions(-) diff --git a/71_Poker/python/players/dealer.py b/71_Poker/python/players/dealer.py index 0467f4add..71068f058 100644 --- a/71_Poker/python/players/dealer.py +++ b/71_Poker/python/players/dealer.py @@ -3,7 +3,7 @@ import random from enum import Enum, auto -from cards import Deck +from cards import CardRank, Deck from pokerhand import Hand, HandEvaluation, HandRank from .player import Player @@ -60,13 +60,13 @@ def decide_postdraw_bet(self) -> None: def _is_hand_weak(self, result: HandEvaluation, is_redeal: bool) -> bool: """Check whether the hand qualifies as 'weak'.""" - # Original logic: IF Z>5 THEN Weak. - # HandRank 1-4 are Schmaltz, Partial Straight, Pair, Two-Pair. - if result.hand_rank < HandRank.THREE_OF_A_KIND: - # Partial Straight is only weak on re-evaluation - if result.hand_rank == HandRank.PARTIAL_STRAIGHT: - return is_redeal - return True + rank = result.hand_rank + if rank < HandRank.PAIR: + # Schmaltz is always weak; partial straight only on re-deal + return rank != HandRank.PARTIAL_STRAIGHT or is_redeal + if rank <= HandRank.TWO_PAIR: + # Pair/two-pair is weak only when high card is Eight or lower + return result.high_card.rank <= CardRank.EIGHT return False def get_opening_action(self) -> Player.Action: diff --git a/71_Poker/python/pokerhand/evaluation.py b/71_Poker/python/pokerhand/evaluation.py index feedaf0e8..121213812 100644 --- a/71_Poker/python/pokerhand/evaluation.py +++ b/71_Poker/python/pokerhand/evaluation.py @@ -25,10 +25,12 @@ class HandEvaluation: hand_rank: HandRank high_card: Card discard_indices: list[int] + _ctx: "_EvaluationContext | None" def __init__(self, hand: "Hand"): """Perform evaluation of the provided hand.""" self.discard_indices = [] + self._ctx = None self._evaluate(hand) def __str__(self) -> str: @@ -68,6 +70,9 @@ def __eq__(self, other: object) -> bool: other.high_card.rank.value, ) + def __hash__(self) -> int: + return hash((self.hand_rank, self.high_card.rank.value)) + class _EvaluationContext: # pylint: disable=too-few-public-methods """Intermediate calculations for hand evaluation.""" @@ -92,9 +97,9 @@ def __init__(self, hand: "Hand"): def _evaluate(self, hand: "Hand") -> None: """Internal algorithm to determine hand strength.""" - ctx = self._EvaluationContext(hand) + self._ctx = self._EvaluationContext(hand) - checks: list[Callable[[HandEvaluation._EvaluationContext], bool]] = [ + checks: list[Callable[[], bool]] = [ self._check_four_of_a_kind, self._check_full_house, self._check_flush, @@ -107,104 +112,104 @@ def _evaluate(self, hand: "Hand") -> None: ] for check in checks: - if check(ctx): + if check(): break - def _check_four_of_a_kind(self, ctx: _EvaluationContext) -> bool: - if ctx.freq_pattern != (4, 1): + def _check_four_of_a_kind(self) -> bool: + if self._ctx.freq_pattern != (4, 1): return False self.hand_rank = HandRank.FOUR_OF_A_KIND self.high_card = next( c - for _, c in reversed(ctx.rank_indexed) - if c.rank == ctx.ranks_by_freq[0] + for _, c in reversed(self._ctx.rank_indexed) + if c.rank == self._ctx.ranks_by_freq[0] ) return True - def _check_full_house(self, ctx: _EvaluationContext) -> bool: - if ctx.freq_pattern != (3, 2): + def _check_full_house(self) -> bool: + if self._ctx.freq_pattern != (3, 2): return False self.hand_rank = HandRank.FULL_HOUSE self.high_card = next( c - for _, c in reversed(ctx.rank_indexed) - if c.rank == ctx.ranks_by_freq[0] + for _, c in reversed(self._ctx.rank_indexed) + if c.rank == self._ctx.ranks_by_freq[0] ) return True - def _check_flush(self, ctx: _EvaluationContext) -> bool: - if len({c.suit for c in ctx.cards}) != 1: + def _check_flush(self) -> bool: + if len({c.suit for c in self._ctx.cards}) != 1: return False self.hand_rank = HandRank.FLUSH - self.high_card = max(ctx.cards, key=lambda c: c.rank) + self.high_card = self._ctx.rank_indexed[4][1] return True - def _check_straight(self, ctx: _EvaluationContext) -> bool: + def _check_straight(self) -> bool: if ( - len(set(ctx.sorted_ranks)) == 5 - and ctx.sorted_ranks[4].value - ctx.sorted_ranks[0].value == 4 + len(set(self._ctx.sorted_ranks)) == 5 + and self._ctx.sorted_ranks[4].value - self._ctx.sorted_ranks[0].value == 4 ): self.hand_rank = HandRank.STRAIGHT - self.high_card = ctx.rank_indexed[4][1] + self.high_card = self._ctx.rank_indexed[4][1] return True return False - def _check_three_of_a_kind(self, ctx: _EvaluationContext) -> bool: - if ctx.freq_pattern != (3, 1, 1): + def _check_three_of_a_kind(self) -> bool: + if self._ctx.freq_pattern != (3, 1, 1): return False self.hand_rank = HandRank.THREE_OF_A_KIND self.high_card = next( c - for _, c in reversed(ctx.rank_indexed) - if c.rank == ctx.ranks_by_freq[0] + for _, c in reversed(self._ctx.rank_indexed) + if c.rank == self._ctx.ranks_by_freq[0] ) - keep_rank = ctx.ranks_by_freq[0] - self.discard_indices = [i for i, c in enumerate(ctx.cards) if c.rank != keep_rank] + keep_rank = self._ctx.ranks_by_freq[0] + self.discard_indices = [i for i, c in enumerate(self._ctx.cards) if c.rank != keep_rank] return True - def _check_two_pair(self, ctx: _EvaluationContext) -> bool: - if ctx.freq_pattern != (2, 2, 1): + def _check_two_pair(self) -> bool: + if self._ctx.freq_pattern != (2, 2, 1): return False self.hand_rank = HandRank.TWO_PAIR self.high_card = next( c - for _, c in reversed(ctx.rank_indexed) - if c.rank == ctx.ranks_by_freq[0] + for _, c in reversed(self._ctx.rank_indexed) + if c.rank == self._ctx.ranks_by_freq[0] ) - keep = {ctx.ranks_by_freq[0], ctx.ranks_by_freq[1]} + keep = {self._ctx.ranks_by_freq[0], self._ctx.ranks_by_freq[1]} self.discard_indices = [ - i for i, c in enumerate(ctx.cards) if c.rank not in keep + i for i, c in enumerate(self._ctx.cards) if c.rank not in keep ] return True - def _check_pair(self, ctx: _EvaluationContext) -> bool: - if ctx.freq_pattern != (2, 1, 1, 1): + def _check_pair(self) -> bool: + if self._ctx.freq_pattern != (2, 1, 1, 1): return False self.hand_rank = HandRank.PAIR self.high_card = next( c - for _, c in reversed(ctx.rank_indexed) - if c.rank == ctx.ranks_by_freq[0] + for _, c in reversed(self._ctx.rank_indexed) + if c.rank == self._ctx.ranks_by_freq[0] ) - keep_rank = ctx.ranks_by_freq[0] - self.discard_indices = [i for i, c in enumerate(ctx.cards) if c.rank != keep_rank] + keep_rank = self._ctx.ranks_by_freq[0] + self.discard_indices = [i for i, c in enumerate(self._ctx.cards) if c.rank != keep_rank] return True - def _check_partial_straight(self, ctx: _EvaluationContext) -> bool: - if ctx.sorted_ranks[3].value - ctx.sorted_ranks[0].value == 3: + def _check_partial_straight(self) -> bool: + if self._ctx.sorted_ranks[3].value - self._ctx.sorted_ranks[0].value == 3: self.hand_rank = HandRank.PARTIAL_STRAIGHT - self.high_card = ctx.rank_indexed[3][1] - self.discard_indices = [ctx.rank_indexed[4][0]] + self.high_card = self._ctx.rank_indexed[3][1] + self.discard_indices = [self._ctx.rank_indexed[4][0]] return True - if ctx.sorted_ranks[4].value - ctx.sorted_ranks[1].value == 3: + if self._ctx.sorted_ranks[4].value - self._ctx.sorted_ranks[1].value == 3: self.hand_rank = HandRank.PARTIAL_STRAIGHT - self.high_card = ctx.rank_indexed[4][1] - self.discard_indices = [ctx.rank_indexed[0][0]] + self.high_card = self._ctx.rank_indexed[4][1] + self.discard_indices = [self._ctx.rank_indexed[0][0]] return True return False - def _check_schmaltz(self, ctx: _EvaluationContext) -> bool: + def _check_schmaltz(self) -> bool: self.hand_rank = HandRank.SCHMALTZ - self.high_card = ctx.rank_indexed[4][1] - self.discard_indices = [idx for idx, _ in ctx.rank_indexed[0:4]] + self.high_card = self._ctx.rank_indexed[4][1] + self.discard_indices = [idx for idx, _ in self._ctx.rank_indexed[0:3]] return True From 5238435d5a46b3f775bd5a9830ed7726ad5e58cd Mon Sep 17 00:00:00 2001 From: astynax Date: Thu, 4 Jun 2026 08:27:46 +0400 Subject: [PATCH 370/377] fix(84_Super_Star_Trek/rust): non-integer torpedo courses --- 84_Super_Star_Trek/rust/src/commands.rs | 38 ++++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index c1c4bc8d4..52f8d59cc 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -529,15 +529,39 @@ fn find_torpedo_path(start_sector: Pos, course: f32) -> Vec { let mut last_sector = start_sector; let mut path = Vec::new(); + let mut nx = last_sector.0 as f32; + let mut ny = last_sector.1 as f32; + loop { - let nx = (last_sector.0 as f32 + dx) as i8; - let ny = (last_sector.1 as f32 + dy) as i8; - if nx < 0 || ny < 0 || nx >= 8 || ny >= 8 { + nx += dx; + ny += dy; + if nx < 0.0 || ny < 0.0 || nx >= 8.0 || ny >= 8.0 { break; } - last_sector = Pos(nx as u8, ny as u8); - path.push(last_sector); + let step = Pos(nx as u8, ny as u8); + if step != last_sector { + last_sector = step; + path.push(last_sector); + } } - + path -} \ No newline at end of file +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_find_torpedo_path() { + let path = find_torpedo_path(Pos(0, 0), 7.5); + assert_eq!( + *path.last().unwrap(), + Pos(7, 3), + ); + assert_eq!( + path, + vec!(Pos(1, 0), Pos(2, 1), Pos(3, 1), Pos(4, 2), Pos(5, 2), Pos(6, 3), Pos(7, 3)) + ); + } +} From 4da5ce3ae6581fc972226c1a6ecf6f7ac2e1d77f Mon Sep 17 00:00:00 2001 From: astynax Date: Fri, 5 Jun 2026 10:28:00 +0400 Subject: [PATCH 371/377] round the torpedo coords properly, add a fuzzy test --- 84_Super_Star_Trek/rust/src/commands.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs index 52f8d59cc..599327cac 100644 --- a/84_Super_Star_Trek/rust/src/commands.rs +++ b/84_Super_Star_Trek/rust/src/commands.rs @@ -538,7 +538,7 @@ fn find_torpedo_path(start_sector: Pos, course: f32) -> Vec { if nx < 0.0 || ny < 0.0 || nx >= 8.0 || ny >= 8.0 { break; } - let step = Pos(nx as u8, ny as u8); + let step = Pos(nx.round() as u8, ny.round() as u8); if step != last_sector { last_sector = step; path.push(last_sector); @@ -554,7 +554,7 @@ mod tests { #[test] fn test_find_torpedo_path() { - let path = find_torpedo_path(Pos(0, 0), 7.5); + let path = find_torpedo_path(Pos(0, 0), 7.45); assert_eq!( *path.last().unwrap(), Pos(7, 3), @@ -563,5 +563,22 @@ mod tests { path, vec!(Pos(1, 0), Pos(2, 1), Pos(3, 1), Pos(4, 2), Pos(5, 2), Pos(6, 3), Pos(7, 3)) ); + + assert_eq!( + find_torpedo_path(Pos(4, 7), 4.5), + vec!(Pos(4, 6), Pos(3, 5), Pos(3, 4), Pos(2, 3), Pos(2, 2), Pos(1, 1), Pos(1, 0)) + ); + + let enterprise = Pos(3, 3); + for y in 0..=7 { + for x in 0..=7 { + let pos = Pos(y, x); + if pos != enterprise { + let course = enterprise.direction(pos); + let path = find_torpedo_path(enterprise, course); + assert!(path.contains(&pos)); + }; + }; + }; } } From b0ff7ef65bc0626c8305bb90fe2947ad46c7fa40 Mon Sep 17 00:00:00 2001 From: aconconi Date: Wed, 24 Jun 2026 11:43:41 +0200 Subject: [PATCH 372/377] Fixed initialization of EvaluationContext --- 71_Poker/python/pokerhand/evaluation.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/71_Poker/python/pokerhand/evaluation.py b/71_Poker/python/pokerhand/evaluation.py index 121213812..2f43658e1 100644 --- a/71_Poker/python/pokerhand/evaluation.py +++ b/71_Poker/python/pokerhand/evaluation.py @@ -25,12 +25,11 @@ class HandEvaluation: hand_rank: HandRank high_card: Card discard_indices: list[int] - _ctx: "_EvaluationContext | None" + _ctx: "_EvaluationContext" def __init__(self, hand: "Hand"): """Perform evaluation of the provided hand.""" self.discard_indices = [] - self._ctx = None self._evaluate(hand) def __str__(self) -> str: From d6347f282601facdc0f4e5a66140cb27f769c1ba Mon Sep 17 00:00:00 2001 From: aconconi Date: Wed, 24 Jun 2026 11:51:39 +0200 Subject: [PATCH 373/377] removed match statement not supported by build pipeline --- 71_Poker/python/pokerhand/evaluation.py | 54 +++++++++++++++---------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/71_Poker/python/pokerhand/evaluation.py b/71_Poker/python/pokerhand/evaluation.py index 2f43658e1..6c4693274 100644 --- a/71_Poker/python/pokerhand/evaluation.py +++ b/71_Poker/python/pokerhand/evaluation.py @@ -36,23 +36,21 @@ def __str__(self) -> str: rank = self.hand_rank card = self.high_card - match rank: - case HandRank.SCHMALTZ | HandRank.PARTIAL_STRAIGHT: - return f"{rank}, {card.rank} high" - case ( - HandRank.PAIR - | HandRank.TWO_PAIR - | HandRank.THREE_OF_A_KIND - | HandRank.FULL_HOUSE - | HandRank.FOUR_OF_A_KIND - ): - return f"{rank} {card.rank}'s" - case HandRank.STRAIGHT: - return f"{rank}, {card.rank} high" - case HandRank.FLUSH: - return f"{rank} {card.suit}" - case _: - return f"{rank} {card.rank}" + if rank in (HandRank.SCHMALTZ, HandRank.PARTIAL_STRAIGHT): + return f"{rank}, {card.rank} high" + if rank in ( + HandRank.PAIR, + HandRank.TWO_PAIR, + HandRank.THREE_OF_A_KIND, + HandRank.FULL_HOUSE, + HandRank.FOUR_OF_A_KIND, + ): + return f"{rank} {card.rank}'s" + if rank == HandRank.STRAIGHT: + return f"{rank}, {card.rank} high" + if rank == HandRank.FLUSH: + return f"{rank} {card.suit}" + return f"{rank} {card.rank}" def __lt__(self, other: "HandEvaluation") -> bool: return (self.hand_rank, self.high_card.rank.value) < ( @@ -146,7 +144,9 @@ def _check_flush(self) -> bool: def _check_straight(self) -> bool: if ( len(set(self._ctx.sorted_ranks)) == 5 - and self._ctx.sorted_ranks[4].value - self._ctx.sorted_ranks[0].value == 4 + and self._ctx.sorted_ranks[4].value + - self._ctx.sorted_ranks[0].value + == 4 ): self.hand_rank = HandRank.STRAIGHT self.high_card = self._ctx.rank_indexed[4][1] @@ -163,7 +163,9 @@ def _check_three_of_a_kind(self) -> bool: if c.rank == self._ctx.ranks_by_freq[0] ) keep_rank = self._ctx.ranks_by_freq[0] - self.discard_indices = [i for i, c in enumerate(self._ctx.cards) if c.rank != keep_rank] + self.discard_indices = [ + i for i, c in enumerate(self._ctx.cards) if c.rank != keep_rank + ] return True def _check_two_pair(self) -> bool: @@ -191,16 +193,24 @@ def _check_pair(self) -> bool: if c.rank == self._ctx.ranks_by_freq[0] ) keep_rank = self._ctx.ranks_by_freq[0] - self.discard_indices = [i for i, c in enumerate(self._ctx.cards) if c.rank != keep_rank] + self.discard_indices = [ + i for i, c in enumerate(self._ctx.cards) if c.rank != keep_rank + ] return True def _check_partial_straight(self) -> bool: - if self._ctx.sorted_ranks[3].value - self._ctx.sorted_ranks[0].value == 3: + if ( + self._ctx.sorted_ranks[3].value - self._ctx.sorted_ranks[0].value + == 3 + ): self.hand_rank = HandRank.PARTIAL_STRAIGHT self.high_card = self._ctx.rank_indexed[3][1] self.discard_indices = [self._ctx.rank_indexed[4][0]] return True - if self._ctx.sorted_ranks[4].value - self._ctx.sorted_ranks[1].value == 3: + if ( + self._ctx.sorted_ranks[4].value - self._ctx.sorted_ranks[1].value + == 3 + ): self.hand_rank = HandRank.PARTIAL_STRAIGHT self.high_card = self._ctx.rank_indexed[4][1] self.discard_indices = [self._ctx.rank_indexed[0][0]] From 46dd015ebd0df8a19cd03382c5343a010a1bb7f3 Mon Sep 17 00:00:00 2001 From: aconconi Date: Wed, 24 Jun 2026 11:55:22 +0200 Subject: [PATCH 374/377] removed match statement not supported by build pipeline --- 71_Poker/python/game.py | 75 ++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/71_Poker/python/game.py b/71_Poker/python/game.py index 68b42331a..be848ec36 100644 --- a/71_Poker/python/game.py +++ b/71_Poker/python/game.py @@ -137,32 +137,31 @@ def _conduct_betting_round(self, post_draw: bool) -> bool: while True: human_action = self._get_human_action() - match human_action: - case Player.Action.FOLD: - # Human fold always ends betting loop (hand ends) - self._settle_bets() - self._award_pot(dealer_wins=True) - return False - - case Player.Action.CALL: - # Human call always ends betting loop (proceed to next phase) - self._settle_bets() - return True + if human_action == Player.Action.FOLD: + # Human fold always ends betting loop (hand ends) + self._settle_bets() + self._award_pot(dealer_wins=True) + return False + + if human_action == Player.Action.CALL: + # Human call always ends betting loop (proceed to next phase) + self._settle_bets() + return True - case Player.Action.CHECK: - # Pre-draw: human check ends human's turn. - # Post-draw: dealer gets a chance to bet/check back. - if not post_draw or self._handle_human_post_draw_check(): - return True - # If dealer bet, we fall through and loop for human response + if human_action == Player.Action.CHECK: + # Pre-draw: human check ends human's turn. + # Post-draw: dealer gets a chance to bet/check back. + if not post_draw or self._handle_human_post_draw_check(): + return True + # If dealer bet, we fall through and loop for human response - case Player.Action.RAISE: - if self._handle_human_raise(): - return True - # If dealer re-raised, we fall through and loop for human response + elif human_action == Player.Action.RAISE: + if self._handle_human_raise(): + return True + # If dealer re-raised, we fall through and loop for human response - case _: - raise ValueError(f"Unknown player action: {human_action}") + else: + raise ValueError(f"Unknown player action: {human_action}") def _handle_human_post_draw_check(self) -> bool: """Process dealer response to human check. Returns True if phase ends.""" @@ -184,25 +183,23 @@ def _handle_human_raise(self) -> bool: if self.dealer.money < self.dealer.bet: self._dealer_try_raise_funds() - match dealer_action: - case Player.Action.FOLD: - print("I fold.") - self._settle_bets() - self._award_pot(dealer_wins=False) - return True # Round ends + if dealer_action == Player.Action.FOLD: + print("I fold.") + self._settle_bets() + self._award_pot(dealer_wins=False) + return True # Round ends - case Player.Action.CALL: - print("I'll see you.") - self._settle_bets() - return True + if dealer_action == Player.Action.CALL: + print("I'll see you.") + self._settle_bets() + return True - case Player.Action.RAISE: - raise_amount = self.dealer.bet - self.human.bet - print(f"I'll see you, and raise you {raise_amount}") - return False + if dealer_action == Player.Action.RAISE: + raise_amount = self.dealer.bet - self.human.bet + print(f"I'll see you, and raise you {raise_amount}") + return False - case _: - raise ValueError(f"Unknown dealer action: {dealer_action}") + raise ValueError(f"Unknown dealer action: {dealer_action}") def _get_human_action(self) -> Player.Action: """Prompt user for a bet and return the resulting Action.""" From 98637a16c2375d50c716cd6e021a3a0523e70288 Mon Sep 17 00:00:00 2001 From: Hamed Mahmoudkhani Date: Wed, 5 Aug 2026 00:45:52 +0200 Subject: [PATCH 375/377] feat: added rust implementation of Basketball --- 07_Basketball/rust/Cargo.lock | 77 ++++++ 07_Basketball/rust/Cargo.toml | 7 + 07_Basketball/rust/src/main.rs | 444 +++++++++++++++++++++++++++++++++ README.md | 2 +- 4 files changed, 529 insertions(+), 1 deletion(-) create mode 100644 07_Basketball/rust/Cargo.lock create mode 100644 07_Basketball/rust/Cargo.toml create mode 100644 07_Basketball/rust/src/main.rs diff --git a/07_Basketball/rust/Cargo.lock b/07_Basketball/rust/Cargo.lock new file mode 100644 index 000000000..5d92a1cf5 --- /dev/null +++ b/07_Basketball/rust/Cargo.lock @@ -0,0 +1,77 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "basketball" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" diff --git a/07_Basketball/rust/Cargo.toml b/07_Basketball/rust/Cargo.toml new file mode 100644 index 000000000..3a4c7c80b --- /dev/null +++ b/07_Basketball/rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "basketball" +version = "0.1.0" +edition = "2024" + +[dependencies] +rand = "0.10.0" diff --git a/07_Basketball/rust/src/main.rs b/07_Basketball/rust/src/main.rs new file mode 100644 index 000000000..ca0d6792d --- /dev/null +++ b/07_Basketball/rust/src/main.rs @@ -0,0 +1,444 @@ +use rand::{RngExt, rngs::ThreadRng}; +use std::io::{self, Write}; + +fn main() { + println!("{:>30}BASKETBALL", ""); + println!("{:>15}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY", ""); + println!("\n\n"); + + println!("THIS IS DARTMOUTH COLLEGE BASKETBALL. YOU WILL BE DARTMOUTH"); + println!(" CAPTAIN AND PLAYMAKER. CALL SHOTS AS FOLLOWS: 1. LONG"); + println!(" (30 FT.) JUMP SHOT; 2. SHORT (15 FT.) JUMP SHOT; 3. LAY"); + println!(" UP; 4. SET SHOT."); + println!("BOTH TEAMS WILL USE THE SAME DEFENSE. CALL DEFENSE AS"); + println!("FOLLOWS: 6. PRESS; 6.5 MAN-TO MAN; 7. ZONE; 7.5 NONE."); + println!("TO CHANGE DEFENSE, JUST TYPE 0 AS YOUR NEXT SHOT."); + + let mut game = BasketballGame::new(); + game.play(); +} + +struct BasketballGame { + rng: ThreadRng, + // D is the defensive alignment. It is one of 6, 6.5, 7 or 7.5 (but the + // original code only validates that D >= 6). + defense: f64, + // The opponent's name. + opponent: String, + // Game clock. Incremented on most possessions; 50 ends the first half, + // 92 triggers the two-minute warning and 100 forces overtime or the + // final whistle. + time: i32, + // Score: index 0 is the opponent, index 1 is Dartmouth. + score: [i32; 2], +} + +impl BasketballGame { + fn new() -> Self { + let rng = rand::rng(); + + // Line 76: prompt for the starting defense. The original accepts any + // value >= 6, so we replicate that rather than restricting to the + // documented options. + let defense = loop { + print!("YOUR STARTING DEFENSE WILL BE"); + let d: f64 = read_input(); + if d >= 6.0 { + break d; + } + // BASIC line 76 falls through to 2010 which re-prompts for the + // defensive alignment; reproducing that behaviour here. + }; + println!(); + + print!("CHOOSE YOUR OPPONENT"); + let opponent = read_line().trim().to_string(); + + Self { + rng, + defense, + opponent, + time: 0, + score: [0, 0], + } + } + + fn play(&mut self) { + // Line 370: center jump to open each half/overtime period. + self.center_jump(); + } + + /// Line 370-420: simulates the center jump that starts each period. + fn center_jump(&mut self) { + println!("CENTER JUMP"); + if self.rng.random::() > 3.0 / 5.0 { + println!("DARTMOUTH CONTROLS THE TAP."); + println!(); + self.dartmouth_possession(); + } else { + println!("{} CONTROLS THE TAP.", self.opponent); + self.opponent_possession(); + } + } + + /// Lines 425-500: Dartmouth has the ball and asks the player for a shot. + fn dartmouth_possession(&mut self) { + let z = self.read_shot(); + // Line 460: half the time, when the clock has run out, we go to the + // end-of-game / overtime logic instead of resolving the shot. + if self.rng.random::() < 0.5 && self.time >= 100 { + self.end_of_game_or_overtime(); + return; + } + + match z { + 1 | 2 => self.dartmouth_jump_shot(), + _ => self.dartmouth_non_jump_shot(z), + } + } + + /// Line 430-455: read and validate the player's shot choice. + fn read_shot(&mut self) -> i32 { + loop { + print!("YOUR SHOT"); + let line = read_line(); + match line.trim().parse::() { + Ok(z) if (0..=4).contains(&z) => return z, + _ => print!("INCORRECT ANSWER. RETYPE IT. "), + } + } + } + + /// Lines 1040-1280: long or short jump shot for Dartmouth. + fn dartmouth_jump_shot(&mut self) { + self.advance_clock_with_two_minute_warning(); + println!("JUMP SHOT"); + + if self.rng.random::() <= 0.341 * self.defense / 8.0 { + println!("SHOT IS GOOD."); + self.add_dartmouth_score(); + self.opponent_possession(); + return; + } + if self.rng.random::() <= 0.682 * self.defense / 8.0 { + println!("SHOT IS OFF TARGET."); + if self.defense / 6.0 * self.rng.random::() > 0.45 { + println!("REBOUND TO {}", self.opponent); + self.opponent_possession(); + } else { + println!("DARTMOUTH CONTROLS THE REBOUND."); + if self.rng.random::() <= 0.4 { + println!(); + self.dartmouth_non_jump_shot(3); + } else if self.defense == 6.0 && self.rng.random::() > 0.6 { + // Line 5100-5130: pass stolen, easy lay-up for opponent. + println!("PASS STOLEN BY {} EASY LAYUP.", self.opponent); + self.add_opponent_score(); + self.dartmouth_possession(); + } else { + print!("BALL PASSED BACK TO YOU. "); + self.dartmouth_possession(); + } + } + return; + } + if self.rng.random::() <= 0.782 * self.defense / 8.0 { + print!("SHOT IS BLOCKED. BALL CONTROLLED BY "); + if self.rng.random::() > 0.5 { + println!("DARTMOUTH."); + self.dartmouth_possession(); + } else { + println!("{}.", self.opponent); + self.opponent_possession(); + } + return; + } + if self.rng.random::() <= 0.843 * self.defense / 8.0 { + println!("SHOOTER IS FOULED. TWO SHOTS."); + self.foul_shots(1); + self.opponent_possession(); + return; + } + println!("CHARGING FOUL. DARTMOUTH LOSES BALL."); + self.opponent_possession(); + } + + /// Lines 1300-1700: lay up (3) or set shot (4); also re-entered for a + /// rebound put-back. A shot value of 0 means the player wants to change + /// the defensive alignment (lines 2010-2040). + fn dartmouth_non_jump_shot(&mut self, z: i32) { + self.advance_clock_with_two_minute_warning(); + + if z == 0 { + self.change_defense(); + return; + } + + if z == 4 { + println!("SET SHOT."); + } else { + println!("LAY UP."); + } + + if 7.0 / self.defense * self.rng.random::() <= 0.4 { + println!("SHOT IS GOOD. TWO POINTS."); + self.add_dartmouth_score(); + self.opponent_possession(); + return; + } + if 7.0 / self.defense * self.rng.random::() <= 0.7 { + println!("SHOT IS OFF THE RIM."); + if self.rng.random::() > 2.0 / 3.0 { + println!("DARTMOUTH CONTROLS THE REBOUND."); + if self.rng.random::() > 0.4 { + println!("BALL PASSED BACK TO YOU."); + self.dartmouth_possession(); + } else { + self.dartmouth_non_jump_shot(3); + } + } else { + println!("{} CONTROLS THE REBOUND.", self.opponent); + self.opponent_possession(); + } + return; + } + if 7.0 / self.defense * self.rng.random::() <= 0.875 { + println!("SHOOTER FOULED. TWO SHOTS."); + self.foul_shots(1); + self.opponent_possession(); + return; + } + if 7.0 / self.defense * self.rng.random::() <= 0.925 { + println!("SHOT BLOCKED. {}'S BALL.", self.opponent); + self.opponent_possession(); + return; + } + println!("CHARGING FOUL. DARTMOUTH LOSES THE BALL."); + self.opponent_possession(); + } + + /// Lines 2010-2040: change the defensive alignment. Any value >= 6 is + /// accepted, matching the original (unvalidated) behaviour. + fn change_defense(&mut self) { + loop { + print!("YOUR NEW DEFENSIVE ALLIGNMENT IS"); + let d: f64 = read_input(); + if d >= 6.0 { + self.defense = d; + break; + } + } + self.dartmouth_possession(); + } + + /// Lines 3000-3810: opponent has the ball. Picks a shot type at random. + fn opponent_possession(&mut self) { + self.advance_clock(); + + let z1 = 10.0 / 4.0 * self.rng.random::() + 1.0; + if z1 > 2.0 { + self.opponent_non_jump_shot(z1); + } else { + self.opponent_jump_shot(); + } + } + + /// Lines 3040-3310: opponent jump shot. + fn opponent_jump_shot(&mut self) { + println!("JUMP SHOT."); + if 8.0 / self.defense * self.rng.random::() <= 0.35 { + println!("SHOT IS GOOD."); + self.add_opponent_score(); + self.dartmouth_possession(); + return; + } + if 8.0 / self.defense * self.rng.random::() <= 0.75 { + println!("SHOT IS OFF RIM."); + if self.defense / 6.0 * self.rng.random::() > 0.5 { + println!("{} CONTROLS THE REBOUND.", self.opponent); + if self.defense == 6.0 && self.rng.random::() > 0.75 { + // Line 5000-5030: ball stolen, easy lay-up for Dartmouth. + println!("BALL STOLEN. EASY LAY UP FOR DARTMOUTH."); + self.add_dartmouth_score(); + self.opponent_possession(); + } else if self.rng.random::() > 0.5 { + println!("PASS BACK TO {} GUARD.", self.opponent); + self.opponent_possession(); + } else { + self.opponent_non_jump_shot(3.0); + } + } else { + println!("DARTMOUTH CONTROLS THE REBOUND."); + self.dartmouth_possession(); + } + return; + } + if 8.0 / self.defense * self.rng.random::() <= 0.9 { + println!("PLAYER FOULED. TWO SHOTS."); + self.foul_shots(0); + self.dartmouth_possession(); + return; + } + println!("OFFENSIVE FOUL. DARTMOUTH'S BALL."); + self.dartmouth_possession(); + } + + /// Lines 3500-3810: opponent lay up or set shot. `z1` carries the + /// randomly chosen shot type so the put-back message can be re-shown. + fn opponent_non_jump_shot(&mut self, z1: f64) { + if z1 > 3.0 { + println!("SET SHOT."); + } else { + println!("LAY UP"); + } + if 7.0 / self.defense * self.rng.random::() <= 0.413 { + println!("SHOT IS GOOD."); + self.add_opponent_score(); + self.dartmouth_possession(); + return; + } + println!("SHOT IS MISSED."); + if self.defense / 6.0 * self.rng.random::() > 0.5 { + println!("{} CONTROLS THE REBOUND.", self.opponent); + if self.defense == 6.0 && self.rng.random::() > 0.75 { + println!("BALL STOLEN. EASY LAY UP FOR DARTMOUTH."); + self.add_dartmouth_score(); + self.opponent_possession(); + } else if self.rng.random::() > 0.5 { + self.opponent_non_jump_shot(z1); + } else { + println!("PASS BACK TO {} GUARD.", self.opponent); + self.opponent_possession(); + } + } else { + println!("DARTMOUTH CONTROLS THE REBOUND."); + self.dartmouth_possession(); + } + } + + /// Lines 4000-4110: two foul shots. `team` is 0 for the opponent (points + /// added to Dartmouth's opponent) or 1 for Dartmouth (points added to + /// Dartmouth). + fn foul_shots(&mut self, team: usize) { + if self.rng.random::() <= 0.49 { + println!("SHOOTER MAKES BOTH SHOTS."); + self.score[1 - team] += 2; + self.print_score(); + } else if self.rng.random::() <= 0.75 { + println!("SHOOTER MAKES ONE SHOT AND MISSES ONE."); + self.score[1 - team] += 1; + self.print_score(); + } else { + println!("BOTH SHOTS MISSED."); + self.print_score(); + } + } + + /// Line 6010: prints the running score. + fn print_score(&self) { + println!("SCORE: {} TO {}", self.score[1], self.score[0]); + } + + /// Line 7000: Dartmouth scores two points, then prints the score. + fn add_dartmouth_score(&mut self) { + self.score[1] += 2; + self.print_score(); + } + + /// Line 6000: opponent scores two points, then prints the score. + fn add_opponent_score(&mut self) { + self.score[0] += 2; + self.print_score(); + } + + /// Lines 1041/1301/3008: advance the clock and handle the end-of-half + /// break at T == 50. + fn advance_clock(&mut self) { + self.time += 1; + if self.time == 50 { + self.end_of_first_half(); + } + } + + /// Lines 1042-1046 / 1302-1304 / 3012-3015: advance the clock, handle the + /// end-of-half break at T == 50 and the two-minute warning at T == 92. + fn advance_clock_with_two_minute_warning(&mut self) { + self.time += 1; + if self.time == 50 { + self.end_of_first_half(); + } + if self.time == 92 { + self.two_minute_warning(); + } + } + + /// Lines 610-620: two-minute warning message. + fn two_minute_warning(&self) { + println!(); + println!(" *** TWO MINUTES LEFT IN THE GAME ***"); + println!(); + } + + /// Lines 8000-8020: end of the first half, then re-jump to start the + /// second half. + fn end_of_first_half(&mut self) { + println!(); + println!(" ***** END OF FIRST HALF *****"); + println!(); + println!( + "SCORE: DARTMOUTH:{} {}:{}", + self.score[1], self.opponent, self.score[0] + ); + println!(); + println!(); + self.center_jump(); + } + + /// Lines 490-520: the clock has expired. Either start overtime (if the + /// game is tied) or end the game. + fn end_of_game_or_overtime(&mut self) { + println!(); + if self.score[1] != self.score[0] { + println!(" ***** END OF GAME *****"); + println!( + "FINAL SCORE: DARTMOUTH:{} {}:{}", + self.score[1], self.opponent, self.score[0] + ); + return; + } + + println!(); + println!(" ***** END OF SECOND HALF *****"); + println!(); + println!("SCORE AT END OF REGULATION TIME:"); + println!( + " DARTMOUTH:{} {}:{}", + self.score[1], self.opponent, self.score[0] + ); + println!(); + println!("BEGIN TWO MINUTE OVERTIME PERIOD"); + self.time = 93; + self.center_jump(); + } +} + +/// Reads a line of input, flushing stdout first so the prompt is visible. +fn read_line() -> String { + print!("? "); + let _ = io::stdout().flush(); + + let mut buffer = String::new(); + let _ = io::stdin().read_line(&mut buffer); + buffer +} + +/// Reads a line and parses it as the requested numeric type, re-prompting on +/// any parse failure. +fn read_input() -> T { + loop { + let line = read_line(); + if let Ok(value) = line.trim().parse::() { + return value; + } + } +} diff --git a/README.md b/README.md index 3b54d4471..adb144cb4 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 04_Awari | x | x | x | | | x | x | x | x | x | | 05_Bagels | x | x | x | x | x | x | x | x | x | x | | 06_Banner | x | x | x | | | x | x | x | x | x | -| 07_Basketball | x | x | x | | | x | x | x | | x | +| 07_Basketball | x | x | x | | | x | x | x | x | x | | 08_Batnum | x | x | x | | | x | x | x | x | x | | 09_Battle | x | x | x | | | | x | | x | x | | 10_Blackjack | x | x | x | | | | x | x | x | x | From 5b0e9849bf03e012264f4bb98924788792b70f54 Mon Sep 17 00:00:00 2001 From: Hamed Mahmoudkhani Date: Wed, 5 Aug 2026 01:14:53 +0200 Subject: [PATCH 376/377] feat: added rust implementation of Bowling --- 14_Bowling/rust/Cargo.lock | 77 +++++++++++++ 14_Bowling/rust/Cargo.toml | 7 ++ 14_Bowling/rust/src/main.rs | 213 ++++++++++++++++++++++++++++++++++++ README.md | 8 +- 4 files changed, 301 insertions(+), 4 deletions(-) create mode 100644 14_Bowling/rust/Cargo.lock create mode 100644 14_Bowling/rust/Cargo.toml create mode 100644 14_Bowling/rust/src/main.rs diff --git a/14_Bowling/rust/Cargo.lock b/14_Bowling/rust/Cargo.lock new file mode 100644 index 000000000..54f98ac40 --- /dev/null +++ b/14_Bowling/rust/Cargo.lock @@ -0,0 +1,77 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bowling" +version = "0.1.0" +dependencies = [ + "rand", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "rand_core", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" diff --git a/14_Bowling/rust/Cargo.toml b/14_Bowling/rust/Cargo.toml new file mode 100644 index 000000000..159e7f1f9 --- /dev/null +++ b/14_Bowling/rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "bowling" +version = "0.1.0" +edition = "2024" + +[dependencies] +rand = "0.10.0" diff --git a/14_Bowling/rust/src/main.rs b/14_Bowling/rust/src/main.rs new file mode 100644 index 000000000..0520cfca1 --- /dev/null +++ b/14_Bowling/rust/src/main.rs @@ -0,0 +1,213 @@ +//! Rust port of "Bowl" (14_Bowling) from _Basic Computer Games_ (1978). +use rand::{rngs::ThreadRng, RngExt}; +use std::io::{self, BufRead, Write}; + +/// Number of cells in the pin-accumulator array (`DIM C(15)` in BASIC). +const CELLS: usize = 15; +/// The first ten cells correspond to the ten real pins drawn on the diagram. +const PINS: usize = 10; + +fn main() { + println!("{:>34}BOWL", ""); + println!("{:>15}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY", ""); + println!("\n\n"); + + println!("WELCOME TO THE ALLEY"); + println!("BRING YOUR FRIENDS"); + println!("OKAY LET'S FIRST GET ACUUAINTED"); + println!(); + + let mut game = BowlingGame::new(); + loop { + let answer = prompt_line("THE INSTRUCTIONS (Y/N)"); + if answer.starts_with('Y') { + print_instructions(); + } else if answer.starts_with('N') { + // fall through to the game + } else { + continue; + } + + game.play(); + + let again = prompt_line("DO YOU WANT ANOTHER GAME"); + if !again.starts_with('Y') { + break; + } + } +} + +fn print_instructions() { + println!("THE GAME OF BOWLING TAKES MIND AND SKILL.DURING THE GAME"); + println!("THE COMPUTER WILL KEEP SCORE.YOU MAY COMPETE WITH"); + println!("OTHER PLAYERS[UP TO FOUR].YOU WILL BE PLAYING TEN FRAMES"); + println!("ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE"); + println!("PIN IS STANDING.AFTER THE GAME THE COMPUTER WILL SHOW YOUR"); + println!("SCORES ."); +} + +struct BowlingGame { + rng: ThreadRng, +} + +impl BowlingGame { + fn new() -> Self { + Self { rng: rand::rng() } + } + + /// Play one complete game (10 frames, all players), then print the scorecard. + fn play(&mut self) { + let players = loop { + // "FIRST OF ALL...HOW MANY ARE PLAYING" + let line = prompt_line("FIRST OF ALL...HOW MANY ARE PLAYING"); + if line.is_empty() { + // EOF on input — bail out of this game. + return; + } + if let Ok(n) = line.trim().parse::() { + if (1..=4).contains(&n) { + break n; + } + } + println!("?RE-ENTER"); + }; + + println!(); + println!("VERY GOOD..."); + + // One row per player: [ball1, ball2, status] for each of 10 frames. + let mut scores: Vec<[[u32; 3]; 10]> = (0..players).map(|_| [[0; 3]; 10]).collect(); + + for frame in 1..=10 { + for (player_idx, player_scores) in scores.iter_mut().enumerate() { + self.play_ball(frame, player_idx + 1, player_scores); + } + } + + print_scorecard(&scores); + } + + /// Roll the balls for one player in one frame, recording the result. + fn play_ball(&mut self, frame: usize, player: usize, scores: &mut [[u32; 3]; 10]) { + let mut prev_down = 0; // M: pins down after the previous ball this frame + let mut status = 0; // Q: 3 strike, 2 spare, 1 error, 0 otherwise + + let mut cells = [0u32; CELLS + 1]; + + for ball in 1..=2 { + // "TYPE ROLL TO GET THE BALL GOING." + let _ = prompt_line("TYPE ROLL TO GET THE BALL GOING"); + + // Knock down more pins: 20 random hits, each landing in cell + // (15*J - X) where J is the smallest bucket with X < 15*J. + self.roll_pins(&mut cells); + + // Draw the triangle diagram (only the first 10 cells are real pins). + print!("PLAYER:{} FRAME:{} BALL:{}\n", player, frame, ball); + print_pin_diagram(&cells); + + // Count pins down among the real pins (cells 1..=10). + let down = cells[1..=PINS].iter().filter(|&&c| c == 1).count() as u32; + + // Roll analysis. Order mirrors the original IF chain. + if down == prev_down { + println!("GUTTER!!"); + } + if ball == 1 && down == 10 { + println!("STRIKE!!!!!\x07\x07\x07\x07"); + status = 3; + } + if ball == 2 && down == 10 { + println!("SPARE!!!!"); + status = 2; + } + if ball == 2 && down < 10 { + println!("ERROR!!!"); + status = 1; + } + if ball == 1 && down < 10 { + println!("ROLL YOUR 2ND BALL"); + } + println!(); + + // Record the score for this ball: total pins down so far this frame. + scores[frame - 1][ball - 1] = down; + + if ball == 1 { + prev_down = down; + // On a strike, the frame ends; otherwise prompt the second ball. + if status == 3 { + scores[frame - 1][1] = 0; + break; + } + } + } + + scores[frame - 1][2] = status; + } + + fn roll_pins(&mut self, cells: &mut [u32]) { + for _ in 0..20 { + let x = (self.rng.random::() * 100.0) as usize; // INT(RND(1)*100) + // Find the smallest J in 1..=10 with x < 15*J. + let mut j = 1; + while j <= 10 && x >= 15 * j { + j += 1; + } + // j may exceed 10 if x >= 150 (impossible here since x < 100) — guard anyway. + if j <= 10 { + let idx = 15 * j - x; // 1..=15 + if idx >= 1 && idx <= CELLS { + cells[idx] = 1; + } + } + } + } +} + +/// Draw the standing/down pins as a triangle: '+' standing, 'O' down. +fn print_pin_diagram(cells: &[u32]) { + let mut k = 1; // pin index, 1-based (K in BASIC) + for i in 0..4 { + print!("{}", " ".repeat(i)); + for _ in 0..(4 - i) { + if cells[k] == 1 { + print!("O "); + } else { + print!("+ "); + } + k += 1; + } + println!(); + } + println!(); +} + +fn print_scorecard(scores: &[[[u32; 3]; 10]]) { + println!("FRAMES"); + for frame in 1..=10 { + print!("{} ", frame); + } + println!(); + for player_scores in scores { + for row in 0..3 { + for frame in 0..10 { + print!("{} ", player_scores[frame][row]); + } + println!(); + } + println!(); + } +} + +fn prompt_line(prompt: &str) -> String { + print!("{}? ", prompt); + let _ = io::stdout().lock().flush(); + + let mut buffer = String::new(); + // Treat EOF (or a read error) as an empty line so callers can decide what + // to do — for this game, an empty answer never matches Y/N, so the program + // simply exits its current loop instead of spinning forever on EOF. + let _ = io::stdin().lock().read_line(&mut buffer); + buffer.trim().to_uppercase() +} diff --git a/README.md b/README.md index 3b54d4471..dc3936e9a 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ I have moved all [the original BASIC source code](http://www.vintage-basic.net/g Each project has subfolders corresponding to the languages we’d like to see the games ported to. This is based on the [2022 TIOBE index of top languages](https://www.tiobe.com/tiobe-index/) that are _**memory safe**_ and _**general purpose scripting languages**_ per [this post](https://discourse.codinghorror.com/t/-/7927/34): -1. C# +1. C# 2. Java 3. JavaScript 4. Kotlin @@ -40,7 +40,7 @@ If you wish to port one of the programs to a language not in our list – that i Feel free to begin converting these classic games into the above list of modern, memory safe languages. In fact, courtesy of @mojoaxel, you can even view the JavaScript versions in your web browser at -https://coding-horror.github.io/basic-computer-games/ + But first, a few guidelines: @@ -66,7 +66,7 @@ We want the general behavior of the original programs to be preserved, _however_ Please note that on the back of the Basic Computer Games book it says **Microsoft 8K Basic, Rev 4.0 was the version David Ahl used to test**, so that is the level of compatibility we are looking for.  QBasic on the DOS emulation is a later version of Basic but one that retains downwards compatibility so far in our testing. To verify behavior, try [running the programs in your browser](https://troypress.com/wp-content/uploads/user/js-basic/index.html) with [JS BASIC, effectively Applesoft BASIC](https://github.com/inexorabletash/jsbasic/). -### Have fun! +### Have fun Thank you for taking part in this project to update a classic programming book – one of the most influential programming books in computing history – for 2022 and beyond! @@ -91,7 +91,7 @@ NOTE: per [the official blog post announcement](https://blog.codinghorror.com/up | 11_Bombardment | x | x | x | | | x | x | x | x | x | | 12_Bombs_Away | x | x | x | | x | x | x | | x | x | | 13_Bounce | x | x | x | | | x | x | x | x | x | -| 14_Bowling | x | x | x | | | x | x | | | x | +| 14_Bowling | x | x | x | | | x | x | | x | x | | 15_Boxing | x | x | x | | | x | x | | | x | | 16_Bug | x | x | x | | | | x | x | | x | | 17_Bullfight | x | x | x | x | | | x | | | x | From 6816f2d2f3eeed4165c78d7d2495813269d46f01 Mon Sep 17 00:00:00 2001 From: Jonatas de Mello Date: Wed, 28 Oct 2026 11:21:10 -0400 Subject: [PATCH 377/377] remove binary files (shoud not be in the repo) --- .../c++/build/x64/Debug/aceyducey.exe | Bin 107008 -> 0 bytes .../c++/build/x64/Debug/aceyducey.pdb | Bin 1404928 -> 0 bytes .../c++/build/x64/Release/aceyducey.exe | Bin 19456 -> 0 bytes .../c++/build/x64/Release/aceyducey.pdb | Bin 872448 -> 0 bytes .../c++/build/x86/Debug/aceyducey.exe | Bin 82432 -> 0 bytes .../c++/build/x86/Debug/aceyducey.pdb | Bin 1667072 -> 0 bytes .../c++/build/x86/Release/aceyducey.exe | Bin 15872 -> 0 bytes .../c++/build/x86/Release/aceyducey.pdb | Bin 856064 -> 0 bytes 8 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.exe delete mode 100644 00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.pdb delete mode 100644 00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.exe delete mode 100644 00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.pdb delete mode 100644 00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.exe delete mode 100644 00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.pdb delete mode 100644 00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.exe delete mode 100644 00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.pdb diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.exe b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.exe deleted file mode 100644 index a68757afdd18a6a38392155bb9a563391b2cb1d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107008 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 diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.pdb b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.pdb deleted file mode 100644 index d33fbd15a39da1b877715c97739b111a5deb6d6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1404928 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 z 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