diff --git a/.github/workflows/check-python.yml b/.github/workflows/check-python.yml index b58cd3bdb..5df15c8b9 100644 --- a/.github/workflows/check-python.yml +++ b/.github/workflows/check-python.yml @@ -20,6 +20,9 @@ jobs: run: | python -m pip install --upgrade pip pip install -r 00_Utilities/python/ci-requirements.txt + - name: Test with pytest + run: | + pytest -m "not slow" - name: Test with mypy run: | mypy . --exclude 79_Slalom --exclude 27_Civil_War --exclude 38_Fur_Trader --exclude 81_Splat --exclude 09_Battle --exclude 40_Gomoko --exclude 36_Flip_Flop --exclude 43_Hammurabi --exclude 04_Awari --exclude 78_Sine_Wave --exclude 77_Salvo --exclude 34_Digits --exclude 17_Bullfight --exclude 16_Bug diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index f4be2fd6a..000000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Rust - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Build All - run: find */rust/Cargo.toml|xargs -I {} dirname {}|xargs -I {} bash -c 'cd {} && cargo build --verbose' - - - name: Run All tests - run: find */rust/Cargo.toml|xargs -I {} dirname {}|xargs -I {} bash -c 'cd {} && cargo test --verbose' diff --git a/.gitignore b/.gitignore index 878190440..2243de053 100644 --- a/.gitignore +++ b/.gitignore @@ -34,9 +34,7 @@ venv/ .DS_Store .vs/ **/target/ +Cargo.lock **/*.rs.bk /target todo.md - -.fake -.fake \ No newline at end of file diff --git a/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md b/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md deleted file mode 100644 index 06640e03b..000000000 --- a/00_Alternate_Languages/01_Acey_Ducey/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/01_Acey_Ducey/MiniScript/aceyducey.ms b/00_Alternate_Languages/01_Acey_Ducey/MiniScript/aceyducey.ms deleted file mode 100644 index c00684ce7..000000000 --- a/00_Alternate_Languages/01_Acey_Ducey/MiniScript/aceyducey.ms +++ /dev/null @@ -1,59 +0,0 @@ -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/01_Acey_Ducey/c++/README.md b/00_Alternate_Languages/01_Acey_Ducey/c++/README.md deleted file mode 100644 index 119825fff..000000000 --- a/00_Alternate_Languages/01_Acey_Ducey/c++/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [C++14](https://en.wikipedia.org/wiki/C%2B%2B14) - -The build folder are executables for x86 and x64 systems. Compiled and built using Visual Studio. \ No newline at end of file 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 a68757afd..000000000 Binary files a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.exe and /dev/null differ 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 d33fbd15a..000000000 Binary files a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Debug/aceyducey.pdb and /dev/null differ 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 6314b08fa..000000000 Binary files a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.exe and /dev/null differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.pdb b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.pdb deleted file mode 100644 index 569e58188..000000000 Binary files a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x64/Release/aceyducey.pdb and /dev/null differ 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 34d54fafc..000000000 Binary files a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.exe and /dev/null differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.pdb b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.pdb deleted file mode 100644 index 100d8fbc3..000000000 Binary files a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Debug/aceyducey.pdb and /dev/null differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.exe b/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.exe deleted file mode 100644 index 565711757..000000000 Binary files a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.exe and /dev/null differ 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 bba540221..000000000 Binary files a/00_Alternate_Languages/01_Acey_Ducey/c++/build/x86/Release/aceyducey.pdb and /dev/null differ diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.cpp b/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.cpp deleted file mode 100644 index c8cb08d60..000000000 --- a/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include -#include -#include "Aceyducey.h" - - -int main() -{ - //Setting Seed for the Random Generator - srand((unsigned int)time(NULL)); - bool isPlaying(true); - Money = 100; - WelcomeMessage(); - while (isPlaying) - { - Play(isPlaying); - } - printf("O.K., HOPE YOU HAD FUN!\n"); -} - -void WelcomeMessage() -{ - for (int i = 0; i < 25; i++) - { - printf(" "); - } - printf("ACEY DUCEY CARD GAME\n"); - for (int i = 0; i < 14; i++) - { - printf(" "); - } - printf("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\nACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER \n"); - printf("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP\nYOU HAVE AN OPTION TO BET OR NOT BET DEPENDING\n"); - printf("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE\nA VALUE BETWEEN THE FIRST TWO.\n"); - printf("IF YOU DO NOT WANT TO BET, INPUT A 0\n"); -} - -void Play(bool& isPlaying) -{ - short int DealerCards[2]; - int Bet; - short int CurrentCard; - printf("YOU NOW HAVE %d DOLLARS.\n\n", Money); - printf("HERE ARE YOUR NEXT TWO CARDS: \n"); - - //Draw Dealers Cards - DrawCard(DealerCards[0]); - printf("\n"); - DrawCard(DealerCards[1]); - printf("\n\n\n"); - - //Check if Bet is Valid - do { - printf("WHAT IS YOUR BET: "); - std::cin >> Bet; - if (Bet == 0) - { - printf("CHICKEN!!\n\n"); - } - } while (Bet > Money || Bet < 0); - - //Draw Players Card - DrawCard(CurrentCard); - printf("\n"); - if (CurrentCard > DealerCards[0] && CurrentCard < DealerCards[1]) - { - printf("YOU WIN!!!\n"); - Money += Bet; - return; - } - else - { - printf("SORRY, YOU LOSE\n"); - Money -= Bet; - } - if (isGameOver()) - { - printf("TRY AGAIN (YES OR NO)\n\n"); - std::string response; - std::cin >> response; - if (response != "YES") - { - isPlaying = false; - } - Money = 100; - } -} - -bool isGameOver() -{ - if (Money <= 0) - { - printf("\n\n"); - printf("SORRY, FRIEND, BUT YOU BLEW YOUR WAD.\n\n"); - return true; - } - return false; -} - -void DrawCard(short int& Card) -{ - //Basically generate 2 numbers first one is between 2-11 and second one 0-3 - short int RandomNum1 = (rand() % 10) + 2; - short int RandomNum2 = rand() % 4; - Card = RandomNum1 + RandomNum2; - - switch (Card) - { - case 11: - printf("JACK"); - break; - case 12: - printf("QUEEN"); - break; - case 13: - printf("KING"); - break; - case 14: - printf("ACE"); - break; - default: - printf("%d", Card); - } -} \ No newline at end of file diff --git a/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.h b/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.h deleted file mode 100644 index 67c56d7e6..000000000 --- a/00_Alternate_Languages/01_Acey_Ducey/c++/source/Aceyducey.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -void WelcomeMessage(); -void DrawCard(short int& Card); -void Play(bool& isPlaying); -bool isGameOver(); -int Money; \ No newline at end of file diff --git a/00_Alternate_Languages/01_Acey_Ducey/go/main.go b/00_Alternate_Languages/01_Acey_Ducey/go/main.go deleted file mode 100644 index 10e965898..000000000 --- a/00_Alternate_Languages/01_Acey_Ducey/go/main.go +++ /dev/null @@ -1,112 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math/rand" - "os" - "sort" - "strconv" - "strings" - "time" -) - -var welcome = ` -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 - ` - -func main() { - rand.Seed(time.Now().UnixNano()) - scanner := bufio.NewScanner(os.Stdin) - - fmt.Println(welcome) - - for { - play(100) - fmt.Println("TRY AGAIN (YES OR NO)") - scanner.Scan() - response := scanner.Text() - if strings.ToUpper(response) != "YES" { - break - } - } - - fmt.Println("O.K., HOPE YOU HAD FUN!") -} - -func play(money int) { - scanner := bufio.NewScanner(os.Stdin) - var bet int - - for { - // Shuffle the cards - cards := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14} - rand.Shuffle(len(cards), func(i, j int) { cards[i], cards[j] = cards[j], cards[i] }) - - // Take the first two for the dealer and sort - dealerCards := cards[0:2] - sort.Ints(dealerCards) - - fmt.Printf("YOU NOW HAVE %d DOLLARS.\n\n", money) - fmt.Printf("HERE ARE YOUR NEXT TWO CARDS:\n%s\n%s", getCardName(dealerCards[0]), getCardName(dealerCards[1])) - fmt.Printf("\n\n") - - //Check if Bet is Valid - for { - fmt.Println("WHAT IS YOUR BET:") - scanner.Scan() - b, err := strconv.Atoi(scanner.Text()) - if err != nil { - fmt.Println("PLEASE ENTER A POSITIVE NUMBER") - continue - } - bet = b - - if bet == 0 { - fmt.Printf("CHICKEN!\n\n") - goto there - } - - if (bet > 0) && (bet <= money) { - break - } - } - - // Draw Players Card - fmt.Printf("YOUR CARD: %s\n", getCardName(cards[2])) - if (cards[2] > dealerCards[0]) && (cards[2] < dealerCards[1]) { - fmt.Println("YOU WIN!!!") - money = money + bet - } else { - fmt.Println("SORRY, YOU LOSE") - money = money - bet - } - fmt.Println() - - if money <= 0 { - fmt.Printf("%s\n", "SORRY, FRIEND, BUT YOU BLEW YOUR WAD.") - return - } - there: - } -} - -func getCardName(c int) string { - switch c { - case 11: - return "JACK" - case 12: - return "QUEEN" - case 13: - return "KING" - case 14: - return "ACE" - default: - return strconv.Itoa(c) - } -} diff --git a/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim b/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim deleted file mode 100644 index abc03defc..000000000 --- a/00_Alternate_Languages/01_Acey_Ducey/nim/aceyducey.nim +++ /dev/null @@ -1,89 +0,0 @@ -import std/[random,strutils] - -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" - 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 "" - -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 result == 0: - echo "CHICKEN!!" - -proc tryAgain(): bool = - echo "TRY AGAIN (YES OR NO)" - var answer = readLine(stdin).normalize() - result = (answer == "y") or (answer == "yes") - -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: - if bet > 0: - echo "SORRY, YOU LOSE" - stash -= bet - echo "SORRY, FRIEND, BUT YOU BLEW YOUR WAD." - echo "" - retry = tryAgain() -echo "O.K., HOPE YOU HAD FUN!" diff --git a/00_Alternate_Languages/02_Amazing/MiniScript/README.md b/00_Alternate_Languages/02_Amazing/MiniScript/README.md deleted file mode 100644 index 35d818ef5..000000000 --- a/00_Alternate_Languages/02_Amazing/MiniScript/README.md +++ /dev/null @@ -1,21 +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 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/02_Amazing/MiniScript/amazing.ms b/00_Alternate_Languages/02_Amazing/MiniScript/amazing.ms deleted file mode 100644 index 3c3589791..000000000 --- a/00_Alternate_Languages/02_Amazing/MiniScript/amazing.ms +++ /dev/null @@ -1,108 +0,0 @@ -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/02_Amazing/go/main.go b/00_Alternate_Languages/02_Amazing/go/main.go deleted file mode 100644 index 11b027ef1..000000000 --- a/00_Alternate_Languages/02_Amazing/go/main.go +++ /dev/null @@ -1,217 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "log" - "math/rand" - "os" - "strconv" - "time" -) - -func main() { - rand.Seed(time.Now().UnixNano()) - - printWelcome() - - h, w := getDimensions() - m := NewMaze(h, w) - m.draw() -} - -type direction int64 - -const ( - LEFT direction = iota - UP - RIGHT - DOWN -) - -const ( - EXIT_DOWN = 1 - EXIT_RIGHT = 2 -) - -type maze struct { - width int - length int - used [][]int - walls [][]int - enterCol int -} - -func NewMaze(w, l int) maze { - if (w < 2) || (l < 2) { - log.Fatal("invalid dimensions supplied") - } - - m := maze{width: w, length: l} - - m.used = make([][]int, l) - for i := range m.used { - m.used[i] = make([]int, w) - } - - m.walls = make([][]int, l) - for i := range m.walls { - m.walls[i] = make([]int, w) - } - - // randomly determine the entry column - m.enterCol = rand.Intn(w) - - // determine layout of walls - m.build() - - // add an exit - col := rand.Intn(m.width - 1) - row := m.length - 1 - m.walls[row][col] = m.walls[row][col] + 1 - - return m -} - -func (m *maze) build() { - row := 0 - col := 0 - count := 2 - - for { - possibleDirs := m.getPossibleDirections(row, col) - - if len(possibleDirs) != 0 { - row, col, count = m.makeOpening(possibleDirs, row, col, count) - } else { - for { - if col != m.width-1 { - col = col + 1 - } else if row != m.length-1 { - row = row + 1 - col = 0 - } else { - row = 0 - col = 0 - } - - if m.used[row][col] != 0 { - break - } - } - } - - if count == (m.width*m.length)+1 { - break - } - } - -} - -func (m *maze) getPossibleDirections(row, col int) []direction { - possible_dirs := make(map[direction]bool, 4) - possible_dirs[LEFT] = true - possible_dirs[UP] = true - possible_dirs[RIGHT] = true - possible_dirs[DOWN] = true - - if (col == 0) || (m.used[row][col-1] != 0) { - possible_dirs[LEFT] = false - } - if (row == 0) || (m.used[row-1][col] != 0) { - possible_dirs[UP] = false - } - if (col == m.width-1) || (m.used[row][col+1] != 0) { - possible_dirs[RIGHT] = false - } - if (row == m.length-1) || (m.used[row+1][col] != 0) { - possible_dirs[DOWN] = false - } - - ret := make([]direction, 0) - for d, v := range possible_dirs { - if v { - ret = append(ret, d) - } - } - return ret -} - -func (m *maze) makeOpening(dirs []direction, row, col, count int) (int, int, int) { - dir := rand.Intn(len(dirs)) - - if dirs[dir] == LEFT { - col = col - 1 - m.walls[row][col] = int(EXIT_RIGHT) - } else if dirs[dir] == UP { - row = row - 1 - m.walls[row][col] = int(EXIT_DOWN) - } else if dirs[dir] == RIGHT { - m.walls[row][col] = m.walls[row][col] + EXIT_RIGHT - col = col + 1 - } else if dirs[dir] == DOWN { - m.walls[row][col] = m.walls[row][col] + EXIT_DOWN - row = row + 1 - } - - m.used[row][col] = count - count = count + 1 - return row, col, count -} - -// draw the maze -func (m *maze) draw() { - for col := 0; col < m.width; col++ { - if col == m.enterCol { - fmt.Print(". ") - } else { - fmt.Print(".--") - } - } - fmt.Println(".") - - for row := 0; row < m.length; row++ { - fmt.Print("|") - for col := 0; col < m.width; col++ { - if m.walls[row][col] < 2 { - fmt.Print(" |") - } else { - fmt.Print(" ") - } - } - fmt.Println() - for col := 0; col < m.width; col++ { - if (m.walls[row][col] == 0) || (m.walls[row][col] == 2) { - fmt.Print(":--") - } else { - fmt.Print(": ") - } - } - fmt.Println(".") - } -} - -func printWelcome() { - fmt.Println(" AMAZING PROGRAM") - fmt.Print(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") -} - -func getDimensions() (int, int) { - scanner := bufio.NewScanner(os.Stdin) - - fmt.Println("Enter a width ( > 1 ):") - scanner.Scan() - w, err := strconv.Atoi(scanner.Text()) - if err != nil { - log.Fatal("invalid dimension") - } - - fmt.Println("Enter a height ( > 1 ):") - scanner.Scan() - h, err := strconv.Atoi(scanner.Text()) - if err != nil { - log.Fatal("invalid dimension") - } - - return w, h -} diff --git a/00_Alternate_Languages/03_Animal/MiniScript/README.md b/00_Alternate_Languages/03_Animal/MiniScript/README.md deleted file mode 100644 index 1e48ea49c..000000000 --- a/00_Alternate_Languages/03_Animal/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/03_Animal/MiniScript/animal.ms b/00_Alternate_Languages/03_Animal/MiniScript/animal.ms deleted file mode 100644 index 5aafdddb4..000000000 --- a/00_Alternate_Languages/03_Animal/MiniScript/animal.ms +++ /dev/null @@ -1,90 +0,0 @@ -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/03_Animal/go/main.go b/00_Alternate_Languages/03_Animal/go/main.go deleted file mode 100644 index 2eb0904eb..000000000 --- a/00_Alternate_Languages/03_Animal/go/main.go +++ /dev/null @@ -1,159 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "log" - "os" - "strings" -) - -type node struct { - text string - yesNode *node - noNode *node -} - -func newNode(text string, yes_node, no_node *node) *node { - n := node{text: text} - if yes_node != nil { - n.yesNode = yes_node - } - if no_node != nil { - n.noNode = no_node - } - return &n -} - -func (n *node) update(newQuestion, newAnswer, newAnimal string) { - oldAnimal := n.text - - n.text = newQuestion - - if newAnswer == "y" { - n.yesNode = newNode(newAnimal, nil, nil) - n.noNode = newNode(oldAnimal, nil, nil) - } else { - n.yesNode = newNode(oldAnimal, nil, nil) - n.noNode = newNode(newAnimal, nil, nil) - } -} - -func (n *node) isLeaf() bool { - return (n.yesNode == nil) && (n.noNode == nil) -} - -func listKnownAnimals(root *node) { - if root == nil { - return - } - - if root.isLeaf() { - fmt.Printf("%s ", root.text) - return - } - - if root.yesNode != nil { - listKnownAnimals(root.yesNode) - } - - if root.noNode != nil { - listKnownAnimals(root.noNode) - } -} - -func parseInput(message string, checkList bool, rootNode *node) string { - scanner := bufio.NewScanner(os.Stdin) - token := "" - - for { - fmt.Println(message) - scanner.Scan() - inp := strings.ToLower(scanner.Text()) - - if checkList && inp == "list" { - fmt.Println("Animals I already know are:") - listKnownAnimals(rootNode) - fmt.Println() - } - - if len(inp) > 0 { - token = inp - } else { - token = "" - } - - if token == "y" || token == "n" { - break - } - } - return token -} - -func avoidVoidInput(message string) string { - scanner := bufio.NewScanner(os.Stdin) - answer := "" - for { - fmt.Println(message) - scanner.Scan() - answer = scanner.Text() - - if answer != "" { - break - } - } - return answer -} - -func printIntro() { - fmt.Println(" Animal") - fmt.Println(" Creative Computing Morristown, New Jersey") - fmt.Println("\nPlay 'Guess the Animal'") - fmt.Println("Think of an animal and the computer will try to guess it") -} - -func main() { - yesChild := newNode("Fish", nil, nil) - noChild := newNode("Bird", nil, nil) - rootNode := newNode("Does it swim?", yesChild, noChild) - - printIntro() - - keepPlaying := (parseInput("Are you thinking of an animal?", true, rootNode) == "y") - - for keepPlaying { - keepAsking := true - - actualNode := rootNode - - for keepAsking { - if !actualNode.isLeaf() { - answer := parseInput(actualNode.text, false, nil) - - if answer == "y" { - if actualNode.yesNode == nil { - log.Fatal("invalid node") - } - actualNode = actualNode.yesNode - } else { - if actualNode.noNode == nil { - log.Fatal("invalid node") - } - actualNode = actualNode.noNode - } - } else { - answer := parseInput(fmt.Sprintf("Is it a %s?", actualNode.text), false, nil) - if answer == "n" { - newAnimal := avoidVoidInput("The animal you were thinking of was a ?") - newQuestion := avoidVoidInput(fmt.Sprintf("Please type in a question that would distinguish a '%s' from a '%s':", newAnimal, actualNode.text)) - newAnswer := parseInput(fmt.Sprintf("For a '%s' the answer would be", newAnimal), false, nil) - actualNode.update(newQuestion+"?", newAnswer, newAnimal) - } else { - fmt.Println("Why not try another animal?") - } - keepAsking = false - } - } - keepPlaying = (parseInput("Are you thinking of an animal?", true, rootNode) == "y") - } -} diff --git a/00_Alternate_Languages/04_Awari/MiniScript/README.md b/00_Alternate_Languages/04_Awari/MiniScript/README.md deleted file mode 100644 index f2b6dfe50..000000000 --- a/00_Alternate_Languages/04_Awari/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/04_Awari/MiniScript/awari.ms b/00_Alternate_Languages/04_Awari/MiniScript/awari.ms deleted file mode 100644 index e01c2d6cc..000000000 --- a/00_Alternate_Languages/04_Awari/MiniScript/awari.ms +++ /dev/null @@ -1,146 +0,0 @@ -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/00_Alternate_Languages/05_Bagels/MiniScript/README.md b/00_Alternate_Languages/05_Bagels/MiniScript/README.md deleted file mode 100644 index 743d5160b..000000000 --- a/00_Alternate_Languages/05_Bagels/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/05_Bagels/MiniScript/bagels.ms b/00_Alternate_Languages/05_Bagels/MiniScript/bagels.ms deleted file mode 100644 index 93b33b010..000000000 --- a/00_Alternate_Languages/05_Bagels/MiniScript/bagels.ms +++ /dev/null @@ -1,83 +0,0 @@ -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." - diff --git a/00_Alternate_Languages/05_Bagels/go/main.go b/00_Alternate_Languages/05_Bagels/go/main.go deleted file mode 100644 index b0d2b106c..000000000 --- a/00_Alternate_Languages/05_Bagels/go/main.go +++ /dev/null @@ -1,166 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math/rand" - "os" - "strconv" - "strings" - "time" -) - -const MAXGUESSES int = 20 - -func printWelcome() { - fmt.Println("\n Bagels") - fmt.Println("Creative Computing Morristown, New Jersey") - fmt.Println() -} -func printRules() { - fmt.Println() - fmt.Println("I am thinking of a three-digit number. Try to guess") - fmt.Println("my number and I will give you clues as follows:") - fmt.Println(" PICO - One digit correct but in the wrong position") - fmt.Println(" FERMI - One digit correct and in the right position") - fmt.Println(" BAGELS - No digits correct") -} - -func getNumber() []string { - numbers := []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"} - rand.Shuffle(len(numbers), func(i, j int) { numbers[i], numbers[j] = numbers[j], numbers[i] }) - - return numbers[:3] -} - -func getValidGuess(guessNumber int) string { - var guess string - scanner := bufio.NewScanner(os.Stdin) - valid := false - for !valid { - fmt.Printf("Guess # %d?\n", guessNumber) - scanner.Scan() - guess = strings.TrimSpace(scanner.Text()) - - // guess must be 3 characters - if len(guess) == 3 { - // and should be numeric - _, err := strconv.Atoi(guess) - if err != nil { - fmt.Println("What?") - } else { - // and the numbers should be unique - if (guess[0:1] != guess[1:2]) && (guess[0:1] != guess[2:3]) && (guess[1:2] != guess[2:3]) { - valid = true - } else { - fmt.Println("Oh, I forgot to tell you that the number I have in mind") - fmt.Println("has no two digits the same.") - } - } - } else { - fmt.Println("Try guessing a three-digit number.") - } - } - - return guess -} - -func buildResultString(num []string, guess string) string { - result := "" - - // correct digits in wrong place - for i := 0; i < 2; i++ { - if num[i] == guess[i+1:i+2] { - result += "PICO " - } - if num[i+1] == guess[i:i+1] { - result += "PICO " - } - } - if num[0] == guess[2:3] { - result += "PICO " - } - if num[2] == guess[0:1] { - result += "PICO " - } - - // correct digits in right place - for i := 0; i < 3; i++ { - if num[i] == guess[i:i+1] { - result += "FERMI " - } - } - - // nothing right? - if result == "" { - result = "BAGELS" - } - - return result -} - -func main() { - rand.Seed(time.Now().UnixNano()) - scanner := bufio.NewScanner(os.Stdin) - - printWelcome() - - fmt.Println("Would you like the rules (Yes or No)? ") - scanner.Scan() - response := scanner.Text() - if len(response) > 0 { - if strings.ToUpper(response[0:1]) != "N" { - printRules() - } - } else { - printRules() - } - - gamesWon := 0 - stillRunning := true - - for stillRunning { - num := getNumber() - numStr := strings.Join(num, "") - guesses := 1 - - fmt.Println("\nO.K. I have a number in mind.") - guessing := true - for guessing { - guess := getValidGuess(guesses) - - if guess == numStr { - fmt.Println("You got it!!") - gamesWon++ - guessing = false - } else { - fmt.Println(buildResultString(num, guess)) - guesses++ - if guesses > MAXGUESSES { - fmt.Println("Oh well") - fmt.Printf("That's %d guesses. My number was %s\n", MAXGUESSES, numStr) - guessing = false - } - } - } - - validRespone := false - for !validRespone { - fmt.Println("Play again (Yes or No)?") - scanner.Scan() - response := scanner.Text() - if len(response) > 0 { - validRespone = true - if strings.ToUpper(response[0:1]) != "Y" { - stillRunning = false - } - } - } - } - - if gamesWon > 0 { - fmt.Printf("\nA %d point Bagels buff!!\n", gamesWon) - } - - fmt.Println("Hope you had fun. Bye") -} diff --git a/00_Alternate_Languages/05_Bagels/nim/bagels.nim b/00_Alternate_Languages/05_Bagels/nim/bagels.nim deleted file mode 100644 index f302b375d..000000000 --- a/00_Alternate_Languages/05_Bagels/nim/bagels.nim +++ /dev/null @@ -1,97 +0,0 @@ -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 - -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: - 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 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)" -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." diff --git a/00_Alternate_Languages/06_Banner/MiniScript/README.md b/00_Alternate_Languages/06_Banner/MiniScript/README.md deleted file mode 100644 index 25a241af9..000000000 --- a/00_Alternate_Languages/06_Banner/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/06_Banner/MiniScript/banner.ms b/00_Alternate_Languages/06_Banner/MiniScript/banner.ms deleted file mode 100644 index d5d57e187..000000000 --- a/00_Alternate_Languages/06_Banner/MiniScript/banner.ms +++ /dev/null @@ -1,89 +0,0 @@ -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/00_Alternate_Languages/07_Basketball/MiniScript/README.md b/00_Alternate_Languages/07_Basketball/MiniScript/README.md deleted file mode 100644 index 5958590e2..000000000 --- a/00_Alternate_Languages/07_Basketball/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/07_Basketball/MiniScript/basketball.ms b/00_Alternate_Languages/07_Basketball/MiniScript/basketball.ms deleted file mode 100644 index d152cb105..000000000 --- a/00_Alternate_Languages/07_Basketball/MiniScript/basketball.ms +++ /dev/null @@ -1,299 +0,0 @@ -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 diff --git a/00_Alternate_Languages/08_Batnum/MiniScript/README.md b/00_Alternate_Languages/08_Batnum/MiniScript/README.md deleted file mode 100644 index b33a3f84d..000000000 --- a/00_Alternate_Languages/08_Batnum/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/08_Batnum/MiniScript/batnum.ms b/00_Alternate_Languages/08_Batnum/MiniScript/batnum.ms deleted file mode 100644 index d1019717b..000000000 --- a/00_Alternate_Languages/08_Batnum/MiniScript/batnum.ms +++ /dev/null @@ -1,109 +0,0 @@ -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/00_Alternate_Languages/08_Batnum/go/main.go b/00_Alternate_Languages/08_Batnum/go/main.go deleted file mode 100644 index 103347995..000000000 --- a/00_Alternate_Languages/08_Batnum/go/main.go +++ /dev/null @@ -1,248 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "strconv" - "strings" -) - -type StartOption int8 - -const ( - StartUndefined StartOption = iota - ComputerFirst - PlayerFirst -) - -type WinOption int8 - -const ( - WinUndefined WinOption = iota - TakeLast - AvoidLast -) - -type GameOptions struct { - pileSize int - winOption WinOption - startOption StartOption - minSelect int - maxSelect int -} - -func NewOptions() *GameOptions { - g := GameOptions{} - - g.pileSize = getPileSize() - if g.pileSize < 0 { - return &g - } - - g.winOption = getWinOption() - g.minSelect, g.maxSelect = getMinMax() - g.startOption = getStartOption() - - return &g -} - -func getPileSize() int { - ps := 0 - var err error - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println("Enter Pile Size ") - scanner.Scan() - ps, err = strconv.Atoi(scanner.Text()) - if err == nil { - break - } - } - return ps -} - -func getWinOption() WinOption { - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println("ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST:") - scanner.Scan() - w, err := strconv.Atoi(scanner.Text()) - if err == nil && (w == 1 || w == 2) { - return WinOption(w) - } - } -} - -func getStartOption() StartOption { - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println("ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ") - scanner.Scan() - s, err := strconv.Atoi(scanner.Text()) - if err == nil && (s == 1 || s == 2) { - return StartOption(s) - } - } -} - -func getMinMax() (int, int) { - minSelect := 0 - maxSelect := 0 - var minErr error - var maxErr error - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println("ENTER MIN AND MAX ") - scanner.Scan() - enteredValues := scanner.Text() - vals := strings.Split(enteredValues, " ") - minSelect, minErr = strconv.Atoi(vals[0]) - maxSelect, maxErr = strconv.Atoi(vals[1]) - if (minErr == nil) && (maxErr == nil) && (minSelect > 0) && (maxSelect > 0) && (maxSelect > minSelect) { - return minSelect, maxSelect - } - } -} - -// This handles the player's turn - asking the player how many objects -// to take and doing some basic validation around that input. Then it -// checks for any win conditions. -// Returns a boolean indicating whether the game is over and the new pile_size. -func playerMove(pile, min, max int, win WinOption) (bool, int) { - scanner := bufio.NewScanner(os.Stdin) - done := false - for !done { - fmt.Println("YOUR MOVE") - scanner.Scan() - m, err := strconv.Atoi(scanner.Text()) - if err != nil { - continue - } - - if m == 0 { - fmt.Println("I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.") - return true, pile - } - - if m > max || m < min { - fmt.Println("ILLEGAL MOVE, REENTER IT") - continue - } - - pile -= m - done = true - - if pile <= 0 { - if win == AvoidLast { - fmt.Println("TOUGH LUCK, YOU LOSE.") - } else { - fmt.Println("CONGRATULATIONS, YOU WIN.") - } - return true, pile - } - } - return false, pile -} - -// This handles the logic to determine how many objects the computer -// will select on its turn. -func computerPick(pile, min, max int, win WinOption) int { - var q int - if win == AvoidLast { - q = pile - 1 - } else { - q = pile - } - c := min + max - - pick := q - (c * int(q/c)) - - if pick < min { - pick = min - } else if pick > max { - pick = max - } - - return pick -} - -// This handles the computer's turn - first checking for the various -// win/lose conditions and then calculating how many objects -// the computer will take. -// Returns a boolean indicating whether the game is over and the new pile_size. -func computerMove(pile, min, max int, win WinOption) (bool, int) { - // first check for end-game conditions - if win == TakeLast && pile <= max { - fmt.Printf("COMPUTER TAKES %d AND WINS\n", pile) - return true, pile - } - - if win == AvoidLast && pile <= min { - fmt.Printf("COMPUTER TAKES %d AND LOSES\n", pile) - return true, pile - } - - // otherwise determine the computer's selection - selection := computerPick(pile, min, max, win) - pile -= selection - fmt.Printf("COMPUTER TAKES %d AND LEAVES %d\n", selection, pile) - return false, pile -} - -// This is the main game loop - repeating each turn until one -// of the win/lose conditions is met. -func play(pile, min, max int, start StartOption, win WinOption) { - gameOver := false - playersTurn := (start == PlayerFirst) - - for !gameOver { - if playersTurn { - gameOver, pile = playerMove(pile, min, max, win) - playersTurn = false - if gameOver { - return - } - } - - if !playersTurn { - gameOver, pile = computerMove(pile, min, max, win) - playersTurn = true - } - } -} - -// Print out the introduction and rules of the game -func printIntro() { - fmt.Printf("%33s%s\n", " ", "BATNUM") - fmt.Printf("%15s%s\n", " ", "CREATIVE COMPUTING MORRISSTOWN, NEW JERSEY") - fmt.Printf("\n\n\n") - fmt.Println("THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE") - fmt.Println("COMPUTER IS YOUR OPPONENT.") - fmt.Println() - fmt.Println("THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU") - fmt.Println("AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.") - fmt.Println("WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR") - fmt.Println("NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.") - fmt.Println("DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.") - fmt.Println("ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.") - fmt.Println() -} - -func main() { - for { - printIntro() - - g := NewOptions() - - if g.pileSize < 0 { - return - } - - play(g.pileSize, g.minSelect, g.maxSelect, g.startOption, g.winOption) - } -} diff --git a/00_Alternate_Languages/09_Battle/MiniScript/README.md b/00_Alternate_Languages/09_Battle/MiniScript/README.md deleted file mode 100644 index 07cd98272..000000000 --- a/00_Alternate_Languages/09_Battle/MiniScript/README.md +++ /dev/null @@ -1,21 +0,0 @@ -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 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/09_Battle/MiniScript/battle.ms b/00_Alternate_Languages/09_Battle/MiniScript/battle.ms deleted file mode 100644 index e082b25b5..000000000 --- a/00_Alternate_Languages/09_Battle/MiniScript/battle.ms +++ /dev/null @@ -1,157 +0,0 @@ -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 diff --git a/00_Alternate_Languages/09_Battle/go/main.go b/00_Alternate_Languages/09_Battle/go/main.go deleted file mode 100644 index c0f911f41..000000000 --- a/00_Alternate_Languages/09_Battle/go/main.go +++ /dev/null @@ -1,266 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math/rand" - "os" - "strconv" - "strings" - "time" -) - -const ( - SEA_WIDTH = 6 - DESTROYER_LENGTH = 2 - CRUISER_LENGTH = 3 - CARRIER_LENGTH = 4 -) - -type Point [2]int -type Vector Point -type Sea [][]int - -func NewSea() Sea { - s := make(Sea, 6) - for r := 0; r < SEA_WIDTH; r++ { - c := make([]int, 6) - s[r] = c - } - - return s -} - -func getRandomVector() Vector { - v := Vector{} - - for { - v[0] = rand.Intn(3) - 1 - v[1] = rand.Intn(3) - 1 - - if !(v[0] == 0 && v[1] == 0) { - break - } - } - return v -} - -func addVector(p Point, v Vector) Point { - newPoint := Point{} - - newPoint[0] = p[0] + v[0] - newPoint[1] = p[1] + v[1] - - return newPoint -} - -func isWithinSea(p Point, s Sea) bool { - return (1 <= p[0] && p[0] <= len(s)) && (1 <= p[1] && p[1] <= len(s)) -} - -func valueAt(p Point, s Sea) int { - return s[p[1]-1][p[0]-1] -} - -func reportInputError() { - fmt.Printf("INVALID. SPECIFY TWO NUMBERS FROM 1 TO %d, SEPARATED BY A COMMA.\n", SEA_WIDTH) -} - -func getNextTarget(s Sea) Point { - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println("\n?") - scanner.Scan() - - vals := strings.Split(scanner.Text(), ",") - - if len(vals) != 2 { - reportInputError() - continue - } - - x, xErr := strconv.Atoi(strings.TrimSpace(vals[0])) - y, yErr := strconv.Atoi(strings.TrimSpace(vals[1])) - - if (len(vals) != 2) || (xErr != nil) || (yErr != nil) { - reportInputError() - continue - } - - p := Point{} - p[0] = x - p[1] = y - if isWithinSea(p, s) { - return p - } - } -} - -func setValueAt(value int, p Point, s Sea) { - s[p[1]-1][p[0]-1] = value -} - -func hasShip(s Sea, code int) bool { - hasShip := false - for r := 0; r < SEA_WIDTH; r++ { - for c := 0; c < SEA_WIDTH; c++ { - if s[r][c] == code { - hasShip = true - break - } - } - } - return hasShip -} - -func countSunk(s Sea, codes []int) int { - sunk := 0 - - for _, c := range codes { - if !hasShip(s, c) { - sunk += 1 - } - } - - return sunk -} - -func placeShip(s Sea, size, code int) { - for { - start := Point{} - start[0] = rand.Intn(SEA_WIDTH) + 1 - start[1] = rand.Intn(SEA_WIDTH) + 1 - vector := getRandomVector() - - point := start - points := []Point{} - - for i := 0; i < size; i++ { - point = addVector(point, vector) - points = append(points, point) - } - - clearPosition := true - for _, p := range points { - if !isWithinSea(p, s) { - clearPosition = false - break - } - if valueAt(p, s) > 0 { - clearPosition = false - break - } - } - if !clearPosition { - continue - } - - for _, p := range points { - setValueAt(code, p, s) - } - break - } -} - -func setupShips(s Sea) { - placeShip(s, DESTROYER_LENGTH, 1) - placeShip(s, DESTROYER_LENGTH, 2) - placeShip(s, CRUISER_LENGTH, 3) - placeShip(s, CRUISER_LENGTH, 4) - placeShip(s, CARRIER_LENGTH, 5) - placeShip(s, CARRIER_LENGTH, 6) -} - -func printIntro() { - fmt.Println(" BATTLE") - fmt.Println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - fmt.Println() - fmt.Println("THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION") - fmt.Println("HAS BEEN CAPTURED BUT NOT DECODED: ") - fmt.Println() -} - -func printInstructions() { - fmt.Println() - fmt.Println() - fmt.Println("DE-CODE IT AND USE IT IF YOU CAN") - fmt.Println("BUT KEEP THE DE-CODING METHOD A SECRET.") - fmt.Println() - fmt.Println("START GAME") -} - -func printEncodedSea(s Sea) { - for x := 0; x < SEA_WIDTH; x++ { - fmt.Println() - for y := SEA_WIDTH - 1; y > -1; y-- { - fmt.Printf(" %d", s[y][x]) - } - } - fmt.Println() -} - -func wipeout(s Sea) bool { - for c := 1; c <= 7; c++ { - if hasShip(s, c) { - return false - } - } - return true -} - -func main() { - rand.Seed(time.Now().UnixNano()) - - s := NewSea() - - setupShips(s) - - printIntro() - - printEncodedSea(s) - - printInstructions() - - splashes := 0 - hits := 0 - - for { - target := getNextTarget(s) - targetValue := valueAt(target, s) - - if targetValue < 0 { - fmt.Printf("YOU ALREADY PUT A HOLE IN SHIP NUMBER %d AT THAT POINT.\n", targetValue) - } - - if targetValue <= 0 { - fmt.Println("SPLASH! TRY AGAIN.") - splashes += 1 - continue - } - - fmt.Printf("A DIRECT HIT ON SHIP NUMBER %d\n", targetValue) - hits += 1 - setValueAt(targetValue*-1, target, s) - - if !hasShip(s, targetValue) { - fmt.Println("AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS.") - fmt.Println("SO FAR, THE BAD GUYS HAVE LOST") - fmt.Printf("%d DESTROYER(S), %d CRUISER(S), AND %d AIRCRAFT CARRIER(S).\n", countSunk(s, []int{1, 2}), countSunk(s, []int{3, 4}), countSunk(s, []int{5, 6})) - } - - if !wipeout(s) { - fmt.Printf("YOUR CURRENT SPLASH/HIT RATIO IS %2f\n", float32(splashes)/float32(hits)) - continue - } - - fmt.Printf("YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET WITH A FINAL SPLASH/HIT RATIO OF %2f\n", float32(splashes)/float32(hits)) - - if splashes == 0 { - fmt.Println("CONGRATULATIONS -- A DIRECT HIT EVERY TIME.") - } - - fmt.Println("\n****************************") - break - } -} diff --git a/00_Alternate_Languages/10_Blackjack/MiniScript/README.md b/00_Alternate_Languages/10_Blackjack/MiniScript/README.md deleted file mode 100644 index 2f68bb794..000000000 --- a/00_Alternate_Languages/10_Blackjack/MiniScript/README.md +++ /dev/null @@ -1,21 +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 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/10_Blackjack/MiniScript/blackjack.ms b/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms deleted file mode 100644 index f6d7959b7..000000000 --- a/00_Alternate_Languages/10_Blackjack/MiniScript/blackjack.ms +++ /dev/null @@ -1,285 +0,0 @@ -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 -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) - -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 - deck.shuffle -end function - -// Function to draw a card from the deck (reshuffling if needed) -getCard = function - if not deck then reshuffle - 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 -// 11-21...Soft 11-21 -// 22-32...Hard 11-21 -// 33+ or -1...Busted -evalHand = function(handNum) - result = 0 - for card in hands[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) - if total < 0 then return total // (already busted) - 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 - -// Get a yes/no response from the user -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 - -// Get a number, within a given range, from the user -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 - -// 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) - betPerHand[i] = getNumber("# " + (i+1) + "? ", 1, 500) - end for -end function - -playOneRound = function - 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, " " - hands[i] = [] - end for - print "DEALER" - hands[numPlayers] = [] - for row in [1,2] - print " ", "" - for i in range(0, numPlayers) - hands[i].push getCard - if row == 1 or i < numPlayers then - print " " + (cardNames[hands[i][-1]] + " ")[:2], " " - end if - end for - print - end for - dealerCard0 = hands[numPlayers][0] - dealerCard1 = hands[numPlayers][1] - // Test for insurance - if dealerCard0 == 1 and getYesNo("Any insurance? ") == "Y" then - print "Insurance Bets" - for i in range(0, numPlayers-1) - insurance = getNumber("# " + (i+1) + "? ", 0, betPerHand[i]/2) - roundWinnings[i] = insurance * (3 * (dealerCard1 >= 10) - 1) - end for - end if - // Test for dealer blackjack - if (dealerCard0==1 and dealerCard1 > 9) or - (dealerCard0 > 9 and dealerCard1==1) then - print; print "Dealer has " + a(dealerCard1) + " in the hole for Blackjack" - for i in range(0, numPlayers) - 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 - 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 hands[i] or hands[i+8] then anyLeft = true - end for - if not anyLeft then - print "Dealer had " + a(hands[numPlayers][1]) + " concealed." - else - // Play dealer's hand. - dispTotal = displayTotal(handValue[numPlayers]) - print "Dealer has " + a(hands[numPlayers][1]) + " concealed" + - " for a total of " + dispTotal + "." - while handValue[numPlayers] > 0 and dispTotal <= 16 - card = getCard - if hands[numPlayers].len == 2 then print "Draws ", "" - print cardNames[card], " " - hands[numPlayers].push card - handValue[numPlayers] = evalHand(numPlayers) - dispTotal = displayTotal(handValue[numPlayers]) - end while - 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, 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 - handValue[handNum] = evalHand(handNum) - if handValue[handNum] == 21 and hands[handNum].len == 2 then - print "Blackjack" - 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 - handValue[handNum] = evalHand(handNum) - if choice == "D" then betPerHand[handNum] *= 2 - card = getCard - print "Received " + a(card), " " - hands[handNum].push card - handValue[handNum] = evalHand(handNum) - if handValue[handNum] < 0 then - print "...Busted" - discardHand handNum - roundWinnings[handNum] = -betPerHand[handNum] - betPerHand[handNum] = 0 - end if - 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 - 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(card) - hands[handNum].push card - card = getCard - print "Second hand receives " + a(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) - hands[handNum] = [] - handValue[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 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(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 = " + playerMoney[numPlayers] - print -end function - -// 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" - 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'." - print -end if -numPlayers = getNumber("Number of players? ", 1, 7) -print -// main loop! -while true - playOneRound -end while diff --git a/00_Alternate_Languages/11_Bombardment/MiniScript/README.md b/00_Alternate_Languages/11_Bombardment/MiniScript/README.md deleted file mode 100644 index 4a399a7bd..000000000 --- a/00_Alternate_Languages/11_Bombardment/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/11_Bombardment/MiniScript/bombardment.ms b/00_Alternate_Languages/11_Bombardment/MiniScript/bombardment.ms deleted file mode 100644 index a6f75009b..000000000 --- a/00_Alternate_Languages/11_Bombardment/MiniScript/bombardment.ms +++ /dev/null @@ -1,101 +0,0 @@ -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/11_Bombardment/go/main.go b/00_Alternate_Languages/11_Bombardment/go/main.go deleted file mode 100644 index e69ff3ea7..000000000 --- a/00_Alternate_Languages/11_Bombardment/go/main.go +++ /dev/null @@ -1,181 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math/rand" - "os" - "strconv" - "strings" - "time" -) - -// Messages correspond to outposts remaining (3, 2, 1, 0) -var PLAYER_PROGRESS_MESSAGES = []string{ - "YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\nMY TRANSISTO&S RECUP%RA*E!", - "THREE DOWN, ONE TO GO.\n\n", - "TWO DOWN, TWO TO GO.\n\n", - "ONE DOWN, THREE TO GO.\n\n", -} - -var ENEMY_PROGRESS_MESSAGES = []string{ - "YOU'RE DEAD. YOUR LAST OUTPOST WAS AT %d. HA, HA, HA.\nBETTER LUCK NEXT TIME.", - "YOU HAVE ONLY ONE OUTPOST LEFT.\n\n", - "YOU HAVE ONLY TWO OUTPOSTS LEFT.\n\n", - "YOU HAVE ONLY THREE OUTPOSTS LEFT.\n\n", -} - -func displayField() { - for r := 0; r < 5; r++ { - initial := r*5 + 1 - for c := 0; c < 5; c++ { - //x := strconv.Itoa(initial + c) - fmt.Printf("\t%d", initial+c) - } - fmt.Println() - } - fmt.Print("\n\n\n\n\n\n\n\n\n") -} - -func printIntro() { - fmt.Println(" BOMBARDMENT") - fmt.Println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - fmt.Println() - fmt.Println() - fmt.Println("YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU") - fmt.Println("HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.") - fmt.Println("YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.") - fmt.Println("THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.") - fmt.Println() - fmt.Println("THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE") - fmt.Println("OUTPOSTS OF THE COMPUTER. IT WILL DO THE SAME TO YOU.") - fmt.Println("THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS") - fmt.Println("FIRST IS THE WINNER.") - fmt.Println() - fmt.Println("GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!") - fmt.Println() - fmt.Println("TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.") - fmt.Print("\n\n\n\n") -} - -func positionList() []int { - positions := make([]int, 25) - for i := 0; i < 25; i++ { - positions[i] = i + 1 - } - return positions -} - -// Randomly choose 4 'positions' out of a range of 1 to 25 -func generateEnemyPositions() []int { - positions := positionList() - rand.Shuffle(len(positions), func(i, j int) { positions[i], positions[j] = positions[j], positions[i] }) - return positions[:4] -} - -func isValidPosition(p int) bool { - return p >= 1 && p <= 25 -} - -func promptForPlayerPositions() []int { - scanner := bufio.NewScanner(os.Stdin) - var positions []int - - for { - fmt.Println("\nWHAT ARE YOUR FOUR POSITIONS (1-25)?") - scanner.Scan() - rawPositions := strings.Split(scanner.Text(), " ") - - if len(rawPositions) != 4 { - fmt.Println("PLEASE ENTER FOUR UNIQUE POSITIONS") - goto there - } - - for _, p := range rawPositions { - pos, err := strconv.Atoi(p) - if (err != nil) || !isValidPosition(pos) { - fmt.Println("ALL POSITIONS MUST RANGE (1-25)") - goto there - } - positions = append(positions, pos) - } - if len(positions) == 4 { - return positions - } - - there: - } -} - -func promptPlayerForTarget() int { - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println("\nWHERE DO YOU WISH TO FIRE YOUR MISSILE?") - scanner.Scan() - target, err := strconv.Atoi(scanner.Text()) - - if (err != nil) || !isValidPosition(target) { - fmt.Println("POSITIONS MUST RANGE (1-25)") - continue - } - return target - } -} - -func generateAttackSequence() []int { - positions := positionList() - rand.Shuffle(len(positions), func(i, j int) { positions[i], positions[j] = positions[j], positions[i] }) - return positions -} - -// Performs attack procedure returning True if we are to continue. -func attack(target int, positions *[]int, hitMsg, missMsg string, progressMsg []string) bool { - for i := 0; i < len(*positions); i++ { - if target == (*positions)[i] { - fmt.Print(hitMsg) - - // remove the target just hit - (*positions)[i] = (*positions)[len((*positions))-1] - (*positions)[len((*positions))-1] = 0 - (*positions) = (*positions)[:len((*positions))-1] - - if len((*positions)) != 0 { - fmt.Print(progressMsg[len((*positions))]) - } else { - fmt.Printf(progressMsg[len((*positions))], target) - } - return len((*positions)) > 0 - } - } - fmt.Print(missMsg) - return len((*positions)) > 0 -} - -func main() { - rand.Seed(time.Now().UnixNano()) - - printIntro() - displayField() - - enemyPositions := generateEnemyPositions() - enemyAttacks := generateAttackSequence() - enemyAttackCounter := 0 - - playerPositions := promptForPlayerPositions() - - for { - // player attacks - if !attack(promptPlayerForTarget(), &enemyPositions, "YOU GOT ONE OF MY OUTPOSTS!\n\n", "HA, HA YOU MISSED. MY TURN NOW:\n\n", PLAYER_PROGRESS_MESSAGES) { - break - } - // computer attacks - hitMsg := fmt.Sprintf("I GOT YOU. IT WON'T BE LONG NOW. POST %d WAS HIT.\n", enemyAttacks[enemyAttackCounter]) - missMsg := fmt.Sprintf("I MISSED YOU, YOU DIRTY RAT. I PICKED %d. YOUR TURN:\n\n", enemyAttacks[enemyAttackCounter]) - if !attack(enemyAttacks[enemyAttackCounter], &playerPositions, hitMsg, missMsg, ENEMY_PROGRESS_MESSAGES) { - break - } - enemyAttackCounter += 1 - } - -} diff --git a/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md b/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md deleted file mode 100644 index 22bcc0b1a..000000000 --- a/00_Alternate_Languages/12_Bombs_Away/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/12_Bombs_Away/MiniScript/bombsaway.ms b/00_Alternate_Languages/12_Bombs_Away/MiniScript/bombsaway.ms deleted file mode 100644 index ea06ea48d..000000000 --- a/00_Alternate_Languages/12_Bombs_Away/MiniScript/bombsaway.ms +++ /dev/null @@ -1,112 +0,0 @@ - -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/00_Alternate_Languages/12_Bombs_Away/go/main.go b/00_Alternate_Languages/12_Bombs_Away/go/main.go deleted file mode 100644 index 616f44515..000000000 --- a/00_Alternate_Languages/12_Bombs_Away/go/main.go +++ /dev/null @@ -1,188 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math/rand" - "os" - "strconv" - "strings" - "time" -) - -type Choice struct { - idx string - msg string -} - -func playerSurvived() { - fmt.Println("YOU MADE IT THROUGH TREMENDOUS FLAK!!") -} - -func playerDeath() { - fmt.Println("* * * * BOOM * * * *") - fmt.Println("YOU HAVE BEEN SHOT DOWN.....") - fmt.Println("DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR") - fmt.Println("LAST TRIBUTE...") -} - -func missionSuccess() { - fmt.Printf("DIRECT HIT!!!! %d KILLED.\n", int(100*rand.Int())) - fmt.Println("MISSION SUCCESSFUL.") -} - -// Takes a float between 0 and 1 and returns a boolean -// if the player has survived (based on random chance) -// Returns True if death, False if survived -func deathWithChance(probability float64) bool { - return probability > rand.Float64() -} - -func startNonKamikaziAttack() { - numMissions := getIntInput("HOW MANY MISSIONS HAVE YOU FLOWN? ") - - for numMissions > 160 { - fmt.Println("MISSIONS, NOT MILES...") - fmt.Println("150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS") - numMissions = getIntInput("HOW MANY MISSIONS HAVE YOU FLOWN? ") - } - - if numMissions > 100 { - fmt.Println("THAT'S PUSHING THE ODDS!") - } - - if numMissions < 25 { - fmt.Println("FRESH OUT OF TRAINING, EH?") - } - - fmt.Println() - - if float32(numMissions) > (160 * rand.Float32()) { - missionSuccess() - } else { - missionFailure() - } -} - -func missionFailure() { - fmt.Printf("MISSED TARGET BY %d MILES!\n", int(2+30*rand.Float32())) - fmt.Println("NOW YOU'RE REALLY IN FOR IT !!") - fmt.Println() - - enemyWeapons := getInputFromList("DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? ", []Choice{{idx: "1", msg: "GUNS"}, {idx: "2", msg: "MISSILES"}, {idx: "3", msg: "BOTH"}}) - - // If there are no gunners (i.e. weapon choice 2) then - // we say that the gunners have 0 accuracy for the purposes - // of calculating probability of player death - enemyGunnerAccuracy := 0.0 - if enemyWeapons.idx != "2" { - enemyGunnerAccuracy = float64(getIntInput("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? ")) - if enemyGunnerAccuracy < 10.0 { - fmt.Println("YOU LIE, BUT YOU'LL PAY...") - playerDeath() - } - } - - missileThreatWeighting := 35.0 - if enemyWeapons.idx == "1" { - missileThreatWeighting = 0 - } - - death := deathWithChance((enemyGunnerAccuracy + missileThreatWeighting) / 100) - - if death { - playerDeath() - } else { - playerSurvived() - } -} - -func playItaly() { - targets := []Choice{{idx: "1", msg: "SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE."}, {idx: "2", msg: "BE CAREFUL!!!"}, {idx: "3", msg: "YOU'RE GOING FOR THE OIL, EH?"}} - target := getInputFromList("YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)", targets) - fmt.Println(target.msg) - startNonKamikaziAttack() -} - -func playAllies() { - aircraftMessages := []Choice{{idx: "1", msg: "YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI."}, {idx: "2", msg: "YOU'RE DUMPING THE A-BOMB ON HIROSHIMA."}, {idx: "3", msg: "YOU'RE CHASING THE BISMARK IN THE NORTH SEA."}, {idx: "4", msg: "YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR."}} - aircraft := getInputFromList("AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4): ", aircraftMessages) - fmt.Println(aircraft.msg) - startNonKamikaziAttack() -} - -func playJapan() { - acknowledgeMessage := []Choice{{idx: "Y", msg: "Y"}, {idx: "N", msg: "N"}} - firstMission := getInputFromList("YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.\nYOUR FIRST KAMIKAZE MISSION? (Y OR N): ", acknowledgeMessage) - if firstMission.msg == "N" { - playerDeath() - } - if rand.Float64() > 0.65 { - missionSuccess() - } else { - playerDeath() - } -} - -func playGermany() { - targets := []Choice{{idx: "1", msg: "YOU'RE NEARING STALINGRAD."}, {idx: "2", msg: "NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR."}, {idx: "3", msg: "NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS."}} - target := getInputFromList("A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\nENGLAND(2), OR FRANCE(3)? ", targets) - fmt.Println(target.msg) - startNonKamikaziAttack() -} - -func playGame() { - fmt.Println("YOU ARE A PILOT IN A WORLD WAR II BOMBER.") - side := getInputFromList("WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4): ", []Choice{{idx: "1", msg: "ITALY"}, {idx: "2", msg: "ALLIES"}, {idx: "3", msg: "JAPAN"}, {idx: "4", msg: "GERMANY"}}) - switch side.idx { - case "1": - playItaly() - case "2": - playAllies() - case "3": - playJapan() - case "4": - playGermany() - } -} - -func main() { - rand.Seed(time.Now().UnixNano()) - - for { - playGame() - if getInputFromList("ANOTHER MISSION (Y OR N):", []Choice{{idx: "Y", msg: "Y"}, {idx: "N", msg: "N"}}).msg == "N" { - break - } - } -} - -func getInputFromList(prompt string, choices []Choice) Choice { - scanner := bufio.NewScanner(os.Stdin) - for { - fmt.Println(prompt) - scanner.Scan() - choice := scanner.Text() - for _, c := range choices { - if strings.EqualFold(strings.ToUpper(choice), strings.ToUpper(c.idx)) { - return c - } - } - fmt.Println("TRY AGAIN...") - } -} - -func getIntInput(prompt string) int { - scanner := bufio.NewScanner(os.Stdin) - for { - fmt.Println(prompt) - scanner.Scan() - choice, err := strconv.Atoi(scanner.Text()) - if err != nil { - fmt.Println("TRY AGAIN...") - continue - } else { - return choice - } - } -} diff --git a/00_Alternate_Languages/13_Bounce/MiniScript/README.md b/00_Alternate_Languages/13_Bounce/MiniScript/README.md deleted file mode 100644 index e7e8f23a7..000000000 --- a/00_Alternate_Languages/13_Bounce/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/13_Bounce/MiniScript/bounce.ms b/00_Alternate_Languages/13_Bounce/MiniScript/bounce.ms deleted file mode 100644 index 64174be62..000000000 --- a/00_Alternate_Languages/13_Bounce/MiniScript/bounce.ms +++ /dev/null @@ -1,55 +0,0 @@ -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 diff --git a/00_Alternate_Languages/14_Bowling/MiniScript/README.md b/00_Alternate_Languages/14_Bowling/MiniScript/README.md deleted file mode 100644 index bfb33e6b5..000000000 --- a/00_Alternate_Languages/14_Bowling/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/14_Bowling/MiniScript/bowling.ms b/00_Alternate_Languages/14_Bowling/MiniScript/bowling.ms deleted file mode 100644 index 139ec225e..000000000 --- a/00_Alternate_Languages/14_Bowling/MiniScript/bowling.ms +++ /dev/null @@ -1,138 +0,0 @@ -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/00_Alternate_Languages/15_Boxing/MiniScript/README.md b/00_Alternate_Languages/15_Boxing/MiniScript/README.md deleted file mode 100644 index 9c0ae8fc2..000000000 --- a/00_Alternate_Languages/15_Boxing/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/15_Boxing/MiniScript/boxing.ms b/00_Alternate_Languages/15_Boxing/MiniScript/boxing.ms deleted file mode 100644 index 948a3bdde..000000000 --- a/00_Alternate_Languages/15_Boxing/MiniScript/boxing.ms +++ /dev/null @@ -1,174 +0,0 @@ -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/00_Alternate_Languages/16_Bug/MiniScript/README.md b/00_Alternate_Languages/16_Bug/MiniScript/README.md deleted file mode 100644 index 554d5e529..000000000 --- a/00_Alternate_Languages/16_Bug/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/16_Bug/MiniScript/bug.ms b/00_Alternate_Languages/16_Bug/MiniScript/bug.ms deleted file mode 100644 index 29349b2a2..000000000 --- a/00_Alternate_Languages/16_Bug/MiniScript/bug.ms +++ /dev/null @@ -1,192 +0,0 @@ -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!!" - diff --git a/00_Alternate_Languages/17_Bullfight/MiniScript/README.md b/00_Alternate_Languages/17_Bullfight/MiniScript/README.md deleted file mode 100644 index 2290e6e12..000000000 --- a/00_Alternate_Languages/17_Bullfight/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/17_Bullfight/MiniScript/bull.ms b/00_Alternate_Languages/17_Bullfight/MiniScript/bull.ms deleted file mode 100644 index 1259d651f..000000000 --- a/00_Alternate_Languages/17_Bullfight/MiniScript/bull.ms +++ /dev/null @@ -1,188 +0,0 @@ -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/00_Alternate_Languages/18_Bullseye/MiniScript/README.md b/00_Alternate_Languages/18_Bullseye/MiniScript/README.md deleted file mode 100644 index 73a1c749a..000000000 --- a/00_Alternate_Languages/18_Bullseye/MiniScript/README.md +++ /dev/null @@ -1,22 +0,0 @@ -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 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/18_Bullseye/MiniScript/bullseye.ms b/00_Alternate_Languages/18_Bullseye/MiniScript/bullseye.ms deleted file mode 100644 index 10dc95cac..000000000 --- a/00_Alternate_Languages/18_Bullseye/MiniScript/bullseye.ms +++ /dev/null @@ -1,59 +0,0 @@ -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." - diff --git a/00_Alternate_Languages/19_Bunny/MiniScript/README.md b/00_Alternate_Languages/19_Bunny/MiniScript/README.md deleted file mode 100644 index 90a054330..000000000 --- a/00_Alternate_Languages/19_Bunny/MiniScript/README.md +++ /dev/null @@ -1,22 +0,0 @@ -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 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/19_Bunny/MiniScript/bunny.ms b/00_Alternate_Languages/19_Bunny/MiniScript/bunny.ms deleted file mode 100644 index 176e1e6cf..000000000 --- a/00_Alternate_Languages/19_Bunny/MiniScript/bunny.ms +++ /dev/null @@ -1,43 +0,0 @@ -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 - diff --git a/00_Alternate_Languages/20_Buzzword/MiniScript/README.md b/00_Alternate_Languages/20_Buzzword/MiniScript/README.md deleted file mode 100644 index 90a054330..000000000 --- a/00_Alternate_Languages/20_Buzzword/MiniScript/README.md +++ /dev/null @@ -1,22 +0,0 @@ -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 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/buzzword.ms b/00_Alternate_Languages/20_Buzzword/MiniScript/buzzword.ms deleted file mode 100644 index 26a377755..000000000 --- a/00_Alternate_Languages/20_Buzzword/MiniScript/buzzword.ms +++ /dev/null @@ -1,38 +0,0 @@ -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!" diff --git a/00_Alternate_Languages/20_Buzzword/go/main.go b/00_Alternate_Languages/20_Buzzword/go/main.go deleted file mode 100644 index fdab9afa7..000000000 --- a/00_Alternate_Languages/20_Buzzword/go/main.go +++ /dev/null @@ -1,91 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math/rand" - "os" - "strings" - "time" -) - -func main() { - rand.Seed(time.Now().UnixNano()) - words := [][]string{ - { - "Ability", - "Basal", - "Behavioral", - "Child-centered", - "Differentiated", - "Discovery", - "Flexible", - "Heterogeneous", - "Homogenous", - "Manipulative", - "Modular", - "Tavistock", - "Individualized", - }, { - "learning", - "evaluative", - "objective", - "cognitive", - "enrichment", - "scheduling", - "humanistic", - "integrated", - "non-graded", - "training", - "vertical age", - "motivational", - "creative", - }, { - "grouping", - "modification", - "accountability", - "process", - "core curriculum", - "algorithm", - "performance", - "reinforcement", - "open classroom", - "resource", - "structure", - "facility", - "environment", - }, - } - - scanner := bufio.NewScanner(os.Stdin) - - // Display intro text - fmt.Println("\n Buzzword Generator") - fmt.Println("Creative Computing Morristown, New Jersey") - fmt.Println("\n\n") - fmt.Println("This program prints highly acceptable phrases in") - fmt.Println("'educator-speak' that you can work into reports") - fmt.Println("and speeches. Whenever a question mark is printed,") - fmt.Println("type a 'Y' for another phrase or 'N' to quit.") - fmt.Println("\n\nHere's the first phrase:") - - for { - phrase := "" - for _, section := range words { - if len(phrase) > 0 { - phrase += " " - } - phrase += section[rand.Intn(len(section))] - } - fmt.Println(phrase) - fmt.Println() - - // continue? - fmt.Println("?") - scanner.Scan() - if strings.ToUpper(scanner.Text())[0:1] != "Y" { - break - } - } - fmt.Println("Come back when you need help with another report!") -} diff --git a/00_Alternate_Languages/20_Buzzword/nim/buzzword.nim b/00_Alternate_Languages/20_Buzzword/nim/buzzword.nim deleted file mode 100644 index dfba31c9d..000000000 --- a/00_Alternate_Languages/20_Buzzword/nim/buzzword.nim +++ /dev/null @@ -1,34 +0,0 @@ -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!" diff --git a/00_Alternate_Languages/21_Calendar/MiniScript/README.md b/00_Alternate_Languages/21_Calendar/MiniScript/README.md deleted file mode 100644 index fea2264e6..000000000 --- a/00_Alternate_Languages/21_Calendar/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/21_Calendar/MiniScript/calendar.ms b/00_Alternate_Languages/21_Calendar/MiniScript/calendar.ms deleted file mode 100644 index 27691bdb9..000000000 --- a/00_Alternate_Languages/21_Calendar/MiniScript/calendar.ms +++ /dev/null @@ -1,89 +0,0 @@ -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/00_Alternate_Languages/22_Change/MiniScript/README.md b/00_Alternate_Languages/22_Change/MiniScript/README.md deleted file mode 100644 index 5708156d8..000000000 --- a/00_Alternate_Languages/22_Change/MiniScript/README.md +++ /dev/null @@ -1,22 +0,0 @@ -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 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/22_Change/MiniScript/change.ms b/00_Alternate_Languages/22_Change/MiniScript/change.ms deleted file mode 100644 index 675a179aa..000000000 --- a/00_Alternate_Languages/22_Change/MiniScript/change.ms +++ /dev/null @@ -1,57 +0,0 @@ -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 diff --git a/00_Alternate_Languages/22_Change/go/main.go b/00_Alternate_Languages/22_Change/go/main.go deleted file mode 100644 index fabe4d4bb..000000000 --- a/00_Alternate_Languages/22_Change/go/main.go +++ /dev/null @@ -1,115 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math" - "os" - "strconv" -) - -func printWelcome() { - fmt.Println(" CHANGE") - fmt.Println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - fmt.Println() - fmt.Println() - fmt.Println() - fmt.Println("I, YOUR FRIENDLY MICROCOMPUTER, WILL DETERMINE") - fmt.Println("THE CORRECT CHANGE FOR ITEMS COSTING UP TO $100.") - fmt.Println() -} - -func computeChange(cost, payment float64) { - change := int(math.Round((payment - cost) * 100)) - - if change == 0 { - fmt.Println("\nCORRECT AMOUNT, THANK YOU.") - return - } - - if change < 0 { - fmt.Printf("\nSORRY, YOU HAVE SHORT-CHANGED ME $%0.2f\n", float64(change)/-100.0) - print() - return - } - - fmt.Printf("\nYOUR CHANGE, $%0.2f:\n", float64(change)/100.0) - - d := change / 1000 - if d > 0 { - fmt.Printf(" %d TEN DOLLAR BILL(S)\n", d) - change -= d * 1000 - } - - d = change / 500 - if d > 0 { - fmt.Printf(" %d FIVE DOLLAR BILL(S)\n", d) - change -= d * 500 - } - - d = change / 100 - if d > 0 { - fmt.Printf(" %d ONE DOLLAR BILL(S)\n", d) - change -= d * 100 - } - - d = change / 50 - if d > 0 { - fmt.Println(" 1 HALF DOLLAR") - change -= d * 50 - } - - d = change / 25 - if d > 0 { - fmt.Printf(" %d QUARTER(S)\n", d) - change -= d * 25 - } - - d = change / 10 - if d > 0 { - fmt.Printf(" %d DIME(S)\n", d) - change -= d * 10 - } - - d = change / 5 - if d > 0 { - fmt.Printf(" %d NICKEL(S)\n", d) - change -= d * 5 - } - - if change > 0 { - fmt.Printf(" %d PENNY(S)\n", change) - } -} - -func main() { - scanner := bufio.NewScanner(os.Stdin) - - printWelcome() - - var cost, payment float64 - var err error - for { - fmt.Println("COST OF ITEM?") - scanner.Scan() - cost, err = strconv.ParseFloat(scanner.Text(), 64) - if err != nil || cost < 0.0 { - fmt.Println("INVALID INPUT. TRY AGAIN.") - continue - } - break - } - for { - fmt.Println("\nAMOUNT OF PAYMENT?") - scanner.Scan() - payment, err = strconv.ParseFloat(scanner.Text(), 64) - if err != nil { - fmt.Println("INVALID INPUT. TRY AGAIN.") - continue - } - break - } - - computeChange(cost, payment) - fmt.Println() -} diff --git a/00_Alternate_Languages/23_Checkers/MiniScript/README.md b/00_Alternate_Languages/23_Checkers/MiniScript/README.md deleted file mode 100644 index 9cb5fd6ee..000000000 --- a/00_Alternate_Languages/23_Checkers/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/23_Checkers/MiniScript/checkers.ms b/00_Alternate_Languages/23_Checkers/MiniScript/checkers.ms deleted file mode 100644 index dc7527128..000000000 --- a/00_Alternate_Languages/23_Checkers/MiniScript/checkers.ms +++ /dev/null @@ -1,243 +0,0 @@ -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/00_Alternate_Languages/24_Chemist/MiniScript/README.md b/00_Alternate_Languages/24_Chemist/MiniScript/README.md deleted file mode 100644 index 82983edc2..000000000 --- a/00_Alternate_Languages/24_Chemist/MiniScript/README.md +++ /dev/null @@ -1,22 +0,0 @@ -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 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/24_Chemist/MiniScript/chemist.ms b/00_Alternate_Languages/24_Chemist/MiniScript/chemist.ms deleted file mode 100644 index 712792ce9..000000000 --- a/00_Alternate_Languages/24_Chemist/MiniScript/chemist.ms +++ /dev/null @@ -1,30 +0,0 @@ -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/00_Alternate_Languages/25_Chief/C/chief.c b/00_Alternate_Languages/25_Chief/C/chief.c deleted file mode 100644 index 83cdd8cf9..000000000 --- a/00_Alternate_Languages/25_Chief/C/chief.c +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include -#include -#include - -//check if windows or linux for the clear screen -#ifdef _WIN32 -#define CLEAR "cls" -#else -#define CLEAR "clear" -#endif - -void show_solution(float guess); -float guess_number(float number); -void game(); - -float guess_number(float number){ - float guess; - guess = ((((number - 4) * 5) / 8) * 5 - 3); - return guess; -} - -void game(){ - float number,guess; - char answer[4]; - printf("Think a number\n"); - printf("Then add to it 3 and divide it by 5\n"); - printf("Now multiply by 8, divide by 5 and then add 5\n"); - printf("Finally substract 1\n"); - printf("What is the number you got?(if you got decimals put them ex: 23.6): "); - scanf("%f",&number); - guess = guess_number(number); - printf("The number you thought was %f am I right(Yes or No)?\n",guess); - scanf("%s",answer); - for(int i = 0; i < strlen(answer); i++){ - answer[i] = tolower(answer[i]); - } - if(strcmp(answer,"yes") == 0){ - printf("\nHuh, I Knew I was unbeatable"); - printf("And here is how i did it:\n"); - show_solution(guess); - } - else if (strcmp(answer,"no") == 0){ - printf("HUH!! what was you original number?: "); - scanf("%f",&number); - if(number == guess){ - printf("Huh, I Knew I was unbeatable"); - printf("And here is how i did it:\n"); - show_solution(guess); - } - else{ - printf("If I got it wrong I guess you are smarter than me"); - } - } - else{ - system(CLEAR); - printf("I don't understand what you said\n"); - printf("Please answer with Yes or No\n"); - game(); - } - -} - -void show_solution(float guess){ - printf("%f plus 3 is %f\n",guess,guess + 3); - printf("%f divided by 5 is %f\n",guess + 3,(guess + 3) / 5); - printf("%f multiplied by 8 is %f\n",(guess + 3) / 5,(guess + 3) / 5 * 8); - printf("%f divided by 5 is %f\n",(guess + 3) / 5 * 8,(guess + 3) / 5 * 8 / 5); - printf("%f plus 5 is %f\n",(guess + 3) / 5 * 8 / 5,(guess + 3) / 5 * 8 / 5 + 5); - printf("%f minus 1 is %f\n",(guess + 3) / 5 * 8 / 5 + 5,(guess + 3) / 5 * 8 / 5 + 5 - 1); -} - -void main(){ - char answer[4]; - printf("I am CHIEF NUMBERS FREEK, The GREAT INDIAN MATH GOD.\n"); - printf("Are you ready to take the test you called me out for(Yes or No)? "); - scanf("%s",answer); - for(int i = 0; i < strlen(answer); i++){ - answer[i] = tolower(answer[i]); - } - if(strcmp(answer,"yes") == 0){ - game(); - }else if (strcmp(answer,"no") == 0){ - printf("You are a coward, I will not play with you.%d %s\n",strcmp(answer,"yes"),answer); - } - else{ - system(CLEAR); - printf("I don't understand what you said\n"); - printf("Please answer with Yes or No\n"); - main(); - } -} \ 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 deleted file mode 100644 index fa28aa67b..000000000 --- a/00_Alternate_Languages/25_Chief/MiniScript/README.md +++ /dev/null @@ -1,24 +0,0 @@ -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 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/25_Chief/MiniScript/chief.ms b/00_Alternate_Languages/25_Chief/MiniScript/chief.ms deleted file mode 100644 index 272e6699e..000000000 --- a/00_Alternate_Languages/25_Chief/MiniScript/chief.ms +++ /dev/null @@ -1,50 +0,0 @@ -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 diff --git a/00_Alternate_Languages/25_Chief/go/main.go b/00_Alternate_Languages/25_Chief/go/main.go deleted file mode 100644 index 19d3e97cb..000000000 --- a/00_Alternate_Languages/25_Chief/go/main.go +++ /dev/null @@ -1,116 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "strconv" - "strings" -) - -func printLightning() { - fmt.Println("************************************") - n := 24 - for n > 16 { - var b strings.Builder - b.Grow(n + 3) - for i := 0; i < n; i++ { - b.WriteString(" ") - } - b.WriteString("x x") - fmt.Println(b.String()) - n-- - } - fmt.Println(" x xxx") - fmt.Println(" x x") - fmt.Println(" xx xx") - n-- - for n > 8 { - var b strings.Builder - b.Grow(n + 3) - for i := 0; i < n; i++ { - b.WriteString(" ") - } - b.WriteString("x x") - fmt.Println(b.String()) - n-- - } - fmt.Println(" xx") - fmt.Println(" x") - fmt.Println("************************************") -} - -func printSolution(n float64) { - fmt.Printf("\n%f plus 3 gives %f. This divided by 5 equals %f\n", n, n+3, (n+3)/5) - fmt.Printf("This times 8 gives %f. If we divide 5 and add 5.\n", ((n+3)/5)*8) - fmt.Printf("We get %f, which, minus 1 equals %f\n", (((n+3)/5)*8)/5+5, ((((n+3)/5)*8)/5+5)-1) -} - -func play() { - fmt.Println("\nTake a Number and ADD 3. Now, Divide this number by 5 and") - fmt.Println("multiply by 8. Now, Divide by 5 and add the same. Subtract 1") - - youHave := getFloat("\nWhat do you have?") - compGuess := (((youHave-4)*5)/8)*5 - 3 - if getYesNo(fmt.Sprintf("\nI bet your number was %f was I right(Yes or No)? ", compGuess)) { - fmt.Println("\nHuh, I knew I was unbeatable") - fmt.Println("And here is how i did it") - printSolution(compGuess) - } else { - originalNumber := getFloat("\nHUH!! what was you original number? ") - if originalNumber == compGuess { - fmt.Println("\nThat was my guess, AHA i was right") - fmt.Println("Shamed to accept defeat i guess, don't worry you can master mathematics too") - fmt.Println("Here is how i did it") - printSolution(compGuess) - } else { - fmt.Println("\nSo you think you're so smart, EH?") - fmt.Println("Now, Watch") - printSolution(originalNumber) - - if getYesNo("\nNow do you believe me? ") { - print("\nOk, Lets play again sometime bye!!!!") - } else { - fmt.Println("\nYOU HAVE MADE ME VERY MAD!!!!!") - fmt.Println("BY THE WRATH OF THE MATHEMATICS AND THE RAGE OF THE GODS") - fmt.Println("THERE SHALL BE LIGHTNING!!!!!!!") - printLightning() - fmt.Println("\nI Hope you believe me now, for your own sake") - } - } - } -} - -func getFloat(prompt string) float64 { - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println(prompt) - scanner.Scan() - val, err := strconv.ParseFloat(scanner.Text(), 64) - if err != nil { - fmt.Println("INVALID INPUT, TRY AGAIN") - continue - } - return val - } -} - -func getYesNo(prompt string) bool { - scanner := bufio.NewScanner(os.Stdin) - fmt.Println(prompt) - scanner.Scan() - - return (strings.ToUpper(scanner.Text())[0:1] == "Y") - -} - -func main() { - fmt.Println("I am CHIEF NUMBERS FREEK, The GREAT INDIAN MATH GOD.") - - if getYesNo("\nAre you ready to take the test you called me out for(Yes or No)? ") { - play() - } else { - fmt.Println("Ok, Nevermind. Let me go back to my great slumber, Bye") - } -} diff --git a/00_Alternate_Languages/26_Chomp/MiniScript/README.md b/00_Alternate_Languages/26_Chomp/MiniScript/README.md deleted file mode 100644 index 2fce3ec72..000000000 --- a/00_Alternate_Languages/26_Chomp/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/26_Chomp/MiniScript/chomp.ms b/00_Alternate_Languages/26_Chomp/MiniScript/chomp.ms deleted file mode 100644 index 01b12f815..000000000 --- a/00_Alternate_Languages/26_Chomp/MiniScript/chomp.ms +++ /dev/null @@ -1,102 +0,0 @@ -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 diff --git a/00_Alternate_Languages/27_Civil_War/MiniScript/README.md b/00_Alternate_Languages/27_Civil_War/MiniScript/README.md deleted file mode 100644 index ad8e06ed8..000000000 --- a/00_Alternate_Languages/27_Civil_War/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/27_Civil_War/MiniScript/civilwar.ms b/00_Alternate_Languages/27_Civil_War/MiniScript/civilwar.ms deleted file mode 100644 index 30b1ce829..000000000 --- a/00_Alternate_Languages/27_Civil_War/MiniScript/civilwar.ms +++ /dev/null @@ -1,437 +0,0 @@ -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/00_Alternate_Languages/28_Combat/MiniScript/README.md b/00_Alternate_Languages/28_Combat/MiniScript/README.md deleted file mode 100644 index 0963185f3..000000000 --- a/00_Alternate_Languages/28_Combat/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/28_Combat/MiniScript/combat.ms b/00_Alternate_Languages/28_Combat/MiniScript/combat.ms deleted file mode 100644 index c5f6596af..000000000 --- a/00_Alternate_Languages/28_Combat/MiniScript/combat.ms +++ /dev/null @@ -1,165 +0,0 @@ -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/00_Alternate_Languages/29_Craps/MiniScript/README.md b/00_Alternate_Languages/29_Craps/MiniScript/README.md deleted file mode 100644 index e500f4c36..000000000 --- a/00_Alternate_Languages/29_Craps/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/29_Craps/MiniScript/craps.ms b/00_Alternate_Languages/29_Craps/MiniScript/craps.ms deleted file mode 100644 index 900ba5d43..000000000 --- a/00_Alternate_Languages/29_Craps/MiniScript/craps.ms +++ /dev/null @@ -1,87 +0,0 @@ -// 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 diff --git a/00_Alternate_Languages/29_Craps/nim/craps.nim b/00_Alternate_Languages/29_Craps/nim/craps.nim deleted file mode 100644 index 770b6c0e1..000000000 --- a/00_Alternate_Languages/29_Craps/nim/craps.nim +++ /dev/null @@ -1,68 +0,0 @@ -import std/[random,strutils] - -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() - 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" diff --git a/00_Alternate_Languages/30_Cube/C/cube.c b/00_Alternate_Languages/30_Cube/C/cube.c deleted file mode 100644 index a42b3bca3..000000000 --- a/00_Alternate_Languages/30_Cube/C/cube.c +++ /dev/null @@ -1,142 +0,0 @@ -#include -#include -#include - -//check if windows or linux for the clear screen -#ifdef _WIN32 -#define CLEAR "cls" -#else -#define CLEAR "clear" -#endif - -typedef struct{ - int x; - int y; - int z; -}coords; - -void instuctions(){ - printf("\nThis is a game in which you will be playing against the\n"); - printf("random decisions of the computer. The field of play is a\n"); - printf("cube of side 3. Any of the 27 locations can be designated\n"); - printf("by inputing three numbers such as 2,3,1. At the start,\n"); - printf("you are automatically at location 1,1,1. The object of\n"); - printf("the game is to get to location 3,3,3. One minor detail:\n"); - printf("the computer will pick, at random, 5 locations at which\n"); - printf("it will plant land mines. If you hit one of these locations\n"); - printf("you lose. One other detail: You may move only one space\n"); - printf("in one direction each move. For example: From 1,1,2 you\n"); - printf("may move to 2,1,2 or 1,1,3. You may not change\n"); - printf("two of the numbers on the same move. If you make an illegal\n"); - printf("move, you lose and the computer takes the money you may\n"); - printf("have bet on that round.\n\n"); - printf("When stating the amount of a wager, printf only the number\n"); - printf("of dollars (example: 250) you are automatically started with\n"); - printf("500 dollars in your account.\n\n"); - printf("Good luck!\n"); -} - -void game(int money){ - coords player,playerold,mines[5]; - int wager,account = money; - char choice; - if(money == 0){ - printf("You have no money left. See ya next time.\n"); - exit(0); - } - player.x = 1; - player.y = 1; - player.z = 1; - - printf("You have $%d in your account.\n",account); - printf("How much do you want to wager? "); - scanf("%d",&wager); - while(wager > account){ - system(CLEAR); - printf("You do not have that much money in your account.\n"); - printf("How much do you want to wager? "); - scanf("%d",&wager); - } - srand(time(NULL)); - for(int i=0;i<5;i++){ - mines[i].x = rand()%3+1; - mines[i].y = rand()%3+1; - mines[i].z = rand()%3+1; - if(mines[i].x == 3 && mines[i].y == 3 && mines[i].z == 3){ - i--; - } - } - while(player.x != 3 || player.y != 3 || player.z != 3){ - printf("You are at location %d.%d.%d\n",player.x,player.y,player.z); - if(player.x == 1 && player.y == 1 && player.z == 1) - printf("Enter new location(use commas like 1,1,2 or else the program will break...): "); - else printf("Enter new location: "); - playerold.x = player.x; - playerold.y = player.y; - playerold.z = player.z; - scanf("%d,%d,%d",&player.x,&player.y,&player.z); - if(((player.x + player.y + player.z) > (playerold.x + playerold.y + playerold.z + 1)) || ((player.x + player.y + player.z) < (playerold.x + playerold.y + playerold.z -1))){ - system(CLEAR); - printf("Illegal move!\n"); - printf("You lose $%d.\n",wager); - game(account -= wager); - break; - } - if(player.x < 1 || player.x > 3 || player.y < 1 || player.y > 3 || player.z < 1 || player.z > 3){ - system(CLEAR); - printf("Illegal move. You lose!\n"); - game(account -= wager); - break; - } - for(int i=0;i<5;i++){ - if(player.x == mines[i].x && player.y == mines[i].y && player.z == mines[i].z){ - system(CLEAR); - printf("You hit a mine!\n"); - printf("You lose $%d.\n",wager); - game(account -= wager); - exit(0); - } - } - if(account == 0){ - system(CLEAR); - printf("You have no money left!\n"); - printf("Game over!\n"); - exit(0); - } - } - if(player.x == 3 && player.y == 3 && player.z == 3){ - system(CLEAR); - printf("You made it to the end. You win!\n"); - game(account += wager); - exit(0); - } -} - -void init(){ - int account = 500; - char choice; - - printf("Welcome to the game of Cube!\n"); - printf("wanna see the instructions? (y/n): "); - scanf("%c",&choice); - if(choice == 'y'){ - system(CLEAR); - instuctions(); - } - else if (choice == 'n'){ - system(CLEAR); - printf("Ok, let's play!\n"); - } - else{ - system(CLEAR); - printf("Invalid choice. Try again...\n"); - init(); - exit(0); - } - game(account); - exit(0); -} - -void main(){ - init(); -} \ 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 deleted file mode 100644 index 17eeb20b7..000000000 --- a/00_Alternate_Languages/30_Cube/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/30_Cube/MiniScript/cube.ms b/00_Alternate_Languages/30_Cube/MiniScript/cube.ms deleted file mode 100644 index 1639ce43f..000000000 --- a/00_Alternate_Languages/30_Cube/MiniScript/cube.ms +++ /dev/null @@ -1,100 +0,0 @@ -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/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md b/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md deleted file mode 100644 index 0c20ea36f..000000000 --- a/00_Alternate_Languages/31_Depth_Charge/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/31_Depth_Charge/MiniScript/depthcharge.ms b/00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms deleted file mode 100644 index 3607cb805..000000000 --- a/00_Alternate_Languages/31_Depth_Charge/MiniScript/depthcharge.ms +++ /dev/null @@ -1,116 +0,0 @@ -// 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 diff --git a/00_Alternate_Languages/31_Depth_Charge/go/main.go b/00_Alternate_Languages/31_Depth_Charge/go/main.go deleted file mode 100644 index 0ab3f8766..000000000 --- a/00_Alternate_Languages/31_Depth_Charge/go/main.go +++ /dev/null @@ -1,156 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math" - "math/rand" - "os" - "strconv" - "strings" - "time" -) - -type Position []int - -func NewPosition() Position { - p := make([]int, 3) - return Position(p) -} - -func showWelcome() { - fmt.Print("\033[H\033[2J") - fmt.Println(" DEPTH CHARGE") - fmt.Println(" Creative Computing Morristown, New Jersey") - fmt.Println() -} - -func getNumCharges() (int, int) { - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println("Dimensions of search area?") - scanner.Scan() - dim, err := strconv.Atoi(scanner.Text()) - if err != nil { - fmt.Println("Must enter an integer number. Please try again...") - continue - } - return dim, int(math.Log2(float64(dim))) + 1 - } -} - -func askForNewGame() { - scanner := bufio.NewScanner(os.Stdin) - - fmt.Println("Another game (Y or N): ") - scanner.Scan() - if strings.ToUpper(scanner.Text()) == "Y" { - main() - } - fmt.Println("OK. Hope you enjoyed yourself") - os.Exit(1) -} - -func showShotResult(shot, location Position) { - result := "Sonar reports shot was " - - if shot[1] > location[1] { // y-direction - result += "north" - } else if shot[1] < location[1] { // y-direction - result += "south" - } - - if shot[0] > location[0] { // x-direction - result += "east" - } else if shot[0] < location[0] { // x-direction - result += "west" - } - - if shot[1] != location[1] || shot[0] != location[0] { - result += " and " - } - if shot[2] > location[2] { - result += "too low." - } else if shot[2] < location[2] { - result += "too high." - } else { - result += "depth OK." - } - - fmt.Println(result) -} - -func getShot() Position { - scanner := bufio.NewScanner(os.Stdin) - - for { - shotPos := NewPosition() - fmt.Println("Enter coordinates: ") - scanner.Scan() - rawGuess := strings.Split(scanner.Text(), " ") - if len(rawGuess) != 3 { - goto there - } - for i := 0; i < 3; i++ { - val, err := strconv.Atoi(rawGuess[i]) - if err != nil { - goto there - } - shotPos[i] = val - } - return shotPos - there: - fmt.Println("Please enter coordinates separated by spaces") - fmt.Println("Example: 3 2 1") - } -} - -func getRandomPosition(searchArea int) Position { - pos := NewPosition() - for i := 0; i < 3; i++ { - pos[i] = rand.Intn(searchArea) - } - return pos -} - -func playGame(searchArea, numCharges int) { - rand.Seed(time.Now().UTC().UnixNano()) - fmt.Println("\nYou are the captain of the destroyer USS Computer.") - fmt.Println("An enemy sub has been causing you trouble. Your") - fmt.Printf("mission is to destroy it. You have %d shots.\n", numCharges) - fmt.Println("Specify depth charge explosion point with a") - fmt.Println("trio of numbers -- the first two are the") - fmt.Println("surface coordinates; the third is the depth.") - fmt.Println("\nGood luck!") - fmt.Println() - - subPos := getRandomPosition(searchArea) - - for c := 0; c < numCharges; c++ { - fmt.Printf("\nTrial #%d\n", c+1) - - shot := getShot() - - if shot[0] == subPos[0] && shot[1] == subPos[1] && shot[2] == subPos[2] { - fmt.Printf("\nB O O M ! ! You found it in %d tries!\n", c+1) - askForNewGame() - } else { - showShotResult(shot, subPos) - } - } - - // out of depth charges - fmt.Println("\nYou have been torpedoed! Abandon ship!") - fmt.Printf("The submarine was at %d %d %d\n", subPos[0], subPos[1], subPos[2]) - askForNewGame() - -} - -func main() { - showWelcome() - - searchArea, numCharges := getNumCharges() - - playGame(searchArea, numCharges) -} diff --git a/00_Alternate_Languages/32_Diamond/MiniScript/README.md b/00_Alternate_Languages/32_Diamond/MiniScript/README.md deleted file mode 100644 index 3a8249a0d..000000000 --- a/00_Alternate_Languages/32_Diamond/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/32_Diamond/MiniScript/diamond.ms b/00_Alternate_Languages/32_Diamond/MiniScript/diamond.ms deleted file mode 100644 index 8166b570a..000000000 --- a/00_Alternate_Languages/32_Diamond/MiniScript/diamond.ms +++ /dev/null @@ -1,23 +0,0 @@ -// 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 - diff --git a/00_Alternate_Languages/33_Dice/C/dice.c b/00_Alternate_Languages/33_Dice/C/dice.c deleted file mode 100644 index 1ab77fcac..000000000 --- a/00_Alternate_Languages/33_Dice/C/dice.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include - -float percent(int number, int total){ - float percent; - percent = (float)number / (float)total * 100; - return percent; -} - -int main(){ - int dice1,dice2,times,rolls[13] = {0}; - srand(time(NULL)); - printf("This program simulates the rolling of a pair of dice\n"); - printf("How many times do you want to roll the dice?(Higher the number longer the waiting time): "); - scanf("%d",×); - for(int i = 0; i < times; i++){ - dice1 = rand() % 6 + 1; - dice2 = rand() % 6 + 1; - rolls[dice1 + dice2]+=1; - } - printf("The number of times each sum was rolled is:\n"); - for(int i = 2; i <= 12; i++){ - printf("%d: rolled %d times, or %f%c of the times\n",i,rolls[i],percent(rolls[i],times),(char)37); - } -} \ No newline at end of file diff --git a/00_Alternate_Languages/33_Dice/Julia/Dice.jl b/00_Alternate_Languages/33_Dice/Julia/Dice.jl deleted file mode 100644 index 8cc982923..000000000 --- a/00_Alternate_Languages/33_Dice/Julia/Dice.jl +++ /dev/null @@ -1,75 +0,0 @@ -#= -Port of Dice from BASIC Computer Games (1978) - -This "game" simulates a given number of dice rolls, and returns the -count for each possible total. - -The only change that has been made from the original program, is that -when asking if the user wants to play again, any string starting with -y or Y will be accepted, instead of only YES. -=# - -function main() - # Array to store the counts for each total. - # There are 11 possible totals. - counts = [0 for i in 1:11] - - # Print intro text - println("\n Dice") - println("Creative Computing Morristown, New Jersey") - println("\n\n") - println("This program simulates the rolling of a") - println("pair of dice.") - println("You enter the number of times you want the computer to") - println("'roll' the dice. Watch out, very large numbers take") - println("a long time. In particular, numbers over 5000.") - - still_playing = true - while still_playing - println() - print("How many rolls? ") - - # Get user input for number of dice rolls - rolls = readline() - rolls = parse(Int64, rolls) - - # Roll dice the specified number of times and update total count - for _ in 1:rolls - dice_roll = rand(1:6, 2) - dice_sum = sum(dice_roll) - - # The index is one less than the sum, as a sum of 1 is impossible, - # the array will only have 11 values - counts[dice_sum-1] += 1 - end - - # Display results - println("\nTotal Spots Number of Times") - for i in 1:8 - print(" ") - print(i+1) - print(" ") - println(counts[i]) - end - for i in 9:11 - print(" ") - print(i+1) - print(" ") - println(counts[i]) - end - - # Ask try again - print("\nTry Again? ") - input = readline() - if length(input) > 0 && uppercase(input)[1] == 'Y' - # If game is continued, resets total counts - counts = [0 for i in 1:11] - else - still_playing = false - end - end -end - -if abspath(PROGRAM_FILE) == @__FILE__ - main() -end \ No newline at end of file diff --git a/00_Alternate_Languages/33_Dice/Julia/README.md b/00_Alternate_Languages/33_Dice/Julia/README.md deleted file mode 100644 index fb77771d1..000000000 --- a/00_Alternate_Languages/33_Dice/Julia/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Python](https://www.julialang.org/) \ 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 deleted file mode 100644 index b670e30da..000000000 --- a/00_Alternate_Languages/33_Dice/MiniScript/README.md +++ /dev/null @@ -1,21 +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 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/33_Dice/MiniScript/dice.ms b/00_Alternate_Languages/33_Dice/MiniScript/dice.ms deleted file mode 100644 index 38b41ef34..000000000 --- a/00_Alternate_Languages/33_Dice/MiniScript/dice.ms +++ /dev/null @@ -1,53 +0,0 @@ -// 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 diff --git a/00_Alternate_Languages/33_Dice/go/main.go b/00_Alternate_Languages/33_Dice/go/main.go deleted file mode 100644 index 75bef387c..000000000 --- a/00_Alternate_Languages/33_Dice/go/main.go +++ /dev/null @@ -1,64 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math/rand" - "os" - "strconv" - "strings" -) - -func printWelcome() { - fmt.Println("\n Dice") - fmt.Println("Creative Computing Morristown, New Jersey") - fmt.Println() - fmt.Println() - fmt.Println("This program simulates the rolling of a") - fmt.Println("pair of dice.") - fmt.Println("You enter the number of times you want the computer to") - fmt.Println("'roll' the dice. Watch out, very large numbers take") - fmt.Println("a long time. In particular, numbers over 5000.") - fmt.Println() -} - -func main() { - printWelcome() - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println("\nHow many rolls? ") - scanner.Scan() - numRolls, err := strconv.Atoi(scanner.Text()) - if err != nil { - fmt.Println("Invalid input, try again...") - continue - } - - // We'll track counts of roll outcomes in a 13-element list. - // The first two indices (0 & 1) are ignored, leaving just - // the indices that match the roll values (2 through 12). - results := make([]int, 13) - - for n := 0; n < numRolls; n++ { - d1 := rand.Intn(6) + 1 - d2 := rand.Intn(6) + 1 - results[d1+d2] += 1 - } - - // Display final results - fmt.Println("\nTotal Spots Number of Times") - for i := 2; i < 13; i++ { - fmt.Printf(" %-14d%d\n", i, results[i]) - } - - fmt.Println("\nTry again? ") - scanner.Scan() - if strings.ToUpper(scanner.Text()) == "Y" { - continue - } else { - os.Exit(1) - } - - } -} diff --git a/00_Alternate_Languages/33_Dice/nim/dice.nim b/00_Alternate_Languages/33_Dice/nim/dice.nim deleted file mode 100644 index 6564ae9ba..000000000 --- a/00_Alternate_Languages/33_Dice/nim/dice.nim +++ /dev/null @@ -1,37 +0,0 @@ -import std/[random,strutils] - -var - a,b,r,x: int - f: array[2..12, int] - 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" -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 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 - 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() - retry = (z=="yes") or (z=="y") diff --git a/00_Alternate_Languages/34_Digits/MiniScript/README.md b/00_Alternate_Languages/34_Digits/MiniScript/README.md deleted file mode 100644 index 280be246e..000000000 --- a/00_Alternate_Languages/34_Digits/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/34_Digits/MiniScript/digits.ms b/00_Alternate_Languages/34_Digits/MiniScript/digits.ms deleted file mode 100644 index 2abde907d..000000000 --- a/00_Alternate_Languages/34_Digits/MiniScript/digits.ms +++ /dev/null @@ -1,99 +0,0 @@ -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/00_Alternate_Languages/34_Digits/go/main.go b/00_Alternate_Languages/34_Digits/go/main.go deleted file mode 100644 index 64326d533..000000000 --- a/00_Alternate_Languages/34_Digits/go/main.go +++ /dev/null @@ -1,171 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math/rand" - "os" - "strconv" - "time" -) - -func printIntro() { - fmt.Println(" DIGITS") - fmt.Println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - fmt.Println() - fmt.Println() - fmt.Println("THIS IS A GAME OF GUESSING.") -} - -func readInteger(prompt string) int { - scanner := bufio.NewScanner(os.Stdin) - for { - fmt.Println(prompt) - scanner.Scan() - response, err := strconv.Atoi(scanner.Text()) - - if err != nil { - fmt.Println("INVALID INPUT, TRY AGAIN... ") - continue - } - - return response - } -} - -func printInstructions() { - fmt.Println() - fmt.Println("PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN") - fmt.Println("THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.") - fmt.Println("ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.") - fmt.Println("I WILL ASK FOR THEN TEN AT A TIME.") - fmt.Println("I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR") - fmt.Println("NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,") - fmt.Println("I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER") - fmt.Println("THAN THAT *****") - fmt.Println() -} - -func readTenNumbers() []int { - numbers := make([]int, 10) - - numbers[0] = readInteger("FIRST NUMBER: ") - for i := 1; i < 10; i++ { - numbers[i] = readInteger("NEXT NUMBER:") - } - - return numbers -} - -func printSummary(correct int) { - fmt.Println() - - if correct > 10 { - fmt.Println() - fmt.Println("I GUESSED MORE THAN 1/3 OF YOUR NUMBERS.") - fmt.Println("I WIN.\u0007") - } else if correct < 10 { - fmt.Println("I GUESSED LESS THAN 1/3 OF YOUR NUMBERS.") - fmt.Println("YOU BEAT ME. CONGRATULATIONS *****") - } else { - fmt.Println("I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.") - fmt.Println("IT'S A TIE GAME.") - } -} - -func buildArray(val, row, col int) [][]int { - a := make([][]int, row) - for r := 0; r < row; r++ { - b := make([]int, col) - for c := 0; c < col; c++ { - b[c] = val - } - a[r] = b - } - return a -} - -func main() { - rand.Seed(time.Now().UnixNano()) - - printIntro() - if readInteger("FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0' ? ") == 1 { - printInstructions() - } - - a := 0 - b := 1 - c := 3 - - m := buildArray(1, 27, 3) - k := buildArray(9, 3, 3) - l := buildArray(3, 9, 3) - - for { - l[0][0] = 2 - l[4][1] = 2 - l[8][2] = 2 - - z := float64(26) - z1 := float64(8) - z2 := 2 - runningCorrect := 0 - - var numbers []int - for round := 1; round <= 4; round++ { - validNumbers := false - for !validNumbers { - numbers = readTenNumbers() - validNumbers = true - for _, n := range numbers { - if n < 0 || n > 2 { - fmt.Println("ONLY USE THE DIGITS '0', '1', OR '2'.") - fmt.Println("LET'S TRY AGAIN.") - validNumbers = false - break - } - } - } - - fmt.Printf("\n%-14s%-14s%-14s%-14s\n", "MY GUESS", "YOUR NO.", "RESULT", "NO. RIGHT") - - for _, n := range numbers { - s := 0 - myGuess := 0 - - for j := 0; j < 3; j++ { - s1 := a*k[z2][j] + b*l[int(z1)][j] + c*m[int(z)][j] - - if s < s1 { - s = s1 - myGuess = j - } else if s1 == s && rand.Float64() > 0.5 { - myGuess = j - } - } - result := "" - - if myGuess != n { - result = "WRONG" - } else { - runningCorrect += 1 - result = "RIGHT" - m[int(z)][n] = m[int(z)][n] + 1 - l[int(z1)][n] = l[int(z1)][n] + 1 - k[int(z2)][n] = k[int(z2)][n] + 1 - z = z - (z/9)*9 - z = 3.0*z + float64(n) - } - fmt.Printf("\n%-14d%-14d%-14s%-14d\n", myGuess, n, result, runningCorrect) - - z1 = z - (z/9)*9 - z2 = n - } - printSummary(runningCorrect) - if readInteger("\nDO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO) ? ") != 1 { - fmt.Println("\nTHANKS FOR THE GAME.") - os.Exit(0) - } - } - } -} diff --git a/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md b/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md deleted file mode 100644 index d52819302..000000000 --- a/00_Alternate_Languages/35_Even_Wins/MiniScript/README.md +++ /dev/null @@ -1,33 +0,0 @@ -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 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/35_Even_Wins/MiniScript/evenwins.ms b/00_Alternate_Languages/35_Even_Wins/MiniScript/evenwins.ms deleted file mode 100644 index 0712b830f..000000000 --- a/00_Alternate_Languages/35_Even_Wins/MiniScript/evenwins.ms +++ /dev/null @@ -1,140 +0,0 @@ -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 deleted file mode 100644 index e533550d1..000000000 --- a/00_Alternate_Languages/35_Even_Wins/MiniScript/gameofevenwins.ms +++ /dev/null @@ -1,90 +0,0 @@ -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 diff --git a/00_Alternate_Languages/35_Even_Wins/go/evenwins.go b/00_Alternate_Languages/35_Even_Wins/go/evenwins.go deleted file mode 100644 index 7c65aacc1..000000000 --- a/00_Alternate_Languages/35_Even_Wins/go/evenwins.go +++ /dev/null @@ -1,197 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "strconv" - "strings" -) - -const MAXTAKE = 4 - -type PlayerType int8 - -const ( - HUMAN PlayerType = iota - COMPUTER -) - -type Game struct { - table int - human int - computer int -} - -func NewGame() Game { - g := Game{} - g.table = 27 - - return g -} - -func printIntro() { - fmt.Println("Welcome to Even Wins!") - fmt.Println("Based on evenwins.bas from Creative Computing") - fmt.Println() - fmt.Println("Even Wins is a two-person game. You start with") - fmt.Println("27 marbles in the middle of the table.") - fmt.Println() - fmt.Println("Players alternate taking marbles from the middle.") - fmt.Println("A player can take 1 to 4 marbles on their turn, and") - fmt.Println("turns cannot be skipped. The game ends when there are") - fmt.Println("no marbles left, and the winner is the one with an even") - fmt.Println("number of marbles.") - fmt.Println() -} - -func (g *Game) printBoard() { - fmt.Println() - fmt.Printf(" marbles in the middle: %d\n", g.table) - fmt.Printf(" # marbles you have: %d\n", g.human) - fmt.Printf("# marbles computer has: %d\n", g.computer) - fmt.Println() -} - -func (g *Game) gameOver() { - fmt.Println() - fmt.Println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") - fmt.Println("!! All the marbles are taken: Game Over!") - fmt.Println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") - fmt.Println() - g.printBoard() - if g.human%2 == 0 { - fmt.Println("You are the winner! Congratulations!") - } else { - fmt.Println("The computer wins: all hail mighty silicon!") - } - fmt.Println() -} - -func getPlural(count int) string { - m := "marble" - if count > 1 { - m += "s" - } - return m -} - -func (g *Game) humanTurn() { - scanner := bufio.NewScanner(os.Stdin) - maxAvailable := MAXTAKE - if g.table < MAXTAKE { - maxAvailable = g.table - } - - fmt.Println("It's your turn!") - for { - fmt.Printf("Marbles to take? (1 - %d) --> ", maxAvailable) - scanner.Scan() - n, err := strconv.Atoi(scanner.Text()) - if err != nil { - fmt.Printf("\n Please enter a whole number from 1 to %d\n", maxAvailable) - continue - } - if n < 1 { - fmt.Println("\n You must take at least 1 marble!") - continue - } - if n > maxAvailable { - fmt.Printf("\n You can take at most %d %s\n", maxAvailable, getPlural(maxAvailable)) - continue - } - fmt.Printf("\nOkay, taking %d %s ...\n", n, getPlural(n)) - g.table -= n - g.human += n - return - } -} - -func (g *Game) computerTurn() { - marblesToTake := 0 - - fmt.Println("It's the computer's turn ...") - r := float64(g.table - 6*int((g.table)/6)) - - if int(g.human/2) == g.human/2 { - if r < 1.5 || r > 5.3 { - marblesToTake = 1 - } else { - marblesToTake = int(r - 1) - } - } else if float64(g.table) < 4.2 { - marblesToTake = 4 - } else if r > 3.4 { - if r < 4.7 || r > 3.5 { - marblesToTake = 4 - } - } else { - marblesToTake = int(r + 1) - } - - fmt.Printf("Computer takes %d %s ...\n", marblesToTake, getPlural(marblesToTake)) - g.table -= marblesToTake - g.computer += marblesToTake -} - -func (g *Game) play(playersTurn PlayerType) { - g.printBoard() - - for { - if g.table == 0 { - g.gameOver() - return - } else if playersTurn == HUMAN { - g.humanTurn() - g.printBoard() - playersTurn = COMPUTER - } else { - g.computerTurn() - g.printBoard() - playersTurn = HUMAN - } - } -} - -func getFirstPlayer() PlayerType { - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println("Do you want to play first? (y/n) --> ") - scanner.Scan() - - if strings.ToUpper(scanner.Text()) == "Y" { - return HUMAN - } else if strings.ToUpper(scanner.Text()) == "N" { - return COMPUTER - } else { - fmt.Println() - fmt.Println("Please enter 'y' if you want to play first,") - fmt.Println("or 'n' if you want to play second.") - fmt.Println() - } - } -} - -func main() { - scanner := bufio.NewScanner(os.Stdin) - - printIntro() - - for { - g := NewGame() - - g.play(getFirstPlayer()) - - fmt.Println("\nWould you like to play again? (y/n) --> ") - scanner.Scan() - if strings.ToUpper(scanner.Text()) == "Y" { - fmt.Println("\nOk, let's play again ...") - } else { - fmt.Println("\nOk, thanks for playing ... goodbye!") - return - } - - } - -} diff --git a/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md b/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md deleted file mode 100644 index e012477dd..000000000 --- a/00_Alternate_Languages/36_Flip_Flop/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/36_Flip_Flop/MiniScript/flipflop.ms b/00_Alternate_Languages/36_Flip_Flop/MiniScript/flipflop.ms deleted file mode 100644 index 6fb07cc0a..000000000 --- a/00_Alternate_Languages/36_Flip_Flop/MiniScript/flipflop.ms +++ /dev/null @@ -1,97 +0,0 @@ -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 diff --git a/00_Alternate_Languages/37_Football/MiniScript/README.md b/00_Alternate_Languages/37_Football/MiniScript/README.md deleted file mode 100644 index 4d8c33066..000000000 --- a/00_Alternate_Languages/37_Football/MiniScript/README.md +++ /dev/null @@ -1,34 +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 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 MiniScript program and this README file. 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 deleted file mode 100644 index e2b4583f6..000000000 --- a/00_Alternate_Languages/37_Football/MiniScript/football.ms +++ /dev/null @@ -1,402 +0,0 @@ -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 deleted file mode 100644 index 31d3f8299..000000000 --- a/00_Alternate_Languages/37_Football/MiniScript/ftball.ms +++ /dev/null @@ -1,431 +0,0 @@ -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 deleted file mode 100644 index 3b15b9926..000000000 --- a/00_Alternate_Languages/38_Fur_Trader/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/38_Fur_Trader/MiniScript/furtrader.ms b/00_Alternate_Languages/38_Fur_Trader/MiniScript/furtrader.ms deleted file mode 100644 index 6fb85e1a2..000000000 --- a/00_Alternate_Languages/38_Fur_Trader/MiniScript/furtrader.ms +++ /dev/null @@ -1,171 +0,0 @@ -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/00_Alternate_Languages/38_Fur_Trader/go/main.go b/00_Alternate_Languages/38_Fur_Trader/go/main.go deleted file mode 100644 index 642d48f06..000000000 --- a/00_Alternate_Languages/38_Fur_Trader/go/main.go +++ /dev/null @@ -1,326 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "log" - "math/rand" - "os" - "strconv" - "strings" - "time" -) - -const ( - MAXFURS = 190 - STARTFUNDS = 600 -) - -type Fur int8 - -const ( - FUR_MINK Fur = iota - FUR_BEAVER - FUR_ERMINE - FUR_FOX -) - -type Fort int8 - -const ( - FORT_MONTREAL Fort = iota - FORT_QUEBEC - FORT_NEWYORK -) - -type GameState int8 - -const ( - STARTING GameState = iota - TRADING - CHOOSINGFORT - TRAVELLING -) - -func FURS() []string { - return []string{"MINK", "BEAVER", "ERMINE", "FOX"} -} - -func FORTS() []string { - return []string{"HOCHELAGA (MONTREAL)", "STADACONA (QUEBEC)", "NEW YORK"} -} - -type Player struct { - funds float32 - furs []int -} - -func NewPlayer() Player { - p := Player{} - p.funds = STARTFUNDS - p.furs = make([]int, 4) - return p -} - -func (p *Player) totalFurs() int { - f := 0 - for _, v := range p.furs { - f += v - } - return f -} - -func (p *Player) lostFurs() { - for f := 0; f < len(p.furs); f++ { - p.furs[f] = 0 - } -} - -func printTitle() { - fmt.Println(" FUR TRADER") - fmt.Println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - fmt.Println() - fmt.Println() - fmt.Println() -} - -func printIntro() { - fmt.Println("YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN ") - fmt.Println("1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET") - fmt.Println("SUPPLIES FOR THE NEXT YEAR. YOU HAVE A CHOICE OF THREE") - fmt.Println("FORTS AT WHICH YOU MAY TRADE. THE COST OF SUPPLIES") - fmt.Println("AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND") - fmt.Println("ON THE FORT THAT YOU CHOOSE.") - fmt.Println() -} - -func getFortChoice() Fort { - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println() - fmt.Println("YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,") - fmt.Println("OR FORT 3. FORT 1 IS FORT HOCHELAGA (MONTREAL)") - fmt.Println("AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.") - fmt.Println("FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE") - fmt.Println("PROTECTION OF THE FRENCH ARMY. HOWEVER, YOU MUST") - fmt.Println("MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.") - fmt.Println("FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.") - fmt.Println("YOU MUST CROSS THROUGH IROQUOIS LAND.") - fmt.Println("ANSWER 1, 2, OR 3.") - fmt.Print(">> ") - scanner.Scan() - - f, err := strconv.Atoi(scanner.Text()) - if err != nil || f < 1 || f > 3 { - fmt.Println("Invalid input, Try again ... ") - continue - } - return Fort(f) - } -} - -func printFortComment(f Fort) { - fmt.Println() - switch f { - case FORT_MONTREAL: - fmt.Println("YOU HAVE CHOSEN THE EASIEST ROUTE. HOWEVER, THE FORT") - fmt.Println("IS FAR FROM ANY SEAPORT. THE VALUE") - fmt.Println("YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST") - fmt.Println("OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.") - case FORT_QUEBEC: - fmt.Println("YOU HAVE CHOSEN A HARD ROUTE. IT IS, IN COMPARSION,") - fmt.Println("HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN") - fmt.Println("THE ROUTE TO NEW YORK. YOU WILL RECEIVE AN AVERAGE VALUE") - fmt.Println("FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.") - case FORT_NEWYORK: - fmt.Println("YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE. AT") - fmt.Println("FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE") - fmt.Println("FOR YOUR FURS. THE COST OF YOUR SUPPLIES") - fmt.Println("WILL BE LOWER THAN AT ALL THE OTHER FORTS.") - } - fmt.Println() -} - -func getYesOrNo() string { - scanner := bufio.NewScanner(os.Stdin) - for { - fmt.Println("ANSWER YES OR NO") - scanner.Scan() - if strings.ToUpper(scanner.Text())[0:1] == "Y" { - return "Y" - } else if strings.ToUpper(scanner.Text())[0:1] == "N" { - return "N" - } - } -} - -func getFursPurchase() []int { - scanner := bufio.NewScanner(os.Stdin) - fmt.Printf("YOUR %d FURS ARE DISTRIBUTED AMONG THE FOLLOWING\n", MAXFURS) - fmt.Println("KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.") - fmt.Println() - - purchases := make([]int, 4) - - for i, f := range FURS() { - retry: - fmt.Printf("HOW MANY %s DO YOU HAVE: ", f) - scanner.Scan() - count, err := strconv.Atoi(scanner.Text()) - if err != nil { - fmt.Println("INVALID INPUT, TRY AGAIN ...") - goto retry - } - purchases[i] = count - } - - return purchases -} - -func main() { - rand.Seed(time.Now().UnixNano()) - - printTitle() - - gameState := STARTING - whichFort := FORT_NEWYORK - var ( - minkPrice int - erminePrice int - beaverPrice int - foxPrice int - ) - player := NewPlayer() - - for { - switch gameState { - case STARTING: - printIntro() - fmt.Println("DO YOU WISH TO TRADE FURS?") - if getYesOrNo() == "N" { - os.Exit(0) - } - gameState = TRADING - case TRADING: - fmt.Println() - fmt.Printf("YOU HAVE $ %1.2f IN SAVINGS\n", player.funds) - fmt.Printf("AND %d FURS TO BEGIN THE EXPEDITION\n", MAXFURS) - player.furs = getFursPurchase() - - if player.totalFurs() > MAXFURS { - fmt.Println() - fmt.Println("YOU MAY NOT HAVE THAT MANY FURS.") - fmt.Println("DO NOT TRY TO CHEAT. I CAN ADD.") - fmt.Println("YOU MUST START AGAIN.") - gameState = STARTING - } else { - gameState = CHOOSINGFORT - } - case CHOOSINGFORT: - whichFort = getFortChoice() - printFortComment(whichFort) - fmt.Println("DO YOU WANT TO TRADE AT ANOTHER FORT?") - changeFort := getYesOrNo() - if changeFort == "N" { - gameState = TRAVELLING - } - case TRAVELLING: - switch whichFort { - case FORT_MONTREAL: - minkPrice = (int((0.2*rand.Float64()+0.70)*100+0.5) / 100) - erminePrice = (int((0.2*rand.Float64()+0.65)*100+0.5) / 100) - beaverPrice = (int((0.2*rand.Float64()+0.75)*100+0.5) / 100) - foxPrice = (int((0.2*rand.Float64()+0.80)*100+0.5) / 100) - - fmt.Println("SUPPLIES AT FORT HOCHELAGA COST $150.00.") - fmt.Println("YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.") - player.funds -= 160 - case FORT_QUEBEC: - minkPrice = (int((0.30*rand.Float64()+0.85)*100+0.5) / 100) - erminePrice = (int((0.15*rand.Float64()+0.80)*100+0.5) / 100) - beaverPrice = (int((0.20*rand.Float64()+0.90)*100+0.5) / 100) - foxPrice = (int((0.25*rand.Float64()+1.10)*100+0.5) / 100) - - event := int(10*rand.Float64()) + 1 - if event <= 2 { - fmt.Println("YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS") - fmt.Println("THE PORTAGE. YOU HAD TO LEAVE THE PELTS, BUT FOUND") - fmt.Println("THEM STOLEN WHEN YOU RETURNED.") - player.furs[FUR_BEAVER] = 0 - } else if event <= 6 { - fmt.Println("YOU ARRIVED SAFELY AT FORT STADACONA.") - } else if event <= 8 { - fmt.Println("YOUR CANOE UPSET IN THE LACHINE RAPIDS. YOU") - fmt.Println("LOST ALL YOUR FURS.") - player.lostFurs() - } else if event <= 10 { - fmt.Println("YOUR FOX PELTS WERE NOT CURED PROPERLY.") - fmt.Println("NO ONE WILL BUY THEM.") - player.furs[FUR_FOX] = 0 - } else { - log.Fatal("Unexpected error") - } - - fmt.Println() - fmt.Println("SUPPLIES AT FORT STADACONA COST $125.00.") - fmt.Println("YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.") - player.funds -= 140 - case FORT_NEWYORK: - minkPrice = (int((0.15*rand.Float64()+1.05)*100+0.5) / 100) - erminePrice = (int((0.15*rand.Float64()+0.95)*100+0.5) / 100) - beaverPrice = (int((0.25*rand.Float64()+1.00)*100+0.5) / 100) - foxPrice = (int((0.25*rand.Float64()+1.05)*100+0.5) / 100) // not in original code - - event := int(10*rand.Float64()) + 1 - if event <= 2 { - fmt.Println("YOU WERE ATTACKED BY A PARTY OF IROQUOIS.") - fmt.Println("ALL PEOPLE IN YOUR TRADING GROUP WERE") - fmt.Println("KILLED. THIS ENDS THE GAME.") - os.Exit(0) - } else if event <= 6 { - fmt.Println("YOU WERE LUCKY. YOU ARRIVED SAFELY") - fmt.Println("AT FORT NEW YORK.") - } else if event <= 8 { - fmt.Println("YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.") - fmt.Println("HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.") - player.lostFurs() - } else if event <= 10 { - minkPrice /= 2 - foxPrice /= 2 - fmt.Println("YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.") - fmt.Println("YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.") - } else { - log.Fatal("Unexpected error") - } - - fmt.Println() - fmt.Println("SUPPLIES AT NEW YORK COST $85.00.") - fmt.Println("YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.") - player.funds -= 110 - } - - beaverValue := beaverPrice * player.furs[FUR_BEAVER] - foxValue := foxPrice * player.furs[FUR_FOX] - ermineValue := erminePrice * player.furs[FUR_ERMINE] - minkValue := minkPrice * player.furs[FUR_MINK] - - fmt.Println() - fmt.Printf("YOUR BEAVER SOLD FOR $%6.2f\n", float64(beaverValue)) - fmt.Printf("YOUR FOX SOLD FOR $%6.2f\n", float64(foxValue)) - fmt.Printf("YOUR ERMINE SOLD FOR $%6.2f\n", float64(ermineValue)) - fmt.Printf("YOUR MINK SOLD FOR $%6.2f\n", float64(minkValue)) - - player.funds += float32(beaverValue + foxValue + ermineValue + minkValue) - - fmt.Println() - fmt.Printf("YOU NOW HAVE $%1.2f INCLUDING YOUR PREVIOUS SAVINGS\n", player.funds) - fmt.Println("\nDO YOU WANT TO TRADE FURS NEXT YEAR?") - if getYesOrNo() == "N" { - os.Exit(0) - } else { - gameState = TRADING - } - } - } -} diff --git a/00_Alternate_Languages/39_Golf/MiniScript/README.md b/00_Alternate_Languages/39_Golf/MiniScript/README.md deleted file mode 100644 index 8a7e5325d..000000000 --- a/00_Alternate_Languages/39_Golf/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/39_Golf/MiniScript/golf.ms b/00_Alternate_Languages/39_Golf/MiniScript/golf.ms deleted file mode 100644 index 634ef0905..000000000 --- a/00_Alternate_Languages/39_Golf/MiniScript/golf.ms +++ /dev/null @@ -1,303 +0,0 @@ -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/00_Alternate_Languages/40_Gomoko/MiniScript/README.md b/00_Alternate_Languages/40_Gomoko/MiniScript/README.md deleted file mode 100644 index 5613d133a..000000000 --- a/00_Alternate_Languages/40_Gomoko/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/40_Gomoko/MiniScript/gomoko.ms b/00_Alternate_Languages/40_Gomoko/MiniScript/gomoko.ms deleted file mode 100644 index 3188e22a1..000000000 --- a/00_Alternate_Languages/40_Gomoko/MiniScript/gomoko.ms +++ /dev/null @@ -1,94 +0,0 @@ -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 diff --git a/00_Alternate_Languages/41_Guess/MiniScript/README.md b/00_Alternate_Languages/41_Guess/MiniScript/README.md deleted file mode 100644 index bf19c7599..000000000 --- a/00_Alternate_Languages/41_Guess/MiniScript/README.md +++ /dev/null @@ -1,21 +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 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/41_Guess/MiniScript/guess.ms b/00_Alternate_Languages/41_Guess/MiniScript/guess.ms deleted file mode 100644 index 496426ce4..000000000 --- a/00_Alternate_Languages/41_Guess/MiniScript/guess.ms +++ /dev/null @@ -1,59 +0,0 @@ -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 diff --git a/00_Alternate_Languages/41_Guess/go/main.go b/00_Alternate_Languages/41_Guess/go/main.go deleted file mode 100644 index eea6ad226..000000000 --- a/00_Alternate_Languages/41_Guess/go/main.go +++ /dev/null @@ -1,95 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math" - "math/rand" - "os" - "strconv" - "time" -) - -func printIntro() { - fmt.Println(" Guess") - fmt.Println("Creative Computing Morristown, New Jersey") - fmt.Println() - fmt.Println() - fmt.Println() - fmt.Println("This is a number guessing game. I'll think") - fmt.Println("of a number between 1 and any limit you want.") - fmt.Println("Then you have to guess what it is") -} - -func getLimit() (int, int) { - scanner := bufio.NewScanner(os.Stdin) - - for { - fmt.Println("What limit do you want?") - scanner.Scan() - - limit, err := strconv.Atoi(scanner.Text()) - if err != nil || limit < 0 { - fmt.Println("Please enter a number greater or equal to 1") - continue - } - - limitGoal := int((math.Log(float64(limit)) / math.Log(2)) + 1) - return limit, limitGoal - } - -} - -func main() { - rand.Seed(time.Now().UnixNano()) - printIntro() - - scanner := bufio.NewScanner(os.Stdin) - - limit, limitGoal := getLimit() - - guessCount := 1 - stillGuessing := true - won := false - myGuess := int(float64(limit)*rand.Float64() + 1) - - fmt.Printf("I'm thinking of a number between 1 and %d\n", limit) - fmt.Println("Now you try to guess what it is.") - - for stillGuessing { - scanner.Scan() - n, err := strconv.Atoi(scanner.Text()) - if err != nil { - fmt.Println("Please enter a number greater or equal to 1") - continue - } - - if n < 0 { - break - } - - fmt.Print("\n\n\n") - if n < myGuess { - fmt.Println("Too low. Try a bigger answer") - guessCount += 1 - } else if n > myGuess { - fmt.Println("Too high. Try a smaller answer") - guessCount += 1 - } else { - fmt.Printf("That's it! You got it in %d tries\n", guessCount) - won = true - stillGuessing = false - } - } - - if won { - if guessCount < limitGoal { - fmt.Println("Very good.") - } else if guessCount == limitGoal { - fmt.Println("Good.") - } else { - fmt.Printf("You should have been able to get it in only %d guesses.\n", limitGoal) - } - fmt.Print("\n\n\n") - } -} diff --git a/00_Alternate_Languages/42_Gunner/MiniScript/README.md b/00_Alternate_Languages/42_Gunner/MiniScript/README.md deleted file mode 100644 index 323499176..000000000 --- a/00_Alternate_Languages/42_Gunner/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/42_Gunner/MiniScript/gunner.ms b/00_Alternate_Languages/42_Gunner/MiniScript/gunner.ms deleted file mode 100644 index 5c52a89ea..000000000 --- a/00_Alternate_Languages/42_Gunner/MiniScript/gunner.ms +++ /dev/null @@ -1,78 +0,0 @@ -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/42_Gunner/go/main.go b/00_Alternate_Languages/42_Gunner/go/main.go deleted file mode 100644 index 8ea76cec8..000000000 --- a/00_Alternate_Languages/42_Gunner/go/main.go +++ /dev/null @@ -1,125 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math" - "math/rand" - "os" - "strconv" - "strings" - "time" -) - -func printIntro() { - fmt.Println(" GUNNER") - fmt.Println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - fmt.Print("\n\n\n") - fmt.Println("YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN") - fmt.Println("CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE") - fmt.Println("WILL PLACE A PROJECTILE ON TARGET. A HIT WITHIN 100 YARDS") - fmt.Println("OF THE TARGET WILL DESTROY IT.") - fmt.Println() -} - -func getFloat() float64 { - scanner := bufio.NewScanner(os.Stdin) - for { - scanner.Scan() - fl, err := strconv.ParseFloat(scanner.Text(), 64) - - if err != nil { - fmt.Println("Invalid input") - continue - } - - return fl - } -} - -func play() { - gunRange := int(40000*rand.Float64() + 20000) - fmt.Printf("\nMAXIMUM RANGE OF YOUR GUN IS %d YARDS\n", gunRange) - - killedEnemies := 0 - S1 := 0 - - for { - targetDistance := int(float64(gunRange) * (0.1 + 0.8*rand.Float64())) - shots := 0 - - fmt.Printf("\nDISTANCE TO THE TARGET IS %d YARDS\n", targetDistance) - - for { - fmt.Print("\n\nELEVATION? ") - elevation := getFloat() - - if elevation > 89 { - fmt.Println("MAXIMUM ELEVATION IS 89 DEGREES") - continue - } - - if elevation < 1 { - fmt.Println("MINIMUM ELEVATION IS 1 DEGREE") - continue - } - - shots += 1 - - if shots < 6 { - B2 := 2 * elevation / 57.3 - shotImpact := int(float64(gunRange) * math.Sin(B2)) - shotProximity := int(targetDistance - shotImpact) - - if math.Abs(float64(shotProximity)) < 100 { // hit - fmt.Printf("*** TARGET DESTROYED *** %d ROUNDS OF AMMUNITION EXPENDED.\n", shots) - S1 += shots - - if killedEnemies == 4 { - fmt.Printf("\n\nTOTAL ROUNDS EXPENDED WERE: %d\n", S1) - if S1 > 18 { - print("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!") - return - } else { - print("NICE SHOOTING !!") - return - } - } else { - killedEnemies += 1 - fmt.Println("\nTHE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...") - break - } - } else { // missed - if shotProximity > 100 { - fmt.Printf("SHORT OF TARGET BY %d YARDS.\n", int(math.Abs(float64(shotProximity)))) - } else { - fmt.Printf("OVER TARGET BY %d YARDS.\n", int(math.Abs(float64(shotProximity)))) - } - } - } else { - fmt.Print("\nBOOM !!!! YOU HAVE JUST BEEN DESTROYED BY THE ENEMY.\n\n\n") - fmt.Println("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!") - return - } - } - } -} - -func main() { - rand.Seed(time.Now().UnixNano()) - scanner := bufio.NewScanner(os.Stdin) - - printIntro() - - for { - play() - - fmt.Print("TRY AGAIN (Y OR N)? ") - scanner.Scan() - - if strings.ToUpper(scanner.Text())[0:1] != "Y" { - fmt.Println("\nOK. RETURN TO BASE CAMP.") - break - } - } -} diff --git a/00_Alternate_Languages/43_Hammurabi/MiniScript/README.md b/00_Alternate_Languages/43_Hammurabi/MiniScript/README.md deleted file mode 100644 index bb4411bbf..000000000 --- a/00_Alternate_Languages/43_Hammurabi/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/43_Hammurabi/MiniScript/hammurabi.ms b/00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms deleted file mode 100644 index f81a1e708..000000000 --- a/00_Alternate_Languages/43_Hammurabi/MiniScript/hammurabi.ms +++ /dev/null @@ -1,190 +0,0 @@ -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 71afd1c51..8f0998f05 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 < A THEN 350 +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) - 0.3)) -550 IF P < C THEN 210 +542 Q=INT(10*(2*RND(1)-.3)) +550 IF P 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!!!" +552 D=P-C: IF D>.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 +945 PRINT "THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND," +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 * 0.8 * RND(1)); "PEOPLE" +965 PRINT "REALLY WASN'T TOO BAD AT ALL. ";INT(P*.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 \ No newline at end of file +990 PRINT: FOR N=1 TO 10: PRINT CHR$(7);: NEXT N +995 PRINT "SO LONG FOR NOW.": PRINT +999 END diff --git a/00_Alternate_Languages/44_Hangman/C/dictionary.txt b/00_Alternate_Languages/44_Hangman/C/dictionary.txt deleted file mode 100644 index ddf7a59fc..000000000 --- a/00_Alternate_Languages/44_Hangman/C/dictionary.txt +++ /dev/null @@ -1,100 +0,0 @@ -harm -retire -principle -tile -biology -show -reporter -profound -prestige -hardship -supplementary -abundant -firm -preparation -mother -welfare -broadcast -virgin -bloody -shaft -bird -buy -passion -south -slant -hesitate -leak -ride -contempt -banner -hurt -disaster -ranch -damage -conceive -environmental -outside -apathy -temple -arrange -hour -tone -intelligence -soup -bishop -fool -chase -snub -develop -domination -cry -distant -poem -implication -rally -assertive -anxiety -home -bear -execute -century -solo -cathedral -terminal -integration -mastermind -pen -X-ray -match -ceremony -stop -linger -slow -desert -superior -tender -debt -criticism -rehabilitation -finish -jest -scream -piece -mask -approach -sequence -negotiation -to -traffic -midnight -aspect -dull -concession -citizen -conception -instrument -compartment -responsibility -resist -withdraw \ No newline at end of file diff --git a/00_Alternate_Languages/44_Hangman/C/main.c b/00_Alternate_Languages/44_Hangman/C/main.c deleted file mode 100644 index 5ad8e43d9..000000000 --- a/00_Alternate_Languages/44_Hangman/C/main.c +++ /dev/null @@ -1,137 +0,0 @@ -#include -#include -#include -#include -#define MAX_WORDS 100 - -//check if windows or linux for the clear screen -#ifdef _WIN32 -#define CLEAR "cls" -#else -#define CLEAR "clear" -#endif - -/** - * @brief Prints the stage of the hangman based on the number of wrong guesses. - * - * @param stage Hangman stage. - */ -void print_hangman(int stage){ - switch (stage){ - case 0: - printf("----------\n"); - printf("| |\n"); - printf("|\n"); - printf("|\n"); - printf("|\n"); - printf("|\n"); - break; - case 1: - printf("----------\n"); - printf("| |\n"); - printf("| O\n"); - printf("| |\n"); - printf("|\n"); - printf("|\n"); - break; - case 2: - printf("----------\n"); - printf("| |\n"); - printf("| o\n"); - printf("| /|\n"); - printf("|\n"); - printf("|\n"); - break; - case 3: - printf("----------\n"); - printf("| |\n"); - printf("| o\n"); - printf("| /|\\\n"); - printf("|\n"); - printf("|\n"); - break; - case 4: - printf("----------\n"); - printf("| |\n"); - printf("| o\n"); - printf("| /|\\\n"); - printf("| /\n"); - printf("|\n"); - break; - case 5: - printf("----------\n"); - printf("| |\n"); - printf("| o\n"); - printf("| /|\\\n"); - printf("| / \\\n"); - printf("|\n"); - break; - default: - break; - } -} - -/** - * @brief Picks and return a random word from the dictionary. - * - * @return Random word - */ -char* random_word_picker(){ - //generate a random english word - char* word = malloc(sizeof(char) * 100); - FILE* fp = fopen("dictionary.txt", "r"); - srand(time(NULL)); - if (fp == NULL){ - printf("Error opening dictionary.txt\n"); - exit(1); - } - int random_number = rand() % MAX_WORDS; - for (int j = 0; j < random_number; j++){ - fscanf(fp, "%s", word); - } - fclose(fp); - return word; -} - - - - -void main(void){ - char* word = malloc(sizeof(char) * 100); - word = random_word_picker(); - char* hidden_word = malloc(sizeof(char) * 100); - for (int i = 0; i < strlen(word); i++){ - hidden_word[i] = '_'; - } - hidden_word[strlen(word)] = '\0'; - int stage = 0; - int wrong_guesses = 0; - int correct_guesses = 0; - char* guess = malloc(sizeof(char) * 100); - while (wrong_guesses < 6 && correct_guesses < strlen(word)){ - CLEAR; - print_hangman(stage); - printf("%s\n", hidden_word); - printf("Enter a guess: "); - scanf("%s", guess); - for (int i = 0; i < strlen(word); i++){ - if (strcmp(guess,word) == 0){ - correct_guesses = strlen(word); - } - else if (guess[0] == word[i]){ - hidden_word[i] = guess[0]; - correct_guesses++; - } - } - if (strchr(word, guess[0]) == NULL){ - wrong_guesses++; - } - stage = wrong_guesses; - } - if (wrong_guesses == 6){ - printf("You lose! The word was %s\n", word); - } - else { - printf("You win!\n"); - } -} \ 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 deleted file mode 100644 index cf8b20021..000000000 --- a/00_Alternate_Languages/44_Hangman/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/44_Hangman/MiniScript/hangman.ms b/00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms deleted file mode 100644 index 53966d45e..000000000 --- a/00_Alternate_Languages/44_Hangman/MiniScript/hangman.ms +++ /dev/null @@ -1,127 +0,0 @@ -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." diff --git a/00_Alternate_Languages/45_Hello/MiniScript/README.md b/00_Alternate_Languages/45_Hello/MiniScript/README.md deleted file mode 100644 index c3e534cbf..000000000 --- a/00_Alternate_Languages/45_Hello/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/45_Hello/MiniScript/hello.ms b/00_Alternate_Languages/45_Hello/MiniScript/hello.ms deleted file mode 100644 index a82344ef2..000000000 --- a/00_Alternate_Languages/45_Hello/MiniScript/hello.ms +++ /dev/null @@ -1,108 +0,0 @@ -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/00_Alternate_Languages/45_Hello/go/main.go b/00_Alternate_Languages/45_Hello/go/main.go deleted file mode 100644 index b0aeda58a..000000000 --- a/00_Alternate_Languages/45_Hello/go/main.go +++ /dev/null @@ -1,240 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "strings" - "time" -) - -type PROBLEM_TYPE int8 - -const ( - SEX PROBLEM_TYPE = iota - HEALTH - MONEY - JOB - UKNOWN -) - -func getYesOrNo() (bool, bool, string) { - scanner := bufio.NewScanner(os.Stdin) - - scanner.Scan() - - if strings.ToUpper(scanner.Text()) == "YES" { - return true, true, scanner.Text() - } else if strings.ToUpper(scanner.Text()) == "NO" { - return true, false, scanner.Text() - } else { - return false, false, scanner.Text() - } -} - -func printTntro() { - fmt.Println(" HELLO") - fmt.Println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - fmt.Print("\n\n\n") - fmt.Println("HELLO. MY NAME IS CREATIVE COMPUTER.") - fmt.Println("\nWHAT'S YOUR NAME?") -} - -func askEnjoyQuestion(user string) { - fmt.Printf("HI THERE %s, ARE YOU ENJOYING YOURSELF HERE?\n", user) - - for { - valid, value, msg := getYesOrNo() - - if valid { - if value { - fmt.Printf("I'M GLAD TO HEAR THAT, %s.\n", user) - fmt.Println() - } else { - fmt.Printf("OH, I'M SORRY TO HEAR THAT, %s. MAYBE WE CAN\n", user) - fmt.Println("BRIGHTEN UP YOUR VISIT A BIT.") - } - break - } else { - fmt.Printf("%s, I DON'T UNDERSTAND YOUR ANSWER OF '%s'.\n", user, msg) - fmt.Println("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE?") - } - } -} - -func promptForProblems(user string) PROBLEM_TYPE { - scanner := bufio.NewScanner(os.Stdin) - fmt.Println() - fmt.Printf("SAY %s, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\n", user) - fmt.Println("THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO") - fmt.Println("YOU HAVE? (ANSWER SEX, HEALTH, MONEY, OR JOB)") - for { - scanner.Scan() - - switch strings.ToUpper(scanner.Text()) { - case "SEX": - return SEX - case "HEALTH": - return HEALTH - case "MONEY": - return MONEY - case "JOB": - return JOB - default: - return UKNOWN - } - } -} - -func promptTooMuchOrTooLittle() (bool, bool) { - scanner := bufio.NewScanner(os.Stdin) - - scanner.Scan() - - if strings.ToUpper(scanner.Text()) == "TOO MUCH" { - return true, true - } else if strings.ToUpper(scanner.Text()) == "TOO LITTLE" { - return true, false - } else { - return false, false - } -} - -func solveSexProblem(user string) { - fmt.Println("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE?") - for { - valid, tooMuch := promptTooMuchOrTooLittle() - if valid { - if tooMuch { - fmt.Println("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!") - fmt.Printf("IF IT BOTHERS YOU, %s, TAKE A COLD SHOWER.\n", user) - } else { - fmt.Printf("WHY ARE YOU HERE IN SUFFERN, %s? YOU SHOULD BE\n", user) - fmt.Println("IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME") - fmt.Println("REAL ACTION.") - } - return - } else { - fmt.Printf("DON'T GET ALL SHOOK, %s, JUST ANSWER THE QUESTION\n", user) - fmt.Println("WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT?") - } - } -} - -func solveHealthProblem(user string) { - fmt.Printf("MY ADVICE TO YOU %s IS:\n", user) - fmt.Println(" 1. TAKE TWO ASPRIN") - fmt.Println(" 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)") - fmt.Println(" 3. GO TO BED (ALONE)") -} - -func solveMoneyProblem(user string) { - fmt.Printf("SORRY, %s, I'M BROKE TOO. WHY DON'T YOU SELL\n", user) - fmt.Println("ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING") - fmt.Println("SO YOU WON'T NEED SO MUCH MONEY?") -} - -func solveJobProblem(user string) { - fmt.Printf("I CAN SYMPATHIZE WITH YOU %s. I HAVE TO WORK\n", user) - fmt.Println("VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES") - fmt.Printf("REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, %s,\n", user) - fmt.Println("IS TO OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.") -} - -func askQuestionLoop(user string) { - for { - problem := promptForProblems(user) - - switch problem { - case SEX: - solveSexProblem(user) - case HEALTH: - solveHealthProblem(user) - case MONEY: - solveMoneyProblem(user) - case JOB: - solveJobProblem(user) - case UKNOWN: - fmt.Printf("OH %s, YOUR ANSWER IS GREEK TO ME.\n", user) - } - - for { - fmt.Println() - fmt.Printf("ANY MORE PROBLEMS YOU WANT SOLVED, %s?\n", user) - - valid, value, _ := getYesOrNo() - if valid { - if value { - fmt.Println("WHAT KIND (SEX, MONEY, HEALTH, JOB)") - break - } else { - return - } - } - fmt.Printf("JUST A SIMPLE 'YES' OR 'NO' PLEASE, %s\n", user) - } - } -} - -func goodbyeUnhappy(user string) { - fmt.Println() - fmt.Printf("TAKE A WALK, %s.\n", user) - fmt.Println() - fmt.Println() -} - -func goodbyeHappy(user string) { - fmt.Printf("NICE MEETING YOU %s, HAVE A NICE DAY.\n", user) -} - -func askForFee(user string) { - fmt.Println() - fmt.Printf("THAT WILL BE $5.00 FOR THE ADVICE, %s.\n", user) - fmt.Println("PLEASE LEAVE THE MONEY ON THE TERMINAL.") - time.Sleep(4 * time.Second) - fmt.Print("\n\n\n") - fmt.Println("DID YOU LEAVE THE MONEY?") - - for { - valid, value, msg := getYesOrNo() - if valid { - if value { - fmt.Printf("HEY, %s, YOU LEFT NO MONEY AT ALL!\n", user) - fmt.Println("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.") - fmt.Println() - fmt.Printf("WHAT A RIP OFF, %s!!!\n", user) - fmt.Println() - } else { - fmt.Printf("THAT'S HONEST, %s, BUT HOW DO YOU EXPECT\n", user) - fmt.Println("ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS") - fmt.Println("DON'T PAY THEIR BILLS?") - } - return - } else { - fmt.Printf("YOUR ANSWER OF '%s' CONFUSES ME, %s.\n", msg, user) - fmt.Println("PLEASE RESPOND WITH 'YES' or 'NO'.") - } - } -} - -func main() { - scanner := bufio.NewScanner(os.Stdin) - - printTntro() - scanner.Scan() - userName := scanner.Text() - fmt.Println() - - askEnjoyQuestion(userName) - - askQuestionLoop(userName) - - askForFee(userName) - - if false { - goodbyeHappy(userName) // unreachable - } else { - goodbyeUnhappy(userName) - } - -} diff --git a/00_Alternate_Languages/45_Hello/hello.c b/00_Alternate_Languages/45_Hello/hello.c deleted file mode 100644 index ac70709ef..000000000 --- a/00_Alternate_Languages/45_Hello/hello.c +++ /dev/null @@ -1,164 +0,0 @@ -#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; -} diff --git a/00_Alternate_Languages/46_Hexapawn/MiniScript/README.md b/00_Alternate_Languages/46_Hexapawn/MiniScript/README.md deleted file mode 100644 index e2cd714ad..000000000 --- a/00_Alternate_Languages/46_Hexapawn/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/46_Hexapawn/MiniScript/hexapawn.ms b/00_Alternate_Languages/46_Hexapawn/MiniScript/hexapawn.ms deleted file mode 100644 index f2505ac4e..000000000 --- a/00_Alternate_Languages/46_Hexapawn/MiniScript/hexapawn.ms +++ /dev/null @@ -1,266 +0,0 @@ -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/00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md b/00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md deleted file mode 100644 index dc20e7c83..000000000 --- a/00_Alternate_Languages/47_Hi-Lo/MiniScript/README.md +++ /dev/null @@ -1,22 +0,0 @@ -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 -``` \ No newline at end of file diff --git a/00_Alternate_Languages/47_Hi-Lo/MiniScript/hi-lo.ms b/00_Alternate_Languages/47_Hi-Lo/MiniScript/hi-lo.ms deleted file mode 100644 index bd0801eed..000000000 --- a/00_Alternate_Languages/47_Hi-Lo/MiniScript/hi-lo.ms +++ /dev/null @@ -1,41 +0,0 @@ -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!!!" diff --git a/00_Alternate_Languages/47_Hi-Lo/go/main.go b/00_Alternate_Languages/47_Hi-Lo/go/main.go deleted file mode 100644 index 99bea1c3c..000000000 --- a/00_Alternate_Languages/47_Hi-Lo/go/main.go +++ /dev/null @@ -1,77 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "math/rand" - "os" - "strconv" - "strings" - "time" -) - -const MAX_ATTEMPTS = 6 - -func printIntro() { - fmt.Println("HI LO") - fmt.Println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - fmt.Println("\n\n\nTHIS IS THE GAME OF HI LO.") - fmt.Println("\nYOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE") - fmt.Println("HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS. IF YOU") - fmt.Println("GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!") - fmt.Println("THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY. HOWEVER,") - fmt.Println("IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.") - fmt.Println() - fmt.Println() -} - -func main() { - rand.Seed(time.Now().UnixNano()) - scanner := bufio.NewScanner(os.Stdin) - - printIntro() - - totalWinnings := 0 - - for { - fmt.Println() - secret := rand.Intn(1000) + 1 - - guessedCorrectly := false - - for attempt := 0; attempt < MAX_ATTEMPTS; attempt++ { - fmt.Println("YOUR GUESS?") - scanner.Scan() - guess, err := strconv.Atoi(scanner.Text()) - if err != nil { - fmt.Println("INVALID INPUT") - } - - if guess == secret { - fmt.Printf("GOT IT!!!!!!!!!! YOU WIN %d DOLLARS.\n", secret) - guessedCorrectly = true - break - } else if guess > secret { - fmt.Println("YOUR GUESS IS TOO HIGH.") - } else { - fmt.Println("YOUR GUESS IS TOO LOW.") - } - } - - if guessedCorrectly { - totalWinnings += secret - fmt.Printf("YOUR TOTAL WINNINGS ARE NOW $%d.\n", totalWinnings) - } else { - fmt.Printf("YOU BLEW IT...TOO BAD...THE NUMBER WAS %d\n", secret) - } - - fmt.Println() - fmt.Println("PLAYAGAIN (YES OR NO)?") - scanner.Scan() - - if strings.ToUpper(scanner.Text())[0:1] != "Y" { - break - } - } - fmt.Println("\nSO LONG. HOPE YOU ENJOYED YOURSELF!!!") -} diff --git a/00_Alternate_Languages/48_High_IQ/MiniScript/README.md b/00_Alternate_Languages/48_High_IQ/MiniScript/README.md deleted file mode 100644 index 794d1c57f..000000000 --- a/00_Alternate_Languages/48_High_IQ/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/48_High_IQ/MiniScript/highiq.ms b/00_Alternate_Languages/48_High_IQ/MiniScript/highiq.ms deleted file mode 100644 index 5d2ab966f..000000000 --- a/00_Alternate_Languages/48_High_IQ/MiniScript/highiq.ms +++ /dev/null @@ -1,163 +0,0 @@ -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 diff --git a/00_Alternate_Languages/49_Hockey/MiniScript/README.md b/00_Alternate_Languages/49_Hockey/MiniScript/README.md deleted file mode 100644 index 8c92997dc..000000000 --- a/00_Alternate_Languages/49_Hockey/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/49_Hockey/MiniScript/hockey.ms b/00_Alternate_Languages/49_Hockey/MiniScript/hockey.ms deleted file mode 100644 index 450736f70..000000000 --- a/00_Alternate_Languages/49_Hockey/MiniScript/hockey.ms +++ /dev/null @@ -1,396 +0,0 @@ -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/00_Alternate_Languages/50_Horserace/MiniScript/README.md b/00_Alternate_Languages/50_Horserace/MiniScript/README.md deleted file mode 100644 index 8f5703a2c..000000000 --- a/00_Alternate_Languages/50_Horserace/MiniScript/README.md +++ /dev/null @@ -1,25 +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 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 deleted file mode 100644 index a8750f5ed..000000000 --- a/00_Alternate_Languages/50_Horserace/MiniScript/horserace.ms +++ /dev/null @@ -1,149 +0,0 @@ -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 deleted file mode 100644 index 2f774e452..000000000 --- a/00_Alternate_Languages/51_Hurkle/MiniScript/README.md +++ /dev/null @@ -1,22 +0,0 @@ -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 -``` \ No newline at end of file diff --git a/00_Alternate_Languages/51_Hurkle/MiniScript/hurkle.ms b/00_Alternate_Languages/51_Hurkle/MiniScript/hurkle.ms deleted file mode 100644 index a1b228222..000000000 --- a/00_Alternate_Languages/51_Hurkle/MiniScript/hurkle.ms +++ /dev/null @@ -1,56 +0,0 @@ -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 diff --git a/00_Alternate_Languages/52_Kinema/MiniScript/README.md b/00_Alternate_Languages/52_Kinema/MiniScript/README.md deleted file mode 100644 index 173e59ad5..000000000 --- a/00_Alternate_Languages/52_Kinema/MiniScript/README.md +++ /dev/null @@ -1,21 +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 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/52_Kinema/MiniScript/kinema.ms b/00_Alternate_Languages/52_Kinema/MiniScript/kinema.ms deleted file mode 100644 index 9fb27071a..000000000 --- a/00_Alternate_Languages/52_Kinema/MiniScript/kinema.ms +++ /dev/null @@ -1,40 +0,0 @@ -// 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 diff --git a/00_Alternate_Languages/53_King/MiniScript/README.md b/00_Alternate_Languages/53_King/MiniScript/README.md deleted file mode 100644 index 34818a09c..000000000 --- a/00_Alternate_Languages/53_King/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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 deleted file mode 100644 index 8d4f106c9..000000000 --- a/00_Alternate_Languages/53_King/MiniScript/king.ms +++ /dev/null @@ -1,403 +0,0 @@ -print " "*34 + "KING" -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 - 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" - 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 - - -// 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 86c3828c3..7f88e1014 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, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR" + 22 PRINT "DETINU, RALLODS 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=YEAR THEN 1900 +1520 IF YEARS_REQUIRED-1=X5 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 YEAR -1962 IF YEAR<0 THEN 1590 -1963 IF YEAR<8 THEN 1969 +1961 INPUT X5 +1962 IF X5<0 THEN 1590 +1963 IF X5<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 YEAR=YEAR+1 +2000 X5=X5+1 2020 DEATHS=0 2040 GOTO 100 2046 END diff --git a/00_Alternate_Languages/54_Letter/MiniScript/README.md b/00_Alternate_Languages/54_Letter/MiniScript/README.md deleted file mode 100644 index dfc5cf386..000000000 --- a/00_Alternate_Languages/54_Letter/MiniScript/README.md +++ /dev/null @@ -1,21 +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 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/54_Letter/MiniScript/letter.ms b/00_Alternate_Languages/54_Letter/MiniScript/letter.ms deleted file mode 100644 index 78a32b3bc..000000000 --- a/00_Alternate_Languages/54_Letter/MiniScript/letter.ms +++ /dev/null @@ -1,44 +0,0 @@ -// 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/55_Life/MiniScript/README.md b/00_Alternate_Languages/55_Life/MiniScript/README.md deleted file mode 100644 index 4cfd557b0..000000000 --- a/00_Alternate_Languages/55_Life/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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 deleted file mode 100644 index 69f3bafc1..000000000 --- a/00_Alternate_Languages/55_Life/MiniScript/life.ms +++ /dev/null @@ -1,132 +0,0 @@ -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 deleted file mode 100644 index 93b25b999..000000000 --- a/00_Alternate_Languages/56_Life_for_Two/MiniScript/README.md +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 49ac531ed..000000000 --- a/00_Alternate_Languages/56_Life_for_Two/MiniScript/lifefortwo.ms +++ /dev/null @@ -1,129 +0,0 @@ -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/00_Alternate_Languages/57_Literature_Quiz/MiniScript/README.md b/00_Alternate_Languages/57_Literature_Quiz/MiniScript/README.md deleted file mode 100644 index e3f12eb47..000000000 --- a/00_Alternate_Languages/57_Literature_Quiz/MiniScript/README.md +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index e465cc6bb..000000000 --- a/00_Alternate_Languages/57_Literature_Quiz/MiniScript/litquiz.ms +++ /dev/null @@ -1,66 +0,0 @@ -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 diff --git a/00_Alternate_Languages/58_Love/MiniScript/README.md b/00_Alternate_Languages/58_Love/MiniScript/README.md deleted file mode 100644 index 1186963df..000000000 --- a/00_Alternate_Languages/58_Love/MiniScript/README.md +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 64693f127..000000000 --- a/00_Alternate_Languages/58_Love/MiniScript/love.ms +++ /dev/null @@ -1,41 +0,0 @@ -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 diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/README.md deleted file mode 100644 index 6ba18136c..000000000 --- a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/README.md +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index 92a263e26..000000000 --- a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lem.ms +++ /dev/null @@ -1,324 +0,0 @@ -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/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lunar.ms b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lunar.ms deleted file mode 100644 index e8da8d72c..000000000 --- a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/lunar.ms +++ /dev/null @@ -1,114 +0,0 @@ -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 diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms b/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms deleted file mode 100644 index 4131290b5..000000000 --- a/00_Alternate_Languages/59_Lunar_LEM_Rocket/MiniScript/rocket.ms +++ /dev/null @@ -1,102 +0,0 @@ -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 - 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 - 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 diff --git a/00_Alternate_Languages/60_Mastermind/MiniScript/README.md b/00_Alternate_Languages/60_Mastermind/MiniScript/README.md deleted file mode 100644 index 088a33011..000000000 --- a/00_Alternate_Languages/60_Mastermind/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 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 deleted file mode 100644 index 93ea30820..000000000 --- a/00_Alternate_Languages/60_Mastermind/MiniScript/mastermind.ms +++ /dev/null @@ -1,260 +0,0 @@ -// -// 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/00_Alternate_Languages/61_Math_Dice/MiniScript/README.md b/00_Alternate_Languages/61_Math_Dice/MiniScript/README.md deleted file mode 100644 index ac7b913c2..000000000 --- a/00_Alternate_Languages/61_Math_Dice/MiniScript/README.md +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 74ed63496..000000000 --- a/00_Alternate_Languages/61_Math_Dice/MiniScript/mathdice.ms +++ /dev/null @@ -1,58 +0,0 @@ -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 - diff --git a/00_Alternate_Languages/62_Mugwump/MiniScript/README.md b/00_Alternate_Languages/62_Mugwump/MiniScript/README.md deleted file mode 100644 index ac7b913c2..000000000 --- a/00_Alternate_Languages/62_Mugwump/MiniScript/README.md +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 8ba5f7fb2..000000000 --- a/00_Alternate_Languages/62_Mugwump/MiniScript/mugwump.ms +++ /dev/null @@ -1,65 +0,0 @@ -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 diff --git a/00_Alternate_Languages/63_Name/MiniScript/README.md b/00_Alternate_Languages/63_Name/MiniScript/README.md deleted file mode 100644 index 819ecf501..000000000 --- a/00_Alternate_Languages/63_Name/MiniScript/README.md +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index bb3d2da23..000000000 --- a/00_Alternate_Languages/63_Name/MiniScript/name.ms +++ /dev/null @@ -1,25 +0,0 @@ -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!" diff --git a/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md b/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md deleted file mode 100644 index 5ea2cf130..000000000 --- a/00_Alternate_Languages/64_Nicomachus/MiniScript/README.md +++ /dev/null @@ -1,21 +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 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/64_Nicomachus/MiniScript/nicomachus.ms b/00_Alternate_Languages/64_Nicomachus/MiniScript/nicomachus.ms deleted file mode 100644 index ebbc394b7..000000000 --- a/00_Alternate_Languages/64_Nicomachus/MiniScript/nicomachus.ms +++ /dev/null @@ -1,45 +0,0 @@ -// 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 diff --git a/00_Alternate_Languages/65_Nim/MiniScript/README.md b/00_Alternate_Languages/65_Nim/MiniScript/README.md deleted file mode 100644 index 0265ff51f..000000000 --- a/00_Alternate_Languages/65_Nim/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index f241c6964..000000000 --- a/00_Alternate_Languages/65_Nim/MiniScript/nim.ms +++ /dev/null @@ -1,194 +0,0 @@ -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/00_Alternate_Languages/66_Number/MiniScript/README.md b/00_Alternate_Languages/66_Number/MiniScript/README.md deleted file mode 100644 index e3c8143ac..000000000 --- a/00_Alternate_Languages/66_Number/MiniScript/README.md +++ /dev/null @@ -1,21 +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 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/66_Number/MiniScript/number.ms b/00_Alternate_Languages/66_Number/MiniScript/number.ms deleted file mode 100644 index 0f242d682..000000000 --- a/00_Alternate_Languages/66_Number/MiniScript/number.ms +++ /dev/null @@ -1,44 +0,0 @@ -// 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." - break - end if - print "You have " + P + " points."; print -end while diff --git a/00_Alternate_Languages/67_One_Check/MiniScript/README.md b/00_Alternate_Languages/67_One_Check/MiniScript/README.md deleted file mode 100644 index d79b401fb..000000000 --- a/00_Alternate_Languages/67_One_Check/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index fee41c8c4..000000000 --- a/00_Alternate_Languages/67_One_Check/MiniScript/onecheck.ms +++ /dev/null @@ -1,101 +0,0 @@ -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 -input "(Press Return.)" -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 diff --git a/00_Alternate_Languages/68_Orbit/MiniScript/README.md b/00_Alternate_Languages/68_Orbit/MiniScript/README.md deleted file mode 100644 index cc0c29669..000000000 --- a/00_Alternate_Languages/68_Orbit/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index 5c624c42b..000000000 --- a/00_Alternate_Languages/68_Orbit/MiniScript/orbit.ms +++ /dev/null @@ -1,95 +0,0 @@ -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." diff --git a/00_Alternate_Languages/69_Pizza/MiniScript/README.md b/00_Alternate_Languages/69_Pizza/MiniScript/README.md deleted file mode 100644 index 993c4056c..000000000 --- a/00_Alternate_Languages/69_Pizza/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index 84c33bb63..000000000 --- a/00_Alternate_Languages/69_Pizza/MiniScript/pizza.ms +++ /dev/null @@ -1,98 +0,0 @@ -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 deleted file mode 100644 index 52effbcc2..000000000 --- a/00_Alternate_Languages/70_Poetry/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index f55d32901..000000000 --- a/00_Alternate_Languages/70_Poetry/MiniScript/poetry.ms +++ /dev/null @@ -1,51 +0,0 @@ -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 diff --git a/00_Alternate_Languages/71_Poker/MiniScript/README.md b/00_Alternate_Languages/71_Poker/MiniScript/README.md deleted file mode 100644 index 95144dcfd..000000000 --- a/00_Alternate_Languages/71_Poker/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index b367db031..000000000 --- a/00_Alternate_Languages/71_Poker/MiniScript/poker.ms +++ /dev/null @@ -1,557 +0,0 @@ -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/00_Alternate_Languages/72_Queen/MiniScript/README.md b/00_Alternate_Languages/72_Queen/MiniScript/README.md deleted file mode 100644 index cf8463343..000000000 --- a/00_Alternate_Languages/72_Queen/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index d3e882b91..000000000 --- a/00_Alternate_Languages/72_Queen/MiniScript/queen.ms +++ /dev/null @@ -1,151 +0,0 @@ -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/73_Reverse/MiniScript/README.md b/00_Alternate_Languages/73_Reverse/MiniScript/README.md deleted file mode 100644 index 18812f302..000000000 --- a/00_Alternate_Languages/73_Reverse/MiniScript/README.md +++ /dev/null @@ -1,16 +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 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 diff --git a/00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms b/00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms deleted file mode 100644 index 9d7396cf3..000000000 --- a/00_Alternate_Languages/73_Reverse/MiniScript/reverse.ms +++ /dev/null @@ -1,71 +0,0 @@ -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 true - turns = 0 - digits = range(1, num) - digits.shuffle - print;print "Here we go ... the list is:" - while true - 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 != "y" then break -end while -print "O.K. Hope you had fun!!" diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/README.md deleted file mode 100644 index bfec2da94..000000000 --- a/00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/README.md +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 322e354b6..000000000 --- a/00_Alternate_Languages/74_Rock_Scissors_Paper/MiniScript/rockscissors.ms +++ /dev/null @@ -1,40 +0,0 @@ -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!!" diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim b/00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim deleted file mode 100644 index 3c0cda0c5..000000000 --- a/00_Alternate_Languages/74_Rock_Scissors_Paper/nim/rockscissors.nim +++ /dev/null @@ -1,68 +0,0 @@ -import std/[random,strformat,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." - 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" -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!!" diff --git a/00_Alternate_Languages/75_Roulette/MiniScript/README.md b/00_Alternate_Languages/75_Roulette/MiniScript/README.md deleted file mode 100644 index 4a2e49289..000000000 --- a/00_Alternate_Languages/75_Roulette/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index 60e7087bc..000000000 --- a/00_Alternate_Languages/75_Roulette/MiniScript/roulette.ms +++ /dev/null @@ -1,200 +0,0 @@ -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/00_Alternate_Languages/76_Russian_Roulette/MiniScript/README.md b/00_Alternate_Languages/76_Russian_Roulette/MiniScript/README.md deleted file mode 100644 index 79d028a92..000000000 --- a/00_Alternate_Languages/76_Russian_Roulette/MiniScript/README.md +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 3eb896f94..000000000 --- a/00_Alternate_Languages/76_Russian_Roulette/MiniScript/russianroulette.ms +++ /dev/null @@ -1,37 +0,0 @@ -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 diff --git a/00_Alternate_Languages/77_Salvo/MiniScript/README.md b/00_Alternate_Languages/77_Salvo/MiniScript/README.md deleted file mode 100644 index d31694466..000000000 --- a/00_Alternate_Languages/77_Salvo/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index e7c2796e7..000000000 --- a/00_Alternate_Languages/77_Salvo/MiniScript/salvo.ms +++ /dev/null @@ -1,240 +0,0 @@ -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/00_Alternate_Languages/78_Sine_Wave/C++/README.md b/00_Alternate_Languages/78_Sine_Wave/C++/README.md deleted file mode 100644 index b62763ffe..000000000 --- a/00_Alternate_Languages/78_Sine_Wave/C++/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [C++17](https://en.wikipedia.org/wiki/C%2B%2B17) \ No newline at end of file diff --git a/00_Alternate_Languages/78_Sine_Wave/C++/sinewave.cpp b/00_Alternate_Languages/78_Sine_Wave/C++/sinewave.cpp deleted file mode 100644 index 9d274e566..000000000 --- a/00_Alternate_Languages/78_Sine_Wave/C++/sinewave.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include // std::cout, std::endl -#include // std::string(size_t n, char c) -#include // std::sin(double x) - -int main() -{ - std::cout << std::string(30, ' ') << "SINE WAVE" << std::endl; - std::cout << std::string(15, ' ') << "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" << std::endl; - std::cout << std::string(5, '\n'); - - bool b = true; - - for (double t = 0.0; t <= 40.0; t += 0.25) - { - int a = int(26 + 25 * std::sin(t)); - std::cout << std::string(a, ' ') << (b ? "CREATIVE" : "COMPUTING") << std::endl; - b = !b; - } - - return 0; -} diff --git a/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md b/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md deleted file mode 100644 index a17e5cf14..000000000 --- a/00_Alternate_Languages/78_Sine_Wave/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/78_Sine_Wave/MiniScript/sinewave.ms b/00_Alternate_Languages/78_Sine_Wave/MiniScript/sinewave.ms deleted file mode 100644 index da3e99a77..000000000 --- a/00_Alternate_Languages/78_Sine_Wave/MiniScript/sinewave.ms +++ /dev/null @@ -1,15 +0,0 @@ -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 diff --git a/00_Alternate_Languages/79_Slalom/MiniScript/README.md b/00_Alternate_Languages/79_Slalom/MiniScript/README.md deleted file mode 100644 index c954f090c..000000000 --- a/00_Alternate_Languages/79_Slalom/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index 41bb0b829..000000000 --- a/00_Alternate_Languages/79_Slalom/MiniScript/slalom.ms +++ /dev/null @@ -1,170 +0,0 @@ -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 47c6d8010..b46cc39be 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 IF YOU WANT TO SEE HOW LONG YOU'VE TAKEN." +845 PRINT " 0 -- TYPE THIS IS 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/00_Alternate_Languages/80_Slots/MiniScript/README.md b/00_Alternate_Languages/80_Slots/MiniScript/README.md deleted file mode 100644 index a8b56b3d6..000000000 --- a/00_Alternate_Languages/80_Slots/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index 310ff95e7..000000000 --- a/00_Alternate_Languages/80_Slots/MiniScript/slots.ms +++ /dev/null @@ -1,108 +0,0 @@ -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/00_Alternate_Languages/81_Splat/MiniScript/README.md b/00_Alternate_Languages/81_Splat/MiniScript/README.md deleted file mode 100644 index 2d133f871..000000000 --- a/00_Alternate_Languages/81_Splat/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index d38ddd237..000000000 --- a/00_Alternate_Languages/81_Splat/MiniScript/splat.ms +++ /dev/null @@ -1,133 +0,0 @@ -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 // (works on Mini Micro only) -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 diff --git a/00_Alternate_Languages/82_Stars/MiniScript/README.md b/00_Alternate_Languages/82_Stars/MiniScript/README.md deleted file mode 100644 index 2e4b6d024..000000000 --- a/00_Alternate_Languages/82_Stars/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 -``` diff --git a/00_Alternate_Languages/82_Stars/MiniScript/stars.ms b/00_Alternate_Languages/82_Stars/MiniScript/stars.ms deleted file mode 100644 index d83d75b74..000000000 --- a/00_Alternate_Languages/82_Stars/MiniScript/stars.ms +++ /dev/null @@ -1,48 +0,0 @@ -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 true - 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 diff --git a/00_Alternate_Languages/83_Stock_Market/MiniScript/README.md b/00_Alternate_Languages/83_Stock_Market/MiniScript/README.md deleted file mode 100644 index ac3893185..000000000 --- a/00_Alternate_Languages/83_Stock_Market/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 deleted file mode 100644 index 850cb725f..000000000 --- a/00_Alternate_Languages/83_Stock_Market/MiniScript/stockmarket.ms +++ /dev/null @@ -1,199 +0,0 @@ -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!!" - diff --git a/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md b/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md deleted file mode 100644 index 0b383f4b5..000000000 --- a/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/README.md +++ /dev/null @@ -1,18 +0,0 @@ -Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html). - -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: - -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 deleted file mode 100644 index 7b7a247c9..000000000 --- a/00_Alternate_Languages/84_Super_Star_Trek/MiniScript/superstartrek.ms +++ /dev/null @@ -1,1267 +0,0 @@ -// 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" - -//================================================================= -// 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!) -//================================================================= -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 "HLP", "for help, i.e. instructions", @Instructions.print // (not in original game) -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 - -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 - 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 837558347..59124d9d6 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 QUADRANT. THEREFORE, TO GET + ONE QUADTANT. 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 HUNDREDS DIGIT IS THE NUMBER OF + STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF KLINGONS. EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS. diff --git a/00_Alternate_Languages/85_Synonym/MiniScript/README.md b/00_Alternate_Languages/85_Synonym/MiniScript/README.md deleted file mode 100644 index f887013c7..000000000 --- a/00_Alternate_Languages/85_Synonym/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 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 -``` diff --git a/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms b/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms deleted file mode 100644 index c64c4f52e..000000000 --- a/00_Alternate_Languages/85_Synonym/MiniScript/synonym.ms +++ /dev/null @@ -1,47 +0,0 @@ -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 " " * 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." -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." diff --git a/00_Alternate_Languages/86_Target/MiniScript/README.md b/00_Alternate_Languages/86_Target/MiniScript/README.md deleted file mode 100644 index c06194764..000000000 --- a/00_Alternate_Languages/86_Target/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 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 -``` diff --git a/00_Alternate_Languages/86_Target/MiniScript/target.ms b/00_Alternate_Languages/86_Target/MiniScript/target.ms deleted file mode 100644 index 125fe2ff5..000000000 --- a/00_Alternate_Languages/86_Target/MiniScript/target.ms +++ /dev/null @@ -1,114 +0,0 @@ -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 - -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; 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: " + coordStr(coords) - - 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: " + coordStr(targeted) - 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 - ready = ans and ans[0].lower == "y" - print -end while diff --git a/00_Alternate_Languages/87_3-D_Plot/MiniScript/3dplot.ms b/00_Alternate_Languages/87_3-D_Plot/MiniScript/3dplot.ms deleted file mode 100644 index 0cf1e5169..000000000 --- a/00_Alternate_Languages/87_3-D_Plot/MiniScript/3dplot.ms +++ /dev/null @@ -1,26 +0,0 @@ -// 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 deleted file mode 100644 index 2bcec68c8..000000000 --- a/00_Alternate_Languages/87_3-D_Plot/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/88_3-D_Tic-Tac-Toe/MiniScript/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/README.md deleted file mode 100644 index 12d6406ec..000000000 --- a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 "qubit" - 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 deleted file mode 100644 index 3074be2d4..000000000 --- a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/MiniScript/qubit.ms +++ /dev/null @@ -1,361 +0,0 @@ -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/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md deleted file mode 100644 index c3c2c9259..000000000 --- a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/README.md +++ /dev/null @@ -1,20 +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 , install, and then run the program with a command such as: - -``` - miniscript tictactoe.ms -``` - -2. Mini Micro: -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 -``` diff --git a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe.ms b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe.ms deleted file mode 100644 index 8d472a7bb..000000000 --- a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe.ms +++ /dev/null @@ -1,90 +0,0 @@ -// 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 diff --git a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe2.ms b/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe2.ms deleted file mode 100644 index 20981ab08..000000000 --- a/00_Alternate_Languages/89_Tic-Tac-Toe/MiniScript/tictactoe2.ms +++ /dev/null @@ -1,155 +0,0 @@ -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 - diff --git a/00_Alternate_Languages/90_Tower/MiniScript/README.md b/00_Alternate_Languages/90_Tower/MiniScript/README.md deleted file mode 100644 index fc9672037..000000000 --- a/00_Alternate_Languages/90_Tower/MiniScript/README.md +++ /dev/null @@ -1,18 +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 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 -``` diff --git a/00_Alternate_Languages/90_Tower/MiniScript/tower.ms b/00_Alternate_Languages/90_Tower/MiniScript/tower.ms deleted file mode 100644 index a1846545a..000000000 --- a/00_Alternate_Languages/90_Tower/MiniScript/tower.ms +++ /dev/null @@ -1,202 +0,0 @@ -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) - 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 "Bye bye, big shot." - exit - else if status == kNotTower then - print "I'll assume you hit the wrong key 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!" diff --git a/00_Alternate_Languages/91_Train/D/README.md b/00_Alternate_Languages/91_Train/D/README.md deleted file mode 100644 index 6c77f0a9e..000000000 --- a/00_Alternate_Languages/91_Train/D/README.md +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index b4e595a0b..000000000 --- a/00_Alternate_Languages/91_Train/D/train.d +++ /dev/null @@ -1,50 +0,0 @@ -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/00_Alternate_Languages/91_Train/MiniScript/README.md b/00_Alternate_Languages/91_Train/MiniScript/README.md deleted file mode 100644 index 13928cccc..000000000 --- a/00_Alternate_Languages/91_Train/MiniScript/README.md +++ /dev/null @@ -1,22 +0,0 @@ -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 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: - -``` - 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 -``` diff --git a/00_Alternate_Languages/91_Train/MiniScript/train.ms b/00_Alternate_Languages/91_Train/MiniScript/train.ms deleted file mode 100644 index 27ce5b98f..000000000 --- a/00_Alternate_Languages/91_Train/MiniScript/train.ms +++ /dev/null @@ -1,28 +0,0 @@ -// 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 diff --git a/00_Alternate_Languages/91_Train/nim/train.nim b/00_Alternate_Languages/91_Train/nim/train.nim deleted file mode 100644 index aa92c1a70..000000000 --- a/00_Alternate_Languages/91_Train/nim/train.nim +++ /dev/null @@ -1,38 +0,0 @@ -import std/[random,strutils] - -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) = - result = (rand(41..65), rand(6..20), rand(21..39)) - -# 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() diff --git a/00_Alternate_Languages/92_Trap/MiniScript/README.md b/00_Alternate_Languages/92_Trap/MiniScript/README.md deleted file mode 100644 index 521d3aff7..000000000 --- a/00_Alternate_Languages/92_Trap/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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/92_Trap/MiniScript/trap.ms b/00_Alternate_Languages/92_Trap/MiniScript/trap.ms deleted file mode 100644 index 687a7a1ea..000000000 --- a/00_Alternate_Languages/92_Trap/MiniScript/trap.ms +++ /dev/null @@ -1,69 +0,0 @@ -// TRAP -// STEVE ULLMAN, 8-1-72 -// Ported to MiniScript by Ryushinaka and Joe Strout, 2023 - -print " "*34 + "TRAP" -print " "*15 + "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 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 645082acf..000000000 --- a/00_Alternate_Languages/93_23_Matches/MiniScript/23matches.ms +++ /dev/null @@ -1,70 +0,0 @@ -print " "*31 + "23 MATCHES" -print " "*15 + "Creative Computing Morristown, New Jersey" -print; print; print - -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 - 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 - 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 - print "Good bye loser!" - else - print "There are now " + matches + " matches remaining." - print - 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 - print - end if - end if - humanTurn = not humanTurn -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 8b9bc04ca..000000000 --- a/00_Alternate_Languages/93_23_Matches/MiniScript/README.md +++ /dev/null @@ -1,18 +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 -``` diff --git a/00_Alternate_Languages/94_War/MiniScript/README.md b/00_Alternate_Languages/94_War/MiniScript/README.md deleted file mode 100644 index 0d964946f..000000000 --- a/00_Alternate_Languages/94_War/MiniScript/README.md +++ /dev/null @@ -1,19 +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 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 diff --git a/00_Alternate_Languages/94_War/MiniScript/war.ms b/00_Alternate_Languages/94_War/MiniScript/war.ms deleted file mode 100644 index acc432157..000000000 --- a/00_Alternate_Languages/94_War/MiniScript/war.ms +++ /dev/null @@ -1,65 +0,0 @@ -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 diff --git a/00_Alternate_Languages/95_Weekday/MiniScript/README.md b/00_Alternate_Languages/95_Weekday/MiniScript/README.md deleted file mode 100644 index 218cb4cc9..000000000 --- a/00_Alternate_Languages/95_Weekday/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 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 deleted file mode 100644 index 65641ebc3..000000000 --- a/00_Alternate_Languages/95_Weekday/MiniScript/weekday.ms +++ /dev/null @@ -1,182 +0,0 @@ -TAB = char(9) - -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" -print; print; print - -print "WEEKDAY is a computer demonstration that" -print "gives facts about a date of interest to you." -print - -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)? ") -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 - 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]) - - 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 -print " "*16 + "*** You 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 deleted file mode 100644 index 567a84baf..000000000 --- a/00_Alternate_Languages/96_Word/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 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/00_Alternate_Languages/96_Word/MiniScript/word.ms b/00_Alternate_Languages/96_Word/MiniScript/word.ms deleted file mode 100644 index 190ad6117..000000000 --- a/00_Alternate_Languages/96_Word/MiniScript/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 diff --git a/00_Alternate_Languages/README.md b/00_Alternate_Languages/README.md index 0cbe947e1..f7c55f95e 100644 --- a/00_Alternate_Languages/README.md +++ b/00_Alternate_Languages/README.md @@ -1,15 +1,9 @@ #### Alternate Languages -This folder contains implementations of each program in alternate languages which are _not_ one of the agreed upon 10 languages. - -Implementations here are NOT bound to these three criteria: +This folder contains implementations of each program in alternate languages which are _not_ one of the agreed upon 10 languages, intended to meet these three criteria: 1. Popular (by TIOBE index) 2. Memory safe 3. Generally considered a 'scripting' language -So for example, (here only) C or PASCAL are allowed. Please still remain faithful to original look-and-feel (console applications). -Try to keep your code portable (unless it is not possible, and then be very explicit about this limitation in your -README and your folder naming). - -We welcome additional ports in whatever language you prefer, but these additional ports are for educational purposes only, and do not count towards the donation total at the end of the project. +We welcome additional ports in whatever language you prefer, but these additional ports are for educational purposes only, and do not count towards the donation total at the end of the project. \ No newline at end of file diff --git a/00_Common/dotnet/Games.Common/Games.Common.csproj b/00_Common/dotnet/Games.Common/Games.Common.csproj index 74c8445fc..d4c395e8c 100644 --- a/00_Common/dotnet/Games.Common/Games.Common.csproj +++ b/00_Common/dotnet/Games.Common/Games.Common.csproj @@ -1,10 +1,7 @@ - net6.0 - 10 - enable - enable + netstandard2.1 diff --git a/00_Common/dotnet/Games.Common/IO/IReadWrite.cs b/00_Common/dotnet/Games.Common/IO/IReadWrite.cs index b4c533f87..3d2cfc7e5 100644 --- a/00_Common/dotnet/Games.Common/IO/IReadWrite.cs +++ b/00_Common/dotnet/Games.Common/IO/IReadWrite.cs @@ -1,4 +1,5 @@ -using Games.Common.Numbers; +using System; +using System.IO; namespace Games.Common.IO; @@ -75,16 +76,17 @@ public interface IReadWrite void WriteLine(string message = ""); /// - /// Writes a to output. + /// Writes a to output, formatted per the BASIC interpreter, with leading and trailing spaces. /// - /// The to be written. - void Write(Number value); + /// The to be written. + void Write(float value); /// - /// Writes a to output. + /// Writes a to output, formatted per the BASIC interpreter, with leading and trailing spaces, + /// followed by a new-line. /// - /// The to be written. - void WriteLine(Number value); + /// The to be written. + void WriteLine(float value); /// /// Writes an to output. diff --git a/00_Common/dotnet/Games.Common/IO/InsufficientInputException.cs b/00_Common/dotnet/Games.Common/IO/InsufficientInputException.cs deleted file mode 100644 index 77100dc1f..000000000 --- a/00_Common/dotnet/Games.Common/IO/InsufficientInputException.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Games.Common.IO; - -public class InsufficientInputException : Exception -{ - public InsufficientInputException() - : base("Insufficient input was supplied") - { - } -} diff --git a/00_Common/dotnet/Games.Common/IO/TextIO.cs b/00_Common/dotnet/Games.Common/IO/TextIO.cs index 33a5b7ca6..5a31e37cd 100644 --- a/00_Common/dotnet/Games.Common/IO/TextIO.cs +++ b/00_Common/dotnet/Games.Common/IO/TextIO.cs @@ -1,4 +1,7 @@ -using Games.Common.Numbers; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; namespace Games.Common.IO; @@ -90,16 +93,16 @@ private IReadOnlyList ReadStrings(string prompt, uint quantityRequired) internal string ReadLine(string prompt) { Write(prompt + "? "); - return _input.ReadLine() ?? throw new InsufficientInputException(); + return _input.ReadLine(); } public void Write(string value) => _output.Write(value); public void WriteLine(string value = "") => _output.WriteLine(value); - public void Write(Number value) => _output.Write(value.ToString()); + public void Write(float value) => _output.Write(GetString(value)); - public void WriteLine(Number value) => _output.WriteLine(value.ToString()); + public void WriteLine(float value) => _output.WriteLine(GetString(value)); public void Write(object value) => _output.Write(value.ToString()); diff --git a/00_Common/dotnet/Games.Common/Numbers/Number.cs b/00_Common/dotnet/Games.Common/Numbers/Number.cs deleted file mode 100644 index 3001009fc..000000000 --- a/00_Common/dotnet/Games.Common/Numbers/Number.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Games.Common.Numbers; - -/// -/// A single-precision floating-point number with string formatting equivalent to the BASIC interpreter. -/// -public struct Number -{ - private readonly float _value; - - public Number (float value) - { - _value = value; - } - - public static implicit operator float(Number value) => value._value; - - public static implicit operator Number(float value) => new Number(value); - - public override string ToString() => _value < 0 ? $"{_value} " : $" {_value} "; -} diff --git a/00_Common/javascript/WebTerminal/HtmlTerminal.css b/00_Common/javascript/WebTerminal/HtmlTerminal.css index eaeea9662..54eac8d31 100644 --- a/00_Common/javascript/WebTerminal/HtmlTerminal.css +++ b/00_Common/javascript/WebTerminal/HtmlTerminal.css @@ -1,5 +1,5 @@ :root { - --terminal-font: 1rem "Lucida Console", "Courier New", monospace; + --terminal-font: 1em "Lucida Console", "Courier New", monospace; --background-color: transparent; --text-color: var(--text); --prompt-char: '$ '; @@ -10,15 +10,12 @@ * If you wan t to overwrite them use custom properties (variables). */ .terminal { - display: block; font: var(--terminal-font); background-color: var(--background-color); color: var(--text-color); overflow-y: scroll; - width: 100%; - max-width: 640px; - margin: 0 auto; + width: max-content; } /* The terminal consits of multiple "line" elements @@ -32,7 +29,10 @@ padding: 0; } -/* The "terminal" has one "prompt" input-element. */ +/* The "terminal" has one "prompt" element. + * This prompt is not any kind of input, but just a simple + * with an id "prompt" and a + */ @keyframes prompt-blink { 100% { opacity: 0; @@ -54,15 +54,6 @@ width: 0.75rem; opacity: 1; } -.terminal input#prompt { - text-transform: uppercase; - background: none; - border: none; - outline: none; - caret-color: var(--text); - color: var(--text); - font: var(--terminal-font); -} /* Terminal scrollbar */ diff --git a/00_Common/javascript/WebTerminal/HtmlTerminal.js b/00_Common/javascript/WebTerminal/HtmlTerminal.js index a2aa2365b..4a095c87a 100644 --- a/00_Common/javascript/WebTerminal/HtmlTerminal.js +++ b/00_Common/javascript/WebTerminal/HtmlTerminal.js @@ -26,7 +26,7 @@ class HtmlTerminal { * @private * @type {HTMLElement} */ - #$prompt; + #$prompt = undefined; /** * Constructor @@ -45,18 +45,13 @@ class HtmlTerminal { this.$output.classList.add('terminal'); // Create a prompt element. - // This element gets added if input is needed. - this.#$prompt = document.createElement("input"); + // This element gets added if input is needed + this.#$prompt = document.createElement("span"); this.#$prompt.setAttribute("id", "prompt"); - this.#$prompt.setAttribute("type", "text"); - this.#$prompt.setAttribute("length", "50"); - this.#$prompt.addEventListener("keydown", this.#handleKey.bind(this)); - - // Force focus on the promt on each click. - // This is needed for mobile support. - document.body.addEventListener('click', () => { - this.#$prompt.focus(); - }); + this.#$prompt.innerText = ""; + + //TODO: this handler shouls be only on the propt element and only active if cursor is visible + document.addEventListener("keyup", this.#handleKey.bind(this)); } /** @@ -82,16 +77,28 @@ class HtmlTerminal { * @param {*} e */ #handleKey(e) { - // if no input-callback is defined just return + // if no input-callback is defined if (!this.#inputCallback) { return; } - if (e.keyCode == 13) { - const text = this.#$prompt.value; - this.#$prompt.value = ''; + if (e.keyCode === 13 /* ENTER */) { + // create a new line with the text input and remove the prompt + const text = this.#$prompt.innerText; + this.write(text + "\n"); + this.#$prompt.innerText = ""; this.#$prompt.remove(); - this.#inputCallback(text + '\n'); + + // return the inputed text + this.#inputCallback(text); + + // remove the callback and the key handler + this.#inputCallback = undefined; + } else if (e.keyCode === 8 /* BACKSPACE */) { + this.#$prompt.innerText = this.#$prompt.innerText.slice(0, -1); + } else { + this.#$prompt.innerHtml = ''; + this.#$prompt.innerText = this.#$prompt.innerText + e.key; } } @@ -106,7 +113,7 @@ class HtmlTerminal { } /** - * Create a new div and add html content. + * TODO: * * @public * @param {*} htmlContent @@ -128,23 +135,27 @@ class HtmlTerminal { * @param {string} text */ write(text) { - if (!text || text.length <= 0) { - // empty line - this.$output.appendChild(document.createElement("br")); - } else if (text.endsWith("\n")) { - // single line with linebrank - const $lineNode = this.#newLine(text); - this.$output.appendChild(this.#newLine(text)); - this.$output.appendChild(document.createElement("br")); - } else if (text.includes("\n")) { - // multible lines + if (text.match(/^\n*$/)) { + // empty new line + text.match(/\n/g).forEach(() => { + const $br = document.createElement("br"); + this.$output.appendChild($br); + }); + } else if (text && text.length && text.includes("\n")) { const lines = text.split("\n"); lines.forEach((line) => { - this.write(line); + if (line.length === 0 || line.match(/^\s*$/)) { + this.$output.appendChild(document.createElement("br")); + } else { + const $lineNode = this.#newLine(line); + this.$output.appendChild($lineNode); + //this.$node.appendChild(document.createElement("br")); + } }); - } else { - // single line - this.$output.appendChild(this.#newLine(text)); + } else if (text && text.length) { + // simple line + const $lineNode = this.#newLine(text); + this.$output.appendChild($lineNode); } // scroll to the buttom of the page @@ -173,8 +184,7 @@ class HtmlTerminal { */ input(callback) { // show prompt with a blinking prompt - this.#inputCallback = callback; this.$output.appendChild(this.#$prompt); - this.#$prompt.focus(); + this.#inputCallback = callback; } } diff --git a/00_Common/javascript/WebTerminal/terminal.html b/00_Common/javascript/WebTerminal/terminal.html index ae68bedb7..f878f0ad5 100644 --- a/00_Common/javascript/WebTerminal/terminal.html +++ b/00_Common/javascript/WebTerminal/terminal.html @@ -1,86 +1,44 @@ Minimal node.js terminal - - - + -
-

BASIC Computer Games

-
-
+
diff --git a/00_Common/javascript/WebTerminal/terminal_tests.mjs b/00_Common/javascript/WebTerminal/terminal_tests.mjs index d2470c958..804de3f28 100644 --- a/00_Common/javascript/WebTerminal/terminal_tests.mjs +++ b/00_Common/javascript/WebTerminal/terminal_tests.mjs @@ -3,21 +3,21 @@ import { print, println, tab, input } from '../common.mjs'; async function main() { - println(tab(30), "Minimal node.js terminal emulator"); - println(); + println(tab(20), "Minimal node.js terminal 2"); + println(""); println(tab(0), "tab 0"); println(tab(5), "tab 5"); println(tab(10), "tab 10"); println(tab(15), "tab 15"); println(tab(20), "tab 20"); println(tab(25), "tab 25"); - println(); - println("1234567890", " _ ", "ABCDEFGHIJKLMNOPRSTUVWXYZ"); - println(); + println(""); + println("1234567890", " ", "ABCDEFGHIJKLMNOPRSTUVWXYZ"); + println(""); print("\nHallo"); print(" "); print("Welt!\n"); println(""); - println("Line 1\nLine 2\nLine 3\nLine 4"); - println("----------------------------------------------"); + print("Line 1\nLine 2\nLine 3\nLine 4"); + println(""); const value = await input("input"); println(`input value was "${value}"`); diff --git a/00_Common/javascript/common.mjs b/00_Common/javascript/common.mjs index 5f489990c..3fcc4212a 100644 --- a/00_Common/javascript/common.mjs +++ b/00_Common/javascript/common.mjs @@ -1,71 +1,21 @@ -/** - * Print multible strings to the terminal. - * Strings get concatinated (add together) without any space betweent them. - * There will be no newline at the end! - * If you want a linebrak at the end use `println`. - * - * This function is normally used if you want to put something on the screen - * and later add some content to the same line. - * For normal output (similar to `console.log`) use `println`! - * - * @param {...string} messages - the strings to print to the terminal. - */ + export function print(...messages) { - process.stdout.write(messages.join("")); + process.stdout.write(messages.join("")); } -/** - * Add multible strings as a new line to the terminal. - * Strings get concatinated (add together) without any space betweent them. - * There will be a newline at the end! - * If you want the terminal to stay active on the current line use `print`. - * - * @param {...any} messages - the strings to print to the terminal. - */ export function println(...messages) { - process.stdout.write(messages.join("") + "\n"); + process.stdout.write(messages.join("") + "\n"); } -/** - * Create an empty string with a given length - * - * @param {number} length - the length of the string in space-characters. - * @returns {string} returns a string containing only ampty spaces with a length of `count`. - */ -export function tab(length) { - return " ".repeat(length); +export function tab(count) { + return " ".repeat(count); } -/** - * Read input from the keyboard and return it as a string. - * TODO: to would be very helpfull to only allow a certain class of input (numbers, letters) - * TODO: also we could convert all inputs to uppercase (where it makes sence). - * - * @param {string=''} message - a message or question to print befor the input. - * @returns {Promise} - returns the entered text as a string - * @async - */ -export async function input(message = '') { - /* First we need to print the mesage - * We append a space by default to seperate the message from the imput. - * TODO: If the message already contains a space at the end this is not needed! */ - process.stdout.write(message + ' '); - - return new Promise(resolve => { - process.stdin.on('data', (input) => { - /* onData returns a Buffer. - * First we need to convert it into a string. */ - const data = input.toString(); - - /* add input to terminal - * The data should end with a newline! */ - process.stdout.write(data); - - /* The result fo onData is a string ending with an `\n`. - * We just need the actual content so let's remove the newline at the end: */ - const content = data.endsWith('\n') ? data.slice(0, -1) : data; - - resolve(content); - }); - }); +export async function input(message = "") { + process.stdout.write(message + ' '); + return new Promise(resolve => { + process.stdin.on('data', (input) => { + resolve(input.toString().replace('\n', '')); + }); + }); } diff --git a/00_Utilities/TODO.md b/00_Utilities/TODO.md index 714807486..05fc21306 100644 --- a/00_Utilities/TODO.md +++ b/00_Utilities/TODO.md @@ -2,100 +2,97 @@ game | C# | Java | JS | Kotlin | Lua | Perl | Python | Ruby | Rust | VB.NET ------------------------------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- 01_Acey_Ducey | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ -[02_Amazing](../02_Amazing) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ -[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) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️ -[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) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ -[19_Bunny](../19_Bunny) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[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) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[27_Civil_War](../27_Civil_War) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[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) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[37_Football](../37_Football) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[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) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ -[44_Hangman](../44_Hangman) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[45_Hello](../45_Hello) | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[46_Hexapawn](../46_Hexapawn) | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[47_Hi-Lo](../47_Hi-Lo) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[48_High_IQ](../48_High_IQ) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[49_Hockey](../49_Hockey) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[50_Horserace](../50_Horserace) | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️ -[51_Hurkle](../51_Hurkle) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[52_Kinema](../52_Kinema) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[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) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[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) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ -[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) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ -[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) | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[79_Slalom](../79_Slalom) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ -[80_Slots](../80_Slots) | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ -[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) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ -[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) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[94_War](../94_War) | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ -[95_Weekday](../95_Weekday) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ -[96_Word](../96_Word) | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ ------------------------------- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- -Sum of 96 | 79 | 83 | 96 | 9 | 16 | 75 | 95 | 51 | 58 | 7 +02_Amazing | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ✅ +03_Animal | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +04_Awari | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +05_Bagels | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +06_Banner | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ +07_Basketball | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ +08_Batnum | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ +09_Battle | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +10_Blackjack | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️ +11_Bombardment | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +12_Bombs_Away | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +13_Bounce | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ +14_Bowling | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +15_Boxing | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +16_Bug | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ +17_Bullfight | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +18_Bullseye | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +19_Bunny | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +20_Buzzword | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +21_Calendar | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +22_Change | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +23_Checkers | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ +24_Chemist | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +25_Chief | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +26_Chomp | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +27_Civil_War | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +28_Combat | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +29_Craps | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +30_Cube | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ +31_Depth_Charge | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +32_Diamond | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +33_Dice | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ +34_Digits | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +35_Even_Wins | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +36_Flip_Flop | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ +37_Football | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ +38_Fur_Trader | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +39_Golf | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +40_Gomoko | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +41_Guess | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +42_Gunner | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +43_Hammurabi | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +44_Hangman | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +45_Hello | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +46_Hexapawn | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +47_Hi-Lo | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +48_High_IQ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +49_Hockey | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ +50_Horserace | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +51_Hurkle | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +52_Kinema | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +53_King | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ +54_Letter | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +55_Life | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +56_Life_for_Two | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ +57_Literature_Quiz | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +58_Love | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +59_Lunar_LEM_Rocket | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ✅ | ⬜️ +60_Mastermind | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +61_Math_Dice | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +62_Mugwump | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +63_Name | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +64_Nicomachus | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +65_Nim | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ +66_Number | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +67_One_Check | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +68_Orbit | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +69_Pizza | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +70_Poetry | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +71_Poker | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ | ⬜️ +72_Queen | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +73_Reverse | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ +74_Rock_Scissors_Paper | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +75_Roulette | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +76_Russian_Roulette | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +77_Salvo | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +78_Sine_Wave | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +79_Slalom | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +80_Slots | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +81_Splat | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +82_Stars | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +83_Stock_Market | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +84_Super_Star_Trek | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +85_Synonym | ✅ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +86_Target | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +87_3-D_Plot | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +88_3-D_Tic-Tac-Toe | ✅ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ | ✅ | ⬜️ | ⬜️ | ⬜️ +89_Tic-Tac-Toe | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ +90_Tower | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +91_Train | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +92_Trap | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ⬜️ +93_23_Matches | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ⬜️ | ⬜️ +94_War | ⬜️ | ✅ | ✅ | ✅ | ⬜️ | ✅ | ✅ | ✅ | ✅ | ⬜️ +95_Weekday | ✅ | ✅ | ✅ | ⬜️ | ⬜️ | ✅ | ✅ | ⬜️ | ✅ | ⬜️ diff --git a/00_Utilities/build-index.js b/00_Utilities/build-index.js index 1ed862efe..2785957e5 100644 --- a/00_Utilities/build-index.js +++ b/00_Utilities/build-index.js @@ -14,29 +14,16 @@ const path = require('path'); const TITLE = 'BASIC Computer Games'; const JAVASCRIPT_FOLDER = 'javascript'; const IGNORE_FOLDERS_START_WITH = ['.', '00_', 'buildJvm', 'Sudoku']; -const IGNORE_FILES = [ - // "84 Super Star Trek" has it's own node/js implementation (using xterm) - 'cli.mjs', 'superstartrek.mjs' -]; function createGameLinks(game) { - const creatFileLink = (file, name = path.basename(file)) => { - if (file.endsWith('.html')) { + if (game.htmlFiles.length > 1) { + const entries = game.htmlFiles.map(htmlFile => { + const name = path.basename(htmlFile).replace('.html', ''); return ` -
  • ${name.replace('.html', '')}
  • +
  • + ${name} +
  • `; - } else if (file.endsWith('.mjs')) { - return ` -
  • ${name.replace('.mjs', '')} (node.js)
  • - `; - } else { - throw new Error(`Unknown file-type found: ${file}`); - } - } - - if (game.files.length > 1) { - const entries = game.files.map(file => { - return creatFileLink(file); }); return `
  • @@ -45,7 +32,7 @@ function createGameLinks(game) {
  • `; } else { - return creatFileLink(game.files[0], game.name); + return `
  • ${game.name}
  • `; } } @@ -86,11 +73,11 @@ function createIndexHtml(title, games) { `.trim().replace(/\s\s+/g, ''); } -function findJSFilesInFolder(folder) { +function findHtmlFilesInFolder(folder) { // filter folders that do not include a subfolder called "javascript" const hasJavascript = fs.existsSync(`${folder}/${JAVASCRIPT_FOLDER}`); if (!hasJavascript) { - throw new Error(`Game "${folder}" is missing a javascript folder`); + throw new Error(`Game "${folder}" is missing a javascript implementation`); } // get all files in the javascript folder @@ -98,17 +85,12 @@ function findJSFilesInFolder(folder) { // filter files only allow .html files const htmlFiles = files.filter(file => file.endsWith('.html')); - const mjsFiles = files.filter(file => file.endsWith('.mjs')); - const entries = [ - ...htmlFiles, - ...mjsFiles - ].filter(file => !IGNORE_FILES.includes(file)); - - if (entries.length == 0) { - throw new Error(`Game "${folder}" is missing a HTML or node.js file in the folder "${folder}/${JAVASCRIPT_FOLDER}"`); + + if (htmlFiles.length == 0) { + throw new Error(`Game "${folder}" is missing a html file in the "${folder}/${JAVASCRIPT_FOLDER}" folder`); } - return entries.map(file => path.join(folder, JAVASCRIPT_FOLDER, file)); + return htmlFiles.map(htmlFile => path.join(folder, JAVASCRIPT_FOLDER, htmlFile)); } function main() { @@ -129,10 +111,10 @@ function main() { // get name and javascript file from folder const games = folders.map(folder => { const name = folder.replace('_', ' '); - let files; + let htmlFiles; try { - files = findJSFilesInFolder(folder); + htmlFiles = findHtmlFilesInFolder(folder); } catch (error) { console.warn(`Game "${name}" is missing a javascript implementation: ${error.message}`); return null; @@ -140,7 +122,7 @@ function main() { return { name, - files + htmlFiles } }).filter(game => game !== null); diff --git a/00_Utilities/find-missing-implementations.js b/00_Utilities/find-missing-implementations.js index a458f190e..61d849feb 100644 --- a/00_Utilities/find-missing-implementations.js +++ b/00_Utilities/find-missing-implementations.js @@ -16,13 +16,10 @@ 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 fb88fdbe2..e048d9ce2 100644 --- a/00_Utilities/find-unimplemented.js +++ b/00_Utilities/find-unimplemented.js @@ -17,14 +17,11 @@ 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) => { diff --git a/00_Utilities/javascript/style_terminal.css b/00_Utilities/javascript/style_terminal.css index c0a23ac57..ddc7f459f 100644 --- a/00_Utilities/javascript/style_terminal.css +++ b/00_Utilities/javascript/style_terminal.css @@ -32,9 +32,6 @@ body { color: var(--text); font: var(--font); margin: 0; -} - -#output { padding: 1rem; } @@ -84,10 +81,143 @@ a:hover { } /* add all the face flicker effects (only on desktop) */ -@media not screen and (max-width: 960px) and (prefers-reduced-motion) { - main { +@media screen and (min-width: 960px) { + body { padding: 3rem; } + @keyframes flicker { + 0% { + opacity: 0.27861; + } + 5% { + opacity: 0.34769; + } + 10% { + opacity: 0.23604; + } + 15% { + opacity: 0.90626; + } + 20% { + opacity: 0.18128; + } + 25% { + opacity: 0.83891; + } + 30% { + opacity: 0.65583; + } + 35% { + opacity: 0.67807; + } + 40% { + opacity: 0.26559; + } + 45% { + opacity: 0.84693; + } + 50% { + opacity: 0.96019; + } + 55% { + opacity: 0.08594; + } + 60% { + opacity: 0.20313; + } + 65% { + opacity: 0.71988; + } + 70% { + opacity: 0.53455; + } + 75% { + opacity: 0.37288; + } + 80% { + opacity: 0.71428; + } + 85% { + opacity: 0.70419; + } + 90% { + opacity: 0.7003; + } + 95% { + opacity: 0.36108; + } + 100% { + opacity: 0.24387; + } + } + @keyframes textShadow { + 0% { + text-shadow: 0.4389924193300864px 0 1px rgba(0,30,255,0.5), -0.4389924193300864px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 5% { + text-shadow: 2.7928974010788217px 0 1px rgba(0,30,255,0.5), -2.7928974010788217px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 10% { + text-shadow: 0.02956275843481219px 0 1px rgba(0,30,255,0.5), -0.02956275843481219px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 15% { + text-shadow: 0.40218538552878136px 0 1px rgba(0,30,255,0.5), -0.40218538552878136px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 20% { + text-shadow: 3.4794037899852017px 0 1px rgba(0,30,255,0.5), -3.4794037899852017px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 25% { + text-shadow: 1.6125630401149584px 0 1px rgba(0,30,255,0.5), -1.6125630401149584px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 30% { + text-shadow: 0.7015590085143956px 0 1px rgba(0,30,255,0.5), -0.7015590085143956px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 35% { + text-shadow: 3.896914047650351px 0 1px rgba(0,30,255,0.5), -3.896914047650351px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 40% { + text-shadow: 3.870905614848819px 0 1px rgba(0,30,255,0.5), -3.870905614848819px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 45% { + text-shadow: 2.231056963361899px 0 1px rgba(0,30,255,0.5), -2.231056963361899px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 50% { + text-shadow: 0.08084290417898504px 0 1px rgba(0,30,255,0.5), -0.08084290417898504px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 55% { + text-shadow: 2.3758461067427543px 0 1px rgba(0,30,255,0.5), -2.3758461067427543px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 60% { + text-shadow: 2.202193051050636px 0 1px rgba(0,30,255,0.5), -2.202193051050636px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 65% { + text-shadow: 2.8638780614874975px 0 1px rgba(0,30,255,0.5), -2.8638780614874975px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 70% { + text-shadow: 0.48874025155497314px 0 1px rgba(0,30,255,0.5), -0.48874025155497314px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 75% { + text-shadow: 1.8948491305757957px 0 1px rgba(0,30,255,0.5), -1.8948491305757957px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 80% { + text-shadow: 0.0833037308038857px 0 1px rgba(0,30,255,0.5), -0.0833037308038857px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 85% { + text-shadow: 0.09769827255241735px 0 1px rgba(0,30,255,0.5), -0.09769827255241735px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 90% { + text-shadow: 3.443339761481782px 0 1px rgba(0,30,255,0.5), -3.443339761481782px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 95% { + text-shadow: 2.1841838852799786px 0 1px rgba(0,30,255,0.5), -2.1841838852799786px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + 100% { + text-shadow: 2.6208764473832513px 0 1px rgba(0,30,255,0.5), -2.6208764473832513px 0 1px rgba(255,0,80,0.3), 0 0 3px; + } + } + #output { + animation: textShadow 1.6s infinite; + } #output::before { content: " "; display: block; @@ -113,5 +243,6 @@ a:hover { opacity: 0; z-index: 2; pointer-events: none; + animation: flicker 0.15s infinite; } } \ No newline at end of file diff --git a/00_Utilities/markdown_todo.py b/00_Utilities/markdown_todo.py index fa5d14c50..5dd0060bb 100644 --- a/00_Utilities/markdown_todo.py +++ b/00_Utilities/markdown_todo.py @@ -55,7 +55,7 @@ def get_data(checklist_orig: List[str], root_dir: str = "..") -> List[List[str]] # it's a new dir strings_done.append(checklist) checklist = [ - f"{f'[{split_dir[1]}](../{split_dir[1]})':<30}", + f"{split_dir[1]:<30}", ] + empty_boxes[1:] prev_game = split_dir[1] elif ( @@ -83,19 +83,6 @@ def write_file(path: str, languages: List[str], strings_done: List[List[str]]) - map(lambda l: " | ".join(l) + "\n", sorted(strings_done, key=lambda x: x[0])) ) write_string += "".join(sorted_strings) - write_string += f"{dashes}\n" - language_indices = range(1, len(languages) + 1) - nb_games = len(strings_done) - write_string += ( - f"{f'Sum of {nb_games}':<30} | " - + " | ".join( - [ - f"{sum(row[lang] == '✅' for row in strings_done)}" - for lang in language_indices - ] - ) - + "\n" - ) with open(path, "w", encoding="utf-8") as f: f.write(write_string) diff --git a/00_Utilities/markdown_todo_rust/src/main.rs b/00_Utilities/markdown_todo_rust/src/main.rs index 9df645677..d1f49bf4f 100644 --- a/00_Utilities/markdown_todo_rust/src/main.rs +++ b/00_Utilities/markdown_todo_rust/src/main.rs @@ -1,4 +1,4 @@ -use std::ffi::OsStr; +use std::ffi::{OsString, OsStr}; use std::{fs, io}; use std::fs::metadata; use std::path::{Path, PathBuf}; @@ -8,6 +8,8 @@ use std::path::{Path, PathBuf}; * @author Anthony Rubick */ + + //DATA const ROOT_DIR: &str = "../../"; const LANGUAGES: [(&str,&str); 10] = [ //first element of tuple is the language name, second element is the file extension @@ -23,19 +25,13 @@ const LANGUAGES: [(&str,&str); 10] = [ //first element of tuple is the language ("vbnet", "vb") ]; const OUTPUT_PATH: &str = "../../todo.md"; +//const INGORE: [&str;5] = ["../../.git","../../.vscode","../../00_Utilities","../../buildJvm","../../node_modules"]; //folders to ignore fn main() { //DATA let mut root_folders:Vec; let mut output_string: String = String::new(); let format_game_first: bool; - let ingore: [PathBuf;5] = [ - PathBuf::from(r"../../.git"), - PathBuf::from(r"../../.github"), - PathBuf::from(r"../../00_Alternate_Languages"), - PathBuf::from(r"../../00_Utilities"), - PathBuf::from(r"../../00_Common"), - ]; //folders to ignore //print welcome message println!(" @@ -70,10 +66,15 @@ fn main() { //for all folders, search for the languages and extensions root_folders = root_folders.into_iter().filter(|path| { - //not one of the ignored folders - !ingore.contains(path) + match fs::read_dir(path) { + Err(why) => {println!("! {:?}", why.kind()); false}, + Ok(paths) => { + paths.into_iter().filter(|f| metadata(f.as_ref().unwrap().path()).unwrap().is_dir()) //filter to only folders + .filter_map( |path| path.ok() ) //extract only the DirEntries + .any(|f| LANGUAGES.iter().any(|tup| OsString::from(tup.1).eq_ignore_ascii_case(f.file_name()))) //filter out ones that don't contain folders with the language names + } + } }).collect(); - root_folders.sort(); //create todo list if format_game_first { diff --git a/00_Utilities/python/ci-requirements.in b/00_Utilities/python/ci-requirements.in index eaa0bc146..218d0de96 100644 --- a/00_Utilities/python/ci-requirements.in +++ b/00_Utilities/python/ci-requirements.in @@ -1,3 +1,4 @@ +pytest flake8 flake8-bugbear flake8-comprehensions diff --git a/00_Utilities/python/ci-requirements.txt b/00_Utilities/python/ci-requirements.txt index 0ba583b15..921b2325f 100644 --- a/00_Utilities/python/ci-requirements.txt +++ b/00_Utilities/python/ci-requirements.txt @@ -8,6 +8,7 @@ attrs==20.3.0 # via # flake8-bugbear # flake8-implicit-str-concat + # pytest flake8==4.0.1 # via # -r ci-requirements.in @@ -19,6 +20,8 @@ flake8-comprehensions==3.8.0 # via -r ci-requirements.in flake8-implicit-str-concat==0.2.0 # via -r ci-requirements.in +iniconfig==1.1.1 + # via pytest mccabe==0.6.1 # via flake8 more-itertools==8.12.0 @@ -27,11 +30,23 @@ mypy==0.931 # via -r ci-requirements.in mypy-extensions==0.4.3 # via mypy +packaging==21.3 + # via pytest +pluggy==1.0.0 + # via pytest +py==1.11.0 + # via pytest pycodestyle==2.8.0 # via flake8 pyflakes==2.4.0 # via flake8 +pyparsing==3.0.7 + # via packaging +pytest==7.0.1 + # via -r ci-requirements.in tomli==2.0.1 - # via mypy + # via + # mypy + # pytest typing-extensions==4.1.1 # via mypy diff --git a/01_Acey_Ducey/README.md b/01_Acey_Ducey/README.md index 0fabfb087..26856f717 100644 --- a/01_Acey_Ducey/README.md +++ b/01_Acey_Ducey/README.md @@ -15,13 +15,10 @@ 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 -- The assignment `N = 100` in line 100 has no effect; variable `N` is not used anywhere else in the program. +(please note any difficulties or challenges in porting here) #### External Links - Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp diff --git a/01_Acey_Ducey/elixir/acey_ducey.exs b/01_Acey_Ducey/elixir/acey_ducey.exs deleted file mode 100644 index 31308df78..000000000 --- a/01_Acey_Ducey/elixir/acey_ducey.exs +++ /dev/null @@ -1,97 +0,0 @@ -######################################################## -# -# 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}) do - [floor, ceiling] = Enum.sort([first, second]) - (floor < third) && (third < ceiling) - end - # for a looser win condition (inclusive) - #defp win?({_, first}, {_, second}, {_, third}) do - #[_, middle, _] = Enum.sort([first, second, third]) - #middle == third - #end - - 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}) diff --git a/01_Acey_Ducey/python/acey_ducey.py b/01_Acey_Ducey/python/acey_ducey.py index 75a1eac27..550d94b25 100755 --- a/01_Acey_Ducey/python/acey_ducey.py +++ b/01_Acey_Ducey/python/acey_ducey.py @@ -6,8 +6,8 @@ import random - cards = { + 1: "1", 2: "2", 3: "3", 4: "4", @@ -16,26 +16,23 @@ 7: "7", 8: "8", 9: "9", - 10: "10", - 11: "Jack", - 12: "Queen", - 13: "King", - 14: "Ace", + 10: "Jack", + 11: "Queen", + 12: "King", + 13: "Ace", } def play_game() -> None: + """Play the game""" 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 - 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 + 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: card_a, card_b = card_b, card_a print(f" {cards[card_a]}") print(f" {cards[card_b]}\n") @@ -57,7 +54,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: @@ -67,6 +64,16 @@ def play_game() -> None: def main() -> None: + """Main""" + keep_playing = True + + while keep_playing: + play_game() + keep_playing = input("Try again? (yes or no) ").lower().startswith("y") + print("Ok hope you had fun") + + +if __name__ == "__main__": print( """ Acey-Ducey is played in the following manner @@ -77,14 +84,4 @@ def main() -> None: If you do not want to bet, input a 0 """ ) - keep_playing = True - - while keep_playing: - play_game() - keep_playing = input("Try again? (yes or no) ").lower().startswith("y") - print("Ok hope you had fun") - - -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 cd5cad76f..c195c8427 100644 --- a/01_Acey_Ducey/python/acey_ducey_oo.py +++ b/01_Acey_Ducey/python/acey_ducey_oo.py @@ -1,22 +1,25 @@ """ AceyDuchy + From: BASIC Computer Games (1978) Edited by David Ahl + "The original BASIC program author was Bill Palmby of Prairie View, Illinois." + Python port by Aviyam Fischer, 2022 """ -from typing import List, Literal, NamedTuple, TypeAlias, get_args -import random +from typing import List, Literal, TypeAlias, get_args Suit: TypeAlias = Literal["\u2665", "\u2666", "\u2663", "\u2660"] Rank: TypeAlias = Literal[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] -class Card(NamedTuple): - suit: Suit - rank: Rank +class Card: + def __init__(self, suit: Suit, rank: Rank) -> None: + self.suit = suit + self.rank = rank def __str__(self) -> str: r = str(self.rank) @@ -35,6 +38,8 @@ def build(self) -> None: self.cards.append(Card(suit, rank)) def shuffle(self) -> None: + import random + random.shuffle(self.cards) def deal(self) -> Card: @@ -71,7 +76,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: @@ -86,6 +91,9 @@ 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 @@ -110,7 +118,7 @@ def game_loop() -> None: game_over = True -def main() -> None: +def main(): print( """ Acey Ducey is a card game where you play against the computer. @@ -125,5 +133,4 @@ def main() -> None: if __name__ == "__main__": - random.seed() main() diff --git a/01_Acey_Ducey/python/aceyducey.py b/01_Acey_Ducey/python/aceyducey.py new file mode 100644 index 000000000..e546963e8 --- /dev/null +++ b/01_Acey_Ducey/python/aceyducey.py @@ -0,0 +1,212 @@ +"""aceyducey.py contains game code""" +######################################################## +# +# 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." +# +# Python port by Jeff Jetton, 2019 +# +######################################################## + + +import random + +# "You may alter [the following statement] if you want +# to start with more or less than $100." +DEFAULT_BANKROLL = 100 + + +def deal_card_num() -> int: + """Get card number""" + return random.randint(0, 12) + + +def get_card_name(number: int) -> str: + """Get card name""" + card_names = ( + " 2", + " 3", + " 4", + " 5", + " 6", + " 7", + " 8", + " 9", + " 10", + "Jack", + "Queen", + "King", + "Ace", + ) + return card_names[number] + + +def display_bankroll(bank_roll: int) -> None: + """Print current bankroll""" + if bank_roll > 0: + print(f"You now have {bank_roll} dollars\n") + + +def main() -> None: + """Display initial title and instructions.""" + print("\n Acey Ducey Card Game") + print("Creative Computing Morristown, New Jersey") + print("\n\n") + 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") + + multiple_game_loop() + + print("OK Hope you had fun\n") + + +def multiple_game_loop() -> None: + """Loop for series of multiple games.""" + keep_playing = True + while keep_playing: + # Initialize bankroll at start of each game + BANK_ROLL = DEFAULT_BANKROLL + display_bankroll(BANK_ROLL) + + single_round(BANK_ROLL) + + print("\n\nSorry, friend but you blew your wad") + player_response = input("Try again (yes or no) ") + if player_response.lower() == "yes": + print() + else: + keep_playing = False + + +def single_round(BANK_ROLL: int) -> None: + """Loop for a single round. Repeat until out of money.""" + while BANK_ROLL > 0: + # Deal out dealer cards + print("Here are your next two cards") + dealer1 = deal_card_num() + # If the cards match, we redeal 2nd card until they don't + dealer2 = dealer1 + while dealer1 == dealer2: + dealer2 = deal_card_num() + # Organize the cards in order if they're not already + if dealer1 >= dealer2: + (dealer1, dealer2) = (dealer2, dealer1) # Ya gotta love Python! + # Show dealer cards to the player + # (use card name rather than internal number) + print(get_card_name(dealer1)) + print(get_card_name(dealer2) + "\n") + + # Get and handle player bet choice + BET_IS_VALID = False + while not BET_IS_VALID: + curr_bet_str = input("What is your bet? ") + try: + curr_bet = int(curr_bet_str) + except ValueError: + # Bad input? Just loop back up and ask again... + pass + else: + if curr_bet == 0: + BET_IS_VALID = True + print("Chicken!!\n") + elif curr_bet > BANK_ROLL: + print("Sorry, my friend but you bet too much") + print(f"You have only {BANK_ROLL} dollars to bet\n") + else: + # Deal player card + BET_IS_VALID = True + player = deal_card_num() + print(get_card_name(player)) + + # Did we win? + if dealer1 < player < dealer2: + print("You win!!!") + BANK_ROLL += curr_bet + else: + print("Sorry, you lose") + BANK_ROLL -= curr_bet + + # Update player on new bankroll level + display_bankroll(BANK_ROLL) + + +if __name__ == "__main__": + main() + + +######################################################## +# +# Porting notes: +# +# The original BASIC version had a variable named N +# that was initialized to 100 and then never used. +# Maybe it did something in feature that was edited +# out of the final version used in the book? +# +# The original program simply generated random numbers +# for each card. It did not simulate a true card deck, +# where the dealing of a card eliminates it from the +# deck and reduces the chances of the same value +# being drawn. This "infinite deck" logic (or "deal, +# with replacement after") has NOT been changed. +# +# In the interests of historical fidelity, the bug +# in the original BASIC listing that let you input a +# negative bet value has been faithfully reproduced. +# This lets the player lose money when they win and +# earn money when they lose! :-) +# +# +# Ideas for Modifications +# +# Give the user the ability to quit the game, perhaps +# by typing "quit" instead of making a bet. Provide a +# final assessment based on how much of the original +# bankroll they have left. +# +# Or have the game run for a set number of rounds or +# until a certain bankroll goal is attained. +# +# Implement an "ante"--a set amount the player has to +# bet each time rather than having the option to lay +# out entirely. +# +# See "porting notes" above about negative bet values. +# How would you fix this? +# +# When the player "chickens out", show them what the +# next card would've been and point out whether they +# made a good or bad decision. +# +# In what situations are the odds of winning high +# enough to justify making a bet? Create a cheat mode +# where the program identifies these situations and +# lets the player know. +# +# Change the card dealing to simulate deals from a +# single deck (or a user-selectable number of decks). +# +# Implement a two-player mode where players take turns +# betting (or both bet on the same dealer cards and +# get their own player card dealt). +# +######################################################## diff --git a/01_Acey_Ducey/python/test_acey_ducey.py b/01_Acey_Ducey/python/test_acey_ducey.py new file mode 100644 index 000000000..44ea38dd5 --- /dev/null +++ b/01_Acey_Ducey/python/test_acey_ducey.py @@ -0,0 +1,29 @@ +import io +from unittest import mock +from typing import TypeVar +from _pytest.capture import CaptureFixture +from _pytest.monkeypatch import MonkeyPatch + +from acey_ducey import play_game + + +@mock.patch("random.shuffle") +def test_play_game_lose( + mock_random_shuffle, monkeypatch: MonkeyPatch, capsys: CaptureFixture +) -> None: + monkeypatch.setattr("sys.stdin", io.StringIO("100\n100")) + T = TypeVar("T") + + def identity(x: T) -> T: + return x + + mock_random_shuffle = identity # noqa: F841 + play_game() + captured = capsys.readouterr() + assert captured.out == ( + "You now have 100 dollars\n\n" + "Here are you next two cards\n King\n Ace\n\n" + "What is your bet? Queen\n" + "Sorry, you lose\n" + "Sorry, friend, but you blew your wad\n" + ) diff --git a/01_Acey_Ducey/python/test_acey_ducey_oo.py b/01_Acey_Ducey/python/test_acey_ducey_oo.py new file mode 100644 index 000000000..12b85212e --- /dev/null +++ b/01_Acey_Ducey/python/test_acey_ducey_oo.py @@ -0,0 +1,36 @@ +from acey_ducey_oo import Card, Deck, Game + + +def test_card_init() -> None: + card = Card("\u2665", 2) + assert card.suit == "\u2665" + assert card.rank == 2 + + +def test_card_str() -> None: + card = Card("\u2665", 2) + assert str(card) == "2\u2665" + + +def test_deck_init() -> None: + deck = Deck() + assert len(deck.cards) == 52 + assert deck.cards[0].suit == "\u2665" + assert deck.cards[0].rank == 2 + + +def test_deck_shuffle() -> None: + deck = Deck() + deck.shuffle() + + +def test_deck_deal() -> None: + deck = Deck() + card = deck.deal() + assert card.rank == 14 + assert card.suit == "\u2660" + + +def test_game_init() -> None: + game = Game() + assert len(game.deck.cards) == 50 # two are already dealt diff --git a/01_Acey_Ducey/rust/Cargo.lock b/01_Acey_Ducey/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/01_Acey_Ducey/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/README.md b/02_Amazing/README.md index b8e4b9b41..b53cbbf50 100644 --- a/02_Amazing/README.md +++ b/02_Amazing/README.md @@ -13,10 +13,6 @@ 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. diff --git a/02_Amazing/python/amazing.py b/02_Amazing/python/amazing.py index 22f141c9f..bdffe7e78 100644 --- a/02_Amazing/python/amazing.py +++ b/02_Amazing/python/amazing.py @@ -1,13 +1,17 @@ -import enum import random -from dataclasses import dataclass +import enum from typing import List, Tuple +from dataclasses import dataclass # Python translation by Frank Palazzolo - 2/2021 class Maze: - def __init__(self, width: int, length: int) -> None: + def __init__( + self, + width: int, + length: int, + ): assert width >= 2 and length >= 2 used: List[List[int]] = [] walls: List[List[int]] = [] @@ -47,7 +51,7 @@ def display(self) -> None: print(" ", end="") print() for col in range(self.width): - if self.walls[row][col] in [0, 2]: + if self.walls[row][col] == 0 or self.walls[row][col] == 2: print(":--", end="") else: print(": ", end="") @@ -73,15 +77,18 @@ class Position: def main() -> None: - print_intro() + welcome_header() width, length = get_maze_dimensions() maze = build_maze(width, length) maze.display() -def print_intro() -> None: +def welcome_header() -> None: print(" " * 28 + "AMAZING PROGRAM") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() def build_maze(width: int, length: int) -> Maze: @@ -113,7 +120,7 @@ def build_maze(width: int, length: int) -> Maze: else: while True: if position.col != width - 1: - position.col += 1 + position.col = position.col + 1 elif position.row != length - 1: position.row, position.col = position.row + 1, 0 else: @@ -148,7 +155,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 += 1 + count = count + 1 return pos, count diff --git a/02_Amazing/python/test_amazing.py b/02_Amazing/python/test_amazing.py new file mode 100644 index 000000000..1d01cbd52 --- /dev/null +++ b/02_Amazing/python/test_amazing.py @@ -0,0 +1,58 @@ +import io +import pytest +from _pytest.capture import CaptureFixture +from _pytest.monkeypatch import MonkeyPatch + +from amazing import build_maze, welcome_header, main + + +def test_welcome_header(capsys: CaptureFixture[str]) -> None: + capsys.readouterr() + welcome_header() + out, err = capsys.readouterr() + assert out == ( + " AMAZING PROGRAM\n" + " CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n\n" + ) + assert err == "" + + +@pytest.mark.parametrize( + ("width", "length"), + [ + (1, 1), + (1, 0), + (1, -1), + (1, 2), + (2, 1), + ], +) +def test_build_maze(width: int, length: int) -> None: + with pytest.raises(AssertionError): + build_maze(width, length) + + +@pytest.mark.parametrize( + ("width", "length"), + [ + (3, 3), + (10, 10), + ], +) +def test_main(monkeypatch: MonkeyPatch, width: int, length: int) -> None: + monkeypatch.setattr( + "sys.stdin", + io.StringIO(f"{width},{length}"), + ) + main() + + +def test_main_error(monkeypatch: MonkeyPatch) -> None: + width = 1 + length = 2 + + monkeypatch.setattr( + "sys.stdin", + io.StringIO(f"{width},{length}\n3,3"), + ) + main() diff --git a/02_Amazing/rust/Cargo.lock b/02_Amazing/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/02_Amazing/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/lua/Animal.lua b/03_Animal/lua/Animal.lua deleted file mode 100644 index 293c53e41..000000000 --- a/03_Animal/lua/Animal.lua +++ /dev/null @@ -1,181 +0,0 @@ --- --- 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 diff --git a/03_Animal/python/animal.py b/03_Animal/python/animal.py index 077b93d7f..10e9041fd 100644 --- a/03_Animal/python/animal.py +++ b/03_Animal/python/animal.py @@ -104,18 +104,22 @@ def parse_input(message: str, check_list: bool, root_node: Optional[Node]) -> st list_known_animals(root_node) print("\n") - token = inp[0].lower() if len(inp) > 0 else "" + if len(inp) > 0: + token = inp[0].lower() + else: + token = "" + return token def avoid_void_input(message: str) -> str: answer = "" - while not answer: + while answer == "": answer = input(message) return answer -def print_intro() -> None: +def initial_message() -> None: print(" " * 32 + "Animal") print(" " * 15 + "Creative Computing Morristown, New Jersey\n") print("Play ´Guess the Animal´") @@ -129,13 +133,9 @@ def main() -> None: root = Node("Does it swim?", yes_child, no_child) # Main loop of game - print_intro() - while ( - keep_playing := parse_input( - "Are you thinking of an animal? ", True, root - ) - == "y" - ): + initial_message() + keep_playing = parse_input("Are you thinking of an animal? ", True, root) == "y" + while keep_playing: keep_asking = True # Start traversing the tree by the root actual_node: Node = root @@ -170,13 +170,17 @@ def main() -> None: f"for a {new_animal} the answer would be: ", False, None ) - actual_node.update_node(f"{new_question}?", answer_new_question, new_animal) + actual_node.update_node( + 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/03_Animal/python/test_animal.py b/03_Animal/python/test_animal.py new file mode 100644 index 000000000..74c73143a --- /dev/null +++ b/03_Animal/python/test_animal.py @@ -0,0 +1,5 @@ +from animal import initial_message + + +def test_initial_message() -> None: + initial_message() diff --git a/03_Animal/rust/Cargo.lock b/03_Animal/rust/Cargo.lock deleted file mode 100644 index 9c4ba014c..000000000 --- a/03_Animal/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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/03_Animal/rust/Cargo.toml b/03_Animal/rust/Cargo.toml deleted file mode 100644 index bf553e329..000000000 --- a/03_Animal/rust/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "animal" -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/03_Animal/rust/README.md b/03_Animal/rust/README.md deleted file mode 100644 index 8b8ed57e0..000000000 --- a/03_Animal/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) by [Anton Kaiukov](https://github.com/batk0) diff --git a/03_Animal/rust/src/main.rs b/03_Animal/rust/src/main.rs deleted file mode 100644 index a48c32689..000000000 --- a/03_Animal/rust/src/main.rs +++ /dev/null @@ -1,291 +0,0 @@ -/******************************************************************************* - * Animal - * - * From: Basic computer Games(1978) - * - * Unlike other computer games in which the computer - * picks a number or letter and you must guess what it is, - * in this game you think of an animal and the computer asks - * you questions and tries to guess the name of your animal. - * If the computer guesses incorrectly, it will ask you for a - * question that differentiates the animal it guessed - * from the one you were thinking of. In this way the - * computer "learns" new animals. Questions to differentiate - * new animals should be input without a question mark. - * This version of the game does not have a SAVE feature. - * If your sistem allows, you may modify the program to - * save array A$, then reload the array when you want - * to play the game again. This way you can save what the - * computer learns over a series of games. - * At any time if you reply 'LIST' to the question "ARE YOU - * THINKING OF AN ANIMAL", the computer will tell you all the - * animals it knows so far. - * The program starts originally by knowing only FISH and BIRD. - * As you build up a file of animals you should use broad, - * general questions first and then narrow down to more specific - * ones with later animals. For example, If an elephant was to be - * your first animal, the computer would ask for a question to distinguish - * an elephant from a bird. Naturally there are hundreds of possibilities, - * however, if you plan to build a large file of animals a good question - * would be "IS IT A MAMAL". - * This program can be easily modified to deal with categories of - * things other than animals by simply modifying the initial data - * in Line 530 and the dialogue references to animal in Lines 10, - * 40, 50, 130, 230, 240 and 600. In an educational environment, this - * would be a valuable program to teach the distinguishing chacteristics - * of many classes of objects -- rock formations, geography, marine life, - * cell structures, etc. - * Originally developed by Arthur Luehrmann at Dartmouth College, - * Animal was subsequently shortened and modified by Nathan Teichholtz at - * DEC and Steve North at Creative Computing - ******************************************************************************/ -/******************************************************************************* - * Porting notes: - * - * The data structure used for the game is B-Tree where each leaf is an animal - * and non-leaf node is a question. - * - * B-Tree is implemented in non-traditional way. It uses HashMap for string - * nodes data and use determenistic method to calculate keys for left (yes) and - * right (no) nodes. (See comments in the code.) - * - * The logic of the game mostly kept in `main` function with the use of some - * helper functions. - ******************************************************************************/ -use std::collections::HashMap; -use std::io; - -/// Main function that contains all the logic. -fn main() { - println!("{: ^80}", "Animal"); - println!("{: ^80}\n", "Creative Computing Morristown, New Jersey"); - println!("Play ´Guess the Animal´"); - println!("Think of an animal and the computer will try to guess it.\n"); - - // Initial game data - let mut animal = BTree::new( - "Does it swim".to_string(), - "Fish".to_string(), - "Bird".to_string(), - ); - - // Main game loop - while keep_playing() { - animal.restart(); - // Ask questions until player reaches an animal. - while ! animal.is_leaf() { - println!("{}? ", animal.get()); - if yes_no() { - animal.yes(); - } else { - animal.no(); - } - } - // Ask if this is the animal player is thinking of. - println!("Is it a {}? ", animal.get()); - if ! yes_no() { - // Add a new animal if it's not, and distiguish it from the existing - // one with a question. - println!("The animal you were thinking of was a ? "); - let new_animal = read_input(); - let old_animal = animal.get(); - println!("Please type in a question that would distinguish a {} from a {}: ", - new_animal, old_animal ); - let new_question = read_input(); - println!("for a {} the answer would be: ", new_animal); - if yes_no() { - animal.set(new_question, new_animal, old_animal) - } else { - animal.set(new_question, old_animal, new_animal) - } - } - println!("Why not try another animal?"); - } -} - -/// Reads the input line from [`io::stdin`] and returns it as a [`String`]. -fn read_input() -> String { - let mut input = String::new(); - io::stdin().read_line(&mut input).unwrap(); - input.trim().parse::().unwrap() -} - -/// Asks the player whether the player wants to continue playing. Returns -/// [`true`] if the answer is yes. -fn keep_playing() -> bool { - println!("Are you thinking of an animal? "); - yes_no() -} - -/// Checks whether given answer is `yes` or `no`, returns [`true`] if yes. -fn yes_no() -> bool { - loop { - let answer = read_input().to_lowercase(); - if answer != "y" && answer != "yes" && answer != "n" && answer != "no" { - println!("Please type `yes` or `no`"); - continue; - } - return answer == "y" || answer == "yes"; - } -} - -/// Binary Tree data structure. Implemented the similar way to Max/Min Heap. -struct BTree { - /// contains all nodes data (questions and animals). - nodes: HashMap, - /// contains the key to current node in the game. - cursor: usize, -} - -impl BTree { - /// Creates new [`BTree`] with one root node (question) and two childs - /// (animals). - fn new(value: String, yes: String, no: String) -> BTree { - let nodes: HashMap = HashMap::from([ - (0, value), - (1, yes), - (2, no), - ]); - BTree { nodes: nodes, cursor: 0 } - } - - /// Returns the key for left node (yes) based on the postition of the - /// [`BTree::cursor`]. - fn get_yes_key(&self) -> usize { - &self.cursor * 2 + 1 - } - - /// Returns the key for right node (no) based on the postition of the - /// [`BTree::cursor`]. - fn get_no_key(&self) -> usize { - &self.cursor * 2 + 2 - } - - /// Check if current node is a leaf (has no children). - fn is_leaf(&self) -> bool { - ! ( self.nodes.contains_key(&self.get_yes_key()) || - self.nodes.contains_key(&self.get_no_key()) ) - } - - /// Moves cursor to `yes` (left node) if the node exists. - fn yes(&mut self) { - if self.nodes.contains_key(&self.get_yes_key()) { - self.cursor = self.get_yes_key(); - } - } - - /// Moves cursor to `no` (right node) if the node exists. - fn no(&mut self) { - if self.nodes.contains_key(&self.get_no_key()) { - self.cursor = self.get_no_key(); - } - } - - /// Sets new value (question) and two children (animals) at current position - /// of the [`BTree::cursor`]. - fn set(&mut self, value: String, yes: String, no: String) { - if let Some(v) = self.nodes.get_mut(&self.cursor) { - *v = value; - } - self.nodes.insert(self.get_yes_key(), yes); - self.nodes.insert(self.get_no_key(), no); - } - - /// Returns the value (question or animal) of the current node. - fn get(&self) -> String { - if let Some(t) = self.nodes.get(&self.cursor) { - return t.to_string(); - } - "".to_string() - } - - /// Reset cursor to 0 (root node). - fn restart(&mut self) { - self.cursor = 0; - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_new() { - let got = BTree::new("root".to_string(), "yes".to_string(), "no".to_string()); - let want = BTree{nodes: HashMap::from([ - (0, "root".to_string()), - (1, "yes".to_string()), - (2, "no".to_string()), - ]), cursor: 0}; - assert_eq!(got.nodes, want.nodes); - assert_eq!(got.cursor, want.cursor); - } - - #[test] - fn test_get() { - let got = BTree::new("root".to_string(), "yes".to_string(), "no".to_string()); - let want = "root".to_string(); - assert_eq!(got.get(), want); - } - - #[test] - fn test_set() { - let mut got = BTree::new("root".to_string(), "yes".to_string(), "no".to_string()); - got.set("Root".to_string(), "Yes".to_string(), "No".to_string()); - let want = BTree{nodes: HashMap::from([ - (0, "Root".to_string()), - (1, "Yes".to_string()), - (2, "No".to_string()), - ]), cursor: 0}; - assert_eq!(got.nodes, want.nodes); - assert_eq!(got.cursor, want.cursor); - } - - #[test] - fn test_yes() { - let mut got = BTree::new("root".to_string(), "yes".to_string(), "no".to_string()); - let want = "yes".to_string(); - let want_cursor = 1; - got.yes(); - assert_eq!(got.get(), want); - assert_eq!(got.cursor, want_cursor); - } - - #[test] - fn test_no() { - let mut got = BTree::new("root".to_string(), "yes".to_string(), "no".to_string()); - let want = "no".to_string(); - let want_cursor = 2; - got.no(); - assert_eq!(got.get(), want); - assert_eq!(got.cursor, want_cursor); - } - - #[test] - fn test_is_leaf() { - let mut got = BTree::new("root".to_string(), "yes".to_string(), "no".to_string()); - assert!(!got.is_leaf(), "should not be leaf"); - got.yes(); - assert!(got.is_leaf(), "should be leaf"); - } - - #[test] - fn test_get_key() { - let mut got = BTree::new("root".to_string(), "yes".to_string(), "no".to_string()); - assert_eq!(got.get_yes_key(), 1); - assert_eq!(got.get_no_key(), 2); - got.yes(); - assert_eq!(got.get_yes_key(), 3); - assert_eq!(got.get_no_key(), 4); - } - - #[test] - fn test_restart() { - let mut got = BTree::new("root".to_string(), "yes".to_string(), "no".to_string()); - assert_eq!(got.cursor, 0); - got.yes(); - assert_eq!(got.cursor, 1); - got.restart(); - assert_eq!(got.cursor, 0); - } -} diff --git a/04_Awari/python/awari.py b/04_Awari/python/awari.py index df4906f58..d05cb0ecd 100644 --- a/04_Awari/python/awari.py +++ b/04_Awari/python/awari.py @@ -81,12 +81,21 @@ LOSING_BOOK_SIZE = 50 +def print_with_tab(space_count: int, msg: str) -> None: + if space_count > 0: + spaces = " " * space_count + else: + spaces = "" + print(spaces + msg) + + def draw_pit(line: str, board, pit_index) -> str: val = board[pit_index] - line += " " + line = line + " " if val < 10: - line += " " - return line + str(val) + " " + line = line + " " + line = line + str(val) + " " + return line def draw_board(board) -> None: @@ -147,7 +156,7 @@ def play_game(board: List[int]) -> None: print(msg) break if landing_spot == home: - landing_spot, is_still_going, home, msg = computer_move(f"{msg} , ", board) + landing_spot, is_still_going, home, msg = computer_move(msg + " , ", board) if not is_still_going: print(msg) break @@ -247,7 +256,7 @@ def computer_move(msg: str, board) -> Tuple[int, bool, int, str]: move_str = chr(42 + selected_move) if msg: - msg += f", {move_str}" + msg += ", " + move_str else: msg = move_str @@ -322,7 +331,10 @@ def execute_move(move, home: int, board) -> Tuple[int, bool, int]: # losses. losing_book[game_number] = losing_book[game_number] * 6 + move_digit - is_still_going = bool(player_has_stones(board) and computer_has_stones(board)) + if player_has_stones(board) and computer_has_stones(board): + is_still_going = True + else: + is_still_going = False return last_location, is_still_going, home @@ -350,8 +362,10 @@ def player_move(board) -> Tuple[int, bool, int]: def main() -> None: - print(" " * 34 + "AWARI") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n") + print_with_tab(34, "AWARI") + print_with_tab(15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() board = [0] * 14 # clear the board representation global losing_book diff --git a/04_Awari/python/test_awari.py b/04_Awari/python/test_awari.py new file mode 100644 index 000000000..7ff61b954 --- /dev/null +++ b/04_Awari/python/test_awari.py @@ -0,0 +1,15 @@ +import io +from _pytest.monkeypatch import MonkeyPatch +import pytest + +from awari import print_with_tab, main + + +def test_print_with_tab() -> None: + print_with_tab(3, "Hello") + + +def test_main(monkeypatch: MonkeyPatch) -> None: + monkeypatch.setattr("sys.stdin", io.StringIO("1\n2\n3\n4\n5\n6")) + with pytest.raises(EOFError): + main() diff --git a/04_Awari/rust/Cargo.lock b/04_Awari/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/04_Awari/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/04_Awari/rust/Cargo.toml b/04_Awari/rust/Cargo.toml deleted file mode 100644 index 1c2935d47..000000000 --- a/04_Awari/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" \ No newline at end of file diff --git a/04_Awari/rust/src/main.rs b/04_Awari/rust/src/main.rs deleted file mode 100644 index 7aa008313..000000000 --- a/04_Awari/rust/src/main.rs +++ /dev/null @@ -1,214 +0,0 @@ -use std::{thread, time::Duration}; - -use rand::Rng; - -// AI "learning" is not implemented. Don't have the time. - Ugur - -fn main() { - loop { - let mut game = Game::default(); - - loop { - game.draw(); - if game.play_turn(false) { - break; - } - } - } -} - -enum DistributeResult { - Normal, - // Leftover beans - EndOnHomePit(bool), - // "true" if ended on Player Home Pit - EndOnEmptyPit(usize), - // "index" of the empty pit within the Row - ChosenEmpty, -} - -struct Game { - pits: [u8; 14], - player_turn: bool, -} - -impl Default for Game { - fn default() -> Self { - println!("\n\n\t\t AWARI"); - println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); - - Self { - pits: [3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 0], - player_turn: true, - } - } -} - -impl Game { - fn step_through(&mut self, mut index: usize) -> usize { - let mut bean_amount = self.pits[index]; - self.pits[index] = 0; - - loop { - index += 1; - - if index > self.pits.len() - 1 { - index = 0; - } - - self.pits[index] += 1; - - bean_amount -= 1; - if bean_amount == 0 { - return index; - } - } - } - - fn play_turn(&mut self, is_repeat: bool) -> bool { - use DistributeResult::*; - - if self.is_game_over() { - println!("\nGame Over!"); - let (player_beans, ai_beans) = (self.pits[6], self.pits[13]); - if player_beans == ai_beans { - println!("It's a draw") - } else if player_beans > ai_beans { - println!("You win by {}", player_beans - ai_beans); - } else { - println!("I win by {}", ai_beans - player_beans); - } - return true; - } - - let chosen_index = if self.player_turn { - player_prompt(if is_repeat { "Again?" } else { "Your move?" }) - 1 - } else { - println!("========================"); - - thread::sleep(Duration::from_secs(1)); - - let non_empty_pits: Vec = self - .pits - .iter() - .enumerate() - .filter(|&(i, p)| (7..13).contains(&i) && *p > 0) - .map(|(i, _)| i) - .collect(); - let random_index = rand::thread_rng().gen_range(0..non_empty_pits.len()); - let ai_move = non_empty_pits[random_index]; - - println!("My move is {}", ai_move - 6); - - println!("========================"); - ai_move - }; - - match self.process_choice(chosen_index) { - Normal => (), - EndOnHomePit(player) => { - self.draw(); - - if player == self.player_turn && !is_repeat { - self.play_turn(true); - } - } - EndOnEmptyPit(last_index) => { - let opposite_index = 12 - last_index; - let home_index = if self.player_turn { 6 } else { 13 }; - let won_beans = 1 + self.pits[opposite_index]; - - self.pits[last_index] = 0; - self.pits[opposite_index] = 0; - self.pits[home_index] += won_beans; - } - ChosenEmpty => { - println!("Chosen pit is empty"); - return self.play_turn(is_repeat); - } - } - - if !is_repeat { - self.player_turn = !self.player_turn; - } - - false - } - - pub fn process_choice(&mut self, index: usize) -> DistributeResult { - use DistributeResult::*; - - if self.pits[index] == 0 { - return ChosenEmpty; - } - - let last_index = self.step_through(index); - - if last_index == 6 && self.player_turn { - return EndOnHomePit(true); - } else if last_index == 13 && !self.player_turn { - return EndOnHomePit(false); - } else if self.pits[last_index] == 1 { - return EndOnEmptyPit(last_index); - } - - Normal - } - - fn is_game_over(&self) -> bool { - let player_empty = !(0..6).any(|i| self.pits[i] > 0); - let ai_empty = !(7..13).any(|i| self.pits[i] > 0); - player_empty || ai_empty - } - - fn draw(&self) { - let row_as_string = |player: bool| -> String { - let mut row_as_string = String::new(); - - let range = if player { 0..6 } else { 7..13 }; - - range.for_each(|i| { - let mut bean_amount_as_string = self.pits[i].to_string(); - bean_amount_as_string.push_str(" "); - - if player { - row_as_string.push_str(&bean_amount_as_string); - } else { - row_as_string.insert_str(0, &bean_amount_as_string); - } - }); - - row_as_string - }; - - println!( - "\n {}\n{} {}\n {}\n", - row_as_string(false), - self.pits[13].to_string(), - self.pits[6].to_string(), - row_as_string(true) - ); - } -} - -pub fn player_prompt(message: &str) -> usize { - loop { - let mut input = String::new(); - println!("{}", message); - - if let Ok(_) = std::io::stdin().read_line(&mut input) { - match input.trim().parse::() { - Ok(n) => { - if (1..=6).contains(&n) { - return n; - } else { - println!("Enter a number between 1 and 6") - } - } - Err(e) => { - println!("{}", e); - } - } - } - } -} diff --git a/05_Bagels/javascript/bagels.js b/05_Bagels/javascript/bagels.js index c0d519e2b..5a62a751a 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("OK. I HAVE A NUMBER IN MIND.\n"); + print("O.K. 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 YOUR TWENTIETH GUESS. MY NUMBER WAS " + a[1] + a[2] + a[3]); + print("THAT'S A TWENTY GUESS. MY NUMBER WAS " + a[1] + a[2] + a[3]); } y++; print("PLAY AGAIN (YES OR NO)"); diff --git a/05_Bagels/lua/Bagels.lua b/05_Bagels/lua/Bagels.lua deleted file mode 100644 index 57c352977..000000000 --- a/05_Bagels/lua/Bagels.lua +++ /dev/null @@ -1,121 +0,0 @@ ---- ---- Bagels ---- Ported by Joe Nellis. ---- Text displayed is altered slightly from the original program to allow for ---- more (or less) than three digits to be guessed. Change the difficulty to ---- the number of digits you wish in the secret code. ---- - ---- difficult is number of digits to use -local difficulty = 3 - -print [[ - BAGELS - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - -]] - -function getInput(prompt) - io.write(prompt) - io.flush() - local input = io.read("l") - if not input then --- test for EOF - print("GOODBYE") - os.exit(0) - end - return input -end - -local needsRules = getInput("WOULD YOU LIKE THE RULES? (YES OR NO) ") -print() -if needsRules:match("[yY].*") then - print(string.format( [[ -I AM THINKING OF A %u DIGIT NUMBER. TRY TO GUESS -MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS: - PICO - ONE DIGIT CORRECT BUT IN THE WRONG POSITION - FERMI - ONE DIGIT CORRECT AND IN THE RIGHT POSITION - BAGELS - NO DIGITS - ]], difficulty)) -end - -function play(numDigits, score) - local digits = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" } - --- secret number must not have duplicate digits - --- randomly swap numDigits at the head of this list to create secret number - for i = 1, numDigits do - local j = math.random(1, 10) - digits[i], digits[j] = digits[j], digits[i] - end - - print "O.K. I HAVE A NUMBER IN MIND." - for guessNum = 1, 20 do - :: GUESS_AGAIN :: --- 0) then - print("A", score, "POINT BAGELS BUFF!!") - end - print "HOPE YOU HAD FUN. BYE." - end -end - -play(difficulty, 0) --- default is numDigits=3, score=0 - diff --git a/05_Bagels/python/bagels.py b/05_Bagels/python/bagels.py index e0662d18c..77e8b4739 100644 --- a/05_Bagels/python/bagels.py +++ b/05_Bagels/python/bagels.py @@ -49,8 +49,9 @@ def pick_number() -> List[str]: # as separate strings, not a single integer or string numbers = list(range(10)) random.shuffle(numbers) - num = numbers[:3] - return [str(i) for i in num] + num = numbers[0:3] + num_str = [str(i) for i in num] + return num_str def get_valid_guess(guesses: int) -> str: @@ -105,7 +106,8 @@ def build_result_string(num: List[str], guess: str) -> str: def main() -> None: # Intro text print("\n Bagels") - print("Creative Computing Morristown, New Jersey\n\n") + print("Creative Computing Morristown, New Jersey") + print("\n\n") # Anything other than N* will show the rules response = input("Would you like the rules (Yes or No)? ") diff --git a/05_Bagels/python/test_bagels.py b/05_Bagels/python/test_bagels.py new file mode 100644 index 000000000..060715451 --- /dev/null +++ b/05_Bagels/python/test_bagels.py @@ -0,0 +1,35 @@ +import io +from _pytest.capture import CaptureFixture +from _pytest.monkeypatch import MonkeyPatch + +from bagels import build_result_string, main, pick_number + + +def test_build_result_string() -> None: + build_result_string(["a", "b", "c"], "abc") + + +def test_pick_number() -> None: + picked = pick_number() + assert len(picked) == 3 + for el in picked: + assert el in "0123456789" + + +def test_main(monkeypatch: MonkeyPatch, capsys: CaptureFixture) -> None: + # Succeed + round_1 = "Y\n4444\nabc\n444\n456\n145\n321\n123" + + # Fail after 20 guesses + round_2 = ( + "666\n132\n321\n312\n132\n213\n678\n678\n678\n678\n678\n" + "678\n678\n678\n678\n678\n678\n678\n678\n678\n678\nNo" + ) + monkeypatch.setattr("sys.stdin", io.StringIO(f"{round_1}\nYES\n{round_2}")) + monkeypatch.setattr("bagels.pick_number", lambda: ["1", "2", "3"]) + main() + captured = capsys.readouterr() + assert "Would you like the rules" in captured.out + assert "I have a number in mind" in captured.out + assert "My number was" in captured.out + assert "Hope you had fun." in captured.out diff --git a/05_Bagels/rust/Cargo.lock b/05_Bagels/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/05_Bagels/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/06_Banner/README.md b/06_Banner/README.md index f01b876d1..3acbf7fc7 100644 --- a/06_Banner/README.md +++ b/06_Banner/README.md @@ -15,9 +15,5 @@ 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) diff --git a/06_Banner/perl/banner.pl b/06_Banner/perl/banner.pl deleted file mode 100644 index 2524ef00c..000000000 --- a/06_Banner/perl/banner.pl +++ /dev/null @@ -1,150 +0,0 @@ -#!/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); diff --git a/06_Banner/python/banner.py b/06_Banner/python/banner.py index d42a7763d..6e563e46e 100644 --- a/06_Banner/python/banner.py +++ b/06_Banner/python/banner.py @@ -74,7 +74,9 @@ def print_banner() -> None: except ValueError: print("Please enter a number greater than zero") - g1 = 1 if input("Centered ").lower().startswith("y") else 0 + g1 = 0 + if input("Centered ").lower().startswith("y"): + g1 = 1 character = input( "Character (type 'ALL' if you want character being printed) " ).upper() @@ -84,10 +86,10 @@ def print_banner() -> None: for statement_char in statement: s = letters[statement_char].copy() - x_str = character - if x_str == "ALL": - x_str = statement_char - if x_str == " ": + xStr = character + if character == "ALL": + xStr = statement_char + if xStr == " ": print("\n" * (7 * horizontal)) else: for u in range(0, 7): @@ -101,13 +103,13 @@ def print_banner() -> None: f[u] = 8 - k break for _t1 in range(1, horizontal + 1): - line_str = " " * int((63 - 4.5 * vertical) * g1 / len(x_str) + 1) + line_str = " " * int((63 - 4.5 * vertical) * g1 / len(xStr) + 1) for b in range(0, f[u] + 1): if j[b] == 0: for _ in range(1, vertical + 1): - line_str = line_str + " " * len(x_str) + line_str = line_str + " " * len(xStr) else: - line_str = line_str + x_str * vertical + line_str = line_str + xStr * vertical print(line_str) print("\n" * (2 * horizontal - 1)) # print("\n" * 75) # Feed some more paper from the printer diff --git a/06_Banner/python/test_banner.py b/06_Banner/python/test_banner.py new file mode 100644 index 000000000..cd5d45ffa --- /dev/null +++ b/06_Banner/python/test_banner.py @@ -0,0 +1,109 @@ +import io +from _pytest.monkeypatch import MonkeyPatch +from _pytest.capture import CaptureFixture +from banner import print_banner + + +def test_print_banner(monkeypatch: MonkeyPatch) -> None: + horizontal = "1" + vertical = "1" + centered = "1" + char = "*" + statement = "O" # only capital letters + set_page = "2" + monkeypatch.setattr( + "sys.stdin", + io.StringIO( + f"{horizontal}\n{vertical}\n{centered}\n{char}\n{statement}\n{set_page}" + ), + ) + print_banner() + + +def test_print_banner_horizontal_0( + monkeypatch: MonkeyPatch, capsys: CaptureFixture +) -> None: + horizontal = "1" + vertical = "1" + centered = "1" + char = "*" + statement = "O" # only capital letters + set_page = "2" + monkeypatch.setattr( + "sys.stdin", + io.StringIO( + f"0\n{horizontal}\n{vertical}\n{centered}\n{char}\n{statement}\n{set_page}" + ), + ) + print_banner() + captured = capsys.readouterr() + assert "Please enter a number greater than zero" in captured.out + + +def test_print_banner_vertical_0( + monkeypatch: MonkeyPatch, capsys: CaptureFixture +) -> None: + horizontal = "1" + vertical = "1" + centered = "1" + char = "*" + statement = "O" # only capital letters + set_page = "2" + monkeypatch.setattr( + "sys.stdin", + io.StringIO( + f"{horizontal}\n0\n{vertical}\n{centered}\n{char}\n{statement}\n{set_page}" + ), + ) + print_banner() + captured = capsys.readouterr() + assert "Please enter a number greater than zero" in captured.out + + +def test_print_banner_centered( + monkeypatch: MonkeyPatch, capsys: CaptureFixture +) -> None: + horizontal = "1" + vertical = "1" + centered = "Y" + char = "*" + statement = "O" # only capital letters + set_page = "2" + monkeypatch.setattr( + "sys.stdin", + io.StringIO( + f"{horizontal}\n{vertical}\n{centered}\n{char}\n{statement}\n{set_page}" + ), + ) + print_banner() + captured = capsys.readouterr() + expected = ( + "Horizontal Vertical Centered Character " + "(type 'ALL' if you want character being printed) Statement Set page " + " *****\n" + " * *\n" + " * *\n" + " * *\n" + " * *\n" + " * *\n" + " *****\n\n\n" + ) + assert captured.out.split("\n") == expected.split("\n") + + +def test_print_banner_all_statement( + monkeypatch: MonkeyPatch, capsys: CaptureFixture +) -> None: + horizontal = "1" + vertical = "1" + centered = "1" + char = "UNIT TESTING" + statement = "ALL" # only capital letters + set_page = "2" + monkeypatch.setattr( + "sys.stdin", + io.StringIO( + f"{horizontal}\n{vertical}\n{centered}\n{char}\n{statement}\n{set_page}" + ), + ) + print_banner() diff --git a/07_Basketball/README.md b/07_Basketball/README.md index ac0662ddf..5200748d1 100644 --- a/07_Basketball/README.md +++ b/07_Basketball/README.md @@ -14,7 +14,7 @@ Both teams use the same defense, but you may call it: - Enter (7): Zone - Enter (7.5): None -To change defense, type "0" as your next shot. +To change defense, type “0” as your next shot. Note: The game is biased slightly in favor of Dartmouth. The average probability of a Dartmouth shot being good is 62.95% compared to a probability of 61.85% for their opponent. (This makes the sample run slightly remarkable in that Cornell won by a score of 45 to 42 Hooray for the Big Red!) @@ -33,19 +33,3 @@ http://www.vintage-basic.net/games.html (please note any difficulties or challenges in porting here) -##### Original bugs - -###### Initial defense selection - -If a number <6 is entered for the starting defense then the original code prompts again until a value >=6 is entered, -but then skips the opponent selection center jump. - -The C# port does not reproduce this behavior. It does prompt for a correct value, but will then go to opponent selection -followed by the center jump. - -###### Unvalidated defense selection - -The original code does not validate the value entered for the defense beyond checking that it is >=6. A large enough -defense value will guarantee that all shots are good, and the game gets rather predictable. - -This bug is preserved in the C# port. diff --git a/07_Basketball/csharp/Basketball.csproj b/07_Basketball/csharp/Basketball.csproj index 91e759c0c..d3fe4757c 100644 --- a/07_Basketball/csharp/Basketball.csproj +++ b/07_Basketball/csharp/Basketball.csproj @@ -6,13 +6,4 @@ enable enable - - - - - - - - - diff --git a/07_Basketball/csharp/Clock.cs b/07_Basketball/csharp/Clock.cs deleted file mode 100644 index 250330523..000000000 --- a/07_Basketball/csharp/Clock.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Basketball.Resources; -using Games.Common.IO; - -namespace Basketball; - -internal class Clock -{ - private readonly IReadWrite _io; - private int time; - - public Clock(IReadWrite io) => _io = io; - - public bool IsHalfTime => time == 50; - public bool IsFullTime => time >= 100; - public bool TwoMinutesLeft => time == 92; - - public void Increment(Scoreboard scoreboard) - { - time += 1; - if (IsHalfTime) { scoreboard.Display(Resource.Formats.EndOfFirstHalf); } - if (TwoMinutesLeft) { _io.Write(Resource.Streams.TwoMinutesLeft); } - } - - public void StartOvertime() => time = 93; -} \ No newline at end of file diff --git a/07_Basketball/csharp/Defense.cs b/07_Basketball/csharp/Defense.cs deleted file mode 100644 index f447266fb..000000000 --- a/07_Basketball/csharp/Defense.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Basketball; - -internal class Defense -{ - private float _value; - - public Defense(float value) => Set(value); - - public void Set(float value) => _value = value; - - public static implicit operator float(Defense defense) => defense._value; -} diff --git a/07_Basketball/csharp/Game.cs b/07_Basketball/csharp/Game.cs deleted file mode 100644 index 5a7d6ffad..000000000 --- a/07_Basketball/csharp/Game.cs +++ /dev/null @@ -1,73 +0,0 @@ -using Basketball.Plays; -using Basketball.Resources; -using Games.Common.IO; -using Games.Common.Randomness; - -namespace Basketball; - -internal class Game -{ - private readonly Clock _clock; - private readonly Scoreboard _scoreboard; - private readonly TextIO _io; - private readonly IRandom _random; - - private Game(Clock clock, Scoreboard scoreboard, TextIO io, IRandom random) - { - _clock = clock; - _scoreboard = scoreboard; - _io = io; - _random = random; - } - - public static Game Create(TextIO io, IRandom random) - { - io.Write(Resource.Streams.Introduction); - - var defense = new Defense(io.ReadDefense("Your starting defense will be")); - var clock = new Clock(io); - - io.WriteLine(); - - var scoreboard = new Scoreboard( - new Team("Dartmouth", new HomeTeamPlay(io, random, clock, defense)), - new Team(io.ReadString("Choose your opponent"), new VisitingTeamPlay(io, random, clock, defense)), - io); - - return new Game(clock, scoreboard, io, random); - } - - public void Play() - { - var ballContest = new BallContest(0.4f, "{0} controls the tap", _io, _random); - - while (true) - { - _io.WriteLine("Center jump"); - ballContest.Resolve(_scoreboard); - - _io.WriteLine(); - - while (true) - { - var isFullTime = _scoreboard.Offense.ResolvePlay(_scoreboard); - if (isFullTime && IsGameOver()) { return; } - if (_clock.IsHalfTime) { break; } - } - } - } - - private bool IsGameOver() - { - _io.WriteLine(); - if (_scoreboard.ScoresAreEqual) - { - _scoreboard.Display(Resource.Formats.EndOfSecondHalf); - _clock.StartOvertime(); - return false; - } - - _scoreboard.Display(Resource.Formats.EndOfGame); - return true; - } -} diff --git a/07_Basketball/csharp/IRandomExtensions.cs b/07_Basketball/csharp/IRandomExtensions.cs deleted file mode 100644 index 876e05a20..000000000 --- a/07_Basketball/csharp/IRandomExtensions.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Games.Common.Randomness; - -namespace Basketball; - -internal static class IRandomExtensions -{ - internal static Shot NextShot(this IRandom random) => Shot.Get(random.NextFloat(1, 3.5f)); -} diff --git a/07_Basketball/csharp/IReadWriteExtensions.cs b/07_Basketball/csharp/IReadWriteExtensions.cs deleted file mode 100644 index 6197ff977..000000000 --- a/07_Basketball/csharp/IReadWriteExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Games.Common.IO; - -namespace Basketball; - -internal static class IReadWriteExtensions -{ - public static float ReadDefense(this IReadWrite io, string prompt) - { - while (true) - { - var defense = io.ReadNumber(prompt); - if (defense >= 6) { return defense; } - } - } - - private static bool TryReadInteger(this IReadWrite io, string prompt, out int intValue) - { - var floatValue = io.ReadNumber(prompt); - intValue = (int)floatValue; - return intValue == floatValue; - } - - public static Shot? ReadShot(this IReadWrite io, string prompt) - { - while (true) - { - if (io.TryReadInteger(prompt, out var value) && Shot.TryGet(value, out var shot)) - { - return shot; - } - io.Write("Incorrect answer. Retype it. "); - } - } -} diff --git a/07_Basketball/csharp/JumpShot.cs b/07_Basketball/csharp/JumpShot.cs deleted file mode 100644 index 46ffc6d89..000000000 --- a/07_Basketball/csharp/JumpShot.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Basketball; - -public class JumpShot : Shot -{ - public JumpShot() - : base("Jump shot") - { - } -} \ No newline at end of file diff --git a/07_Basketball/csharp/Plays/BallContest.cs b/07_Basketball/csharp/Plays/BallContest.cs deleted file mode 100644 index a12ddc36b..000000000 --- a/07_Basketball/csharp/Plays/BallContest.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Games.Common.IO; -using Games.Common.Randomness; - -namespace Basketball.Plays; - -internal class BallContest -{ - private readonly float _probability; - private readonly string _messageFormat; - private readonly IReadWrite _io; - private readonly IRandom _random; - - internal BallContest(float probability, string messageFormat, IReadWrite io, IRandom random) - { - _io = io; - _probability = probability; - _messageFormat = messageFormat; - _random = random; - } - - internal bool Resolve(Scoreboard scoreboard) - { - var winner = _random.NextFloat() <= _probability ? scoreboard.Home : scoreboard.Visitors; - scoreboard.Offense = winner; - _io.WriteLine(_messageFormat, winner); - return false; - } -} diff --git a/07_Basketball/csharp/Plays/HomeTeamPlay.cs b/07_Basketball/csharp/Plays/HomeTeamPlay.cs deleted file mode 100644 index 48ef249e5..000000000 --- a/07_Basketball/csharp/Plays/HomeTeamPlay.cs +++ /dev/null @@ -1,93 +0,0 @@ -using Games.Common.IO; -using Games.Common.Randomness; - -namespace Basketball.Plays; - -internal class HomeTeamPlay : Play -{ - private readonly TextIO _io; - private readonly IRandom _random; - private readonly Clock _clock; - private readonly Defense _defense; - private readonly BallContest _ballContest; - - public HomeTeamPlay(TextIO io, IRandom random, Clock clock, Defense defense) - : base(io, random, clock) - { - _io = io; - _random = random; - _clock = clock; - _defense = defense; - _ballContest = new BallContest(0.5f, "Shot is blocked. Ball controlled by {0}.", _io, _random); - } - - internal override bool Resolve(Scoreboard scoreboard) - { - var shot = _io.ReadShot("Your shot"); - - if (_random.NextFloat() >= 0.5f && _clock.IsFullTime) { return true; } - - if (shot is null) - { - _defense.Set(_io.ReadDefense("Your new defensive alignment is")); - _io.WriteLine(); - return false; - } - - if (shot is JumpShot jumpShot) - { - if (ClockIncrementsToHalfTime(scoreboard)) { return false; } - if (!Resolve(jumpShot, scoreboard)) { return false; } - } - - do - { - if (ClockIncrementsToHalfTime(scoreboard)) { return false; } - } while (Resolve(shot, scoreboard)); - - return false; - } - - // The Resolve* methods resolve the probabilistic outcome of the current game state. - // They return true if the Home team should continue the play and attempt a layup, false otherwise. - private bool Resolve(JumpShot shot, Scoreboard scoreboard) => - Resolve(shot.ToString(), _defense / 8) - .Do(0.341f, () => scoreboard.AddBasket("Shot is good")) - .Or(0.682f, () => ResolveShotOffTarget(scoreboard)) - .Or(0.782f, () => _ballContest.Resolve(scoreboard)) - .Or(0.843f, () => ResolveFreeThrows(scoreboard, "Shooter is fouled. Two shots.")) - .Or(() => scoreboard.Turnover($"Charging foul. {scoreboard.Home} loses ball.")); - - private bool Resolve(Shot shot, Scoreboard scoreboard) => - Resolve(shot.ToString(), _defense / 7) - .Do(0.4f, () => scoreboard.AddBasket("Shot is good. Two points.")) - .Or(0.7f, () => ResolveShotOffTheRim(scoreboard)) - .Or(0.875f, () => ResolveFreeThrows(scoreboard, "Shooter fouled. Two shots.")) - .Or(0.925f, () => scoreboard.Turnover($"Shot blocked. {scoreboard.Visitors}'s ball.")) - .Or(() => scoreboard.Turnover($"Charging foul. {scoreboard.Home} loses ball.")); - - private bool ResolveShotOffTarget(Scoreboard scoreboard) => - Resolve("Shot is off target", 6 / _defense) - .Do(0.45f, () => ResolveHomeRebound(scoreboard, ResolvePossibleSteal)) - .Or(() => scoreboard.Turnover($"Rebound to {scoreboard.Visitors}")); - - private bool ResolveHomeRebound(Scoreboard scoreboard, Action endOfPlayAction) => - Resolve($"{scoreboard.Home} controls the rebound.") - .Do(0.4f, () => true) - .Or(() => endOfPlayAction.Invoke(scoreboard)); - private void ResolvePossibleSteal(Scoreboard scoreboard) - { - if (_defense == 6 && _random.NextFloat() > 0.6f) - { - scoreboard.Turnover(); - scoreboard.AddBasket($"Pass stolen by {scoreboard.Visitors} easy layup."); - _io.WriteLine(); - } - _io.Write("Ball passed back to you. "); - } - - private void ResolveShotOffTheRim(Scoreboard scoreboard) => - Resolve("Shot is off the rim.") - .Do(2 / 3f, () => scoreboard.Turnover($"{scoreboard.Visitors} controls the rebound.")) - .Or(() => ResolveHomeRebound(scoreboard, _ => _io.WriteLine("Ball passed back to you."))); -} diff --git a/07_Basketball/csharp/Plays/Play.cs b/07_Basketball/csharp/Plays/Play.cs deleted file mode 100644 index 9b82a74ea..000000000 --- a/07_Basketball/csharp/Plays/Play.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Games.Common.IO; -using Games.Common.Randomness; - -namespace Basketball.Plays; - -internal abstract class Play -{ - private readonly IReadWrite _io; - private readonly IRandom _random; - private readonly Clock _clock; - - public Play(IReadWrite io, IRandom random, Clock clock) - { - _io = io; - _random = random; - _clock = clock; - } - - protected bool ClockIncrementsToHalfTime(Scoreboard scoreboard) - { - _clock.Increment(scoreboard); - return _clock.IsHalfTime; - } - - internal abstract bool Resolve(Scoreboard scoreboard); - - protected void ResolveFreeThrows(Scoreboard scoreboard, string message) => - Resolve(message) - .Do(0.49f, () => scoreboard.AddFreeThrows(2, "Shooter makes both shots.")) - .Or(0.75f, () => scoreboard.AddFreeThrows(1, "Shooter makes one shot and misses one.")) - .Or(() => scoreboard.AddFreeThrows(0, "Both shots missed.")); - - protected Probably Resolve(string message) => Resolve(message, 1f); - - protected Probably Resolve(string message, float defenseFactor) - { - _io.WriteLine(message); - return new Probably(defenseFactor, _random); - } -} diff --git a/07_Basketball/csharp/Plays/VisitingTeamPlay.cs b/07_Basketball/csharp/Plays/VisitingTeamPlay.cs deleted file mode 100644 index 3975a6ba7..000000000 --- a/07_Basketball/csharp/Plays/VisitingTeamPlay.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Games.Common.IO; -using Games.Common.Randomness; - -namespace Basketball.Plays; - -internal class VisitingTeamPlay : Play -{ - private readonly TextIO _io; - private readonly IRandom _random; - private readonly Defense _defense; - - public VisitingTeamPlay(TextIO io, IRandom random, Clock clock, Defense defense) - : base(io, random, clock) - { - _io = io; - _random = random; - _defense = defense; - } - - internal override bool Resolve(Scoreboard scoreboard) - { - if (ClockIncrementsToHalfTime(scoreboard)) { return false; } - - _io.WriteLine(); - var shot = _random.NextShot(); - - if (shot is JumpShot jumpShot) - { - var continuePlay = Resolve(jumpShot, scoreboard); - _io.WriteLine(); - if (!continuePlay) { return false; } - } - - while (true) - { - var continuePlay = Resolve(shot, scoreboard); - _io.WriteLine(); - if (!continuePlay) { return false; } - } - } - - // The Resolve* methods resolve the probabilistic outcome of the current game state. - // They return true if the Visiting team should continue the play and attempt a layup, false otherwise. - private bool Resolve(JumpShot shot, Scoreboard scoreboard) => - Resolve(shot.ToString(), _defense / 8) - .Do(0.35f, () => scoreboard.AddBasket("Shot is good.")) - .Or(0.75f, () => ResolveBadShot(scoreboard, "Shot is off the rim.", _defense * 6)) - .Or(0.9f, () => ResolveFreeThrows(scoreboard, "Player fouled. Two shots.")) - .Or(() => _io.WriteLine($"Offensive foul. {scoreboard.Home}'s ball.")); - - private bool Resolve(Shot shot, Scoreboard scoreboard) => - Resolve(shot.ToString(), _defense / 7) - .Do(0.413f, () => scoreboard.AddBasket("Shot is good.")) - .Or(() => ResolveBadShot(scoreboard, "Shot is missed.", 6 / _defense)); - - private bool ResolveBadShot(Scoreboard scoreboard, string message, float defenseFactor) => - Resolve(message, defenseFactor) - .Do(0.5f, () => scoreboard.Turnover($"{scoreboard.Home} controls the rebound.")) - .Or(() => ResolveVisitorsRebound(scoreboard)); - - private bool ResolveVisitorsRebound(Scoreboard scoreboard) - { - _io.Write($"{scoreboard.Visitors} controls the rebound."); - if (_defense == 6 && _random.NextFloat() <= 0.25f) - { - _io.WriteLine(); - scoreboard.Turnover(); - scoreboard.AddBasket($"Ball stolen. Easy lay up for {scoreboard.Home}."); - return false; - } - - if (_random.NextFloat() <= 0.5f) - { - _io.WriteLine(); - _io.Write($"Pass back to {scoreboard.Visitors} guard."); - return false; - } - - return true; - } -} diff --git a/07_Basketball/csharp/Probably.cs b/07_Basketball/csharp/Probably.cs deleted file mode 100644 index 0ba5864a0..000000000 --- a/07_Basketball/csharp/Probably.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Games.Common.Randomness; - -namespace Basketball; - -/// -/// Supports a chain of actions to be performed based on various probabilities. The original game code gets a new -/// random number for each probability check. Evaluating a set of probabilities against a single random number is -/// much simpler, but yield a very different outcome distribution. The purpose of this class is to simplify the code -/// to for the original probabilistic branch decisions. -/// -internal struct Probably -{ - private readonly float _defenseFactor; - private readonly IRandom _random; - private readonly bool? _result; - - internal Probably(float defenseFactor, IRandom random, bool? result = null) - { - _defenseFactor = defenseFactor; - _random = random; - _result = result; - } - - public Probably Do(float probability, Action action) => - ShouldResolveAction(probability) - ? new Probably(_defenseFactor, _random, Resolve(action) ?? false) - : this; - - public Probably Do(float probability, Func action) => - ShouldResolveAction(probability) - ? new Probably(_defenseFactor, _random, Resolve(action) ?? false) - : this; - - public Probably Or(float probability, Action action) => Do(probability, action); - - public Probably Or(float probability, Func action) => Do(probability, action); - - public bool Or(Action action) => _result ?? Resolve(action) ?? false; - - private bool? Resolve(Action action) - { - action.Invoke(); - return _result; - } - - private bool? Resolve(Func action) => action.Invoke(); - - private readonly bool ShouldResolveAction(float probability) => - _result is null && _random.NextFloat() <= probability * _defenseFactor; -} diff --git a/07_Basketball/csharp/Program.cs b/07_Basketball/csharp/Program.cs deleted file mode 100644 index 7a6103368..000000000 --- a/07_Basketball/csharp/Program.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Basketball; -using Games.Common.IO; -using Games.Common.Randomness; - -var game = Game.Create(new ConsoleIO(), new RandomNumberGenerator()); - -game.Play(); \ No newline at end of file diff --git a/07_Basketball/csharp/Resources/EndOfFirstHalf.txt b/07_Basketball/csharp/Resources/EndOfFirstHalf.txt deleted file mode 100644 index 6a132a0ec..000000000 --- a/07_Basketball/csharp/Resources/EndOfFirstHalf.txt +++ /dev/null @@ -1,5 +0,0 @@ - - ***** End of first half ***** - -Score: {0}: {1} {2}: {3} - diff --git a/07_Basketball/csharp/Resources/EndOfGame.txt b/07_Basketball/csharp/Resources/EndOfGame.txt deleted file mode 100644 index fc65416c4..000000000 --- a/07_Basketball/csharp/Resources/EndOfGame.txt +++ /dev/null @@ -1,2 +0,0 @@ - ***** End of game ***** -Final score: {0}: {1} {2}: {3} \ No newline at end of file diff --git a/07_Basketball/csharp/Resources/EndOfSecondHalf.txt b/07_Basketball/csharp/Resources/EndOfSecondHalf.txt deleted file mode 100644 index c5f73218a..000000000 --- a/07_Basketball/csharp/Resources/EndOfSecondHalf.txt +++ /dev/null @@ -1,7 +0,0 @@ - - ***** End of second half ***** - -Score at end of regulation time: - {0}: {1} {2}: {3} - -Begin two minute overtime period \ No newline at end of file diff --git a/07_Basketball/csharp/Resources/Introduction.txt b/07_Basketball/csharp/Resources/Introduction.txt deleted file mode 100644 index b5ad510b6..000000000 --- a/07_Basketball/csharp/Resources/Introduction.txt +++ /dev/null @@ -1,12 +0,0 @@ - Basketball - Creative Computing Morristown, New Jersey - - - -This is Dartmouth College basketball. You will be Dartmouth - captain and playmaker. Call shots as follows: 1. Long - (30 ft.) jump shot; 2. Short (15 ft.) jump shot; 3. Lay - up; 4. Set shot. -Both teams will use the same defense. Call defense as -follows: 6. Press; 6.5 Man-to-man; 7. Zone; 7.5 None. -To change defense, just type 0 as your next shot. \ No newline at end of file diff --git a/07_Basketball/csharp/Resources/Resource.cs b/07_Basketball/csharp/Resources/Resource.cs deleted file mode 100644 index c442a3ff1..000000000 --- a/07_Basketball/csharp/Resources/Resource.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Basketball.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Introduction => GetStream(); - public static Stream TwoMinutesLeft => GetStream(); - } - - internal static class Formats - { - public static string EndOfFirstHalf => GetString(); - public static string EndOfGame => GetString(); - public static string EndOfSecondHalf => GetString(); - public static string Score => GetString(); - } - - 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($"Basketball.Resources.{name}.txt") - ?? throw new Exception($"Could not find embedded resource stream '{name}'."); -} \ No newline at end of file diff --git a/07_Basketball/csharp/Resources/Score.txt b/07_Basketball/csharp/Resources/Score.txt deleted file mode 100644 index 7b317cb39..000000000 --- a/07_Basketball/csharp/Resources/Score.txt +++ /dev/null @@ -1 +0,0 @@ -Score: {1} to {3} \ No newline at end of file diff --git a/07_Basketball/csharp/Resources/TwoMinutesLeft.txt b/07_Basketball/csharp/Resources/TwoMinutesLeft.txt deleted file mode 100644 index 0ad169930..000000000 --- a/07_Basketball/csharp/Resources/TwoMinutesLeft.txt +++ /dev/null @@ -1,3 +0,0 @@ - - *** Two minutes left in the game *** - diff --git a/07_Basketball/csharp/Scoreboard.cs b/07_Basketball/csharp/Scoreboard.cs deleted file mode 100644 index 79068392f..000000000 --- a/07_Basketball/csharp/Scoreboard.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Basketball.Resources; -using Games.Common.IO; - -namespace Basketball; - -internal class Scoreboard -{ - private readonly Dictionary _scores; - private readonly IReadWrite _io; - - public Scoreboard(Team home, Team visitors, IReadWrite io) - { - _scores = new() { [home] = 0, [visitors] = 0 }; - Home = home; - Visitors = visitors; - Offense = home; // temporary value till first center jump - _io = io; - } - - public bool ScoresAreEqual => _scores[Home] == _scores[Visitors]; - public Team Offense { get; set; } - public Team Home { get; } - public Team Visitors { get; } - - public void AddBasket(string message) => AddScore(2, message); - - public void AddFreeThrows(uint count, string message) => AddScore(count, message); - - private void AddScore(uint score, string message) - { - if (Offense is null) { throw new InvalidOperationException("Offense must be set before adding to score."); } - - _io.WriteLine(message); - _scores[Offense] += score; - Turnover(); - Display(); - } - - public void Turnover(string? message = null) - { - if (message is not null) { _io.WriteLine(message); } - - Offense = Offense == Home ? Visitors : Home; - } - - public void Display(string? format = null) => - _io.WriteLine(format ?? Resource.Formats.Score, Home, _scores[Home], Visitors, _scores[Visitors]); -} diff --git a/07_Basketball/csharp/Shot.cs b/07_Basketball/csharp/Shot.cs deleted file mode 100644 index fb7c2f3e4..000000000 --- a/07_Basketball/csharp/Shot.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace Basketball; - -public class Shot -{ - private readonly string _name; - - public Shot(string name) - { - _name = name; - } - - public static bool TryGet(int shotNumber, out Shot? shot) - { - shot = shotNumber switch - { - // Although the game instructions reference two different jump shots, - // the original game code treats them both the same and just prints "Jump shot" - 0 => null, - <= 2 => new JumpShot(), - 3 => new Shot("Lay up"), - 4 => new Shot("Set shot"), - _ => null - }; - return shotNumber == 0 || shot is not null; - } - - public static Shot Get(float shotNumber) => - shotNumber switch - { - <= 2 => new JumpShot(), - > 3 => new Shot("Set shot"), - > 2 => new Shot("Lay up"), - _ => throw new Exception("Unexpected value") - }; - - public override string ToString() => _name; -} diff --git a/07_Basketball/csharp/Team.cs b/07_Basketball/csharp/Team.cs deleted file mode 100644 index 2cf262aa8..000000000 --- a/07_Basketball/csharp/Team.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Basketball.Plays; - -namespace Basketball; - -internal record Team(string Name, Play PlayResolver) -{ - public override string ToString() => Name; - - public bool ResolvePlay(Scoreboard scoreboard) => PlayResolver.Resolve(scoreboard); -} diff --git a/07_Basketball/perl/README.md b/07_Basketball/perl/README.md index 51373c0c8..e69c8b819 100644 --- a/07_Basketball/perl/README.md +++ b/07_Basketball/perl/README.md @@ -1,21 +1,3 @@ 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 deleted file mode 100755 index 14627ffc6..000000000 --- a/07_Basketball/perl/basketball-orig.pl +++ /dev/null @@ -1,415 +0,0 @@ -#!/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 deleted file mode 100755 index ac3483094..000000000 --- a/07_Basketball/perl/basketball.pl +++ /dev/null @@ -1,393 +0,0 @@ -#!/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") - { - 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(); -} diff --git a/07_Basketball/python/basketball.py b/07_Basketball/python/basketball.py index e3a598628..762b0d1b2 100644 --- a/07_Basketball/python/basketball.py +++ b/07_Basketball/python/basketball.py @@ -6,10 +6,10 @@ """ import random -from typing import List, Literal, Optional +from typing import Optional, List, Literal -def print_intro() -> None: +def explain_keyboard_inputs(): print("\t\t\t Basketball") print("\t Creative Computing Morristown, New Jersey\n\n\n") print("This is Dartmouth College basketball. ") @@ -35,7 +35,7 @@ def __init__(self) -> None: self.shot_choices: List[Literal[0, 1, 2, 3, 4]] = [0, 1, 2, 3, 4] self.z1: Optional[float] = None - print_intro() + explain_keyboard_inputs() self.defense = get_defense_choice(self.defense_choices) @@ -122,37 +122,39 @@ 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() - elif random.random() > 0.5: - print( - "Shot is blocked. Ball controlled by " - + self.opponent - + ".\n" - ) - self.opponent_ball() + self.opponent_ball() else: - print("Shot is blocked. Ball controlled by Dartmouth.") - self.dartmouth_ball() + 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() else: print("Shot is off target.") if self.defense / 6 * random.random() > 0.45: - print(f"Rebound to {self.opponent}" + "\n") + print("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(f"Pass stolen by {self.opponent}, easy lay up") + print("Pass stolen by " + self.opponent + ", easy lay up") self.add_points(0, 2) self.dartmouth_ball() else: # ball is passed back to you self.ball_passed_back() else: - print() + print("") self.dartmouth_non_jump_shot() else: print("Shot is good.") @@ -184,11 +186,13 @@ 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(f"Shot blocked. {self.opponent}" + "'s ball.\n") + print("Shot blocked. " + self.opponent + "'s ball.\n") + self.opponent_ball() else: self.foul_shots(1) - self.opponent_ball() + self.opponent_ball() else: print("Shot is off the rim.") if random.random() > 2 / 3: @@ -212,35 +216,35 @@ def dartmouth_ball(self) -> None: self.shot = shot if self.time < 100 or random.random() < 0.5: - if self.shot in [1, 2]: + if self.shot == 1 or self.shot == 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: - print("\n ***** End Of Game *****") - print( - "Final Score: Dartmouth: " - + str(self.score[1]) - + " " - + self.opponent - + ": " - + str(self.score[0]) - ) + 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() def opponent_jumpshot(self) -> None: """Simulate the opponents jumpshot""" @@ -249,35 +253,32 @@ 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(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() + 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() else: - self.opponent_non_jumpshot() + if random.random() > 0.5: + self.opponent_non_jumpshot() + else: + print("Pass back to " + self.opponent + " guard.\n") + self.opponent_ball() else: print("Dartmouth controls the rebound.\n") self.dartmouth_ball() @@ -295,30 +296,26 @@ 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(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() + 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() else: - print(f"Pass back to {self.opponent}" + " guard\n") - self.opponent_ball() + if random.random() > 0.5: + print("") + self.opponent_non_jumpshot() + else: + print("Pass back to " + self.opponent + " guard\n") + self.opponent_ball() else: print("Dartmouth controls the rebound.\n") self.dartmouth_ball() diff --git a/07_Basketball/python/test_basketball.py b/07_Basketball/python/test_basketball.py new file mode 100644 index 000000000..8644dc86c --- /dev/null +++ b/07_Basketball/python/test_basketball.py @@ -0,0 +1,16 @@ +import io + +import pytest +from _pytest.monkeypatch import MonkeyPatch +from _pytest.capture import CaptureFixture + +from basketball import Basketball + + +def test_basketball(monkeypatch: MonkeyPatch, capsys: CaptureFixture[str]) -> None: + monkeypatch.setattr( + "sys.stdin", + io.StringIO("\n1\n6\n1\n2\n1\n2\n1\n2\n1\n2\n3\n4\n5\n4"), + ) + with pytest.raises(EOFError): + Basketball() diff --git a/08_Batnum/README.md b/08_Batnum/README.md index bb74a4ec7..840529867 100644 --- a/08_Batnum/README.md +++ b/08_Batnum/README.md @@ -19,10 +19,6 @@ 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/08_Batnum/python/batnum.py b/08_Batnum/python/batnum.py index bb41d8619..60c7aad95 100644 --- a/08_Batnum/python/batnum.py +++ b/08_Batnum/python/batnum.py @@ -1,5 +1,5 @@ from enum import IntEnum -from typing import Any, Tuple +from typing import Tuple, Any class WinOptions(IntEnum): @@ -41,7 +41,7 @@ def _missing_(cls, value: Any) -> "StartOptions": def print_intro() -> None: - """Print out the introduction and rules for the game.""" + """Prints out the introduction and rules for the game.""" print("BATNUM".rjust(33, " ")) print("CREATIVE COMPUTING MORRISSTOWN, NEW JERSEY".rjust(15, " ")) print() @@ -64,12 +64,12 @@ def get_params() -> Tuple[int, int, int, StartOptions, WinOptions]: """This requests the necessary parameters to play the game. Returns a set with the 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 - 1 if the computer is first + pileSize - the starting size of the object pile + minSelect - minimum selection that can be made on each turn + maxSelect - maximum selection that can be made on each turn + startOption - 1 if the computer is first or 2 if the player is first - win_option - 1 if the goal is to take the last object + winOption - 1 if the goal is to take the last object or 2 if the goal is to not take the last object """ pile_size = get_pile_size() @@ -123,7 +123,7 @@ def player_move( to take and doing some basic validation around that input. Then it checks for any win conditions. - Returns a boolean indicating whether the game is over and the new pile_size.""" + Returns a boolean indicating whether the game is over and the new pileSize.""" player_done = False while not player_done: player_move = int(input("YOUR MOVE ")) @@ -153,8 +153,11 @@ 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)) - computer_pick = max(computer_pick, min_select) - return min(computer_pick, max_select) + if computer_pick < min_select: + computer_pick = min_select + if computer_pick > max_select: + computer_pick = max_select + return computer_pick def computer_move( @@ -164,7 +167,7 @@ def computer_move( win/lose conditions and then calculating how many objects the computer will take. - Returns a boolean indicating whether the game is over and the new pile_size.""" + Returns a boolean indicating whether the game is over and the new pileSize.""" # First, check for win conditions on this move # In this case, we win by taking the last object and # the remaining pile is less than max select @@ -181,7 +184,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 -= curr_sel + pile_size = pile_size - curr_sel print(f"COMPUTER TAKES {curr_sel} AND LEAVES {pile_size}") return (False, pile_size) @@ -197,7 +200,7 @@ def play_game( of the win/lose conditions is met. """ game_over = False - # players_turn is a boolean keeping track of whether it's the + # playersTurn is a boolean keeping track of whether it's the # player's or computer's turn players_turn = start_option == StartOptions.PlayerFirst diff --git a/08_Batnum/python/test_batnum.py b/08_Batnum/python/test_batnum.py new file mode 100644 index 000000000..50929388e --- /dev/null +++ b/08_Batnum/python/test_batnum.py @@ -0,0 +1,21 @@ +import io +from _pytest.capture import CaptureFixture +from _pytest.monkeypatch import MonkeyPatch + +from batnum import main + + +def test_main_win(monkeypatch: MonkeyPatch, capsys: CaptureFixture[str]) -> None: + pile_size = 1 + monkeypatch.setattr("sys.stdin", io.StringIO(f"{pile_size}\n1\n1 2\n2\n1\n-1\n")) + main() + captured = capsys.readouterr() + assert "CONGRATULATIONS, YOU WIN" in captured.out + + +def test_main_lose(monkeypatch: MonkeyPatch, capsys: CaptureFixture[str]) -> None: + pile_size = 3 + monkeypatch.setattr("sys.stdin", io.StringIO(f"{pile_size}\n2\n1 2\n2\n1\n1\n-1\n")) + main() + captured = capsys.readouterr() + assert "TOUGH LUCK, YOU LOSE" in captured.out diff --git a/08_Batnum/ruby/batnum.rb b/08_Batnum/ruby/batnum.rb deleted file mode 100755 index a390e339f..000000000 --- a/08_Batnum/ruby/batnum.rb +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env ruby - -def instructions - puts <<~EOF - THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE - COMPUTER IS YOUR OPPONENT. - - THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU - AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE. - WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR - NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS. - DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME. - ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING. - EOF -end - -def ask_for_pile_size - loop do - puts "ENTER PILE SIZE:" - pile_size = gets.to_i - break pile_size if pile_size != 0 - end -end - -GOAL_TAKE_LAST = 1 -GOAL_AVOID_LAST = 2 -def ask_for_goal - loop do - puts "ENTER WIN OPTION - #{GOAL_TAKE_LAST} TO TAKE LAST, #{GOAL_AVOID_LAST} TO AVOID LAST:" - response = gets.to_i - break response if [GOAL_TAKE_LAST, GOAL_AVOID_LAST].member? response - end -end - -def ask_for_min_max_take - loop do - puts "ENTER MIN AND MAX, SEPARATED BY A COMMA:" - response = gets.split(',').map {|piece| piece.to_i} - next if response.length != 2 - min_take, max_take = response - break min_take, max_take if 0 < min_take && min_take <= max_take - end -end - -COMPUTER_MOVE = 1 -PLAYER_MOVE = 2 -def ask_who_makes_first_move - loop do - puts "ENTER START OPTION - #{COMPUTER_MOVE} COMPUTER FIRST, #{PLAYER_MOVE} YOU FIRST:" - response = gets.to_i - break response if [COMPUTER_MOVE, PLAYER_MOVE].member? response - end -end - -def ask_for_player_take(min_take:, max_take:) - loop do - puts "YOUR MOVE:" - response = gets.to_i - break response if response == 0 || response == response.clamp(min_take, max_take) - puts "ILLEGAL MOVE, REENTER IT." - end -end - -def battle(pile:, goal:, min_take:, max_take:, first_move:) - next_move = first_move - loop do - if next_move == COMPUTER_MOVE - next_move = PLAYER_MOVE - take = ( - if goal == GOAL_TAKE_LAST - pile % (min_take + max_take) - else - (pile - 1) % (min_take + max_take) - end - ).clamp(min_take, max_take) - pile = pile - take - if pile > 0 - puts "COMPUTER TAKES #{take} AND LEAVES #{pile}" - else - if goal == GOAL_TAKE_LAST - puts "COMPUTER TAKES #{take} AND WINS." - break - else - puts "COMPUTER TAKES #{take} AND LOSES." - break - end - end - else - next_move = COMPUTER_MOVE - take = ask_for_player_take(min_take: min_take, max_take: max_take) - if take == 0 - puts "I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT." - break - end - pile = pile - take - if pile > 0 - puts "PLAYER TAKES #{take} AND LEAVES #{pile}" - else - if goal == GOAL_TAKE_LAST - puts "CONGRATULATIONS, YOU WIN." - break - else - puts "TOUGH LUCK, YOU LOSE." - break - end - end - end - end -end - - -def main - instructions - loop do - pile = ask_for_pile_size - break if pile < 0 - goal = ask_for_goal - min_take, max_take = ask_for_min_max_take - first_move = ask_who_makes_first_move - battle( - pile: pile, - goal: goal, - min_take: min_take, - max_take: max_take, - first_move: first_move, - ) - end -end - -main diff --git a/08_Batnum/rust/Cargo.lock b/08_Batnum/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/08_Batnum/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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 deleted file mode 100644 index 1ec696335..000000000 --- a/08_Batnum/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/08_Batnum/rust/src/main.rs b/08_Batnum/rust/src/main.rs deleted file mode 100644 index 761e1939b..000000000 --- a/08_Batnum/rust/src/main.rs +++ /dev/null @@ -1,239 +0,0 @@ -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/09_Battle/README.md b/09_Battle/README.md index 29d2622e7..042864528 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 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 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 original author of both the program and these descriptive notes is Ray Westergard of Lawrence Hall of Science, Berkeley, California. @@ -28,4 +28,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -- 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 +(please note any difficulties or challenges in porting here) diff --git a/09_Battle/javascript/battle.js b/09_Battle/javascript/battle.js index d3f307f65..8ffb7fa08 100644 --- a/09_Battle/javascript/battle.js +++ b/09_Battle/javascript/battle.js @@ -258,11 +258,6 @@ async function main() print("START GAME\n"); while (1) { str = await input(); - // Check if user types anything other than a number - if (isNaN(str)) { - print("INVALID INPUT. TRY ENTERING A NUMBER INSTEAD.\n"); - continue; - } x = parseInt(str); y = parseInt(str.substr(str.indexOf(",") + 1)); if (x < 1 || x > 6 || y < 1 || y > 6) { diff --git a/09_Battle/python/battle.py b/09_Battle/python/battle.py index 2418b35d5..993b9f458 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/09_Battle/python/battle_oo.py b/09_Battle/python/battle_oo.py new file mode 100755 index 000000000..2227a22ad --- /dev/null +++ b/09_Battle/python/battle_oo.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python3 +from dataclasses import dataclass +from random import randrange + +DESTROYER_LENGTH = 2 +CRUISER_LENGTH = 3 +AIRCRAFT_CARRIER_LENGTH = 4 + + +@dataclass(frozen=True) +class Point: + x: int + y: int + + @classmethod + def random(cls, start: int, stop: int) -> "Point": + return Point(randrange(start, stop), randrange(start, stop)) + + def __add__(self, vector: "Vector") -> "Point": + return Point(self.x + vector.x, self.y + vector.y) + + +@dataclass(frozen=True) +class Vector: + x: int + y: int + + @staticmethod + def random() -> "Vector": + return Vector(randrange(-1, 2, 2), randrange(-1, 2, 2)) + + def __mul__(self, factor: int) -> "Vector": + return Vector(self.x * factor, self.y * factor) + + +class Sea: + WIDTH = 6 + + def __init__(self) -> None: + self._graph = tuple([0 for _ in range(self.WIDTH)] for _ in range(self.WIDTH)) + + def _validate_item_indices(self, point: Point) -> None: + if not isinstance(point, Point): + raise ValueError(f"Sea indices must be Points, not {type(point).__name__}") + + if not ((1 <= point.x <= self.WIDTH) and (1 <= point.y <= self.WIDTH)): + raise IndexError("Sea index out of range") + + # Allows us to get the value using a point as a key, for example, `sea[Point(3,2)]` + def __getitem__(self, point: Point) -> int: + self._validate_item_indices(point) + + return self._graph[point.y - 1][point.x - 1] + + # Allows us to get the value using a point as a key, for example, `sea[Point(3,2)] = 3` + def __setitem__(self, point: Point, value: int) -> None: + self._validate_item_indices(point) + self._graph[point.y - 1][point.x - 1] = value + + # Allows us to check if a point exists in the sea for example, `if Point(3,2) in sea:` + def __contains__(self, point: Point) -> bool: + try: + self._validate_item_indices(point) + except IndexError: + return False + + return True + + # Redefines how python will render this object when asked as a str + def __str__(self) -> str: + # Display it encoded + return "\n".join( + [ + " ".join( + [str(self._graph[y][x]) for y in range(self.WIDTH - 1, -1, -1)] + ) + for x in range(self.WIDTH) + ] + ) + + def has_ship(self, ship_code: int) -> bool: + return any(ship_code in row for row in self._graph) + + def count_sunk(self, *ship_codes: int) -> int: + return sum(not self.has_ship(ship_code) for ship_code in ship_codes) + + +class Battle: + def __init__(self) -> None: + self.sea = Sea() + self.place_ship(DESTROYER_LENGTH, 1) + self.place_ship(DESTROYER_LENGTH, 2) + self.place_ship(CRUISER_LENGTH, 3) + self.place_ship(CRUISER_LENGTH, 4) + self.place_ship(AIRCRAFT_CARRIER_LENGTH, 5) + self.place_ship(AIRCRAFT_CARRIER_LENGTH, 6) + self.splashes = 0 + self.hits = 0 + + def _next_target(self) -> Point: + while True: + try: + guess = input("? ") + coordinates = guess.split(",") + + if len(coordinates) != 2: + raise ValueError() + + point = Point(int(coordinates[0]), int(coordinates[1])) + + if point not in self.sea: + raise ValueError() + + return point + except ValueError: + print( + f"INVALID. SPECIFY TWO NUMBERS FROM 1 TO {Sea.WIDTH}, SEPARATED BY A COMMA." + ) + + @property + def splash_hit_ratio(self) -> str: + return f"{self.splashes}/{self.hits}" + + @property + def _is_finished(self) -> bool: + return self.sea.count_sunk(*(i for i in range(1, 7))) == 6 + + def place_ship(self, size: int, ship_code: int) -> None: + while True: + start = Point.random(1, self.sea.WIDTH + 1) + vector = Vector.random() + # Get potential ship points + points = [start + vector * i for i in range(size)] + + if not ( + all([point in self.sea for point in points]) + and not any([self.sea[point] for point in points]) + ): + # ship out of bounds or crosses other ship, trying again + continue + + # We found a valid spot, so actually place it now + for point in points: + self.sea[point] = ship_code + + break + + def loop(self) -> None: + while True: + target = self._next_target() + target_value = self.sea[target] + + if target_value < 0: + print( + f"YOU ALREADY PUT A HOLE IN SHIP NUMBER {abs(target_value)} AT THAT POINT." + ) + + if target_value <= 0: + print("SPLASH! TRY AGAIN.") + self.splashes += 1 + continue + + print(f"A DIRECT HIT ON SHIP NUMBER {target_value}") + self.hits += 1 + self.sea[target] = -target_value + + if not self.sea.has_ship(target_value): + print("AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS.") + self._display_sunk_report() + + if self._is_finished: + self._display_game_end() + break + + print(f"YOUR CURRENT SPLASH/HIT RATIO IS {self.splash_hit_ratio}") + + def _display_sunk_report(self) -> None: + print( + "SO FAR, THE BAD GUYS HAVE LOST", + f"{self.sea.count_sunk(1, 2)} DESTROYER(S),", + f"{self.sea.count_sunk(3, 4)} CRUISER(S),", + f"AND {self.sea.count_sunk(5, 6)} AIRCRAFT CARRIER(S).", + ) + + def _display_game_end(self) -> None: + print( + "YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET " + f"WITH A FINAL SPLASH/HIT RATIO OF {self.splash_hit_ratio}" + ) + + if not self.splashes: + print("CONGRATULATIONS -- A DIRECT HIT EVERY TIME.") + + print("\n****************************") + + +def main() -> None: + game = Battle() + print( + f""" + BATTLE +CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + +THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION +HAS BEEN CAPTURED BUT NOT DECODED: + +{game.sea} + +DE-CODE IT AND USE IT IF YOU CAN +BUT KEEP THE DE-CODING METHOD A SECRET. + +START GAME""" + ) + game.loop() + + +if __name__ == "__main__": + main() diff --git a/09_Battle/python/test_battle.py b/09_Battle/python/test_battle.py new file mode 100644 index 000000000..30164350c --- /dev/null +++ b/09_Battle/python/test_battle.py @@ -0,0 +1,27 @@ +import io +from typing import Callable + +import pytest +from _pytest.monkeypatch import MonkeyPatch + +from battle import main as main_one +from battle_oo import main as main_oo + + +@pytest.mark.parametrize( + "main", + [main_one, main_oo], +) +def test_main(monkeypatch: MonkeyPatch, main: Callable[[], None]) -> None: + monkeypatch.setattr( + "sys.stdin", + io.StringIO( + "1,1\n1,2\n1,3\n1,4\n1,5\n1,6\n" + "2,1\n2,2\n2,3\n2,4\n2,5\n2,6\n" + "3,1\n3,2\n3,3\n3,4\n3,5\n3,6\n" + "4,1\n4,2\n4,3\n4,4\n4,5\n4,6\n" + "5,1\n5,2\n5,3\n5,4\n5,5\n5,6\n" + "6,1\n6,2\n6,3\n6,4\n6,5\n6,6\n" + ), + ) + main() diff --git a/09_Battle/rust/Cargo.lock b/09_Battle/rust/Cargo.lock deleted file mode 100644 index 10a595996..000000000 --- a/09_Battle/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/src/main.rs b/09_Battle/rust/src/main.rs deleted file mode 100644 index f9e8d36ec..000000000 --- a/09_Battle/rust/src/main.rs +++ /dev/null @@ -1,273 +0,0 @@ -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/10_Blackjack/README.md b/10_Blackjack/README.md index 66cfee65c..dcbe53bb9 100644 --- a/10_Blackjack/README.md +++ b/10_Blackjack/README.md @@ -15,16 +15,6 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at 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 - - 2850 - - 3100 - - 3400 - - 3410 - - 3420 +(please note any difficulties or challenges in porting here) diff --git a/10_Blackjack/python/blackjack.py b/10_Blackjack/python/blackjack.py index 615aec79b..e4d6fa401 100644 --- a/10_Blackjack/python/blackjack.py +++ b/10_Blackjack/python/blackjack.py @@ -58,7 +58,10 @@ def add_card(self, card: Card) -> None: def get_total(self) -> int: """returns the total points of the cards in this hand""" - total: int = sum(int(card.value) for card in self.cards) + total: int = 0 + for card in self.cards: + total += int(card.value) + # 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): @@ -106,21 +109,24 @@ 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: - 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() + 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 @dataclass @@ -165,19 +171,24 @@ 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 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] - ) + if not hide_dealer: + 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 + 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: @@ -186,7 +197,10 @@ 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: - return Play.Stand if self.hand.get_total() > 16 else Play.Hit + if self.hand.get_total() > 16: + return Play.Stand + else: + return Play.Hit elif self.player_type == PlayerType.Player: valid_results: List[str] if len(self.hand.cards) > 2: @@ -218,13 +232,17 @@ class Game: @classmethod def new(cls, num_players: int) -> "Game": - players: List[Player] = [Player.new(PlayerType.Dealer, 0)] + players: List[Player] = [] + # add dealer + players.append(Player.new(PlayerType.Dealer, 0)) # create human player(s) (at least one) players.append(Player.new(PlayerType.Player, 1)) - players.extend(Player.new(PlayerType.Player, i) for i in range(2, num_players)) + for i in range(2, num_players): # one less than num_players players + players.append(Player.new(PlayerType.Player, i)) + if get_char_from_user_input("Do you want instructions", ["y", "n"]) == "y": - print_instructions() + instructions() print() return Game(players=players, decks=Decks.new(), games_played=0) @@ -266,7 +284,7 @@ def play_game(self) -> None: # turn loop, ends when player finishes their turn while True: clear() - print_welcome_screen() + welcome() print(f"\n\t\t\tGame {game}") print(scores) print(player_hands_message) @@ -304,6 +322,9 @@ 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" @@ -386,7 +407,7 @@ def play_game(self) -> None: def main() -> None: game: Game - print_welcome_screen() + welcome() # create game game = Game.new( @@ -400,7 +421,9 @@ def main() -> None: char = get_char_from_user_input("Play Again?", ["y", "n"]) -def print_welcome_screen() -> None: +def welcome() -> None: + """prints the welcome screen""" + # welcome message print( """ BLACK JACK @@ -409,7 +432,8 @@ def print_welcome_screen() -> None: ) -def print_instructions() -> None: +def instructions() -> None: + """prints the instructions""" print( """ THIS IS THE GAME OF 21. AS MANY AS 7 PLAYERS MAY PLAY THE @@ -439,7 +463,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(f"{prompt} ({min_value}-{max_value})? ") + raw_input = input(prompt + f" ({min_value}-{max_value})? ") try: user_input = int(raw_input) @@ -454,7 +478,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(f"{prompt} {valid_results}? ").lower() + user_input = input(prompt + f" {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/10_Blackjack/python/test_blackjack.py b/10_Blackjack/python/test_blackjack.py new file mode 100644 index 000000000..56b7c262e --- /dev/null +++ b/10_Blackjack/python/test_blackjack.py @@ -0,0 +1,17 @@ +import io + +from _pytest.monkeypatch import MonkeyPatch +from _pytest.capture import CaptureFixture + +from blackjack import main + + +def test_blackjack(monkeypatch: MonkeyPatch, capsys: CaptureFixture[str]) -> None: + nb_players = 1 + instructions = "y" + bet = 100 + monkeypatch.setattr( + "sys.stdin", + io.StringIO(f"{nb_players}\n{instructions}\n\n{bet}\ns\nn\n"), + ) + main() diff --git a/10_Blackjack/ruby/blackjack.rb b/10_Blackjack/ruby/blackjack.rb deleted file mode 100644 index f2346f447..000000000 --- a/10_Blackjack/ruby/blackjack.rb +++ /dev/null @@ -1,20 +0,0 @@ -require_relative "./game.rb" - -def intro - puts "Welcome to Blackjack" -end - -def ask_for_players_count - puts "How many of you want to join the table?" - return gets.to_i -end - -begin - intro - players_count = ask_for_players_count - Game.new(players_count).start -rescue SystemExit, Interrupt - exit -rescue => exception - p exception -end diff --git a/10_Blackjack/ruby/game.rb b/10_Blackjack/ruby/game.rb deleted file mode 100644 index b73fb9f08..000000000 --- a/10_Blackjack/ruby/game.rb +++ /dev/null @@ -1,152 +0,0 @@ -require_relative "./model/hand.rb" -require_relative "./model/player.rb" -require_relative "./model/card_kind.rb" -require_relative "./model/pack.rb" - -class Game - - ALLOWED_HAND_ACTIONS = { - "hit" => ["H", "S"], - "split" => ["H", "S", "D"], - "normal" => ["H", "S", "/", "D"] - } - - def initialize(players_count) - @pack = Model::Pack.new - @dealer_balance = 0 - @dealer_hand = nil - @players = 1.upto(players_count).map { |id| Model::Player.new(id) } - end - - def start - loop do - collect_bets_and_deal - play_players - check_for_insurance_bets - play_dealer - settle - end - end - - private - - def collect_bets_and_deal - puts "BETS" - - @players.each_entry do |player| - print "# #{player.id} ? " - bet = gets.to_i - player.deal_initial_hand Model::Hand.new(bet, [@pack.draw, @pack.draw]) - end - - @dealer_hand = Model::Hand.new(0, [@pack.draw, @pack.draw]) - print_players_and_dealer_hands - end - - def play_players - @players.each_entry do |player| - play_hand player, player.hand - end - end - - def check_for_insurance_bets - return if @dealer_hand.cards[0].label != "A" - - print "ANY INSURANCE? " - return if gets.strip != "Y" - - @players.each_entry do |player| - print "PLAYER #{player.id} INSURANCE BET? " - player.bet_insurance(gets.to_i) - end - end - - def play_dealer - puts "DEALER HAS A \t#{@dealer_hand.cards[1].label} CONCEALED FOR A TOTAL OF #{@dealer_hand.total}" - - while @dealer_hand.total(is_dealer: true) < 17 - card = @pack.draw - @dealer_hand.hit card - - puts "DRAWS #{card.label} \t---TOTAL = #{@dealer_hand.total}" - end - - if !@dealer_hand.is_busted? - @dealer_hand.stand - end - end - - def settle - @players.each_entry do |player| - player_balance_update = player.update_balance @dealer_hand - @dealer_balance -= player_balance_update - - puts "PLAYER #{player.id} #{player_balance_update < 0 ? "LOSES" : "WINS"} \t#{player_balance_update} \tTOTAL=#{player.balance}" - end - - puts "DEALER'S TOTAL = #{@dealer_balance}" - end - - - def print_players_and_dealer_hands - puts "PLAYER\t#{@players.map(&:id).join("\t")}\tDEALER" - puts " \t#{@players.map {|p| p.hand.cards[0].label}.join("\t")}\t#{@dealer_hand.cards[0].label}" - puts " \t#{@players.map {|p| p.hand.cards[1].label}.join("\t")}" - end - - def play_hand player, hand - allowed_actions = ALLOWED_HAND_ACTIONS[(hand.is_split_hand || !hand.can_split?) ? "split" : "normal"] - name = "PLAYER #{player.id}" - if hand.is_split_hand - name += " - HAND #{hand === player.hand ? 1 : 2}" - end - - did_hit = false - - while hand.is_playing? - print "#{name}? " - - action = gets.strip - - if !allowed_actions.include?(action) - puts "Possible actions: #{allowed_actions.join(", ")}" - next - end - - if action === "/" - player.split - - play_hand player, player.hand - play_hand player, player.split_hand - - return - end - - if action === "S" - hand.stand - end - - if action === "D" - card = @pack.draw - hand.double_down card - - puts "RECEIVED #{card.label}" - end - - if action === "H" - did_hit = true - allowed_actions = ALLOWED_HAND_ACTIONS["hit"] - card = @pack.draw - hand.hit card - - puts "RECEIVED #{card.label}" - end - end - - puts "TOTAL IS #{hand.total}" - - if hand.is_busted? - puts "... BUSTED" - end - end -end diff --git a/10_Blackjack/ruby/model/card_kind.rb b/10_Blackjack/ruby/model/card_kind.rb deleted file mode 100644 index 0be340ce0..000000000 --- a/10_Blackjack/ruby/model/card_kind.rb +++ /dev/null @@ -1,41 +0,0 @@ -module Model -class CardKind - def initialize(label, value) - @label = label - @value = value - end - - private_class_method :new - - TWO = self.new("2", 2) - THREE = self.new("3", 3) - FOUR = self.new("4", 4) - FIVE = self.new("5", 5) - SIX = self.new("6", 6) - SEVEN = self.new("7", 7) - EIGHT = self.new("8", 8) - NINE = self.new("9", 9) - TEN = self.new("10", 10) - JACK = self.new("J", 10) - QUEEN = self.new("Q", 10) - KING = self.new("K", 10) - ACE = self.new("A", 11) - - KINDS_SET = [ - TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, - JACK, QUEEN, KING, ACE - ] - - def same_value?(other_card) - value == other_card.value - end - - def +(other) - throw "other doesn't respond to +" unless other.responds_to? :+ - - other.+(@value) - end - - attr_reader :label, :value -end -end diff --git a/10_Blackjack/ruby/model/hand.rb b/10_Blackjack/ruby/model/hand.rb deleted file mode 100644 index e52052cf6..000000000 --- a/10_Blackjack/ruby/model/hand.rb +++ /dev/null @@ -1,97 +0,0 @@ -require_relative "./card_kind.rb" - -module Model -class Hand - HAND_STATE_PLAYING = :hand_playing - HAND_STATE_BUSTED = :hand_busted - HAND_STATE_STAND = :hand_stand - HAND_STATE_DOUBLED_DOWN = :hand_doubled_down - - def initialize(bet, cards, is_split_hand: false) - @state = HAND_STATE_PLAYING - @bet = bet - @cards = cards - @total = nil - @is_split_hand = is_split_hand - end - - attr_reader :bet, :cards, :is_split_hand - - def is_playing? - @state == HAND_STATE_PLAYING - end - - def is_busted? - @state == HAND_STATE_BUSTED - end - - def is_standing? - @state == HAND_STATE_STAND - end - - def is_blackjack? - total == 21 && @cards.length == 2 - end - - def total(is_dealer: false) - return @total unless @total.nil? - - @total = @cards.reduce(0) {|sum, card| sum + card.value} - - if @total > 21 - aces_count = @cards.count {|c| c == CardKind::ACE} - while ((!is_dealer && @total > 21) || (is_dealer && @total < 16)) && aces_count > 0 do - @total -= 10 - aces_count -= 1 - end - end - - @total - end - - ## Hand actions - - def can_split? - not @is_split_hand and @cards.length == 2 && @cards[0].same_value?(cards[1]) - end - - def split - throw "can't split" unless can_split? - [ - Hand.new(@bet, @cards[0...1], is_split_hand: true), - Hand.new(@bet, @cards[1..1], is_split_hand: true) - ] - end - - def hit(card) - throw "can't hit" unless is_playing? - - @cards.push(card) - @total = nil - - check_busted - end - - def double_down(card) - throw "can't double down" unless is_playing? - - @bet *= 2 - hit card - - @state = HAND_STATE_DOUBLED_DOWN - end - - def stand - throw "can't stand" unless is_playing? - - @state = HAND_STATE_STAND - end - - - private - - def check_busted - @state = HAND_STATE_BUSTED if total > 21 - end -end -end diff --git a/10_Blackjack/ruby/model/pack.rb b/10_Blackjack/ruby/model/pack.rb deleted file mode 100644 index 20c0f227f..000000000 --- a/10_Blackjack/ruby/model/pack.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative "./card_kind.rb" - -module Model -class Pack - def initialize - @cards = [] - reshuffle - end - - def reshuffle_if_necessary - return if @cards.count > 2 - reshuffle - end - - def draw - reshuffle_if_necessary - @cards.pop - end - - private - - def reshuffle - puts "RESHUFFLING" - @cards = 4.times.map {|_| CardKind::KINDS_SET}.flatten - @cards.shuffle! - end -end -end diff --git a/10_Blackjack/ruby/model/player.rb b/10_Blackjack/ruby/model/player.rb deleted file mode 100644 index 134cf2dc4..000000000 --- a/10_Blackjack/ruby/model/player.rb +++ /dev/null @@ -1,89 +0,0 @@ -require_relative "./hand.rb" - -module Model -class Player - def initialize(id) - @id = id - @balance = 0 - @original_bet = 0 - @insurance = 0 - - @hand = nil - @split_hand = nil - end - - attr_reader :id, :balance, :hand, :split_hand, :insurance - - ## Begining of hand dealing actions - def deal_initial_hand(hand) - @hand = hand - @split_hand = nil - @max_insurance = @hand.bet / 2 - @insurance = 0 - end - - def has_split_hand? - !@split_hand.nil? - end - - def can_split? - not has_split_hand? and @hand.can_split? - end - - def split - throw "can't split" unless can_split? - - @hand, @split_hand = @hand.split - end - - def bet_insurance(bet) - if bet < 0 - bet = 0 - puts "NEGATIVE BET -- using 0 insurance bet" - end - - if bet > @max_insurance - bet = @max_insurance - puts "TOO HIGH -- using max insurance bet of #{bet}" - end - - @insurance = bet - end - - ## End of hand dealing actions - - def update_balance(dealer_hand) - balance_update = 0 - - balance_update += get_balance_update(@hand, dealer_hand) - if has_split_hand? then - balance_update += get_balance_update(@split_hand, dealer_hand) - end - - if dealer_hand.is_blackjack? - balance_update += 2 * @insurance - else - balance_update -= @insurance - end - - @balance += balance_update - - balance_update - end - - - private - - def get_balance_update(hand, dealer_hand) - if hand.is_busted? - return -hand.bet - elsif dealer_hand.is_busted? - return hand.bet - elsif dealer_hand.total == hand.total - return 0 - else - return (dealer_hand.total < hand.total ? 1 : -1) * hand.bet - end - end -end -end diff --git a/10_Blackjack/rust/Cargo.lock b/10_Blackjack/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/10_Blackjack/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/README.md b/11_Bombardment/README.md index d4bd08d74..d0d05bf9b 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 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. +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. This program was slightly modified from the original written by Martin Burdash of Parlin, New Jersey. @@ -15,12 +15,6 @@ 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) diff --git a/11_Bombardment/python/bombardment.py b/11_Bombardment/python/bombardment.py index b125987aa..2457a87a2 100755 --- a/11_Bombardment/python/bombardment.py +++ b/11_Bombardment/python/bombardment.py @@ -4,9 +4,9 @@ from typing import Callable, List, Set -def print_intro() -> None: - print(" " * 33 + "BOMBARDMENT") - print(" " * 15 + " CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") +def display_intro() -> None: + print("" * 33 + "BOMBARDMENT") + print("" * 15 + " CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print("\n\n") print("YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU") print("HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.") @@ -28,6 +28,7 @@ def display_field() -> None: for row in range(5): initial = row * 5 + 1 print("\t".join([str(initial + column) for column in range(5)])) + print("\n" * 9) @@ -127,8 +128,8 @@ def choose() -> int: ) -def main() -> None: - print_intro() +def play() -> None: + display_intro() display_field() enemy_positions = generate_enemy_positions() @@ -161,4 +162,4 @@ def main() -> None: if __name__ == "__main__": - main() + play() diff --git a/11_Bombardment/python/test_bombardment.py b/11_Bombardment/python/test_bombardment.py new file mode 100644 index 000000000..ddf8943ae --- /dev/null +++ b/11_Bombardment/python/test_bombardment.py @@ -0,0 +1,17 @@ +import io + +from _pytest.monkeypatch import MonkeyPatch + +from bombardment import play + + +def test_bombardment(monkeypatch: MonkeyPatch) -> None: + monkeypatch.setattr( + "sys.stdin", + io.StringIO( + "\n1 2 3 4\n6\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10" + "\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20" + "\n21\n22\n23\n24\n25" + ), + ) + play() diff --git a/11_Bombardment/rust/Cargo.lock b/11_Bombardment/rust/Cargo.lock deleted file mode 100644 index 81365033b..000000000 --- a/11_Bombardment/rust/Cargo.lock +++ /dev/null @@ -1,82 +0,0 @@ -# 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/11_Bombardment/rust/Cargo.toml b/11_Bombardment/rust/Cargo.toml deleted file mode 100644 index a3c90d23c..000000000 --- a/11_Bombardment/rust/Cargo.toml +++ /dev/null @@ -1,10 +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] -rand = "0.8.5" -morristown = "0.1.4" \ No newline at end of file diff --git a/11_Bombardment/rust/README.md b/11_Bombardment/rust/README.md deleted file mode 100644 index f1c9749e7..000000000 --- a/11_Bombardment/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) by [ugurkupeli](https://github.com/ugurkupeli) diff --git a/11_Bombardment/rust/src/main.rs b/11_Bombardment/rust/src/main.rs deleted file mode 100644 index a90c17b35..000000000 --- a/11_Bombardment/rust/src/main.rs +++ /dev/null @@ -1,134 +0,0 @@ -use morristown::PromptMultiOption; -use rand::{prelude::SliceRandom, thread_rng}; -use std::time::Duration; - -fn main() { - morristown::print_intro("BOMBARDMENT"); - - println!( - r#" - -YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU -HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED. -YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST. -THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS. - -THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE -OUTPOSTS OF THE COMPUTER. IT WILL DO THE SAME TO YOU. -THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS -FIRST IS THE WINNER. - -GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT! - -TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS. - - -"# - ); - - let mut all_positions = Vec::with_capacity(25); - - for i in 1u8..=25 { - all_positions.push(i); - - print!("{i}\t"); - if (i % 5) == 0 { - println!(); - } - } - - let mut player_positions = morristown::prompt_multi_number::( - "WHAT ARE YOUR FOUR POSITIONS?\n", - ",", - Some(PromptMultiOption::UnitAmount(4)), - Some(1..=25), - ); - - let mut rng = thread_rng(); - - let ai_positions = rand::seq::index::sample(&mut rng, 24, 4).into_vec(); - let mut ai_positions: Vec = ai_positions.iter().map(|i| (i + 1) as u8).collect(); - - loop { - if !player_turn(&mut ai_positions) { - break; - } else if !ai_turn(&mut all_positions, &mut player_positions) { - break; - } - } -} - -fn player_turn(ai_positions: &mut Vec) -> bool { - let player_missile = - morristown::prompt_number_range::("WHERE DO YOU WISH TO FIRE YOUR MISSILE?", 1..=25); - - if let Some(index) = ai_positions.iter().position(|p| *p == player_missile) { - ai_positions.remove(index); - - let remaining = ai_positions.len(); - - if remaining > 0 { - let down = 4 - remaining; - - println!( - "YOU GOT ONE OF MY OUTPOSTS.\n{} DOWN, {} TO GO\n", - get_text_from_number(down), - get_text_from_number(remaining) - ); - } else { - println!( - "YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN MY TRANSISTO&S RECUP%RA*E!\n\n" - ); - return false; - } - } else { - println!("HA, HA YOU MISSED. MY TURN NOW\n"); - } - true -} - -fn ai_turn(all_positions: &mut Vec, player_positions: &mut Vec) -> bool { - std::thread::sleep(Duration::from_secs(1)); - - let ai_missile = *all_positions - .choose(&mut rand::thread_rng()) - .expect("AI RAN OUT OF OPTIONS!"); - - let index = all_positions - .iter() - .position(|p| p == &ai_missile) - .expect("AI CHOOSE AN INVALID POSITION!"); - - all_positions.remove(index); - - if let Some(index) = player_positions.iter().position(|p| p == &ai_missile) { - player_positions.remove(index); - - let remaining = player_positions.len(); - - if remaining > 0 { - println!("I GOT YOU. IT WON'T BE LONG NOW. POST {ai_missile} WAS HIT."); - println!( - "YOU HAVE ONLY {} OUTPOST LEFT.\n", - get_text_from_number(remaining) - ); - } else { - println!("YOU'RE DEAD. YOUR LAST OUTPOST WAS AT {ai_missile} . HA, HA, HA."); - println!("BETTER LUCK NEXT TIME."); - return false; - } - } else { - println!("I MISSED YOU, YOU DIRTY RAT. I PICKED {ai_missile} . YOUR TURN.\n") - } - - true -} - -fn get_text_from_number(n: usize) -> &'static str { - match n { - 1 => "ONE", - 2 => "TWO", - 3 => "THREE", - _ => panic!("INVALID INDEX!"), - } -} diff --git a/12_Bombs_Away/README.md b/12_Bombs_Away/README.md index 603516fb1..8a2decaa1 100644 --- a/12_Bombs_Away/README.md +++ b/12_Bombs_Away/README.md @@ -13,10 +13,6 @@ 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) diff --git a/12_Bombs_Away/lua/bombs_away.lua b/12_Bombs_Away/lua/bombs_away.lua deleted file mode 100644 index 27c857448..000000000 --- a/12_Bombs_Away/lua/bombs_away.lua +++ /dev/null @@ -1,211 +0,0 @@ --- Ported by Brian Wilkins (BrianWilkinsFL) --- Influenced by bombsaway.py --- Requires: Lua 5.4.x - -missileHitRate = 0 -gunsHitRate = 0 - -nanMessage = "Invalid user entry! Please use a number and try again." -function has_key(table, key) - return table[key]~=nil -end - -function choice(prompt, table) - resp = getInput(prompt) - while not has_key(table, resp) do - print("TRY AGAIN...") - resp = getInput(prompt) - end - return resp -end - --- reused from Bagels.lua -function getInput(prompt) - io.write(prompt) - io.flush() - local input = io.read("l") - if not input then --- test for EOF - print("GOODBYE") - os.exit(0) - end - return input -end - -function playerSurvived() - print("YOU MADE IT THROUGH TREMENDOUS FLAK!!") -end - -function playerDeath() - print("* * * * BOOM * * * *") - print("YOU HAVE BEEN SHOT DOWN.....") - print("DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR") - print("LAST TRIBUTE...") -end - --- Enhancement: Partially killed don't count so floor the float -function missionSuccess() - print("DIRECT HIT!!!! " .. math.floor(100*math.random()) .. " KILLED.") - print("MISSION SUCCESSFUL.") -end - -function missionFailure() - weapons_choices = { - ["1"] = "GUNS", - ["2"] = "MISSILES", - ["3"] = "BOTH", - } - print("MISSED TARGET BY " .. math.floor(2 + 30 * math.random()) .. " MILES!") - print("NOW YOU'RE REALLY IN FOR IT !!") - print() - enemy_weapons = choice("DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? ", weapons_choices) - - if enemy_weapons == "2" or enemy_weapons == "3" then - missileHitRate = 35 - end - - if enemy_weapons == "2" then - -- gunsHitRate is a reused global variable so - -- its possible that previously selected gunsHitRate - -- will be used here leading to interesting - -- randomness - if missileHitRate+gunsHitRate > 100*math.random() then - playerDeath() - else - playerSurvived() - end - end - - if enemy_weapons == "1" or enemy_weapons == "3" then - while true do - resp = getInput("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? ") - if assert(tonumber(resp)) then - gunsHitRate = tonumber(resp) - break - end - end - if gunsHitRate < 10 then - print("YOU LIE, BUT YOU'LL PAY...") - playerDeath() - return - end - if missileHitRate+gunsHitRate > 100*math.random() then - playerDeath() - else - playerSurvived() - end - end -end - --- override assert so Lua doesn't throw an error --- and stack trace --- We just want the user to enter in a correct value -assert = function(truth, message) - if not truth then - print(message) - end - return truth -end - --- Added logic to verify user is actually entering in a number -function commence_non_kamikaze_attack() - local numMissions = 0 - while numMissions < 160 do - while numMissions == 0 do - resp = getInput("HOW MANY MISSIONS HAVE YOU FLOWN? ") - if assert(tonumber(resp), nanMessage) then - numMissions = tonumber(resp) - break - end - end - if numMissions < 160 then break end - - print("MISSIONS, NOT MILES...") - print("150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS.") - print("NOW THEN, ") - numMissions = 0 - end - - if numMissions >= 100 then - print("THAT'S PUSHING THE ODDS!") - end - - if numMissions < 25 then - print("FRESH OUT OF TRAINING, EH?") - end - - if numMissions >= 160*math.random() then - missionSuccess() - else - missionFailure() - end -end - -function playItaly() - targets_to_messages = { - ["1"] = "SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.", - ["2"] = "BE CAREFUL!!!", - ["3"] = "YOU'RE GOING FOR THE OIL, EH?", - } - - target = choice("YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)? ", targets_to_messages) - print(targets_to_messages[target]) - commence_non_kamikaze_attack() -end - -function playAllies() - aircraft_to_message = { - ["1"] = "YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.", - ["2"] = "YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.", - ["3"] = "YOU'RE CHASING THE BISMARK IN THE NORTH SEA.", - ["4"] = "YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.", - } - aircraft = choice("AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)? ", aircraft_to_message) - print(aircraft_to_message[aircraft]) - commence_non_kamikaze_attack() -end - -function playJapan() - print("YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.") - first_mission = getInput("YOUR FIRST KAMIKAZE MISSION? (Y OR N)? "):match("[yYnN].*") - if first_mission:lower() == "n" then - return playerDeath() - end - if math.random() > 0.65 then - return missionSuccess() - else - playerDeath() - end -end - -function playGermany() - targets_to_messages = { - ["1"] = "YOU'RE NEARING STALINGRAD.", - ["2"] = "NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR.", - ["3"] = "NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.", - } - target = choice("A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\nENGLAND(2), OR FRANCE(3)? ", targets_to_messages) - - print(targets_to_messages[target]) - return commence_non_kamikaze_attack() -end - -function playGame() - sides = { - ["1"] = playItaly, - ["2"] = playAllies, - ["3"] = playJapan, - ["4"] = playGermany - } - print("YOU ARE A PILOT IN A WORLD WAR II BOMBER.") - - target = choice("WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)? ", sides) - sides[target]() -end - -local again = true -while again do - playGame() - again = getInput("ANOTHER MISSION (Y OR N)? "):match("[yY].*") -end - -print("CHICKEN !!!") \ No newline at end of file diff --git a/12_Bombs_Away/python/test_bombs_away.py b/12_Bombs_Away/python/test_bombs_away.py new file mode 100644 index 000000000..764cb7ad6 --- /dev/null +++ b/12_Bombs_Away/python/test_bombs_away.py @@ -0,0 +1,16 @@ +import io + +from _pytest.monkeypatch import MonkeyPatch + +from bombs_away import play_game + + +def test_bombs_away(monkeypatch: MonkeyPatch) -> None: + side = 1 + target = 1 + missions = 1 + monkeypatch.setattr( + "sys.stdin", + io.StringIO(f"{side}\n{target}\n{missions}\n3\n50"), + ) + play_game() diff --git a/12_Bombs_Away/rust/Cargo.lock b/12_Bombs_Away/rust/Cargo.lock deleted file mode 100644 index 59dc11cca..000000000 --- a/12_Bombs_Away/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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 deleted file mode 100644 index 3b1d02f52..000000000 --- a/12_Bombs_Away/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/12_Bombs_Away/rust/src/main.rs b/12_Bombs_Away/rust/src/main.rs deleted file mode 100644 index d049fd849..000000000 --- a/12_Bombs_Away/rust/src/main.rs +++ /dev/null @@ -1,309 +0,0 @@ -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; - } - } -} diff --git a/13_Bounce/csharp/Bounce.cs b/13_Bounce/csharp/Bounce.cs deleted file mode 100644 index c250e7df3..000000000 --- a/13_Bounce/csharp/Bounce.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Bounce; - -/// -/// Represents the bounce of the ball, calculating duration, height and position in time. -/// -/// -/// All calculations are derived from the equation for projectile motion: s = vt + 0.5at^2 -/// -internal class Bounce -{ - private const float _acceleration = -32; // feet/s^2 - - private readonly float _velocity; - - internal Bounce(float velocity) - { - _velocity = velocity; - } - - public float Duration => -2 * _velocity / _acceleration; - - public float MaxHeight => - (float)Math.Round(-_velocity * _velocity / 2 / _acceleration, MidpointRounding.AwayFromZero); - - public float Plot(Graph graph, float startTime) - { - var time = 0f; - for (; time <= Duration; time += graph.TimeIncrement) - { - var height = _velocity * time + _acceleration * time * time / 2; - graph.Plot(startTime + time, height); - } - - return startTime + time; - } - - public Bounce Next(float elasticity) => new Bounce(_velocity * elasticity); -} diff --git a/13_Bounce/csharp/Bounce.csproj b/13_Bounce/csharp/Bounce.csproj index e377b9049..d3fe4757c 100644 --- a/13_Bounce/csharp/Bounce.csproj +++ b/13_Bounce/csharp/Bounce.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/13_Bounce/csharp/Game.cs b/13_Bounce/csharp/Game.cs deleted file mode 100644 index 155bdf481..000000000 --- a/13_Bounce/csharp/Game.cs +++ /dev/null @@ -1,38 +0,0 @@ -using static Bounce.Resources.Resource; - -namespace Bounce; - -internal class Game -{ - private readonly IReadWrite _io; - - public Game(IReadWrite io) - { - _io = io; - } - - public void Play(Func playAgain) - { - _io.Write(Streams.Title); - _io.Write(Streams.Instructions); - - while (playAgain.Invoke()) - { - var timeIncrement = _io.ReadParameter("Time increment (sec)"); - var velocity = _io.ReadParameter("Velocity (fps)"); - var elasticity = _io.ReadParameter("Coefficient"); - - var bounce = new Bounce(velocity); - var bounceCount = (int)(Graph.Row.Width * timeIncrement / bounce.Duration); - var graph = new Graph(bounce.MaxHeight, timeIncrement); - - var time = 0f; - for (var i = 0; i < bounceCount; i++, bounce = bounce.Next(elasticity)) - { - time = bounce.Plot(graph, time); - } - - _io.WriteLine(graph); - } - } -} diff --git a/13_Bounce/csharp/Graph.cs b/13_Bounce/csharp/Graph.cs deleted file mode 100644 index 608b5bda4..000000000 --- a/13_Bounce/csharp/Graph.cs +++ /dev/null @@ -1,116 +0,0 @@ -using System.Text; - -namespace Bounce; - -/// -/// Provides support for plotting a graph of height vs time, and rendering it to a string. -/// -internal class Graph -{ - private readonly Dictionary _rows; - - public Graph(float maxHeight, float timeIncrement) - { - // 1 row == 1/2 foot + 1 row for zero - var rowCount = 2 * (int)Math.Round(maxHeight, MidpointRounding.AwayFromZero) + 1; - _rows = Enumerable.Range(0, rowCount) - .ToDictionary(x => x, x => new Row(x % 2 == 0 ? $" {x / 2} " : "")); - TimeIncrement = timeIncrement; - } - - public float TimeIncrement { get; } - public float MaxTimePlotted { get; private set; } - - public void Plot(float time, float height) - { - var rowIndex = (int)Math.Round(height * 2, MidpointRounding.AwayFromZero); - var colIndex = (int)(time / TimeIncrement) + 1; - if (_rows.TryGetValue(rowIndex, out var row)) - { - row[colIndex] = '0'; - } - MaxTimePlotted = Math.Max(time, MaxTimePlotted); - } - - public override string ToString() - { - var sb = new StringBuilder().AppendLine("Feet").AppendLine(); - foreach (var (_, row) in _rows.OrderByDescending(x => x.Key)) - { - sb.Append(row).AppendLine(); - } - sb.Append(new Axis(MaxTimePlotted, TimeIncrement)); - - return sb.ToString(); - } - - internal class Row - { - public const int Width = 70; - - private readonly char[] _chars = new char[Width + 2]; - private int nextColumn = 0; - - public Row(string label) - { - Array.Fill(_chars, ' '); - Array.Copy(label.ToCharArray(), _chars, label.Length); - nextColumn = label.Length; - } - - public char this[int column] - { - set - { - if (column >= _chars.Length) { return; } - if (column < nextColumn) { column = nextColumn; } - _chars[column] = value; - nextColumn = column + 1; - } - } - - public override string ToString() => new string(_chars); - } - - internal class Axis - { - private readonly int _maxTimeMark; - private readonly float _timeIncrement; - private readonly Labels _labels; - - internal Axis(float maxTimePlotted, float timeIncrement) - { - _maxTimeMark = (int)Math.Ceiling(maxTimePlotted); - _timeIncrement = timeIncrement; - - _labels = new Labels(); - for (var i = 1; i <= _maxTimeMark; i++) - { - _labels.Add((int)(i / _timeIncrement), $" {i} "); - } - } - - public override string ToString() - => new StringBuilder() - .Append(' ').Append('.', (int)(_maxTimeMark / _timeIncrement) + 1).AppendLine() - .Append(_labels).AppendLine() - .Append(' ', (int)(_maxTimeMark / _timeIncrement / 2 - 2)).AppendLine("Seconds") - .ToString(); - } - - internal class Labels : Row - { - public Labels() - : base(" 0") - { - } - - public void Add(int column, string label) - { - for (var i = 0; i < label.Length; i++) - { - this[column + i] = label[i]; - } - } - } -} diff --git a/13_Bounce/csharp/IReadWriteExtensions.cs b/13_Bounce/csharp/IReadWriteExtensions.cs deleted file mode 100644 index bafeee42f..000000000 --- a/13_Bounce/csharp/IReadWriteExtensions.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Bounce; - -internal static class IReadWriteExtensions -{ - internal static float ReadParameter(this IReadWrite io, string parameter) - { - var value = io.ReadNumber(parameter); - io.WriteLine(); - return value; - } -} \ No newline at end of file diff --git a/13_Bounce/csharp/Program.cs b/13_Bounce/csharp/Program.cs deleted file mode 100644 index 86af3365e..000000000 --- a/13_Bounce/csharp/Program.cs +++ /dev/null @@ -1,6 +0,0 @@ -global using Games.Common.IO; -global using Games.Common.Numbers; - -using Bounce; - -new Game(new ConsoleIO()).Play(() => true); \ No newline at end of file diff --git a/13_Bounce/csharp/README.md b/13_Bounce/csharp/README.md index 6323d9d1e..4daabb5c1 100644 --- a/13_Bounce/csharp/README.md +++ b/13_Bounce/csharp/README.md @@ -1,26 +1,3 @@ -# Bounce - Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) - -## Conversion notes - -### Mode of Operation - -This conversion performs the same function as the original, and provides the same experience, but does it in a different -way. - -The original BASIC code builds the graph as it writes to the screen, scanning each line for points that need to be -plotted. - -This conversion steps through time, calculating the position of the ball at each instant, building the graph in memory. -It then writes the graph to the output in one go. - -### Failure Modes - -The original BASIC code performs no validation of the input parameters. Some combinations of parameters produce no -output, others crash the program. - -In the spirit of the original this conversion also performs no validation of the parameters, but it does not attempt to -replicate the original's failure modes. It fails quite happily in its own way. diff --git a/13_Bounce/csharp/Resources/Instructions.txt b/13_Bounce/csharp/Resources/Instructions.txt deleted file mode 100644 index d2901d6e6..000000000 --- a/13_Bounce/csharp/Resources/Instructions.txt +++ /dev/null @@ -1,8 +0,0 @@ -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). - diff --git a/13_Bounce/csharp/Resources/Resource.cs b/13_Bounce/csharp/Resources/Resource.cs deleted file mode 100644 index 68bebee01..000000000 --- a/13_Bounce/csharp/Resources/Resource.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Bounce.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Instructions => GetStream(); - public static Stream Title => GetStream(); - } - - private static Stream GetStream([CallerMemberName] string? name = null) - => Assembly.GetExecutingAssembly().GetManifestResourceStream($"Bounce.Resources.{name}.txt") - ?? throw new ArgumentException($"Resource stream {name} does not exist", nameof(name)); -} \ No newline at end of file diff --git a/13_Bounce/csharp/Resources/Title.txt b/13_Bounce/csharp/Resources/Title.txt deleted file mode 100644 index 5bcd04962..000000000 --- a/13_Bounce/csharp/Resources/Title.txt +++ /dev/null @@ -1,5 +0,0 @@ - Bounce - Creative Computing Morristown, New Jersey - - - diff --git a/13_Bounce/perl/README.md b/13_Bounce/perl/README.md index 6d213dba3..e69c8b819 100644 --- a/13_Bounce/perl/README.md +++ b/13_Bounce/perl/README.md @@ -1,6 +1,3 @@ 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 deleted file mode 100755 index 4aeacf1f7..000000000 --- a/13_Bounce/perl/bounce.pl +++ /dev/null @@ -1,97 +0,0 @@ -#!/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 $line_pos; # position on line - my $S1 # duration in full seconds? - - # 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"; - $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) - { - if (int($height) == $height) { print sprintf("%2d", $height); } - else { print " "; } - $line_pos = 0; - my $curr_line = ""; - for my $i (1 .. $S1) - { - my $time; - for ($time=0 ; $time <= $T[$i] ; $time += $time_inc) - { - $line_pos += $time_inc; - 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); - } - 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); - } - print "$curr_line\n"; - print " " x (int($line_pos + 1) / (2 * $time_inc) - 2), "SECONDS\n\n"; -} diff --git a/13_Bounce/python/bounce.py b/13_Bounce/python/bounce.py index e454183b0..f36acc94f 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 -= 0.5 + h = h - 0.5 print("." * (int((total_time + 1) / delta_t) + 1)) print diff --git a/13_Bounce/python/test_bounce.py b/13_Bounce/python/test_bounce.py new file mode 100644 index 000000000..2960919d2 --- /dev/null +++ b/13_Bounce/python/test_bounce.py @@ -0,0 +1,72 @@ +import io + +from _pytest.monkeypatch import MonkeyPatch +from _pytest.capture import CaptureFixture + +from bounce import main + + +def test_bounce(monkeypatch: MonkeyPatch, capsys: CaptureFixture[str]) -> None: + time_increment = 0.1 + velocity = 30 + coefficient = 1 + monkeypatch.setattr( + "sys.stdin", + io.StringIO(f"{time_increment:0.1f}\n{velocity}\n{coefficient}\n"), + ) + main() + actual = capsys.readouterr().out + expected = """ BOUNCE + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + +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). + +TIME INCREMENT (SEC)? +VELOCITY (FPS)? +COEFFICIENT? +FEET + +14 000 000 000 + 0 0 0 +13 0 0 0 0 0 0 + +12 0 0 0 0 0 0 + +11 0 0 0 + 0 0 0 +10 + 0 0 0 +9 0 0 0 + +8 + 0 0 0 +7 0 0 0 + +6 + 0 0 0 +5 0 0 0 + +4 + +3 0 0 0 + +2 0 0 0 + +1 + +00 0 0 +................................................................... + 0 1 2 3 4 5 6 + + SECONDS + +""" # noqa: W291 + assert actual.split("\n") == expected.split("\n") diff --git a/13_Bounce/rust/Cargo.lock b/13_Bounce/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/13_Bounce/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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 deleted file mode 100644 index 7d75412a6..000000000 --- a/13_Bounce/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[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 deleted file mode 100644 index 99050227d..000000000 --- a/13_Bounce/rust/src/main.rs +++ /dev/null @@ -1,183 +0,0 @@ -/** 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 { - 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(); - //let s2 = 0.2f32; - - //140 PRINT - println!(); - - //150 INPUT "VELOCITY (FPS)";V - 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.6f32; - - //180 PRINT - //182 PRINT "FEET" - //184 PRINT - print!("\nFEET\n\n"); - - //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); // 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(); - while h >= 0.0 { - let mut line_content = String::new(); - //221 IF INT(H)<>H THEN 225 - if h.floor() == h { - //222 PRINT H; - line_content.push_str(h.to_string().as_str()); - line_content.push(' '); - } - //225 L=0 - l = 0.0; - //230 FOR I=1 TO S1 - for i in 1..=s1 { - let mut t_val = 0.0; - //240 FOR T=0 TO T(I) STEP S2 - while t_val <= 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) * t_val.powf(2.0) + v * c.powf((i-1) as f32) * t_val); - if condition.abs() >= 0.25{ - t_val = t_val + s2; - continue; - } - // TABS ARE NOT SPACES, BUT A TERMINAL POSITION - //260 PRINT TAB(L/S2);"0"; - let spaces = ((l / s2) - 1.0) as usize; - while line_content.len() < spaces { - line_content.push(' '); - } - line_content.push('0'); - - //270 NEXT T - t_val = t_val + s2; - } - - //275 T=T(I+1)/2 - if i as usize == t.len() { break; } - t_val = t[i as usize] / 2.0; - - //276 IF -16*T^2+V*C^(I-1)*T)); -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; -} diff --git a/14_Bowling/python/bowling.py b/14_Bowling/python/bowling.py index fc923ddbc..f4a566aaa 100644 --- a/14_Bowling/python/bowling.py +++ b/14_Bowling/python/bowling.py @@ -33,7 +33,7 @@ def calculate_score(rolls: List[int]) -> int: class Player: - def __init__(self, name: str) -> None: + def __init__(self, name: str): self.name = name self.rolls: List[int] = [] @@ -57,9 +57,10 @@ def play_frame(self, frame: int) -> None: break # cannot roll more than once in a frame else: print(f"next roll {self.name}") - elif score == 10: - print("SPARE!") - extra = 1 + else: + if score == 10: + print("SPARE!") + extra = 1 prev_score = score # remember previous pins to distinguish ... if frame == 9 and extra > 0: @@ -111,12 +112,12 @@ def main() -> None: print("SCORES.") total_players = int(input("FIRST OF ALL...HOW MANY ARE PLAYING? ")) + player_names = [] print() print("VERY GOOD...") - player_names = [ - Player(input(f"Enter name for player {index + 1}: ")) - for index in range(total_players) - ] + for index in range(total_players): + player_names.append(Player(input(f"Enter name for player {index + 1}: "))) + for frame in range(10): for player in player_names: player.play_frame(frame) diff --git a/14_Bowling/python/test_bowling.py b/14_Bowling/python/test_bowling.py new file mode 100644 index 000000000..04bb7cf62 --- /dev/null +++ b/14_Bowling/python/test_bowling.py @@ -0,0 +1,273 @@ +import io +from typing import List + +from _pytest.capture import CaptureFixture +from _pytest.monkeypatch import MonkeyPatch + +from bowling import main + + +def test_bowling_strikes(monkeypatch: MonkeyPatch, capsys: CaptureFixture[str]) -> None: + def perfect_roll(pins: List[int]) -> None: + for i in range(20): + x = i + if x < len(pins): + pins[x] = 1 + + monkeypatch.setattr("bowling.simulate_roll", perfect_roll) + + instructions1 = "Y" + players1 = 1 + name1 = "Martin" + another_game1 = "Y" + + instructions2 = "N" + players2 = 2 + name21 = "Anna" + name22 = "Bob" + another_game2 = "N" + monkeypatch.setattr( + "sys.stdin", + io.StringIO( + f"{instructions1}\n{players1}\n{name1}\n{another_game1}\n" + f"{instructions2}\n{players2}\n{name21}\n{name22}\n{another_game2}" + ), + ) + main() + actual = capsys.readouterr().out + expected = """ Bowl + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + +WELCOME TO THE ALLEY. +BRING YOUR FRIENDS. +OKAY LET'S FIRST GET ACQUAINTED. + +THE INSTRUCTIONS (Y/N)? THE GAME OF BOWLING TAKES MIND AND SKILL. DURING THE GAME +THE COMPUTER WILL KEEP SCORE. YOU MAY COMPETE WITH +OTHER PLAYERS[UP TO FOUR]. YOU WILL BE PLAYING TEN FRAMES. +ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE +PIN IS STANDING. AFTER THE GAME THE COMPUTER WILL SHOW YOUR +SCORES. +FIRST OF ALL...HOW MANY ARE PLAYING? +VERY GOOD... +Enter name for player 1: +O O O O + O O O + O O + O +10 for Martin +STRIKE!!! + +O O O O + O O O + O O + O +10 for Martin +STRIKE!!! + +O O O O + O O O + O O + O +10 for Martin +STRIKE!!! + +O O O O + O O O + O O + O +10 for Martin +STRIKE!!! + +O O O O + O O O + O O + O +10 for Martin +STRIKE!!! + +O O O O + O O O + O O + O +10 for Martin +STRIKE!!! + +O O O O + O O O + O O + O +10 for Martin +STRIKE!!! + +O O O O + O O O + O O + O +10 for Martin +STRIKE!!! + +O O O O + O O O + O O + O +10 for Martin +STRIKE!!! + +O O O O + O O O + O O + O +10 for Martin +STRIKE!!! +Extra rolls for Martin +Martin: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10], total:300 +DO YOU WANT ANOTHER GAME? +THE INSTRUCTIONS (Y/N)? FIRST OF ALL...HOW MANY ARE PLAYING? +VERY GOOD... +Enter name for player 1: Enter name for player 2: +O O O O + O O O + O O + O +10 for Anna +STRIKE!!! + +O O O O + O O O + O O + O +10 for Bob +STRIKE!!! + +O O O O + O O O + O O + O +10 for Anna +STRIKE!!! + +O O O O + O O O + O O + O +10 for Bob +STRIKE!!! + +O O O O + O O O + O O + O +10 for Anna +STRIKE!!! + +O O O O + O O O + O O + O +10 for Bob +STRIKE!!! + +O O O O + O O O + O O + O +10 for Anna +STRIKE!!! + +O O O O + O O O + O O + O +10 for Bob +STRIKE!!! + +O O O O + O O O + O O + O +10 for Anna +STRIKE!!! + +O O O O + O O O + O O + O +10 for Bob +STRIKE!!! + +O O O O + O O O + O O + O +10 for Anna +STRIKE!!! + +O O O O + O O O + O O + O +10 for Bob +STRIKE!!! + +O O O O + O O O + O O + O +10 for Anna +STRIKE!!! + +O O O O + O O O + O O + O +10 for Bob +STRIKE!!! + +O O O O + O O O + O O + O +10 for Anna +STRIKE!!! + +O O O O + O O O + O O + O +10 for Bob +STRIKE!!! + +O O O O + O O O + O O + O +10 for Anna +STRIKE!!! + +O O O O + O O O + O O + O +10 for Bob +STRIKE!!! + +O O O O + O O O + O O + O +10 for Anna +STRIKE!!! +Extra rolls for Anna + +O O O O + O O O + O O + O +10 for Bob +STRIKE!!! +Extra rolls for Bob +Anna: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10], total:300 +Bob: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10], total:300 +DO YOU WANT ANOTHER GAME? """ # noqa: W291 + assert actual.split("\n") == expected.split("\n") diff --git a/15_Boxing/README.md b/15_Boxing/README.md index f0e6692dd..12ecab4f1 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 of three rounds wins. +There are approximately seven major punches per round, although this may be varied. The best out if three rounds wins. Jesse Lynch of St. Paul, Minnesota created this program. @@ -15,14 +15,6 @@ 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) diff --git a/15_Boxing/perl/boxing.pl b/15_Boxing/perl/boxing.pl deleted file mode 100644 index 5068e58a4..000000000 --- a/15_Boxing/perl/boxing.pl +++ /dev/null @@ -1,252 +0,0 @@ -#!/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"; - } -} diff --git a/15_Boxing/python/boxing.py b/15_Boxing/python/boxing.py index 907f645c7..f1c2ae598 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, cast +from typing import Dict, Literal, NamedTuple, Tuple class PunchProfile(NamedTuple): @@ -39,11 +39,12 @@ class Player: def get_punch_choice(self) -> Literal[1, 2, 3, 4]: if self.is_computer: return random.randint(1, 4) # 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 + 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 KNOCKOUT_THRESHOLD = 35 @@ -54,7 +55,8 @@ def get_punch_choice(self) -> Literal[1, 2, 3, 4]: def get_vulnerability() -> int: print("WHAT IS HIS VULNERABILITY", end=QUESTION_PROMPT) - return int(input()) + vulnerability = int(input()) + return vulnerability def get_opponent_stats() -> Tuple[int, int]: @@ -69,13 +71,13 @@ 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) - return { - cast(Literal[1, 2, 3, 4], int(key)): PunchProfile(**value) - for key, value in punch_profile_dict.items() - } + result = {} + for key, value in punch_profile_dict.items(): + result[int(key)] = PunchProfile(**value) + return result # type: ignore -def main() -> None: +def play() -> None: print("BOXING") print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print("\n\n") @@ -177,4 +179,4 @@ def play_round(round_number: int, player: Player, opponent: Player) -> None: if __name__ == "__main__": - main() + play() diff --git a/15_Boxing/python/test_boxing.py b/15_Boxing/python/test_boxing.py new file mode 100644 index 000000000..71b2a6a9a --- /dev/null +++ b/15_Boxing/python/test_boxing.py @@ -0,0 +1,61 @@ +import io + +from _pytest.capture import CaptureFixture +from _pytest.monkeypatch import MonkeyPatch +from boxing import play + + +def test_boxing_bad_opponent( + monkeypatch: MonkeyPatch, capsys: CaptureFixture[str] +) -> None: + monkeypatch.setattr("boxing.Player.get_punch_choice", lambda self: 1) + monkeypatch.setattr("boxing.get_opponent_stats", lambda: (2, 1)) + monkeypatch.setattr("boxing.is_opponents_turn", lambda: False) + + opponent = "Anna" + my_man = "Bob" + strength = "1" + weakness = "2" + + monkeypatch.setattr( + "sys.stdin", + io.StringIO(f"{opponent}\n{my_man}\n{strength}\n{weakness}\n1\n1\n1"), + ) + play() + actual = capsys.readouterr().out + expected = """BOXING +CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + +BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS) +WHAT IS YOUR OPPONENT'S NAME? WHAT IS YOUR MAN'S NAME? DIFFERENT PUNCHES ARE 1 FULL SWING 2 HOOK 3 UPPERCUT 4 JAB +WHAT IS YOUR MAN'S BEST? WHAT IS HIS VULNERABILITY? Anna'S ADVANTAGE is 1 AND VULNERABILITY IS SECRET. +ROUND 1 BEGINS... + +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob WINS ROUND 1 +ROUND 2 BEGINS... + +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob SWINGS AND HE CONNECTS! +Bob WINS ROUND 2 +ROUND 3 BEGINS... + +Bob AMAZINGLY WINS + + +AND NOW GOODBYE FROM THE OLYMPIC ARENA. +""" + assert actual.split("\n") == expected.split("\n") diff --git a/16_Bug/csharp/Bug.cs b/16_Bug/csharp/Bug.cs deleted file mode 100644 index 42e686d4b..000000000 --- a/16_Bug/csharp/Bug.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Text; -using BugGame.Parts; -using BugGame.Resources; - -namespace BugGame; - -internal class Bug -{ - private readonly Body _body = new(); - - public bool IsComplete => _body.IsComplete; - - public bool TryAdd(IPart part, out Message message) => _body.TryAdd(part, out message); - - public string ToString(string pronoun, char feelerCharacter) - { - var builder = new StringBuilder($"*****{pronoun} Bug*****").AppendLine().AppendLine().AppendLine(); - _body.AppendTo(builder, feelerCharacter); - return builder.ToString(); - } -} \ No newline at end of file diff --git a/16_Bug/csharp/Bug.csproj b/16_Bug/csharp/Bug.csproj index 91e759c0c..d3fe4757c 100644 --- a/16_Bug/csharp/Bug.csproj +++ b/16_Bug/csharp/Bug.csproj @@ -6,13 +6,4 @@ enable enable - - - - - - - - - diff --git a/16_Bug/csharp/Game.cs b/16_Bug/csharp/Game.cs deleted file mode 100644 index a8989a4c6..000000000 --- a/16_Bug/csharp/Game.cs +++ /dev/null @@ -1,86 +0,0 @@ -using BugGame.Parts; -using BugGame.Resources; -using Games.Common.IO; -using Games.Common.Randomness; -using static System.StringComparison; -namespace BugGame; - -internal class Game -{ - private readonly IReadWrite _io; - private readonly IRandom _random; - - public Game(IReadWrite io, IRandom random) - { - _io = io; - _random = random; - } - - public void Play() - { - _io.Write(Resource.Streams.Introduction); - if (!_io.ReadString("Do you want instructions").Equals("no", InvariantCultureIgnoreCase)) - { - _io.Write(Resource.Streams.Instructions); - } - - BuildBugs(); - - _io.Write(Resource.Streams.PlayAgain); - } - - private void BuildBugs() - { - var yourBug = new Bug(); - var myBug = new Bug(); - - while (true) - { - var partAdded = TryBuild(yourBug, m => m.You); - Thread.Sleep(500); - _io.WriteLine(); - partAdded |= TryBuild(myBug, m => m.I); - - if (partAdded) - { - if (yourBug.IsComplete) { _io.WriteLine("Your bug is finished."); } - if (myBug.IsComplete) { _io.WriteLine("My bug is finished."); } - - if (!_io.ReadString("Do you want the picture").Equals("no", InvariantCultureIgnoreCase)) - { - _io.Write(yourBug.ToString("Your", 'A')); - _io.WriteLine(); - _io.WriteLine(); - _io.WriteLine(); - _io.WriteLine(); - _io.Write(myBug.ToString("My", 'F')); - } - } - - if (yourBug.IsComplete || myBug.IsComplete) { break; } - } - } - - private bool TryBuild(Bug bug, Func messageTransform) - { - var roll = _random.Next(6) + 1; - _io.WriteLine(messageTransform(Message.Rolled.ForValue(roll))); - - IPart part = roll switch - { - 1 => new Body(), - 2 => new Neck(), - 3 => new Head(), - 4 => new Feeler(), - 5 => new Tail(), - 6 => new Leg(), - _ => throw new Exception("Unexpected roll value") - }; - _io.WriteLine($"{roll}={part.GetType().Name}"); - - var partAdded = bug.TryAdd(part, out var message); - _io.WriteLine(messageTransform.Invoke(message)); - - return partAdded; - } -} \ No newline at end of file diff --git a/16_Bug/csharp/Parts/Body.cs b/16_Bug/csharp/Parts/Body.cs deleted file mode 100644 index 58f80405a..000000000 --- a/16_Bug/csharp/Parts/Body.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Text; -using BugGame.Resources; - -namespace BugGame.Parts; - -internal class Body : ParentPart -{ - private readonly Neck _neck = new(); - private readonly Tail _tail = new(); - private readonly Legs _legs = new(); - - public Body() - : base(Message.BodyAdded, Message.BodyNotNeeded) - { - } - - public override bool IsComplete => _neck.IsComplete && _tail.IsComplete && _legs.IsComplete; - - protected override bool TryAddCore(IPart part, out Message message) - => part switch - { - Neck => _neck.TryAdd(out message), - Head or Feeler => _neck.TryAdd(part, out message), - Tail => _tail.TryAdd(out message), - Leg => _legs.TryAddOne(out message), - _ => throw new NotSupportedException($"Can't add a {part.Name} to a {Name}.") - }; - - public void AppendTo(StringBuilder builder, char feelerCharacter) - { - if (IsPresent) - { - _neck.AppendTo(builder, feelerCharacter); - builder - .AppendLine(" BBBBBBBBBBBB") - .AppendLine(" B B") - .AppendLine(" B B"); - _tail.AppendTo(builder); - builder - .AppendLine(" BBBBBBBBBBBB"); - _legs.AppendTo(builder); - } - } -} diff --git a/16_Bug/csharp/Parts/Feeler.cs b/16_Bug/csharp/Parts/Feeler.cs deleted file mode 100644 index 9508d5410..000000000 --- a/16_Bug/csharp/Parts/Feeler.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace BugGame.Parts; - -internal class Feeler : IPart -{ - public string Name => nameof(Feeler); -} diff --git a/16_Bug/csharp/Parts/Feelers.cs b/16_Bug/csharp/Parts/Feelers.cs deleted file mode 100644 index 165a073da..000000000 --- a/16_Bug/csharp/Parts/Feelers.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Text; -using BugGame.Resources; - -namespace BugGame.Parts; - -internal class Feelers : PartCollection -{ - public Feelers() - : base(2, Message.FeelerAdded, Message.FeelersFull) - { - } - - public void AppendTo(StringBuilder builder, char character) => AppendTo(builder, 10, 4, character); -} diff --git a/16_Bug/csharp/Parts/Head.cs b/16_Bug/csharp/Parts/Head.cs deleted file mode 100644 index d71355752..000000000 --- a/16_Bug/csharp/Parts/Head.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Text; -using BugGame.Resources; - -namespace BugGame.Parts; - -internal class Head : ParentPart -{ - private Feelers _feelers = new(); - - public Head() - : base(Message.HeadAdded, Message.HeadNotNeeded) - { - } - - public override bool IsComplete => _feelers.IsComplete; - - protected override bool TryAddCore(IPart part, out Message message) - => part switch - { - Feeler => _feelers.TryAddOne(out message), - _ => throw new NotSupportedException($"Can't add a {part.Name} to a {Name}.") - }; - - public void AppendTo(StringBuilder builder, char feelerCharacter) - { - if (IsPresent) - { - _feelers.AppendTo(builder, feelerCharacter); - builder - .AppendLine(" HHHHHHH") - .AppendLine(" H H") - .AppendLine(" H O O H") - .AppendLine(" H H") - .AppendLine(" H V H") - .AppendLine(" HHHHHHH"); - } - } -} diff --git a/16_Bug/csharp/Parts/IPart.cs b/16_Bug/csharp/Parts/IPart.cs deleted file mode 100644 index e325a7c17..000000000 --- a/16_Bug/csharp/Parts/IPart.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace BugGame.Parts; - -internal interface IPart -{ - string Name { get; } -} diff --git a/16_Bug/csharp/Parts/Leg.cs b/16_Bug/csharp/Parts/Leg.cs deleted file mode 100644 index c2d4aaaf5..000000000 --- a/16_Bug/csharp/Parts/Leg.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace BugGame.Parts; - -internal class Leg : IPart -{ - public string Name => nameof(Leg); -} diff --git a/16_Bug/csharp/Parts/Legs.cs b/16_Bug/csharp/Parts/Legs.cs deleted file mode 100644 index 0ed8d8fc7..000000000 --- a/16_Bug/csharp/Parts/Legs.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Text; -using BugGame.Resources; - -namespace BugGame.Parts; - -internal class Legs : PartCollection -{ - public Legs() - : base(6, Message.LegAdded, Message.LegsFull) - { - } - - public void AppendTo(StringBuilder builder) => AppendTo(builder, 6, 2, 'L'); -} diff --git a/16_Bug/csharp/Parts/Neck.cs b/16_Bug/csharp/Parts/Neck.cs deleted file mode 100644 index 23dacfb79..000000000 --- a/16_Bug/csharp/Parts/Neck.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Text; -using BugGame.Resources; - -namespace BugGame.Parts; - -internal class Neck : ParentPart -{ - private Head _head = new(); - - public Neck() - : base(Message.NeckAdded, Message.NeckNotNeeded) - { - } - - public override bool IsComplete => _head.IsComplete; - - protected override bool TryAddCore(IPart part, out Message message) - => part switch - { - Head => _head.TryAdd(out message), - Feeler => _head.TryAdd(part, out message), - _ => throw new NotSupportedException($"Can't add a {part.Name} to a {Name}.") - }; - - public void AppendTo(StringBuilder builder, char feelerCharacter) - { - if (IsPresent) - { - _head.AppendTo(builder, feelerCharacter); - builder.AppendLine(" N N").AppendLine(" N N"); - } - } -} diff --git a/16_Bug/csharp/Parts/ParentPart.cs b/16_Bug/csharp/Parts/ParentPart.cs deleted file mode 100644 index 1ca6682f3..000000000 --- a/16_Bug/csharp/Parts/ParentPart.cs +++ /dev/null @@ -1,27 +0,0 @@ -using BugGame.Resources; - -namespace BugGame.Parts; - -internal abstract class ParentPart : Part -{ - public ParentPart(Message addedMessage, Message duplicateMessage) - : base(addedMessage, duplicateMessage) - { - } - - public bool TryAdd(IPart part, out Message message) - => (part.GetType() == GetType(), IsPresent) switch - { - (true, _) => TryAdd(out message), - (false, false) => ReportDoNotHave(out message), - _ => TryAddCore(part, out message) - }; - - protected abstract bool TryAddCore(IPart part, out Message message); - - private bool ReportDoNotHave(out Message message) - { - message = Message.DoNotHaveA(this); - return false; - } -} diff --git a/16_Bug/csharp/Parts/Part.cs b/16_Bug/csharp/Parts/Part.cs deleted file mode 100644 index f29fbd81f..000000000 --- a/16_Bug/csharp/Parts/Part.cs +++ /dev/null @@ -1,34 +0,0 @@ -using BugGame.Resources; - -namespace BugGame.Parts; - -internal class Part : IPart -{ - private readonly Message _addedMessage; - private readonly Message _duplicateMessage; - - public Part(Message addedMessage, Message duplicateMessage) - { - _addedMessage = addedMessage; - _duplicateMessage = duplicateMessage; - } - - public virtual bool IsComplete => IsPresent; - - protected bool IsPresent { get; private set; } - - public string Name => GetType().Name; - - public bool TryAdd(out Message message) - { - if (IsPresent) - { - message = _duplicateMessage; - return false; - } - - message = _addedMessage; - IsPresent = true; - return true; - } -} diff --git a/16_Bug/csharp/Parts/PartCollection.cs b/16_Bug/csharp/Parts/PartCollection.cs deleted file mode 100644 index 9a0fd2eee..000000000 --- a/16_Bug/csharp/Parts/PartCollection.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Text; -using BugGame.Resources; - -namespace BugGame.Parts; - -internal class PartCollection -{ - private readonly int _maxCount; - private readonly Message _addedMessage; - private readonly Message _fullMessage; - private int _count; - - public PartCollection(int maxCount, Message addedMessage, Message fullMessage) - { - _maxCount = maxCount; - _addedMessage = addedMessage; - _fullMessage = fullMessage; - } - - public bool IsComplete => _count == _maxCount; - - public bool TryAddOne(out Message message) - { - if (_count < _maxCount) - { - _count++; - message = _addedMessage.ForValue(_count); - return true; - } - - message = _fullMessage; - return false; - } - - protected void AppendTo(StringBuilder builder, int offset, int length, char character) - { - if (_count == 0) { return; } - - for (var i = 0; i < length; i++) - { - builder.Append(' ', offset); - - for (var j = 0; j < _count; j++) - { - builder.Append(character).Append(' '); - } - builder.AppendLine(); - } - } -} diff --git a/16_Bug/csharp/Parts/Tail.cs b/16_Bug/csharp/Parts/Tail.cs deleted file mode 100644 index ebf4b28fa..000000000 --- a/16_Bug/csharp/Parts/Tail.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Text; -using BugGame.Resources; - -namespace BugGame.Parts; - -internal class Tail : Part -{ - public Tail() - : base(Message.TailAdded, Message.TailNotNeeded) - { - } - - public void AppendTo(StringBuilder builder) - { - if (IsPresent) - { - builder.AppendLine("TTTTTB B"); - } - } -} \ No newline at end of file diff --git a/16_Bug/csharp/Program.cs b/16_Bug/csharp/Program.cs deleted file mode 100644 index 883e62d18..000000000 --- a/16_Bug/csharp/Program.cs +++ /dev/null @@ -1,5 +0,0 @@ -using BugGame; -using Games.Common.IO; -using Games.Common.Randomness; - -new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); diff --git a/16_Bug/csharp/Resources/Instructions.txt b/16_Bug/csharp/Resources/Instructions.txt deleted file mode 100644 index bdbdadd35..000000000 --- a/16_Bug/csharp/Resources/Instructions.txt +++ /dev/null @@ -1,18 +0,0 @@ -The object of Bug is to finish your bug before I finish -mine. Each number stands for a part of the bug body. -I will roll the die for you, tell you what I rolled for you -what the number stands for, and if you can get the part. -If you can get the part I will give it to you. -The same will happen on my turn. -If there is a change in either bug I will give you the -option of seeing the pictures of the bugs. -The numbers stand for parts as follows: -Number Part Number of part needed - 1 Body 1 - 2 Neck 1 - 3 Head 1 - 4 Feelers 2 - 5 Tail 1 - 6 Legs 6 - - diff --git a/16_Bug/csharp/Resources/Introduction.txt b/16_Bug/csharp/Resources/Introduction.txt deleted file mode 100644 index e74a833e7..000000000 --- a/16_Bug/csharp/Resources/Introduction.txt +++ /dev/null @@ -1,8 +0,0 @@ - Bug - Creative Computing Morristown, New Jersey - - - -The Game Bug -I hope you enjoy this game. - diff --git a/16_Bug/csharp/Resources/Message.cs b/16_Bug/csharp/Resources/Message.cs deleted file mode 100644 index 20a59d9a8..000000000 --- a/16_Bug/csharp/Resources/Message.cs +++ /dev/null @@ -1,46 +0,0 @@ -using BugGame.Parts; - -namespace BugGame.Resources; - -internal class Message -{ - public static Message Rolled = new("rolled a {0}"); - - public static Message BodyAdded = new("now have a body."); - public static Message BodyNotNeeded = new("do not need a body."); - - public static Message NeckAdded = new("now have a neck."); - public static Message NeckNotNeeded = new("do not need a neck."); - - public static Message HeadAdded = new("needed a head."); - public static Message HeadNotNeeded = new("I do not need a head.", "You have a head."); - - public static Message TailAdded = new("I now have a tail.", "I now give you a tail."); - public static Message TailNotNeeded = new("I do not need a tail.", "You already have a tail."); - - public static Message FeelerAdded = new("I get a feeler.", "I now give you a feeler"); - public static Message FeelersFull = new("I have 2 feelers already.", "You have two feelers already"); - - public static Message LegAdded = new("now have {0} legs"); - public static Message LegsFull = new("I have 6 feet.", "You have 6 feet already"); - - public static Message Complete = new("bug is finished."); - - private Message(string common) - : this("I " + common, "You " + common) - { - } - - private Message(string i, string you) - { - I = i; - You = you; - } - - public string I { get; } - public string You { get; } - - public static Message DoNotHaveA(Part part) => new($"do not have a {part.Name}"); - - public Message ForValue(int quantity) => new(string.Format(I, quantity), string.Format(You, quantity)); -} \ No newline at end of file diff --git a/16_Bug/csharp/Resources/PlayAgain.txt b/16_Bug/csharp/Resources/PlayAgain.txt deleted file mode 100644 index 2380e1308..000000000 --- a/16_Bug/csharp/Resources/PlayAgain.txt +++ /dev/null @@ -1 +0,0 @@ -I hope you enjoyed the game, play it again soon!! diff --git a/16_Bug/csharp/Resources/Resource.cs b/16_Bug/csharp/Resources/Resource.cs deleted file mode 100644 index 2b34a4e67..000000000 --- a/16_Bug/csharp/Resources/Resource.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace BugGame.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Introduction => GetStream(); - public static Stream Instructions => GetStream(); - public static Stream PlayAgain => GetStream(); - } - - private static Stream GetStream([CallerMemberName] string? name = null) => - Assembly.GetExecutingAssembly() - .GetManifestResourceStream($"Bug.Resources.{name}.txt") - ?? throw new Exception($"Could not find embedded resource stream '{name}'."); -} \ No newline at end of file diff --git a/16_Bug/python/bug.py b/16_Bug/python/bug.py index 846002f8f..4d93c1581 100644 --- a/16_Bug/python/bug.py +++ b/16_Bug/python/bug.py @@ -36,6 +36,10 @@ def display(self) -> None: print_legs(self.legs) +def print_n_whitespaces(n: int) -> None: + print(" " * n, end="") + + def print_n_newlines(n: int) -> None: for _ in range(n): print() @@ -43,7 +47,7 @@ def print_n_newlines(n: int) -> None: def print_feelers(n_feelers: int, is_player: bool = True) -> None: for _ in range(4): - print(" " * 10, end="") + print_n_whitespaces(10) for _ in range(n_feelers): print("A " if is_player else "F ", end="") print() @@ -73,7 +77,7 @@ def print_body(has_tail: bool = False) -> None: def print_legs(n_legs: int) -> None: for _ in range(2): - print(" " * 5, end="") + print_n_whitespaces(5) for _ in range(n_legs): print(" L", end="") print() @@ -152,8 +156,10 @@ def handle_roll(diceroll: Literal[1, 2, 3, 4, 5, 6], state: State) -> bool: def main() -> None: - print(" " * 34 + "BUG") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print_n_whitespaces(34) + print("BUG") + print_n_whitespaces(15) + print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print_n_newlines(3) print("THE GAME BUG") diff --git a/16_Bug/python/bug_overengineered.py b/16_Bug/python/bug_overengineered.py new file mode 100644 index 000000000..bc12a3c3b --- /dev/null +++ b/16_Bug/python/bug_overengineered.py @@ -0,0 +1,350 @@ +""" +BUG (overengineered) + +Overengineered version of bug game +Demonstrates function-based Model View Controller pattern + +Ported by Peter Sharp +""" + +from collections import namedtuple +from random import randint +from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, TypedDict, Union + +PAGE_WIDTH = 64 + +OneParamFunc = Callable[[Any], Any] +TwoParamFunc = Callable[[Any, Any], Any] +StateFunctions = Tuple[OneParamFunc, OneParamFunc, TwoParamFunc] +Action = Literal["instructions", "game", "pictures", "won", "start", "exit"] + +Bodypart = namedtuple("Bodypart", ["name", "count", "depends"]) + +# body part types used by the game to work out whether a player's body part can be added +part_types = ( + Bodypart(name="BODY", count=1, depends=None), + Bodypart(name="NECK", count=1, depends=0), + Bodypart(name="HEAD", count=1, depends=1), + Bodypart(name="FEELERS", count=2, depends=2), + Bodypart(name="TAIL", count=1, depends=0), + Bodypart(name="LEGS", count=6, depends=0), +) + + +class DataDict(TypedDict): + state: Action + partNo: Optional[Any] + players: Dict[str, List[int]] + partTypes: Tuple[Bodypart, ...] + finished: List[Any] + logs: List[Any] + + +def game_loop(states: Dict[Action, StateFunctions], data: DataDict) -> None: + """ + Starts the game loop using given states and data + + Uses a modified version of the MVC (Model View Controller) pattern that uses functions instead of objects + + each state in the game has one of each of the following: + View, displays data + Control, converts raw command from user into something the model understands + Model, updates game data based on action received from controller + """ + + while True: + if data["state"] == "exit": + break + view, control, model = states[data["state"]] + cmd = view(data) + action = control(cmd) + data = model(data, action) + + +def print_start(_: Any) -> str: + """ + Prints start message + """ + print_centered("BUG") + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() + print("THE GAME BUG") + print("I HOPE YOU ENJOY THIS GAME.") + print() + return input("DO YOU WANT INSTRUCTIONS? ") + + +def control_start(cmd: str) -> str: + """ + Controls the start state + """ + if cmd.lower() in ("y", "yes"): + action = "instructions" + else: + action = "game" + return action + + +def print_instructions(data: DataDict) -> str: + """ + Prints game instructions + """ + 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("THE NUMBERS STAND FOR PARTS AS FOLLOWS:") + + print_table( + [ + ("NUMBER", "PART", "NUMBER OF PART NEEDED"), + *[ + (i + 1, part.name, part.count) + for i, part in enumerate(data["partTypes"]) + ], + ] + ) + print() + print() + return "" + + +def goto_game(_: Any) -> Literal["game"]: + return "game" + + +def update_state(data: DataDict, action: Action) -> DataDict: + """ + sets game state to given player value + """ + return {**data, "state": action} # type: ignore + + +def update_game(data: DataDict, action: Action) -> DataDict: + """ + Updates game data for player turns until one player successfully gets a body part + """ + # stores logs of what happened during a particular round + Log1 = Tuple[str, int, Any] + Log2 = Tuple[str, int, Any, Any] + logs: List[Union[Log1, Log2]] = [] + + if action == "pictures": + data["state"] = "pictures" + else: + part_added = False + while not part_added: + for player, parts in data["players"].items(): + # rolls the dice for a part + new_part_idx = randint(1, 6) - 1 + + # gets information about the picked part + part_type = data["partTypes"][new_part_idx] + + # gets the number of existing parts of that type the player has + part_count = parts[new_part_idx] + + logs.append(("rolled", new_part_idx, player)) + + # a new part can only be added if the player has the parts + # the new part depends on and doesn't have enough of the part already + overMaxParts = part_type.count < part_count + 1 + missing_part_dep = ( + part_type.depends is not None and parts[part_type.depends] == 0 + ) + + if not overMaxParts and not missing_part_dep: + # adds a new part + part_count += 1 + logs.append(("added", new_part_idx, player)) + part_added = True + elif missing_part_dep: + logs.append(("missingDep", new_part_idx, player, part_type.depends)) + if overMaxParts: + logs.append(("overMax", new_part_idx, player, part_count)) + + data["players"][player][new_part_idx] = part_count + data["logs"] = logs + + # checks if any players have finished their bug + finished = get_finished(data) + if len(finished) > 0: + # and sets the state to 'won' if that's the case + data["finished"] = finished + data["state"] = "won" + return data + + +def get_finished(data: DataDict) -> List[str]: + """ + Gets players who have finished their bugs + """ + total_parts = sum(part_type.count for part_type in data["partTypes"]) + finished = [] + for player, parts in data["players"].items(): + if sum(parts) == total_parts: + finished.append(player) + return finished + + +def print_game(data: DataDict) -> str: + """ + Displays the results of the game turn + """ + for log in data["logs"]: + code, part_idx, player, *logdata = log + part_type = data["partTypes"][part_idx] + + if code == "rolled": + print() + print(f"{player} ROLLED A {part_idx + 1}") + print(f"{part_idx + 1}={part_type.name}") + + elif code == "added": + if player == "YOU": + if part_type.name in ["FEELERS", "LEGS", "TAIL"]: + print(f"I NOW GIVE YOU A {part_type.name.replace('s', '')}.") + else: + print(f"YOU NOW HAVE A {part_type.name}.") + elif player == "I": + if part_type.name in ["BODY", "NECK", "TAIL"]: + print(f"I NOW HAVE A {part_type.name}.") + elif part_type.name == "FEELERS": + print("I GET A FEELER.") + + if part_type.count > 2: + print( + f"{player} NOW HAVE {data['players'][player][part_idx]} {part_type.name}" + ) + + elif code == "missingDep": + (dep_idx,) = logdata + dep = data["partTypes"][dep_idx] + print( + f"YOU DO NOT HAVE A {dep.name}" + if player == "YOU" + else f"I NEEDED A {dep.name}" + ) + + elif code == "overMax": + (part_count,) = logdata + if part_count > 1: + num = "TWO" if part_count == 2 else part_count + maxMsg = f"HAVE {num} {part_type.name}S ALREADY" + else: + maxMsg = f"ALREADY HAVE A {part_type.name}" + print(f"{player} {maxMsg}") + + return input("DO YOU WANT THE PICTURES? ") if len(data["logs"]) else "n" + + +def print_pictures(data: DataDict) -> None: + """ + Displays what the bugs look like for each player + """ + typeIxs = {part_type.name: idx for idx, part_type in enumerate(data["partTypes"])} + PIC_WIDTH = 22 + for player, parts in data["players"].items(): + print(f"*****{'YOUR' if player == 'YOU' else 'MY'} BUG*****") + print() + print() + if parts[typeIxs["BODY"]] > 0: + if parts[typeIxs["FEELERS"]] > 0: + F = " ".join(["F"] * parts[typeIxs["FEELERS"]]) + for _ in range(4): + print(" " * 9 + F) + if parts[typeIxs["HEAD"]] > 0: + print_centered("HHHHHHH", PIC_WIDTH) + print_centered("H H", PIC_WIDTH) + print_centered("H O O H", PIC_WIDTH) + print_centered("H H", PIC_WIDTH) + print_centered("H V H", PIC_WIDTH) + print_centered("HHHHHHH", PIC_WIDTH) + if parts[typeIxs["NECK"]] > 0: + for _ in range(2): + print_centered("N N", PIC_WIDTH) + print_centered("BBBBBBBBBBBB", PIC_WIDTH) + for _ in range(2): + print_centered("B B", PIC_WIDTH) + + if parts[typeIxs["TAIL"]] > 0: + print("TTTTTB B") + print_centered("BBBBBBBBBBBB", PIC_WIDTH) + if parts[typeIxs["LEGS"]] > 0: + L = "L" * parts[typeIxs["LEGS"]] + for _ in range(2): + print(" " * 5 + L) + print() + + +def control_game(cmd: str) -> Literal["pictures", "game"]: + """ + returns state based on command + """ + if cmd.lower() in ("y", "yes"): + action = "pictures" + else: + action = "game" + return action # type: ignore + + +def print_winner(data: DataDict) -> None: + """ + Displays the winning message + """ + for player in data["finished"]: + print(f"{'YOUR' if player == 'YOU' else 'MY'} BUG IS FINISHED.") + print("I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!") + + +def exit_game(_: Any) -> Literal["exit"]: + """Exist the game regardless of input""" + return "exit" + + +def print_centered(msg: str, width: int = PAGE_WIDTH) -> None: + """Print given message centered to given width.""" + spaces = " " * ((width - len(msg)) // 2) + print(spaces + msg) + + +def print_table(rows: List[Any]) -> None: + for row in rows: + print(*row, sep="\t") + + +def main() -> None: + # The main states in the game + states: Dict[Action, StateFunctions] = { + # Initial state of the game + "start": (print_start, control_start, update_state), + # displays game instructions + "instructions": (print_instructions, goto_game, update_state), + # the main game state + "game": (print_game, control_game, update_game), + # displays pictures before returning to game + "pictures": (print_pictures, goto_game, update_state), + # Displays the winning players and message + "won": (print_winner, exit_game, update_state), + } + + # all the data used by the game + data = DataDict( + state="start", + partNo=None, + players={"YOU": [0] * len(part_types), "I": [0] * len(part_types)}, + partTypes=part_types, + finished=[], + logs=[], + ) + game_loop(states, data) + + +if __name__ == "__main__": + main() diff --git a/16_Bug/python/test_bug.py b/16_Bug/python/test_bug.py new file mode 100644 index 000000000..0b5b008ab --- /dev/null +++ b/16_Bug/python/test_bug.py @@ -0,0 +1,25 @@ +import io +from typing import Callable + +import pytest +from _pytest.monkeypatch import MonkeyPatch + +from bug import main +from bug_overengineered import main as overengineered_main + + +@pytest.mark.parametrize( + "main", + [main, overengineered_main], +) +def test_main(monkeypatch: MonkeyPatch, main: Callable[[], None]) -> None: + monkeypatch.setattr("time.sleep", lambda n: n) + instructions = "Y" + pictures = "Y" + monkeypatch.setattr( + "sys.stdin", + io.StringIO( + f"{instructions}\n{pictures}\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\nN\n" + ), + ) + main() diff --git a/17_Bullfight/README.md b/17_Bullfight/README.md index b81aab0b7..cf331235c 100644 --- a/17_Bullfight/README.md +++ b/17_Bullfight/README.md @@ -26,6 +26,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -- 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. - -- Lines 1800-1820 (part of the pre-fight subroutine) can never be reached. +(please note any difficulties or challenges in porting here) diff --git a/17_Bullfight/java/Bullfight.java b/17_Bullfight/java/Bullfight.java deleted file mode 100644 index 16fe299c0..000000000 --- a/17_Bullfight/java/Bullfight.java +++ /dev/null @@ -1,466 +0,0 @@ -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/17_Bullfight/kotlin/src/bullfight/Main.kt b/17_Bullfight/kotlin/src/bullfight/Main.kt deleted file mode 100644 index 7a1a0681e..000000000 --- a/17_Bullfight/kotlin/src/bullfight/Main.kt +++ /dev/null @@ -1,356 +0,0 @@ -package bullfight - -import bullfight.Yorn.* -import kotlin.random.Random -import kotlin.system.exitProcess - -private val Boolean.asInteger get() = if (this) 1 else 2 -private val Float.squared: Float - get() = this * this -val fna: Boolean get() = RandomNumbers.nextBoolean() - -enum class Quality(private val typeName: String) { - Superb("SUPERB"), - Good("GOOD"), - Fair("FAIR"), - Poor("POOR"), - Awful("AWFUL"); - override fun toString() = typeName - - val level get() = (ordinal + 1).toFloat() -} - -enum class BullDeath(val factor: Float) { - Alive(1f), Dead(2f); -} - -var l = 1f -lateinit var bullQuality: Quality -var momentOfTruth = false -var picadoresSuccess = 0f -var toreadoresSuccess = 0f -var passNumber = 0f -var honor = 0f -var bullDeath = BullDeath.Alive - - -interface RandomNumberSource { - fun nextBoolean(): Boolean - fun nextInt(from: Int, until: Int): Int - fun nextFloat(): Float -} - -object RandomNumbers : RandomNumberSource { - override fun nextBoolean() = Random.nextBoolean() - override fun nextInt(from: Int, until: Int) = Random.nextInt(from, until) - override fun nextFloat() = Random.nextFloat() -} - - -fun main() { - intro() - instructions() - bullDeath = BullDeath.Alive - honor = 1f - - bullQuality = Quality.values()[RandomNumbers.nextInt(1, 6)] - println("YOU HAVE DRAWN A $bullQuality BULL.") - when (bullQuality) { - Quality.Superb -> println("GOOD LUCK. YOU'LL NEED IT.") - Quality.Awful -> println("YOU'RE LUCKY.") - else -> Unit - } - - picadoresSuccess = fight(FirstAct.picadores) - toreadoresSuccess = fight(FirstAct.toreadores) - println() - println() - - var gored: Boolean - - gameLoop@ do { - passNumber++ - println("PASS NUMBER ${passNumber.toInt()}") - gored = if (passNumber >= 3) { - print("HERE COMES THE BULL. TRY FOR A KILL") - killAttempt("CAPE MOVE") - } else { - println("THE BULL IS CHARGING AT YOU! YOU ARE THE MATADOR--") - print("DO YOU WANT TO KILL THE BULL") - killAttempt("WHAT MOVE DO YOU MAKE WITH THE CAPE") - } - - if (!gored) { - val move = restrictedInput( - values = Cape.values(), - errorMessage = "DON'T PANIC, YOU IDIOT! PUT DOWN A CORRECT NUMBER" - ) - val m = when (move) { - Cape.Veronica -> 3f - Cape.Outside -> 2f - Cape.Swirl -> 0.5f - } - - l += m - val f = - (6 - bullQuality.level + m / 10f) * RandomNumbers.nextFloat() / ((picadoresSuccess + toreadoresSuccess + passNumber / 10f) * 5f) - if (f < 0.51) - continue - } - - println("THE BULL HAS GORED YOU!") - goreLoop@ do { - when (fna) { - false -> { - println("YOU ARE DEAD.") - honor = 1.5f - gameResult() - } - - true -> { - println("YOU ARE STILL ALIVE.") - println() - print("DO YOU RUN FROM THE RING") - when (Yorn.input()) { - - YES -> { - println("COWARD") - honor = 0f - } - - NO -> { - println("YOU ARE BRAVE. STUPID, BUT BRAVE.") - when (fna) { - true -> { - honor = 2f - continue@gameLoop - } - - false -> { - println("YOU ARE GORED AGAIN!") - continue@goreLoop - } - } - } - } - - } - } - } while (true) - - } while (true) - -} - -fun fnd() = 4.5 + - l / 6 - - (picadoresSuccess + toreadoresSuccess) * 2.5 + - 4 * honor + - 2 * bullDeath.factor - - passNumber.squared / 120f - - bullQuality.level - -fun fnc() = fnd() * RandomNumbers.nextFloat() - -private fun killAttempt(capeMessage: String): Boolean { - when (Yorn.input()) { - - YES -> - when (momentOfTruth()) { - KillResult.Success -> gameResult() - KillResult.Fail -> return true - } - - NO -> - print(capeMessage) - - } - return false -} - -private fun gameResult() { - println() - println() - if (honor == 0f) { - println( - """ - THE CROWD BOOS FOR TEN MINUTES. IF YOU EVER DARE TO SHOW - YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU-- - UNLESS THE BULL DOES FIRST. - """.trimIndent() - ) - } else { - if (honor == 2f) - println("THE CROWD CHEERS WILDLY!") - else - if (bullDeath == BullDeath.Dead) { - println("THE CROWD CHEERS!") - println() - } - println("THE CROWD AWARDS YOU") - if (fnc() < 2.4) - println("NOTHING AT ALL.") - else if (fnc() < 4.9) - println("ONE EAR OF THE BULL.") - else - if (fnc() < 7.4) - println("BOTH EARS OF THE BULL!") - else - println("OLE! YOU ARE 'MUY HOMBRE'!! OLE! OLE!") - println() - } - println() - println("ADIOS") - println() - println() - println() - exitProcess(0) -} - -enum class KillResult { Success, Fail } - -fun momentOfTruth(): KillResult { - momentOfTruth = true - print( - """ - - IT IS THE MOMENT OF TRUTH. - - HOW DO YOU WANT TO KILL THE BULL - """.trimIndent() - ) - - val k = - (6 - bullQuality.level) * 10 * RandomNumbers.nextFloat() / ((picadoresSuccess + toreadoresSuccess) * 5 * passNumber) - - val chance = when (stdInput(KillMethod.values())) { - KillMethod.OverHorns -> .8 - KillMethod.Chest -> .2 - null -> { - println("YOU PANICKED. THE BULL GORED YOU.") - return KillResult.Fail - } - } - return if (k <= chance) { - println("YOU KILLED THE BULL!") - bullDeath = BullDeath.Dead - KillResult.Success - } else { - println("THE BULL HAS GORED YOU!") - KillResult.Fail - } -} - -interface InputOption { - val input: String -} - -enum class Cape(override val input: String) : InputOption { - Veronica("0"), - Outside("1"), - Swirl("2"), -} - -enum class KillMethod(override val input: String) : InputOption { - OverHorns("4"), - Chest("5"), -} - -private fun restrictedInput(values: Array, errorMessage: String): T { - do { - stdInput(values)?.let { return it } - println(errorMessage) - } while (true) -} - -private fun stdInput(values: Array): T? { - print("? ") - val z1 = readln() - return values.firstOrNull { z1 == it.input } -} - -enum class Yorn(override val input: String) : InputOption { - YES("YES"), NO("NO"); - - companion object { - fun input(): Yorn { - return restrictedInput(values(), "YES OR NO") - } - } -} - -enum class FirstAct(val str: String) { - picadores("PICADORES"), toreadores("TOREADORES"); - - override fun toString() = str -} - -fun fight(firstAct: FirstAct): Float { - - val b = 3.0 / bullQuality.level * RandomNumbers.nextFloat() - val firstActQuality = when { - b < .37 -> Quality.Awful - b < .5 -> Quality.Poor - b < .63 -> Quality.Fair - b < .87 -> Quality.Good - else -> Quality.Superb - } - val c = firstActQuality.level / 10f - val t = firstActQuality.level - println("THE $firstAct DID A $firstActQuality JOB.") - - if (t >= 4f) { - if (t == 5f) { - if (firstAct != FirstAct.toreadores) { - println("${fna.asInteger} OF THE HORSES OF THE $firstAct KILLED.") - } - println("${fna.asInteger} OF THE $firstAct KILLED.") - } else { - println( - when (fna) { - true -> "ONE OF THE $firstAct WAS KILLED." - false -> "NO $firstAct WERE KILLED." - } - ) - } - } - println() - - return c -} - -private fun instructions() { - print("DO YOU WANT INSTRUCTIONS? ") - if (readln().trim() != "NO") { - println("HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS.") - println("HERE IS YOUR BIG CHANCE TO KILL A BULL.") - println() - println("ON EACH PASS OF THE BULL, YOU MAY TRY") - println("0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)") - println("1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE") - println("2 - ORDINARY SWIRL OF THE CAPE.") - println() - println("INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL") - println("ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST).") - println("BUT IF I WERE YOU,") - println("I WOULDN'T TRY IT BEFORE THE SEVENTH PASS.") - println() - println("THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE") - println("(POSTHUMOUSLY IF NECESSARY).") - println("THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE.") - println() - println("THE BETTER THE JOB THE PICADORES AND TOREADORES DO,") - println("THE BETTER YOUR CHANCES ARE.") - } - repeat(2) { - println() - } -} - -fun intro() { - println(" ".repeat(34) + "BULL") - println(" ".repeat(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - println() - println() - println() -} diff --git a/17_Bullfight/python/bullfight.py b/17_Bullfight/python/bullfight.py index 32a6ac107..0c85ae1ea 100644 --- a/17_Bullfight/python/bullfight.py +++ b/17_Bullfight/python/bullfight.py @@ -3,6 +3,10 @@ from typing import Dict, List, Literal, Tuple, Union +def print_n_whitespaces(n: int) -> None: + print(" " * n, end="") + + def print_n_newlines(n: int) -> None: for _ in range(n): print() @@ -29,8 +33,11 @@ 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]): + player_was_killed = random.choice([True, False]) + if player_was_killed: 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) @@ -66,8 +73,10 @@ def calculate_final_score( def print_header() -> None: - print(" " * 34 + "BULL") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print_n_whitespaces(34) + print("BULL") + print_n_whitespaces(15) + print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print_n_newlines(2) @@ -103,10 +112,10 @@ def print_intro() -> None: def ask_bool(prompt: str) -> bool: while True: - answer = input(prompt).lower() - if answer == "yes": + answer = input(prompt) + if answer == "YES": return True - elif answer == "no": + elif answer == "NO": return False else: print("INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'.") @@ -174,13 +183,12 @@ def handle_bullkill_attempt( * job_quality_by_round[3] ) ) - if ( - kill_method == 4 - and kill_probability > 0.8 - or kill_method != 4 - and kill_probability > 0.2 - ): - gore = 1 + if kill_method == 4: + if kill_probability > 0.8: + gore = 1 + else: + if kill_probability > 0.2: + gore = 1 if gore == 0: print("YOU KILLED THE BULL!") job_quality_by_round[5] = 2 @@ -252,7 +260,7 @@ def main() -> None: # Round 3 job_quality_by_round[3] = 0 while True: - job_quality_by_round[3] += 1 + job_quality_by_round[3] = 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? ") @@ -297,13 +305,8 @@ def main() -> None: print("YOU ARE STILL ALIVE.") print() print("DO YOU RUN FROM THE RING? ", end="") - if run_from_ring := ask_bool("DO YOU RUN FROM THE RING? "): - print("COWARD") - job_quality_by_round[4] = 0 - death = True - break - - else: + run_from_ring = ask_bool("DO YOU RUN FROM THE RING? ") + if not run_from_ring: print("YOU ARE BRAVE. STUPID, BUT BRAVE.") if random.randint(1, 2) == 1: job_quality_by_round[4] = 2 @@ -311,6 +314,12 @@ 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/17_Bullfight/python/test_bullfight.py b/17_Bullfight/python/test_bullfight.py new file mode 100644 index 000000000..f61c6b65d --- /dev/null +++ b/17_Bullfight/python/test_bullfight.py @@ -0,0 +1,16 @@ +import io + +from _pytest.monkeypatch import MonkeyPatch +from bullfight import main + + +def test_main(monkeypatch: MonkeyPatch) -> None: + instructions = "Y" + kill_bull = "YES" + kill_method = "0" + run_from_ring = "YES" + monkeypatch.setattr( + "sys.stdin", + io.StringIO(f"{instructions}\n{kill_bull}\n{kill_method}\n{run_from_ring}\n"), + ) + main() diff --git a/18_Bullseye/python/bullseye.py b/18_Bullseye/python/bullseye.py index df931f35c..490a08984 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 not winners: + while len(winners) == 0: 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 in {1, 2, 3}: - break - else: + if throw not in [1, 2, 3]: print("INPUT 1, 2, OR 3!") + else: + break if throw == 1: probability_1 = 0.65 probability_2 = 0.55 @@ -99,11 +99,10 @@ def main() -> None: points = 0 player.score += points print(f"TOTAL SCORE = {player.score}") - winners.extend( - player_index - for player_index, player in enumerate(players) - if player.score > 200 - ) + for player_index, player in enumerate(players): + if player.score > 200: + winners.append(player_index) + print_outro(players, winners) diff --git a/18_Bullseye/python/test_bullseye.py b/18_Bullseye/python/test_bullseye.py new file mode 100644 index 000000000..d3d0735f9 --- /dev/null +++ b/18_Bullseye/python/test_bullseye.py @@ -0,0 +1,13 @@ +import io + +from _pytest.monkeypatch import MonkeyPatch +from bullseye import main + + +def test_main(monkeypatch: MonkeyPatch) -> None: + nb_players = 1 + monkeypatch.setattr( + "sys.stdin", + io.StringIO(f"{nb_players}\nMartin\n3\n2\n1" + ("\n2" * 21)), + ) + main() diff --git a/18_Bullseye/rust/Cargo.lock b/18_Bullseye/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/18_Bullseye/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/18_Bullseye/rust/Cargo.toml b/18_Bullseye/rust/Cargo.toml deleted file mode 100644 index 1c2935d47..000000000 --- a/18_Bullseye/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" \ No newline at end of file diff --git a/18_Bullseye/rust/README.md b/18_Bullseye/rust/README.md deleted file mode 100644 index f84e546c2..000000000 --- a/18_Bullseye/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) \ No newline at end of file diff --git a/18_Bullseye/rust/src/lib.rs b/18_Bullseye/rust/src/lib.rs deleted file mode 100644 index cb70ea163..000000000 --- a/18_Bullseye/rust/src/lib.rs +++ /dev/null @@ -1,223 +0,0 @@ -/* - lib.rs contains all the logic of the program -*/ - -use std::{error::Error, fmt::Display, str::FromStr, io::{self, Write}}; - -use rand::Rng; - -/// handles setup for the game -pub struct Config { - players: Vec, -} -impl Config { - /// creates and returns a new Config from user input - pub fn new() -> Result> { - //DATA - let mut config: Config = Config { players: Vec::new() }; - let num_players: usize; - - //get data from user input - - //get num players - //input looop - num_players = loop { - match get_number_from_input("HOW MANY PLAYERS? ", 1, 0) { - Ok(num) => break num, - Err(e) => { - println!("{}",e); - continue; - }, - } - }; - - //get names of all players - for id in 1..=num_players { - let name = get_string_from_user_input( format!("NAME OF PLAYER#{}: ", id).as_str())?; - config.players.push(Player::from(&name)); - } - - //return new config - return Ok(config); - } -} -pub struct Player { - name: String, - score: usize, -} -impl Player { - fn from(name: &str) -> Player { - return Player { name: String::from(name), score: 0 }; - } -} - -/// run the program -pub fn run(config: &mut Config) -> Result<(), Box> { - //DATA - let mut round = 1; - let mut rng = rand::thread_rng(); - - //gameloop - loop { - //print round - println!(""); - println!(""); - println!("ROUND {}", round); - println!("---------"); - - //each players play - for player in config.players.iter_mut() { - //prompt user for players move - //input loop - let throw = loop { - match get_number_from_input( format!("{}'S THROW (input 1, 2, or 3): ", player.name).as_str(), 1, 3) { - Ok(t) => break t, - Err(err) => { - println!("{}", err); - continue; - }, - }; - }; - - //get probabilities of the various outcomes based on the throw - let p_bullseye; - let p_30_point_zone; - let p_20_point_zone; - let p_10_point_zone; - match throw { - 1 => { - p_bullseye = 0.65; - p_30_point_zone = 0.55; - p_20_point_zone = 0.5; - p_10_point_zone = 0.5; - }, - 2 => { - p_bullseye = 0.99; - p_30_point_zone = 0.77; - p_20_point_zone = 0.43; - p_10_point_zone = 0.01; - }, - _ => { - p_bullseye = 0.95; - p_30_point_zone = 0.75; - p_20_point_zone = 0.45; - p_10_point_zone = 0.05; - }, - } - - //determine results - let roll = rng.gen::(); - if roll >= p_bullseye{ - println!("BULLSEYE!! 40 POINTS!"); - player.score += 40; - } else if roll >= p_30_point_zone { - println!("30-POINT ZONE!"); - player.score += 30; - } else if roll >= p_20_point_zone { - println!("20-POINT ZONE"); - player.score += 20; - } else if roll >= p_10_point_zone { - println!("WHEW! 10 POINTS."); - player.score += 10; - } else { - println!("MISSED THE TARGET! TOO BAD."); - } - - //print their score - println!("TOTAL SCORE = {}", player.score); - } - - //stuff to do before next round - if config.players.iter().any(|player| player.score >= 200) { - //print congradulations and scores - println!("\nWE HAVE A WINNER!!\n"); - for player in config.players.iter() { - println!("{} SCORED {} POINTS", player.name, player.score); - } - //exit loop - break; - } else { - //otherwise do another round - round += 1; - } - } - - - - - //return to main - Ok(()) -} - -/// gets a string from user input -fn get_string_from_user_input(prompt: &str) -> Result> { - //DATA - let mut raw_input = String::new(); - - //print prompt - print!("{}", prompt); - //make sure it's printed before getting input - io::stdout().flush().unwrap(); - - //read user input from standard input, and store it to raw_input, then return it or an error as needed - raw_input.clear(); //clear input - match io::stdin().read_line(&mut raw_input) { - Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())), - Err(err) => return Err(format!("ERROR: CANNOT READ INPUT!: {}", err).into()), - } -} - -/// generic function to get a number from the passed string (user input) -/// pass a min lower than the max to have minimun and maximun bounds -/// pass a min higher than the max to only have a minumum bound -/// pass a min equal to the max to only have a maximun bound -/// -/// Errors: -/// no number on user input -fn get_number_from_input(prompt: &str, min:T, max:T) -> Result> { - //DATA - let raw_input: String; - let processed_input: String; - - - //input looop - raw_input = loop { - match get_string_from_user_input(prompt) { - Ok(input) => break input, - Err(e) => { - eprintln!("{}",e); - continue; - }, - } - }; - - //filter out num-numeric characters from user input - processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect(); - - //from input, try to read a number - match processed_input.trim().parse() { - Ok(i) => { - //what bounds must the input fall into - if min < max { //have a min and max bound: [min,max] - if i >= min && i <= max {//is input valid, within bounds - return Ok(i); //exit the loop with the value i, returning it - } else { //print error message specific to this case - return Err(format!("ONLY BETWEEN {} AND {}, PLEASE!", min, max).into()); - } - } else if min > max { //only a min bound: [min, infinity) - if i >= min { - return Ok(i); - } else { - return Err(format!("NO LESS THAN {}, PLEASE!", min).into()); - } - } else { //only a max bound: (-infinity, max] - if i <= max { - return Ok(i); - } else { - return Err(format!("NO MORE THAN {}, PLEASE!", max).into()); - } - } - }, - Err(_e) => return Err(format!("Error: couldn't find a valid number in {}",raw_input).into()), - } -} diff --git a/18_Bullseye/rust/src/main.rs b/18_Bullseye/rust/src/main.rs deleted file mode 100644 index 2e92f7506..000000000 --- a/18_Bullseye/rust/src/main.rs +++ /dev/null @@ -1,54 +0,0 @@ -/* - The responsibilities that remain in the main function after separating concerns - should be limited to the following: - - Setting up any configuration - - Calling a run function in lib.rs - - Handling the error if run returns an error -*/ - -use std::process; //allows for some better error handling - -mod lib; -use lib::Config; - -/// main function -fn main() { - //greet user - welcome(); - - // set up other configuration - let mut config = Config::new().unwrap_or_else(|err| { - eprintln!("Problem configuring program: {}", err); - process::exit(1); - }); - - // run the program - if let Err(e) = lib::run(&mut config) { - eprintln!("Application Error: {}", e); //use the eprintln! macro to output to standard error - process::exit(1); //exit the program with an error code - } - - //end of program - println!("THANKS FOR PLAYING!"); -} - -/// prints the welcome/start message -fn welcome() { - println!(" - BULLSEYE - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - - - - IN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET - WITH 10, 20, 30, AND 40 POINT ZONES. THE OBJECTIVE IS - TO GET 200 POINTS. - - | Throw | Description | Probable Score | - |-------|--------------------|---------------------------| - | 1 | Fast overarm | Bullseye or complete miss | - | 2 | Controlled overarm | 10, 20, or 30 points | - | 3 | Underarm | Anything | - - "); -} diff --git a/18_Bullseye/rust/src/note on separation of converns for rust projects.md b/18_Bullseye/rust/src/note on separation of converns for rust projects.md deleted file mode 100644 index 04e540f4b..000000000 --- a/18_Bullseye/rust/src/note on separation of converns for rust projects.md +++ /dev/null @@ -1,16 +0,0 @@ - # Separation of concerns for Binary Projects - -The organizational problem of allocating responsibility for multiple tasks to the main function is common to many projects. As a result, the Rust community has developed a process to use as a guideline for splitting the separate concerns of a binary program when main starts getting large. - - ## The process has the following steps: - - Split your program into a main.rs and a lib.rs and move your program’s logic to lib.rs. - - As long as your command line logic is small, it can remain in main.rs. - - When the command line logic starts getting complicated, extract it from main.rs and move it to lib.rs. - - ## The responsibilities that remain in the main function after this process should be limited to the following: - - Calling the command line or input parsing logic with the argument values - - Setting up any other configuration - - Calling a run function in lib.rs - - Handling the error if run returns an error - -This pattern is about separating concerns: main.rs handles running the program, and lib.rs handles all the logic of the task at hand. Because you can’t test the main function directly, this structure lets you test all of your program’s logic by moving it into functions in lib.rs. The only code that remains in main.rs will be small enough to verify its correctness by reading it. \ No newline at end of file diff --git a/19_Bunny/python/bunny.py b/19_Bunny/python/bunny.py index 31b09eb39..e6e267cff 100755 --- a/19_Bunny/python/bunny.py +++ b/19_Bunny/python/bunny.py @@ -1,21 +1,258 @@ #!/usr/bin/env python3 -import json - # This data is meant to be read-only, so we are storing it in a tuple -with open("data.json") as f: - DATA = tuple(json.load(f)) +DATA = ( + 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, +) -def print_intro() -> None: - print(" " * 33 + "BUNNY") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") +def display_intro() -> None: + print(tab(33) + "BUNNY") + print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print("\n\n") -def main() -> None: - print_intro() +def tab(column) -> str: + """Emulates the TAB command in BASIC. Returns a string with ASCII + codes for setting the cursor to the specified column.""" + return f"\r\33[{column}C" + + +def play() -> None: + display_intro() # Using an iterator will give us a similar interface to BASIC's READ # command. Instead of READ, we will call 'next(data)' to fetch the next element. @@ -49,7 +286,7 @@ def main() -> None: # position of a line segment. start = command # Position cursor at start - print(" " * start, end="") + print(tab(start), end="") # The following number, indicates the end of the segment. end = next(data) @@ -61,4 +298,4 @@ def main() -> None: if __name__ == "__main__": - main() + play() diff --git a/19_Bunny/python/data.json b/19_Bunny/python/data.json deleted file mode 100644 index 9e6ae9025..000000000 --- a/19_Bunny/python/data.json +++ /dev/null @@ -1,235 +0,0 @@ -[ - 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 -] diff --git a/19_Bunny/rust/Cargo.toml b/19_Bunny/rust/Cargo.toml deleted file mode 100644 index 7d75412a6..000000000 --- a/19_Bunny/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[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 deleted file mode 100644 index 4eb9b7316..000000000 --- a/19_Bunny/rust/src/main.rs +++ /dev/null @@ -1,114 +0,0 @@ -/** 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 -} - diff --git a/20_Buzzword/lua/buzzword.lua b/20_Buzzword/lua/buzzword.lua deleted file mode 100644 index aacfe5b29..000000000 --- a/20_Buzzword/lua/buzzword.lua +++ /dev/null @@ -1,81 +0,0 @@ ---- Buzzword ---- Ported by Brian Wilkins. ---- Updated for modern buzzwords and corporate-speak - -print [[ - BUZZWORD GENERATOR - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - -]] - -print [[ - - -THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN -'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS -AND SPEECHES. WHENEVER A QUESTION MARK IS PRINTED, -TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT. -]] - -local phraseList = {"ABILITY","BASAL","BEHAVIORAL","CHILD-CENTERED", - "DIFFERENTIATED","DISCOVERY","FLEXIBLE","HETEROGENEOUS", - "HOMOGENEOUS","MANIPULATIVE","MODULAR","TAVISTOCK", - "INDIVIDUALIZED","LEARNING","EVALUATIVE","OBJECTIVE", - "COGNITIVE","ENRICHMENT","SCHEDULING","HUMANISTIC", - "INTEGRATED","NON-GRADED","TRAINING","VERTICAL AGE", - "MOTIVATIONAL","CREATIVE","GROUPING","MODIFICATION", - "ACCOUNTABILITY","PROCESS","CORE CURRICULUM","ALGORITHM", - "PERFORMANCE","REINFORCEMENT","OPEN CLASSROOM","RESOURCE", - "STRUCTURE","FACILITY","ENVIRONMENT"} - ---- Credit to https://stackoverflow.com/a/33468353/19232282 ---- for the pickPhrase function -local copyPhraseList = {} - -function pickPhrase() - local i - -- make a copy of the original table if we ran out of phrases - if #copyPhraseList == 0 then - for k,v in pairs(phraseList) do - copyPhraseList[k] = v - end - end - - -- pick a random element from the copy - i = math.random(#copyPhraseList) - phrase = copyPhraseList[i] - - -- remove phrase from copy - table.remove(copyPhraseList, i) - - return phrase -end - ---- Reused from Bagels.lua -function getInput(prompt) - io.write(prompt) - io.flush() - local input = io.read("l") - if not input then --- test for EOF - print("COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!") - os.exit(0) - end - return input -end - -for i=1,3,1 do - ::phrasepick:: - io.write (pickPhrase() .. " ") - io.write (pickPhrase() .. " ") - io.write (pickPhrase()) - print() - io.stdin:flush() - local response = getInput("? ") - if response:match("[yY].*") then - goto phrasepick - else - print("COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!") - os.exit(0) - end -end - diff --git a/20_Buzzword/python/buzzword.py b/20_Buzzword/python/buzzword.py index 48552edc1..820b89df4 100644 --- a/20_Buzzword/python/buzzword.py +++ b/20_Buzzword/python/buzzword.py @@ -1,28 +1,30 @@ -""" -Buzzword Generator - -From: BASIC Computer Games (1978) - Edited by David H. Ahl - -"This program is an invaluable aid for preparing speeches and - briefings about education technology. This buzzword generator - provides sets of three highly-acceptable words to work into your - material. Your audience will never know that the phrases don't - really mean much of anything because they sound so great! Full - instructions for running are given in the program. - -"This version of Buzzword was written by David Ahl." - - -Python port by Jeff Jetton, 2019 -""" +###################################################################### +# +# Buzzword Generator +# +# From: BASIC Computer Games (1978) +# Edited by David H. Ahl +# +# "This program is an invaluable aid for preparing speeches and +# briefings about education technology. This buzzword generator +# provides sets of three highly-acceptable words to work into your +# material. Your audience will never know that the phrases don't +# really mean much of anything because they sound so great! Full +# instructions for running are given in the program. +# +# "This version of Buzzword was written by David Ahl." +# +# +# Python port by Jeff Jetton, 2019 +# +###################################################################### import random def main() -> None: - words = [ + WORDS = [ [ "Ability", "Basal", @@ -83,13 +85,13 @@ def main() -> None: still_running = True while still_running: phrase = "" - for section in words: + for section in WORDS: if len(phrase) > 0: phrase += " " phrase += section[random.randint(0, len(section) - 1)] print(phrase) - print() + print("") response = input("? ") try: diff --git a/20_Buzzword/rust/Cargo.lock b/20_Buzzword/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/20_Buzzword/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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.toml b/20_Buzzword/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/20_Buzzword/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/20_Buzzword/rust/README.md b/20_Buzzword/rust/README.md deleted file mode 100644 index fc6468b9f..000000000 --- a/20_Buzzword/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index dae4b8198..000000000 --- a/20_Buzzword/rust/src/main.rs +++ /dev/null @@ -1,112 +0,0 @@ -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! -// -///////////////////////////////////////////////////////////////////////// diff --git a/21_Calendar/README.md b/21_Calendar/README.md index 5f5b04eac..05c3ab965 100644 --- a/21_Calendar/README.md +++ b/21_Calendar/README.md @@ -24,6 +24,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -- 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. +(please note any difficulties or challenges in porting here) diff --git a/21_Calendar/python/calendar.py b/21_Calendar/python/calendar.py index 5c59e37e3..29faff015 100644 --- a/21_Calendar/python/calendar.py +++ b/21_Calendar/python/calendar.py @@ -1,23 +1,24 @@ -""" -Calendar - -From: BASIC Computer Games (1978) - Edited by David Ahl# - - This program prints out a calendar -for any year. You must specify the -starting day of the week of the year in -statement 130. (Sunday(0), Monday -(-1), Tuesday(-2), etc.) You can determine -this by using the program WEEKDAY. -You must also make two changes -for leap years in statement 360 and 620. -The program listing describes the necessary -changes. Running the program produces a -nice 12-month calendar. - The program was written by Geofrey -Chase of the Abbey, Portsmouth, Rhode Island. -""" +######################################################## +# Calendar +# +# From: BASIC Computer Games (1978) +# Edited by David Ahl# +# +# This program prints out a calendar +# for any year. You must specify the +# starting day of the week of the year in +# statement 130. (Sunday(0), Monday +# (-1), Tuesday(-2), etc.) You can determine +# this by using the program WEEKDAY. +# You must also make two changes +# for leap years in statement 360 and 620. +# The program listing describes the necessary +# changes. Running the program produces a +# nice 12-month calendar. +# The program was written by Geofrey +# Chase of the Abbey, Portsmouth, Rhode Island. +# +######################################################## from typing import Tuple @@ -44,7 +45,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: + for day_k in days_mapping.keys(): if weekday.lower() in day_k: day = days_mapping[day_k] correct_day_input = True @@ -64,7 +65,7 @@ def parse_input() -> Tuple[int, bool]: return day, leap_day -def calendar(weekday: int, leap_year: bool) -> None: +def calendar(weekday, leap_year): """ function to print a year's calendar. @@ -103,8 +104,9 @@ def calendar(weekday: int, leap_year: bool) -> None: for n in range(1, 13): days_count += months_days[n - 1] print( - f"** {days_count} ****************** {months_names[n - 1]} " - f"****************** {years_day - days_count} **\n" + "** {} ****************** {} ****************** {} **\n".format( + days_count, months_names[n - 1], years_day - days_count + ) ) print(days) print(sep) @@ -119,7 +121,7 @@ def calendar(weekday: int, leap_year: bool) -> None: break if d2 <= 0: - print(" ", end=" ") + print("{}".format(" "), end=" ") elif d2 < 10: print(f" {d2}", end=" ") else: @@ -149,6 +151,8 @@ def main() -> None: if __name__ == "__main__": main() +######################################################## +# ######################################################## # # Porting notes: diff --git a/21_Calendar/rust/Cargo.lock b/21_Calendar/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/21_Calendar/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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/21_Calendar/rust/Cargo.toml b/21_Calendar/rust/Cargo.toml deleted file mode 100644 index 1ec696335..000000000 --- a/21_Calendar/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/21_Calendar/rust/README.md b/21_Calendar/rust/README.md deleted file mode 100644 index e616424e3..000000000 --- a/21_Calendar/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) by [Uğur Küpeli](https://github.com/ugurkupeli) \ No newline at end of file diff --git a/21_Calendar/rust/src/main.rs b/21_Calendar/rust/src/main.rs deleted file mode 100644 index a279f95d4..000000000 --- a/21_Calendar/rust/src/main.rs +++ /dev/null @@ -1,152 +0,0 @@ -use std::io::stdin; - -const WIDTH: usize = 64; -const DAYS_WIDTH: usize = WIDTH / 8; -const MONTH_WIDTH: usize = WIDTH - (DAYS_WIDTH * 2); -const DAY_NUMS_WIDTH: usize = WIDTH / 7; - -const DAYS: [&str; 7] = [ - "SUNDAY", - "MONDAY", - "TUESDAY", - "WEDNESDAY", - "THURSDAY", - "FRIDAY", - "SATURDAY", -]; - -fn main() { - println!("\n\t\t CALENDAR"); - println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); - - let (starting_day, leap_year) = prompt(); - let (months, total_days) = get_months_and_days(leap_year); - - let mut days_passed = 0; - let mut current_day_index = DAYS.iter().position(|d| *d == starting_day).unwrap(); - - for (month, days) in months { - print_header(month, days_passed, total_days - days_passed); - print_days(&mut current_day_index, days); - days_passed += days as u16; - println!("\n"); - } -} - -fn prompt() -> (String, bool) { - let mut day = String::new(); - - loop { - println!("\nFirst day of the year?"); - if let Ok(_) = stdin().read_line(&mut day) { - day = day.trim().to_uppercase(); - if DAYS.contains(&day.as_str()) { - break; - } else { - day.clear(); - } - } - } - - let mut leap = false; - - loop { - println!("Is this a leap year?"); - let mut input = String::new(); - if let Ok(_) = stdin().read_line(&mut input) { - match input.to_uppercase().trim() { - "Y" | "YES" => { - leap = true; - break; - } - "N" | "NO" => break, - _ => (), - } - } - } - - println!(); - (day, leap) -} - -fn get_months_and_days(leap_year: bool) -> (Vec<(String, u8)>, u16) { - let months = [ - "JANUARY", - "FEBUARY", - "MARCH", - "APRIL", - "MAY", - "JUNE", - "JULY", - "AUGUST", - "SEPTEMBER", - "OCTOBER", - "NOVEMBER", - "DECEMBER", - ]; - - let mut months_with_days = Vec::new(); - let mut total_days: u16 = 0; - - for (i, month) in months.iter().enumerate() { - let days = if i == 1 { - if leap_year { - 29u8 - } else { - 28 - } - } else if if i < 7 { (i % 2) == 0 } else { (i % 2) != 0 } { - 31 - } else { - 30 - }; - - total_days += days as u16; - months_with_days.push((month.to_string(), days)); - } - - (months_with_days, total_days) -} - -fn print_between(s: String, w: usize, star: bool) { - let s = format!(" {s} "); - if star { - print!("{:*^w$}", s); - return; - } - print!("{:^w$}", s); -} - -fn print_header(month: String, days_passed: u16, days_left: u16) { - print_between(days_passed.to_string(), DAYS_WIDTH, true); - print_between(month.to_string(), MONTH_WIDTH, true); - print_between(days_left.to_string(), DAYS_WIDTH, true); - println!(); - - for d in DAYS { - let d = d.chars().nth(0).unwrap(); - print_between(d.to_string(), DAY_NUMS_WIDTH, false); - } - println!(); - - println!("{:*>WIDTH$}", ""); -} - -fn print_days(current_day_index: &mut usize, days: u8) { - let mut current_date = 1u8; - - print!("{:>w$}", " ", w = DAY_NUMS_WIDTH * *current_day_index); - - for _ in 1..=days { - print_between(current_date.to_string(), DAY_NUMS_WIDTH, false); - - if ((*current_day_index + 1) % 7) == 0 { - *current_day_index = 0; - println!(); - } else { - *current_day_index += 1; - } - - current_date += 1; - } -} diff --git a/22_Change/python/change.py b/22_Change/python/change.py index 14ee4d4f5..bba5a8604 100644 --- a/22_Change/python/change.py +++ b/22_Change/python/change.py @@ -16,17 +16,23 @@ def print_centered(msg: str) -> None: def print_header(title: str) -> None: print_centered(title) - print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() def print_introduction() -> None: print("I, YOUR FRIENDLY MICROCOMPUTER, WILL DETERMINE") - print("THE CORRECT CHANGE FOR ITEMS COSTING UP TO $100.\n\n") + print("THE CORRECT CHANGE FOR ITEMS COSTING UP TO $100.") + print() + print() -def pennies_to_dollar_string(p: float) -> str: +def pennies_to_dollar_string(p): d = p / 100 - return f"${d:0.2f}" + ds = f"${d:0.2f}" + return ds def compute_change() -> None: @@ -88,13 +94,19 @@ def compute_change() -> None: print(f"{change_in_pennies} PENNY(S)") +def print_thanks() -> None: + print("THANK YOU, COME AGAIN.") + print() + print() + + def main() -> None: print_header("CHANGE") print_introduction() while True: compute_change() - print("THANK YOU, COME AGAIN.\n\n") + print_thanks() if __name__ == "__main__": diff --git a/22_Change/rust/Cargo.lock b/22_Change/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/22_Change/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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/23_Checkers/README.md b/23_Checkers/README.md index f2263df51..1d9143ca2 100644 --- a/23_Checkers/README.md +++ b/23_Checkers/README.md @@ -24,6 +24,5 @@ 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, and may make a number - other illegal moves (jumping their own pieces, jumping empty squares, etc.). + - Human players are not required to jump if it is possible. - Curious writing to "I" variable without ever reading it. (See lines 1700 and 1806) diff --git a/23_Checkers/perl/README.md b/23_Checkers/perl/README.md index 4323cf4ad..e69c8b819 100644 --- a/23_Checkers/perl/README.md +++ b/23_Checkers/perl/README.md @@ -1,9 +1,3 @@ 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 deleted file mode 100755 index 46b8f2d4c..000000000 --- a/23_Checkers/perl/checkers.pl +++ /dev/null @@ -1,351 +0,0 @@ -#!/usr/bin/perl - -# Checkers 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 @ratings = (-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 @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 $neg1 = -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"; -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 = (); -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) - { - $board[$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 ($board[$x][$y] > -1); - - # If this is one of my ordinary pieces, analyze possible - # forward moves. - if ($board[$x][$y] == -1) - { - for (my $a = -1 ; $a <= 1 ; $a +=2) - { - $b = $neg1; - find_move($x, $y, $a, $b); - } - } - - # If this is one of my kings, analyze possible forward - # and backward moves. - if ($board[$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 ($ratings[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 $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 ($ratings[4] == 0) - { - $board[$ratings[3]][$ratings[4]] = -2; - last LOOP1240; - } - $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($ratings[1] - $ratings[3]) == 2) - { - $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 = $ratings[3]; - my $y = $ratings[4]; - for (my $a = -2 ; $a <= 2 ; $a += 4) - { - if ($board[$x][$y] == -1) - { - $b = -2; - eval_move($x, $y, $a, $b); - } - 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 ($ratings[0] != -99) - { - print "TO $ratings[3], $ratings[4] "; - $ratings[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[$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); - } - 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 ($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; } - if ($t != 1) { $winner = "you"; last; } - - # Prompt the player for their move. - ($z, $t) = (0, 0); - my ($x, $y, $e, $h, $a, $b); - do { - ($e,$h) = get_pos("FROM:"); - $x = $e; - $y = $h; - } while ($board[$x][$y] <= 0); - do { - ($a,$b) = get_pos("TO:"); - $x = $a; - $y = $b; - } 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. - $board[$a][$b] = $board[$e][$h]; - $board[$e][$h] = 0; - if (abs($e-$a) != 2) { last LOOP1750; } - - # Remove the piece jumped over - $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 { - ($a1,$b1) = get_pos("+TO:"); - if ($a1 < 0) { last LOOP1750; } - } 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; - $h = $b; - $a = $a1; - $b = $b1; - } - - # If the player has reached the end of the board, crown this piece - if ($b == 7) { $board[$a][$b] = 2; } - - # And play the next turn. -} - -# Endgame: -print "\n", ($winner eq "you" ? "YOU" : "I"), " WIN\n"; -exit(0); - -########################################### - -# 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 -# s = string to write -# returns the resultant string, which might not have been changed -sub tab -{ - my ($line, $pos, $str) = @_; - my $len = length($line); - # if curser is past position, do nothing - if ($len <= $pos) { $line .= " " x ($pos - $len) . $str; } - 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 ($board[$u][$v] == 0); - - # If it's got an opponent's piece, jump it instead - if ($board[$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 ($board[$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 @ratings. -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 && $board[$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+$neg1 < 0); - - # +1 for each adjacent friendly piece - if ($board[$u+$c][$v+$neg1] < 0) - { - $q++; - next; - } - - # Prevent out-of-bounds testing - 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 ($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 > $ratings[0]) - { - $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 @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 ($board[$u][$v] == 0 && $board[$x+$a/2][$y+$b/2] > 0); -} diff --git a/23_Checkers/python/checkers.py b/23_Checkers/python/checkers.py index 42ae48c8b..f05353ad3 100644 --- a/23_Checkers/python/checkers.py +++ b/23_Checkers/python/checkers.py @@ -37,7 +37,10 @@ def print_centered(msg: str) -> None: def print_header(title: str) -> None: print_centered(title) - print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() def get_coordinates(prompt: str) -> Tuple[int, int]: @@ -64,7 +67,7 @@ def is_legal_board_coordinate(x: int, y: int) -> bool: class Board: def __init__(self) -> None: - self.spaces = [[0 for _ in range(8)] for _ in range(8)] + self.spaces = [[0 for y in range(8)] for x in range(8)] for x in range(8): if (x % 2) == 0: self.spaces[x][6] = COMPUTER_PIECE @@ -114,10 +117,11 @@ 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] - for delta_x in (-1, 1): - if contents == COMPUTER_PIECE: + if contents == COMPUTER_PIECE: + for delta_x in (-1, 1): yield (delta_x, -1) - else: + else: + for delta_x in (-1, 1): for delta_y in (-1, 1): yield (delta_x, delta_y) @@ -182,7 +186,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): @@ -271,8 +275,9 @@ def play_computer_move(self, move_record: MoveRecord) -> None: if best_move is None: return - print(f"TO {best_move.dest_x} {best_move.dest_y}") - move_record = best_move + else: + 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 @@ -350,10 +355,10 @@ def play_human_move( self.spaces[dest_x][dest_y] = HUMAN_KING def check_pieces(self) -> bool: - if not list(self.get_spaces_with_computer_pieces()): + if len(list(self.get_spaces_with_computer_pieces())) == 0: print_human_won() return False - if not list(self.get_spaces_with_computer_pieces()): + if len(list(self.get_spaces_with_computer_pieces())) == 0: print_computer_won() return False return True @@ -368,15 +373,20 @@ def print_instructions() -> None: 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.\n\n\n") + print("JUMP. TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP.") + print() + print() + print() def print_human_won() -> None: - print("\nYOU WIN.") + print() + print("YOU WIN.") def print_computer_won() -> None: - print("\nI WIN.") + print() + print("I WIN.") def play_game() -> None: diff --git a/24_Chemist/README.md b/24_Chemist/README.md index 8871a0acb..b36f0b048 100644 --- a/24_Chemist/README.md +++ b/24_Chemist/README.md @@ -13,10 +13,6 @@ 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) diff --git a/24_Chemist/python/chemist.py b/24_Chemist/python/chemist.py index 561f67c39..a019eea73 100644 --- a/24_Chemist/python/chemist.py +++ b/24_Chemist/python/chemist.py @@ -11,7 +11,16 @@ MAX_LIVES = 9 -def play_scenario() -> bool: +def print_with_tab(space_count: int, msg: str) -> None: + if space_count > 0: + spaces = " " * space_count + else: + spaces = "" + + print(spaces + msg) + + +def play_scenario(): acid_amount = random.randint(1, 50) water_amount = 7 * acid_amount / 3 @@ -34,23 +43,27 @@ def play_scenario() -> bool: return True -def show_failure() -> None: +def show_failure(): print(" SIZZLE! YOU HAVE JUST BEEN DESALINATED INTO A BLOB") print(" OF QUIVERING PROTOPLASM!") -def show_success() -> None: - print(" GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!\n") +def show_success(): + print(" GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!") + print() -def show_ending() -> None: +def show_ending(): print(f" YOUR {MAX_LIVES} LIVES ARE USED, BUT YOU WILL BE LONG REMEMBERED FOR") print(" YOUR CONTRIBUTIONS TO THE FIELD OF COMIC BOOK CHEMISTRY.") def main() -> None: - print(" " * 33 + "CHEMIST") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_with_tab(33, "CHEMIST") + print_with_tab(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.") diff --git a/24_Chemist/rust/Cargo.lock b/24_Chemist/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/24_Chemist/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/24_Chemist/rust/Cargo.toml b/24_Chemist/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/24_Chemist/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/24_Chemist/rust/src/lib.rs b/24_Chemist/rust/src/lib.rs deleted file mode 100644 index b3618ccfb..000000000 --- a/24_Chemist/rust/src/lib.rs +++ /dev/null @@ -1,158 +0,0 @@ -/* - lib.rs contains all the logic of the program -*/ -use rand::{Rng, prelude::thread_rng}; //rng -use std::error::Error; //better errors -use std::io::{self, Write}; //io interactions -use std::{str::FromStr, fmt::Display}; //traits - -//DATA - -/// handles setup for the game -pub struct Config { -} -impl Config { - /// creates and returns a new Config from user input - pub fn new() -> Result> { - //DATA - let config: Config = Config { - }; - - //return new config - return Ok(config); - } -} - -/// run the program -pub fn run(_config: &Config) -> Result<(), Box> { - //DATA - let mut rng = thread_rng(); - let mut lives: i8 = 9; - - let mut amount_of_acid:i8; - - let mut guess:f32; - let mut answer:f32; - - let mut error:f32; - - //Game loop - loop { - //initialize variables - amount_of_acid = rng.gen_range(1..50); - answer = 7.0 * (amount_of_acid as f32/3.0); - - //print starting message / conditions - println!(); - //get guess - guess = loop { - match get_number_from_input(&format!("{} Liters of Kryptocyanic acid. How much water? ", amount_of_acid),0.0,-1.0) { - Ok(num) => break num, - Err(err) => { - eprintln!("{}",err); - continue; - }, - } - }; - - //calculate error - error = (answer as f32 - guess).abs() / guess; - - println!("answer: {} | error: {}%", answer,error*100.); - - //check guess against answer - if error > 0.05 { //error > 5% - println!(" Sizzle! You may have just been desalinated into a blob"); - println!(" of quivering protoplasm!"); - //update lives - lives -= 1; - - if lives <= 0 { - println!(" Your 9 lives are used, but you will be long remembered for"); - println!(" your contributions to the field of comic book chemistry."); - break; - } - else { - println!(" However, you may try again with another life.") - } - } else { - println!(" Good job! You may breathe now, but don't inhale the fumes!"); - println!(); - } - } - - //return to main - Ok(()) -} - -/// gets a string from user input -fn get_string_from_user_input(prompt: &str) -> Result> { - //DATA - let mut raw_input = String::new(); - - //print prompt - print!("{}", prompt); - //make sure it's printed before getting input - io::stdout().flush().expect("couldn't flush stdout"); - - //read user input from standard input, and store it to raw_input, then return it or an error as needed - raw_input.clear(); //clear input - match io::stdin().read_line(&mut raw_input) { - Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())), - Err(err) => return Err(format!("ERROR: CANNOT READ INPUT!: {}", err).into()), - } -} -/// generic function to get a number from the passed string (user input) -/// pass a min lower than the max to have minimum and maximum bounds -/// pass a min higher than the max to only have a minimum bound -/// pass a min equal to the max to only have a maximum bound -/// -/// Errors: -/// no number on user input -fn get_number_from_input(prompt: &str, min:T, max:T) -> Result> { - //DATA - let raw_input: String; - let processed_input: String; - - - //input loop - raw_input = loop { - match get_string_from_user_input(prompt) { - Ok(input) => break input, - Err(e) => { - eprintln!("{}",e); - continue; - }, - } - }; - - //filter out non-numeric characters from user input - processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect(); - - //from input, try to read a number - match processed_input.trim().parse() { - Ok(i) => { - //what bounds must the input fall into - if min < max { //have a min and max bound: [min,max] - if i >= min && i <= max {//is input valid, within bounds - return Ok(i); //exit the loop with the value i, returning it - } else { //print error message specific to this case - return Err(format!("ONLY BETWEEN {} AND {}, PLEASE!", min, max).into()); - } - } else if min > max { //only a min bound: [min, infinity) - if i >= min { - return Ok(i); - } else { - return Err(format!("NO LESS THAN {}, PLEASE!", min).into()); - } - } else { //only a max bound: (-infinity, max] - if i <= max { - return Ok(i); - } else { - return Err(format!("NO MORE THAN {}, PLEASE!", max).into()); - } - } - }, - Err(_e) => return Err(format!("Error: couldn't find a valid number in {}",raw_input).into()), - } -} diff --git a/24_Chemist/rust/src/main.rs b/24_Chemist/rust/src/main.rs deleted file mode 100644 index 91b1f86ac..000000000 --- a/24_Chemist/rust/src/main.rs +++ /dev/null @@ -1,46 +0,0 @@ -use std::process;//allows for some better error handling - -mod lib; //allows access to lib.rs -use lib::Config; - -/// main function -/// responsibilities: -/// - Calling the command line logic with the argument values -/// - Setting up any other configuration -/// - Calling a run function in lib.rs -/// - Handling the error if run returns an error -fn main() { - //greet user - welcome(); - - // set up other configuration - let mut config = Config::new().unwrap_or_else(|err| { - eprintln!("Problem configuring program: {}", err); - process::exit(1); - }); - - // run the program - if let Err(e) = lib::run(&mut config) { - eprintln!("Application Error: {}", e); //use the eprintln! macro to output to standard error - process::exit(1); //exit the program with an error code - } - - //end of program - println!("THANKS FOR PLAYING!"); -} - -/// print the welcome message -fn welcome() { - println!(" - Chemist - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - - -The fictitious chemical kryptocyanic acid can only be -diluted by the ratio of 7 parts water to 3 parts acid. -If any other ratio is attempted, the acid becomes unstable -and soon explodes. Given the amount of acid, you must -decide how much water to add for dilution. If you miss -you face the consequences. - "); -} diff --git a/25_Chief/csharp/Chief.csproj b/25_Chief/csharp/Chief.csproj index 3870320c9..d3fe4757c 100644 --- a/25_Chief/csharp/Chief.csproj +++ b/25_Chief/csharp/Chief.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/25_Chief/csharp/Game.cs b/25_Chief/csharp/Game.cs deleted file mode 100644 index 1884c9b51..000000000 --- a/25_Chief/csharp/Game.cs +++ /dev/null @@ -1,49 +0,0 @@ -using static Chief.Resources.Resource; - -namespace Chief; - -internal class Game -{ - private readonly IReadWrite _io; - - public Game(IReadWrite io) - { - _io = io; - } - - internal void Play() - { - DoIntroduction(); - - var result = _io.ReadNumber(Prompts.Answer); - - if (_io.ReadYes(Formats.Bet, Math.CalculateOriginal(result))) - { - _io.Write(Streams.Bye); - return; - } - - var original = _io.ReadNumber(Prompts.Original); - - _io.WriteLine(Math.ShowWorking(original)); - - if (_io.ReadYes(Prompts.Believe)) - { - _io.Write(Streams.Bye); - return; - } - - _io.Write(Streams.Lightning); - } - - private void DoIntroduction() - { - _io.Write(Streams.Title); - if (!_io.ReadYes(Prompts.Ready)) - { - _io.Write(Streams.ShutUp); - } - - _io.Write(Streams.Instructions); - } -} diff --git a/25_Chief/csharp/IReadWriteExtensions.cs b/25_Chief/csharp/IReadWriteExtensions.cs deleted file mode 100644 index ff190952c..000000000 --- a/25_Chief/csharp/IReadWriteExtensions.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Chief; - -internal static class IReadWriteExtensions -{ - internal static bool ReadYes(this IReadWrite io, string format, Number value) => - io.ReadYes(string.Format(format, value)); - internal static bool ReadYes(this IReadWrite io, string prompt) => - io.ReadString(prompt).Equals("Yes", StringComparison.InvariantCultureIgnoreCase); -} \ No newline at end of file diff --git a/25_Chief/csharp/Math.cs b/25_Chief/csharp/Math.cs deleted file mode 100644 index a9bf7285e..000000000 --- a/25_Chief/csharp/Math.cs +++ /dev/null @@ -1,18 +0,0 @@ -using static Chief.Resources.Resource; - -namespace Chief; - -public static class Math -{ - public static float CalculateOriginal(float result) => (result + 1 - 5) * 5 / 8 * 5 - 3; - - public static string ShowWorking(Number value) => - string.Format( - Formats.Working, - value, - value += 3, - value /= 5, - value *= 8, - value = value / 5 + 5, - value - 1); -} \ No newline at end of file diff --git a/25_Chief/csharp/Program.cs b/25_Chief/csharp/Program.cs deleted file mode 100644 index 0686ce1e7..000000000 --- a/25_Chief/csharp/Program.cs +++ /dev/null @@ -1,4 +0,0 @@ -global using Games.Common.IO; -global using Chief; - -new Game(new ConsoleIO()).Play(); \ No newline at end of file diff --git a/25_Chief/csharp/Resources/Answer.txt b/25_Chief/csharp/Resources/Answer.txt deleted file mode 100644 index 2ac8f3a63..000000000 --- a/25_Chief/csharp/Resources/Answer.txt +++ /dev/null @@ -1 +0,0 @@ - What do you have \ No newline at end of file diff --git a/25_Chief/csharp/Resources/Believe.txt b/25_Chief/csharp/Resources/Believe.txt deleted file mode 100644 index 01963221d..000000000 --- a/25_Chief/csharp/Resources/Believe.txt +++ /dev/null @@ -1 +0,0 @@ -Now do you believe me \ No newline at end of file diff --git a/25_Chief/csharp/Resources/Bet.txt b/25_Chief/csharp/Resources/Bet.txt deleted file mode 100644 index 724512fc2..000000000 --- a/25_Chief/csharp/Resources/Bet.txt +++ /dev/null @@ -1 +0,0 @@ -I bet your number was{0}. Am I right \ No newline at end of file diff --git a/25_Chief/csharp/Resources/Bye.txt b/25_Chief/csharp/Resources/Bye.txt deleted file mode 100644 index 087bcf7a0..000000000 --- a/25_Chief/csharp/Resources/Bye.txt +++ /dev/null @@ -1 +0,0 @@ -Bye!!! diff --git a/25_Chief/csharp/Resources/Instructions.txt b/25_Chief/csharp/Resources/Instructions.txt deleted file mode 100644 index b4425be04..000000000 --- a/25_Chief/csharp/Resources/Instructions.txt +++ /dev/null @@ -1,2 +0,0 @@ - Take a number and add 3. Divide this number by 5 and -multiply by 8. Divide by 5 and add the same. Subtract 1. diff --git a/25_Chief/csharp/Resources/Lightning.txt b/25_Chief/csharp/Resources/Lightning.txt deleted file mode 100644 index c2f564bd2..000000000 --- a/25_Chief/csharp/Resources/Lightning.txt +++ /dev/null @@ -1,31 +0,0 @@ -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!! diff --git a/25_Chief/csharp/Resources/Original.txt b/25_Chief/csharp/Resources/Original.txt deleted file mode 100644 index 954b026d7..000000000 --- a/25_Chief/csharp/Resources/Original.txt +++ /dev/null @@ -1 +0,0 @@ -What was your original number \ No newline at end of file diff --git a/25_Chief/csharp/Resources/Ready.txt b/25_Chief/csharp/Resources/Ready.txt deleted file mode 100644 index c57946cbc..000000000 --- a/25_Chief/csharp/Resources/Ready.txt +++ /dev/null @@ -1,2 +0,0 @@ -I am Chief Numbers Freek, the great Indian math god. -Are you ready to take the test you called me out for \ No newline at end of file diff --git a/25_Chief/csharp/Resources/Resource.cs b/25_Chief/csharp/Resources/Resource.cs deleted file mode 100644 index 4255d6c6e..000000000 --- a/25_Chief/csharp/Resources/Resource.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Chief.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Bye => GetStream(); - public static Stream Instructions => GetStream(); - public static Stream Lightning => GetStream(); - public static Stream ShutUp => GetStream(); - public static Stream Title => GetStream(); - } - - internal static class Formats - { - public static string Bet => GetString(); - public static string Working => GetString(); - } - - internal static class Prompts - { - public static string Answer => GetString(); - public static string Believe => GetString(); - public static string Original => GetString(); - public static string Ready => GetString(); - } - - 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($"Chief.Resources.{name}.txt") - ?? throw new ArgumentException($"Resource stream {name} does not exist", nameof(name)); -} \ No newline at end of file diff --git a/25_Chief/csharp/Resources/ShutUp.txt b/25_Chief/csharp/Resources/ShutUp.txt deleted file mode 100644 index 0b36668c7..000000000 --- a/25_Chief/csharp/Resources/ShutUp.txt +++ /dev/null @@ -1 +0,0 @@ -Shut up, pale face with wise tongue. \ No newline at end of file diff --git a/25_Chief/csharp/Resources/Title.txt b/25_Chief/csharp/Resources/Title.txt deleted file mode 100644 index 980d407d2..000000000 --- a/25_Chief/csharp/Resources/Title.txt +++ /dev/null @@ -1,5 +0,0 @@ - Chief - Creative Computing Morristown, New Jersey - - - diff --git a/25_Chief/csharp/Resources/Working.txt b/25_Chief/csharp/Resources/Working.txt deleted file mode 100644 index 75f1bf7aa..000000000 --- a/25_Chief/csharp/Resources/Working.txt +++ /dev/null @@ -1,5 +0,0 @@ -So you think you're so smart, eh? -Now watch. -{0}plus 3 equals{1}. This divided by 5 equals{2}; -This times by 8 equals{3}. If we divide by 5 and add 5, -we get{4}, which, minus 1, equals{5}. diff --git a/25_Chief/lua/README.md b/25_Chief/lua/README.md index 937d758c4..c063f42fd 100644 --- a/25_Chief/lua/README.md +++ b/25_Chief/lua/README.md @@ -1,24 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Lua](https://www.lua.org/) by Alex Conconi - ---- - -### Lua porting notes - -- I did not like the old Western movie language style in the game introduction -and decided to tone it down, even if this deviates from the original BASIC -version. - -- The `craps_game` function contains the main game logic: it - - prints the game credits and presents the intro question; - - asks for the end result and computes the original numer; - - calls `explain_solution` to print the various steps of the computation; - - presents the outro question and prints a `bolt` if necessary. - -- Added basic input validation to accept only valid integers for numeric input. - -- Minor formatting edits (lowercase, punctuation). - -- Any answer to a "yes or no" question is regarded as "yes" if the input line -starts with 'y' or 'Y', else no. +Conversion to [Lua](https://www.lua.org/) diff --git a/25_Chief/lua/chief.lua b/25_Chief/lua/chief.lua deleted file mode 100644 index 6ac885b2e..000000000 --- a/25_Chief/lua/chief.lua +++ /dev/null @@ -1,121 +0,0 @@ ---[[ -Chief - -From: BASIC Computer Games (1978) -Edited by David H. Ahl - - In the words of the program author, John Graham, “CHIEF is designed to - give people (mostly kids) practice in the four operations (addition, - multiplication, subtraction, and division). - - It does this while giving people some fun. And then, if the people are - wrong, it shows them how they should have done it. - - CHIEF was written by John Graham of Upper Brookville, New York. - - -Lua port by Alex Conconi, 2022. -]]-- - - ---- Helper function for tabulating messages. -local function space(n) return string.rep(" ", n) end - - ---- Generates a multi-line string representing a lightning bolt -local function bolt() - local bolt_lines = {} - for n = 29, 21, -1 do - table.insert(bolt_lines, space(n) .. "x x") - end - table.insert(bolt_lines, space(20) .. "x xxx") - table.insert(bolt_lines, space(19) .. "x x") - table.insert(bolt_lines, space(18) .. "xx x") - for n = 19, 12, -1 do - table.insert(bolt_lines, space(n) .. "x x") - end - table.insert(bolt_lines, space(11) .. "xx") - table.insert(bolt_lines, space(10) .. "x") - table.insert(bolt_lines, space(9) .. "*\n") - table.insert(bolt_lines, string.rep("#", 25) .. "\n") - return table.concat(bolt_lines, "\n") -end - - ---- Print the prompt and read a yes/no answer from stdin. -local function ask_yes_or_no(prompt) - io.stdout:write(prompt .. " ") - local answer = string.lower(io.stdin:read("*l")) - -- any line starting with a 'y' or 'Y' is considered a 'yes' - return answer:sub(1, 1) == "y" -end - - ---- Print the prompt and read a valid number from stdin. -local function ask_number(prompt) - io.stdout:write(prompt .. " ") - while true do - local n = tonumber(io.stdin:read("*l")) - if n then - return n - else - print("Enter a valid number.") - end - end -end - - ---- Explain the solution to persuade the player. -local function explain_solution() - local k = ask_number("What was your original number?") - -- For clarity we kept the same variable names of the original BASIC version - local f = k + 3 - local g = f / 5 - local h = g * 8 - local i = h / 5 + 5 - local 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 .. ".") -end - - ---- Main game function. -local function chief_game() - --- Print game introduction and challenge - print(space(29) .. "Chief") - print(space(14) .. "Creative Computing Morristown, New Jersey\n\n") - print("I am Chief Numbers Freek, the great math god.") - if not ask_yes_or_no("Are you ready to take the test you called me out for?") then - print("Shut up, wise tongue.") - end - - -- Print how to obtain the end result. - 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.") - - -- Ask the result end and reverse calculate the original number. - local end_result = ask_number(" What do you have?") - local original_number = (end_result + 1 - 5) * 5 / 8 * 5 - 3 - - -- If it is an integer we do not want to print any zero decimals. - local int_part, dec_part = math.modf(original_number) - if dec_part == 0 then original_number = int_part end - - -- If the player challenges the answer, print the explanation. - if not ask_yes_or_no("I bet your number was " .. original_number .. ". Am I right?") then - explain_solution() - -- If the player does not accept the explanation, zap them. - if not ask_yes_or_no("Now do you believe me?") then - print("YOU HAVE MADE ME MAD!!!") - print("THERE MUST BE A GREAT LIGHTNING BOLT!\n\n") - print(bolt()) - print("I hope you believe me now, for your sake!!") - end - end -end - ---- Run the game. -chief_game() diff --git a/25_Chief/python/Chief.py b/25_Chief/python/Chief.py new file mode 100644 index 000000000..bf65d3bf2 --- /dev/null +++ b/25_Chief/python/Chief.py @@ -0,0 +1,84 @@ +def print_lightning_bolt() -> None: + + print("*" * 36) + n = 24 + while n > 16: + print(" " * n + "x x") + n -= 1 + print(" " * 16 + "x xxx") + print(" " * 15 + "x x") + print(" " * 14 + "xxx x") + n -= 1 + while n > 8: + print(" " * n + "x x") + n -= 1 + print(" " * 8 + "xx") + print(" " * 7 + "x") + print("*" * 36) + + +def print_solution(n: int) -> None: + + print(f"\n{n} plus 3 gives {n + 3}. This Divided by 5 equals {(n + 3) / 5}") + print(f"This times 8 gives {((n + 3) / 5) * 8}. If we divide 5 and add 5.") + print( + f"We get {(((n + 3) / 5) * 8) / 5 + 5}, " + f"which, minus 1 equals {((((n + 3) / 5) * 8) / 5 + 5) - 1}" + ) + + +def Game(): + print("\nTake a Number and ADD 3. Now, Divide this number by 5 and") + print("multiply by 8. Now, Divide by 5 and add the same. Subtract 1") + + resp = float(input("\nWhat do you have? ")) + comp_guess = (((resp - 4) * 5) / 8) * 5 - 3 + resp2 = input(f"\nI bet your number was {comp_guess} was i right(Yes or No)? ") + + if resp2 == "Yes" or resp2 == "YES" or resp2 == "yes": + print("\nHuh, I Knew I was unbeatable") + print("And here is how i did it") + print_solution(comp_guess) + input("") + + else: + resp3 = float(input("\nHUH!! what was you original number? ")) + + if resp3 == comp_guess: + print("\nThat was my guess, AHA i was right") + print( + "Shamed to accept defeat i guess, don't worry you can master mathematics too" + ) + 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") + print_solution(resp3) + + resp4 = input("\nNow do you believe me? ") + + if resp4 == "Yes" or resp4 == "YES" or resp4 == "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("") + + +if __name__ == "__main__": + + print("I am CHIEF NUMBERS FREEK, The GREAT INDIAN MATH GOD.") + play = input("\nAre you ready to take the test you called me out for(Yes or No)? ") + if play == "Yes" or play == "YES" or play == "yes": + Game() + else: + print("Ok, Nevermind. Let me go back to my great slumber, Bye") + input("") diff --git a/25_Chief/python/chief.py b/25_Chief/python/chief.py deleted file mode 100644 index 050e281f3..000000000 --- a/25_Chief/python/chief.py +++ /dev/null @@ -1,78 +0,0 @@ -def print_lightning_bolt() -> None: - print("*" * 36) - n = 24 - while n > 16: - print(" " * n + "x x") - n -= 1 - print(" " * 16 + "x xxx") - print(" " * 15 + "x x") - print(" " * 14 + "xxx x") - n -= 1 - while n > 8: - print(" " * n + "x x") - n -= 1 - print(" " * 8 + "xx") - print(" " * 7 + "x") - print("*" * 36) - - -def print_solution(n: float) -> None: - print(f"\n{n} plus 3 gives {n + 3}. This Divided by 5 equals {(n + 3) / 5}") - print(f"This times 8 gives {((n + 3) / 5) * 8}. If we divide 5 and add 5.") - print( - f"We get {(((n + 3) / 5) * 8) / 5 + 5}, " - f"which, minus 1 equals {((((n + 3) / 5) * 8) / 5 + 5) - 1}" - ) - - -def game() -> None: - print("\nTake a Number and ADD 3. Now, Divide this number by 5 and") - print("multiply by 8. Now, Divide by 5 and add the same. Subtract 1") - - you_have = float(input("\nWhat do you have? ")) - comp_guess = (((you_have - 4) * 5) / 8) * 5 - 3 - first_guess_right = input( - f"\nI bet your number was {comp_guess} was I right(Yes or No)? " - ) - - if first_guess_right.lower() == "yes": - print("\nHuh, I Knew I was unbeatable") - print("And here is how i did it") - print_solution(comp_guess) - else: - original_number = float(input("\nHUH!! what was you original number? ")) - - if original_number == comp_guess: - print("\nThat was my guess, AHA i was right") - print( - "Shamed to accept defeat i guess, don't worry you can master mathematics too" - ) - print("Here is how i did it") - print_solution(comp_guess) - else: - print("\nSo you think you're so smart, EH?") - print("Now, Watch") - print_solution(original_number) - - believe_me = input("\nNow do you believe me? ") - - if believe_me.lower() == "yes": - print("\nOk, Lets play again sometime bye!!!!") - 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() - - -if __name__ == "__main__": - print("I am CHIEF NUMBERS FREEK, The GREAT INDIAN MATH GOD.") - play = input("\nAre you ready to take the test you called me out for(Yes or No)? ") - if play.lower() == "yes": - game() - else: - print("Ok, Nevermind. Let me go back to my great slumber, Bye") - input() diff --git a/25_Chief/rust/Cargo.lock b/25_Chief/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/25_Chief/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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/25_Chief/rust/Cargo.toml b/25_Chief/rust/Cargo.toml deleted file mode 100644 index 1ec696335..000000000 --- a/25_Chief/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/25_Chief/rust/README.md b/25_Chief/rust/README.md deleted file mode 100644 index 8bdbf2e2b..000000000 --- a/25_Chief/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 123f1a670..000000000 --- a/25_Chief/rust/src/main.rs +++ /dev/null @@ -1,133 +0,0 @@ -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 -/////////////////////////////////////////////////////////////////// diff --git a/26_Chomp/csharp/Chomp.csproj b/26_Chomp/csharp/Chomp.csproj index 3870320c9..d3fe4757c 100644 --- a/26_Chomp/csharp/Chomp.csproj +++ b/26_Chomp/csharp/Chomp.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/26_Chomp/csharp/Cookie.cs b/26_Chomp/csharp/Cookie.cs deleted file mode 100644 index 725eadfeb..000000000 --- a/26_Chomp/csharp/Cookie.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Text; - -namespace Chomp; - -internal class Cookie -{ - private readonly int _rowCount; - private readonly int _columnCount; - private readonly char[][] _bits; - - public Cookie(int rowCount, int columnCount) - { - _rowCount = rowCount; - _columnCount = columnCount; - - // The calls to Math.Max here are to duplicate the original behaviour - // when negative values are given for the row or column count. - _bits = new char[Math.Max(_rowCount, 1)][]; - for (int row = 0; row < _bits.Length; row++) - { - _bits[row] = Enumerable.Repeat('*', Math.Max(_columnCount, 1)).ToArray(); - } - _bits[0][0] = 'P'; - } - - public bool TryChomp(int row, int column, out char chomped) - { - if (row < 1 || row > _rowCount || column < 1 || column > _columnCount || _bits[row - 1][column - 1] == ' ') - { - chomped = default; - return false; - } - - chomped = _bits[row - 1][column - 1]; - - for (int r = row; r <= _rowCount; r++) - { - for (int c = column; c <= _columnCount; c++) - { - _bits[r - 1][c - 1] = ' '; - } - } - - return true; - } - - public override string ToString() - { - var builder = new StringBuilder().AppendLine(" 1 2 3 4 5 6 7 8 9"); - for (int row = 1; row <= _bits.Length; row++) - { - builder.Append(' ').Append(row).Append(" ").AppendLine(string.Join(' ', _bits[row - 1])); - } - return builder.ToString(); - } -} \ No newline at end of file diff --git a/26_Chomp/csharp/Game.cs b/26_Chomp/csharp/Game.cs deleted file mode 100644 index 77a8ccd1e..000000000 --- a/26_Chomp/csharp/Game.cs +++ /dev/null @@ -1,64 +0,0 @@ -namespace Chomp; - -internal class Game -{ - private readonly IReadWrite _io; - - public Game(IReadWrite io) - { - _io = io; - } - - internal void Play() - { - _io.Write(Resource.Streams.Introduction); - if (_io.ReadNumber("Do you want the rules (1=Yes, 0=No!)") != 0) - { - _io.Write(Resource.Streams.Rules); - } - - while (true) - { - _io.Write(Resource.Streams.HereWeGo); - - var (playerCount, rowCount, columnCount) = _io.ReadParameters(); - - var loser = Play(new Cookie(rowCount, columnCount), new PlayerNumber(playerCount)); - - _io.WriteLine(string.Format(Resource.Formats.YouLose, loser)); - - if (_io.ReadNumber("Again (1=Yes, 0=No!)") != 1) { break; } - } - } - - private PlayerNumber Play(Cookie cookie, PlayerNumber player) - { - while (true) - { - _io.WriteLine(cookie); - - var poisoned = Chomp(cookie, player); - - if (poisoned) { return player; } - - player++; - } - } - - private bool Chomp(Cookie cookie, PlayerNumber player) - { - while (true) - { - _io.WriteLine(string.Format(Resource.Formats.Player, player)); - - var (row, column) = _io.Read2Numbers(Resource.Prompts.Coordinates); - - if (cookie.TryChomp((int)row, (int)column, out char chomped)) - { - return chomped == 'P'; - } - - _io.Write(Resource.Streams.NoFair); - } - } -} diff --git a/26_Chomp/csharp/IOExtensions.cs b/26_Chomp/csharp/IOExtensions.cs deleted file mode 100644 index c94053a90..000000000 --- a/26_Chomp/csharp/IOExtensions.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Chomp; - -internal static class IOExtensions -{ - public static (float, int, int) ReadParameters(this IReadWrite io) - => ( - (int)io.ReadNumber(Resource.Prompts.HowManyPlayers), - io.ReadNumberWithMax(Resource.Prompts.HowManyRows, 9, Resource.Strings.TooManyRows), - io.ReadNumberWithMax(Resource.Prompts.HowManyColumns, 9, Resource.Strings.TooManyColumns) - ); - - private static int ReadNumberWithMax(this IReadWrite io, string initialPrompt, int max, string reprompt) - { - var prompt = initialPrompt; - - while (true) - { - var response = io.ReadNumber(prompt); - if (response <= 9) { return (int)response; } - - prompt = $"{reprompt} {initialPrompt.ToLowerInvariant()}"; - } - } -} \ No newline at end of file diff --git a/26_Chomp/csharp/PlayerNumber.cs b/26_Chomp/csharp/PlayerNumber.cs deleted file mode 100644 index 16138a9be..000000000 --- a/26_Chomp/csharp/PlayerNumber.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Chomp; - -internal class PlayerNumber -{ - private readonly float _playerCount; - private int _counter; - private float _number; - - // The original code does not constrain playerCount to be an integer - public PlayerNumber(float playerCount) - { - _playerCount = playerCount; - _number = 0; - Increment(); - } - - public static PlayerNumber operator ++(PlayerNumber number) => number.Increment(); - - private PlayerNumber Increment() - { - if (_playerCount == 0) { throw new DivideByZeroException(); } - - // The increment logic here is the same as the original program, and exhibits - // interesting behaviour when _playerCount is not an integer. - _counter++; - _number = _counter - (float)Math.Floor(_counter / _playerCount) * _playerCount; - if (_number == 0) { _number = _playerCount; } - return this; - } - - public override string ToString() => (_number >= 0 ? " " : "") + _number.ToString(); -} \ No newline at end of file diff --git a/26_Chomp/csharp/Program.cs b/26_Chomp/csharp/Program.cs deleted file mode 100644 index f541259c1..000000000 --- a/26_Chomp/csharp/Program.cs +++ /dev/null @@ -1,5 +0,0 @@ -global using Games.Common.IO; -global using Chomp.Resources; -using Chomp; - -new Game(new ConsoleIO()).Play(); \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/Coordinates.txt b/26_Chomp/csharp/Resources/Coordinates.txt deleted file mode 100644 index e78dd644d..000000000 --- a/26_Chomp/csharp/Resources/Coordinates.txt +++ /dev/null @@ -1 +0,0 @@ -Coordinates of Chomp (row, column) \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/HereWeGo.txt b/26_Chomp/csharp/Resources/HereWeGo.txt deleted file mode 100644 index 00975d31a..000000000 --- a/26_Chomp/csharp/Resources/HereWeGo.txt +++ /dev/null @@ -1,2 +0,0 @@ -Here we go... - diff --git a/26_Chomp/csharp/Resources/HowManyColumns.txt b/26_Chomp/csharp/Resources/HowManyColumns.txt deleted file mode 100644 index e323f959a..000000000 --- a/26_Chomp/csharp/Resources/HowManyColumns.txt +++ /dev/null @@ -1 +0,0 @@ -How many columns \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/HowManyPlayers.txt b/26_Chomp/csharp/Resources/HowManyPlayers.txt deleted file mode 100644 index 98ff0ad72..000000000 --- a/26_Chomp/csharp/Resources/HowManyPlayers.txt +++ /dev/null @@ -1 +0,0 @@ -How many players \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/HowManyRows.txt b/26_Chomp/csharp/Resources/HowManyRows.txt deleted file mode 100644 index 1ad9464ee..000000000 --- a/26_Chomp/csharp/Resources/HowManyRows.txt +++ /dev/null @@ -1 +0,0 @@ -How many rows \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/Introduction.txt b/26_Chomp/csharp/Resources/Introduction.txt deleted file mode 100644 index 7c95e7a6e..000000000 --- a/26_Chomp/csharp/Resources/Introduction.txt +++ /dev/null @@ -1,6 +0,0 @@ - Chomp - Creative Computing Morristown, New Jersey - - - -This is the game of Chomp (Scientific American, Jan 1973) diff --git a/26_Chomp/csharp/Resources/NoFair.txt b/26_Chomp/csharp/Resources/NoFair.txt deleted file mode 100644 index 9fe310eb2..000000000 --- a/26_Chomp/csharp/Resources/NoFair.txt +++ /dev/null @@ -1 +0,0 @@ -No fair. You're trying to chomp on empty space! diff --git a/26_Chomp/csharp/Resources/Player.txt b/26_Chomp/csharp/Resources/Player.txt deleted file mode 100644 index f743df3a0..000000000 --- a/26_Chomp/csharp/Resources/Player.txt +++ /dev/null @@ -1 +0,0 @@ -Player{0} \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/Resource.cs b/26_Chomp/csharp/Resources/Resource.cs deleted file mode 100644 index d080b1fba..000000000 --- a/26_Chomp/csharp/Resources/Resource.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Chomp.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream HereWeGo => GetStream(); - public static Stream Introduction => GetStream(); - public static Stream Rules => GetStream(); - public static Stream NoFair => GetStream(); - } - - internal static class Formats - { - public static string Player => GetString(); - public static string YouLose => GetString(); - } - - internal static class Prompts - { - public static string Coordinates => GetString(); - public static string HowManyPlayers => GetString(); - public static string HowManyRows => GetString(); - public static string HowManyColumns => GetString(); - public static string TooManyColumns => GetString(); - } - - internal static class Strings - { - public static string TooManyColumns => GetString(); - public static string TooManyRows => GetString(); - } - - 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/26_Chomp/csharp/Resources/Rules.txt b/26_Chomp/csharp/Resources/Rules.txt deleted file mode 100644 index 2fd9177f4..000000000 --- a/26_Chomp/csharp/Resources/Rules.txt +++ /dev/null @@ -1,22 +0,0 @@ -Chomp is for 1 or more players (humans only). - -Here's how a board looks (this one is 5 by 7): - - 1 2 3 4 5 6 7 8 9 - 1 P * * * * * * - 2 * * * * * * * - 3 * * * * * * * - 4 * * * * * * * - 5 * * * * * * * - - -The board is a big cookie - R rows high and C columns -wide. You input R and C at the start. In the upper left -corner of the cookie is a poison square (P). The one who -chomps the poison square loses. To take a chomp, type the -row and column of one of the squares on the cookie. -All of the squares below and to the right of that square -(including that square, too) disappear -- Chomp!! -No fair chomping on squares that have already been chomped, -or that are outside the original dimensions of the cookie. - diff --git a/26_Chomp/csharp/Resources/TooManyColumns.txt b/26_Chomp/csharp/Resources/TooManyColumns.txt deleted file mode 100644 index 1e8766a7f..000000000 --- a/26_Chomp/csharp/Resources/TooManyColumns.txt +++ /dev/null @@ -1 +0,0 @@ -Too many rows (9 is maximum). Now, \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/TooManyRows.txt b/26_Chomp/csharp/Resources/TooManyRows.txt deleted file mode 100644 index 1e8766a7f..000000000 --- a/26_Chomp/csharp/Resources/TooManyRows.txt +++ /dev/null @@ -1 +0,0 @@ -Too many rows (9 is maximum). Now, \ No newline at end of file diff --git a/26_Chomp/csharp/Resources/YouLose.txt b/26_Chomp/csharp/Resources/YouLose.txt deleted file mode 100644 index 1015e2717..000000000 --- a/26_Chomp/csharp/Resources/YouLose.txt +++ /dev/null @@ -1 +0,0 @@ -You lose, player{0} diff --git a/26_Chomp/python/chomp.py b/26_Chomp/python/chomp.py index d7b67950e..e4d379812 100755 --- a/26_Chomp/python/chomp.py +++ b/26_Chomp/python/chomp.py @@ -1,31 +1,28 @@ #!/usr/bin/env python3 - -""" -CHOMP - -Converted from BASIC to Python by Trevor Hobson -""" +# CHOMP +# +# Converted from BASIC to Python by Trevor Hobson class Canvas: """For drawing the cookie""" - def __init__(self, width=9, height=9, fill="*") -> None: + def __init__(self, width=9, height=9, fill="*"): self._buffer = [] for _ in range(height): - line = [fill for _ in range(width)] + line = [] + for _ in range(width): + line.append(fill) self._buffer.append(line) self._buffer[0][0] = "P" - def render(self) -> str: + def render(self): lines = [" 1 2 3 4 5 6 7 8 9"] - lines.extend( - f" {str(row)}" + " " * 5 + " ".join(line) - for row, line in enumerate(self._buffer, start=1) - ) + for row, line in enumerate(self._buffer, start=1): + lines.append(" " + str(row) + " " * 5 + " ".join(line)) return "\n".join(lines) - def chomp(self, r, c) -> str: + def chomp(self, r, c): if not 1 <= r <= len(self._buffer) or not 1 <= c <= len(self._buffer[0]): return "Empty" elif self._buffer[r - 1][c - 1] == " ": @@ -39,7 +36,7 @@ def chomp(self, r, c) -> str: return "Chomp" -def play_game() -> None: +def play_game(): """Play one round of the game""" players = 0 while players == 0: @@ -72,9 +69,9 @@ def play_game() -> None: player = 0 alive = True while alive: - print() + print("") print(cookie.render()) - print() + print("") player += 1 if player > players: player = 1 @@ -128,6 +125,7 @@ def main() -> None: keep_playing = True while keep_playing: + play_game() keep_playing = input("\nAgain (1=Yes, 0=No!) ") == "1" diff --git a/27_Civil_War/README.md b/27_Civil_War/README.md index 7cbd62e2a..714b2ebec 100644 --- a/27_Civil_War/README.md +++ b/27_Civil_War/README.md @@ -1,6 +1,6 @@ ### Civil War -This simulation is based on 14 battles in the Civil War. Facts and figures are based on the actual occurrence. If you follow the same strategy used in the actual battle, the results will be the same. Generally, this is a good strategy since the generals in the Civil War were fairly good military strategists. However, you can frequently outperform the Civil War generals, particularly in cases where they did not have good enemy intelligence and consequently followed a poor course of action. Naturally, it helps to know your Civil War history, although the computer gives you the rudiments. +This simulation is based on 14 battles in the Civil War. Facts and figures are based on the actual occurrence. If you follow the same strategy used in the actual battle, the results will be the same. Generally, this is a good strategy since the generals in the Civil War were fairly good military strategists. However, you can frequently outperform the Civil War generals, particularly in cases where they did not have good enemy intelligence and consequently followed a poor course of action. Naturally, it helps to know your Civil War history, although the computer gives yuo the rudiments. After each of the 14 battles, your casualties are compared to the actual casualties of the battle, and you are told whether you win or lose the battle. @@ -17,10 +17,6 @@ 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) diff --git a/27_Civil_War/python/Civilwar.py b/27_Civil_War/python/Civilwar.py index 309a35172..4878bffad 100644 --- a/27_Civil_War/python/Civilwar.py +++ b/27_Civil_War/python/Civilwar.py @@ -1,91 +1,9 @@ -""" -Original game design: Cram, Goodie, Hibbard Lexington H.S. -Modifications: G. Paul, R. Hess (Ties), 1973 -""" -import enum import math -import random -from dataclasses import dataclass -from typing import Dict, List, Literal, Tuple +from typing import List -class AttackState(enum.Enum): - DEFENSIVE = 1 - BOTH_OFFENSIVE = 2 - OFFENSIVE = 3 - - -CONF = 1 -UNION = 2 - - -@dataclass -class PlayerStat: - food: float = 0 - salaries: float = 0 - ammunition: float = 0 - - desertions: float = 0 - casualties: float = 0 - morale: float = 0 - strategy: int = 0 - available_men: int = 0 - available_money: int = 0 - - army_c: float = 0 - army_m: float = 0 # available_men ???? - inflation: float = 0 - - r: float = 0 - t: float = 0 # casualties + desertions - q: float = 0 # accumulated cost? - p: float = 0 - m: float = 0 - - is_player = False - excessive_losses = False - - def set_available_money(self): - 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 - ) - - def get_cost(self) -> float: - return self.food + self.salaries + self.ammunition - - def get_army_factor(self) -> float: - return 1 + (self.p - self.t) / (self.m + 1) - - def get_present_men(self) -> float: - return self.army_m * self.get_army_factor() - - -def simulate_losses(player1: PlayerStat, player2: PlayerStat) -> float: - """Simulate losses of player 1""" - tmp = (2 * player1.army_c / 5) * ( - 1 + 1 / (2 * (abs(player1.strategy - player2.strategy) + 1)) - ) - tmp = tmp * (1.28 + (5 * player1.army_m / 6) / (player1.ammunition + 1)) - return math.floor(tmp * (1 + 1 / player1.morale) + 0.5) - - -def update_army(player: PlayerStat, enemy: PlayerStat, use_factor=False) -> None: - player.casualties = simulate_losses(player, enemy) - player.desertions = 100 / player.morale - - loss = player.casualties + player.desertions - if not use_factor: - present_men: float = player.available_men - else: - present_men = player.get_present_men() - if loss >= present_men: - factor = player.get_army_factor() - if not use_factor: - factor = 1 - player.casualties = math.floor(13 * player.army_m / 20 * factor) - player.desertions = 7 * player.casualties / 13 - player.excessive_losses = True +def tab(n: int) -> str: + return " " * n def get_choice(prompt: str, choices: List[str]) -> str: @@ -96,15 +14,7 @@ def get_choice(prompt: str, choices: List[str]) -> str: return choice -def get_morale(stat: PlayerStat, enemy: PlayerStat) -> float: - """Higher is better""" - enemy_strength = 5 * enemy.army_m / 6 - return (2 * math.pow(stat.food, 2) + math.pow(stat.salaries, 2)) / math.pow( - enemy_strength, 2 - ) + 1 - - -def main() -> None: +def main(): battles = [ [ "JULY 21, 1861. GEN. BEAUREGARD, COMMANDING THE SOUTH, MET", @@ -163,39 +73,42 @@ def main() -> None: ], ] - historical_data: List[Tuple[str, float, float, float, int, AttackState]] = [ - ("", 0, 0, 0, 0, AttackState.DEFENSIVE), - ("BULL RUN", 18000, 18500, 1967, 2708, AttackState.DEFENSIVE), - ("SHILOH", 40000.0, 44894.0, 10699, 13047, AttackState.OFFENSIVE), - ("SEVEN DAYS", 95000.0, 115000.0, 20614, 15849, AttackState.OFFENSIVE), - ("SECOND BULL RUN", 54000.0, 63000.0, 10000, 14000, AttackState.BOTH_OFFENSIVE), - ("ANTIETAM", 40000.0, 50000.0, 10000, 12000, AttackState.OFFENSIVE), - ("FREDERICKSBURG", 75000.0, 120000.0, 5377, 12653, AttackState.DEFENSIVE), - ("MURFREESBORO", 38000.0, 45000.0, 11000, 12000, AttackState.DEFENSIVE), - ("CHANCELLORSVILLE", 32000, 90000.0, 13000, 17197, AttackState.BOTH_OFFENSIVE), - ("VICKSBURG", 50000.0, 70000.0, 12000, 19000, AttackState.DEFENSIVE), - ("GETTYSBURG", 72500.0, 85000.0, 20000, 23000, AttackState.OFFENSIVE), - ("CHICKAMAUGA", 66000.0, 60000.0, 18000, 16000, AttackState.BOTH_OFFENSIVE), - ("CHATTANOOGA", 37000.0, 60000.0, 36700.0, 5800, AttackState.BOTH_OFFENSIVE), - ("SPOTSYLVANIA", 62000.0, 110000.0, 17723, 18000, AttackState.BOTH_OFFENSIVE), - ("ATLANTA", 65000.0, 100000.0, 8500, 3700, AttackState.DEFENSIVE), + historical_data = [ + [], + ["BULL RUN", 18000, 18500, 1967, 2708, 1], + ["SHILOH", 40000.0, 44894.0, 10699, 13047, 3], + ["SEVEN DAYS", 95000.0, 115000.0, 20614, 15849, 3], + ["SECOND BULL RUN", 54000.0, 63000.0, 10000, 14000, 2], + ["ANTIETAM", 40000.0, 50000.0, 10000, 12000, 3], + ["FREDERICKSBURG", 75000.0, 120000.0, 5377, 12653, 1], + ["MURFREESBORO", 38000.0, 45000.0, 11000, 12000, 1], + ["CHANCELLORSVILLE", 32000, 90000.0, 13000, 17197, 2], + ["VICKSBURG", 50000.0, 70000.0, 12000, 19000, 1], + ["GETTYSBURG", 72500.0, 85000.0, 20000, 23000, 3], + ["CHICKAMAUGA", 66000.0, 60000.0, 18000, 16000, 2], + ["CHATTANOOGA", 37000.0, 60000.0, 36700.0, 5800, 2], + ["SPOTSYLVANIA", 62000.0, 110000.0, 17723, 18000, 2], + ["ATLANTA", 65000.0, 100000.0, 8500, 3700, 1], ] - confederate_strategy_prob_distribution = {} - - # What do you spend money on? - stats: Dict[int, PlayerStat] = { - CONF: PlayerStat(), - UNION: PlayerStat(), - } - - print(" " * 26 + "CIVIL WAR") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") - + sa = {} + dollars_available = {} + food_array = {} + salaries = {} + ammunition = {} + oa = {} + print(tab(26) + "CIVIL WAR") + print(tab(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 # Union info on likely confederate strategy - confederate_strategy_prob_distribution[1] = 25 - confederate_strategy_prob_distribution[2] = 25 - confederate_strategy_prob_distribution[3] = 25 - confederate_strategy_prob_distribution[4] = 25 + sa[1] = 25 + sa[2] = 25 + sa[3] = 25 + sa[4] = 25 + party = -1 # number of players in the game print() show_instructions = get_choice( "DO YOU WANT INSTRUCTIONS? YES OR NO -- ", ["YES", "NO"] @@ -232,12 +145,10 @@ def main() -> None: print() print() print("ARE THERE TWO GENERALS PRESENT ", end="") - two_generals = get_choice("(ANSWER YES OR NO) ", ["YES", "NO"]) == "YES" - stats[CONF].is_player = True - if two_generals: - party: Literal[1, 2] = 2 # number of players in the game - stats[UNION].is_player = True - else: + bs = get_choice("(ANSWER YES OR NO) ", ["YES", "NO"]) + if bs == "YES": + party = 2 + elif bs == "NO": party = 1 print() print("YOU ARE THE CONFEDERACY. GOOD LUCK!") @@ -254,286 +165,282 @@ def main() -> None: print("AFTER REQUESTING A BATTLE, DO YOU WISH ", end="") print("BATTLE DESCRIPTIONS ", end="") xs = get_choice("(ANSWER YES OR NO) ", ["YES", "NO"]) - confederacy_lost = 0 - confederacy_win = 0 - for i in [CONF, UNION]: - stats[i].p = 0 - stats[i].m = 0 - stats[i].t = 0 - stats[i].available_money = 0 - stats[i].food = 0 - stats[i].salaries = 0 - stats[i].ammunition = 0 - stats[i].strategy = 0 - stats[i].excessive_losses = False - confederacy_unresolved = 0 - random_nb: float = 0 + line = 0 + w = 0 + r1 = 0 + q1 = 0 + m3 = 0 + m4 = 0 + p1 = 0 + p2 = 0 + t1 = 0 + t2 = 0 + for i in range(1, 3): + dollars_available[i] = 0 + food_array[i] = 0 + salaries[i] = 0 + ammunition[i] = 0 + oa[i] = 0 + r2 = 0 + q2 = 0 + c6 = 0 + food = 0 + w0 = 0 + strategy_index = 0 + union_strategy_index = 0 + u = 0 + u2 = 0 + random_nb = 0 while True: print() print() print() - simulated_battle_index = int( - get_choice( - "WHICH BATTLE DO YOU WISH TO SIMULATE? (0-14) ", - [str(i) for i in range(15)], - ) - ) + simulated_battle_index = int(input("WHICH BATTLE DO YOU WISH TO SIMULATE? ")) if simulated_battle_index < 1 or simulated_battle_index > 14: break if simulated_battle_index != 0 or random_nb == 0: - loaded_battle = historical_data[simulated_battle_index] - battle_name = loaded_battle[0] - stats[CONF].army_m = loaded_battle[1] - stats[UNION].army_m = loaded_battle[2] - stats[CONF].army_c = loaded_battle[3] - stats[UNION].army_c = loaded_battle[4] - stats[CONF].excessive_losses = False - + cs = historical_data[simulated_battle_index][0] + m1 = historical_data[simulated_battle_index][1] + m2 = historical_data[simulated_battle_index][2] + c1 = historical_data[simulated_battle_index][3] + c2 = historical_data[simulated_battle_index][4] + m = historical_data[simulated_battle_index][5] + u = 0 # Inflation calc - stats[CONF].inflation = 10 + (confederacy_lost - confederacy_win) * 2 - stats[UNION].inflation = 10 + (confederacy_win - confederacy_lost) * 2 - - # Money and Men available - for i in [CONF, UNION]: - stats[i].set_available_money() - stats[i].available_men = math.floor(stats[i].get_army_factor()) + i1 = 10 + (line - w) * 2 + i2 = 10 + (w - line) * 2 + # Money available + dollars_available[1] = 100 * math.floor( + (m1 * (100 - i1) / 2000) * (1 + (r1 - q1) / (r1 + 1)) + 0.5 + ) + dollars_available[2] = 100 * math.floor(m2 * (100 - i2) / 2000 + 0.5) + if bs == "YES": + dollars_available[2] = 100 * math.floor( + (m2 * (100 - i2) / 2000) * (1 + (r2 - q2) / (r2 + 1)) + 0.5 + ) + # Men available + m5 = math.floor(m1 * (1 + (p1 - t1) / (m3 + 1))) + m6 = math.floor(m2 * (1 + (p2 - t2) / (m4 + 1))) + f1 = 5 * m1 / 6 print() print() print() print() print() - print(f"THIS IS THE BATTLE OF {battle_name}") + print(f"THIS IS THE BATTLE OF {cs}") if xs != "NO": print("\n".join(battles[simulated_battle_index - 1])) else: - print(f"{battle_name} INSTANT REPLAY") + print(cs + " INSTANT REPLAY") print() - print(" CONFEDERACY\t UNION") - print(f"MEN {stats[CONF].available_men}\t\t {stats[UNION].available_men}") - print( - f"MONEY ${stats[CONF].available_money}\t${stats[UNION].available_money}" - ) - print(f"INFLATION {stats[CONF].inflation + 15}%\t\t {stats[UNION].inflation}%") + print(" \tCONFEDERACY\t UNION") + print(f"MEN\t {m5}\t\t {m6}") + print(f"MONEY\t ${dollars_available[1]}\t\t${dollars_available[2]}") + print(f"INFLATION\t {i1 + 15}%\t {i2}%") print() # ONLY IN PRINTOUT IS CONFED INFLATION = I1 + 15 % # IF TWO GENERALS, INPUT CONFED, FIRST - for player_index in range(1, party + 1): - if two_generals and player_index == 1: + for i in range(1, party + 1): + if bs == "YES" and i == 1: print("CONFEDERATE GENERAL---", end="") print("HOW MUCH DO YOU WISH TO SPEND FOR") while True: - food_input = int(input(" - FOOD...... ? ")) - if food_input < 0: - if stats[CONF].r == 0: + food = int(input(" - FOOD...... ? ")) + if food < 0: + if r1 == 0: print("NO PREVIOUS ENTRIES") continue print("ASSUME YOU WANT TO KEEP SAME ALLOCATIONS") print() break - stats[player_index].food = food_input + food_array[i] = food while True: - stats[player_index].salaries = int(input(" - SALARIES.. ? ")) - if stats[player_index].salaries >= 0: + salaries[i] = int(input(" - SALARIES.. ? ")) + if salaries[i] >= 0: break print("NEGATIVE VALUES NOT ALLOWED.") while True: - stats[player_index].ammunition = int(input(" - AMMUNITION ? ")) - if stats[player_index].ammunition >= 0: + ammunition[i] = int(input(" - AMMUNITION ? ")) + if ammunition[i] >= 0: break print("NEGATIVE VALUES NOT ALLOWED.") print() - if stats[player_index].get_cost() > stats[player_index].available_money: - print( - f"THINK AGAIN! YOU HAVE ONLY ${stats[player_index].available_money}" - ) + if food_array[i] + salaries[i] + ammunition[i] > dollars_available[i]: + print("THINK AGAIN! YOU HAVE ONLY $" + dollars_available[i]) else: break - if not two_generals or player_index == 2: + if bs != "YES" or i == 2: break print("UNION GENERAL---", end="") - for player_index in range(1, party + 1): - if two_generals: - if player_index == 1: + for z in range(1, party + 1): + if bs == "YES": + if z == 1: print("CONFEDERATE ", end="") else: print(" UNION ", end="") - morale = get_morale(stats[player_index], stats[1 + player_index % 2]) - - if morale >= 10: + # Find morale + o = (2 * math.pow(food_array[z], 2) + math.pow(salaries[z], 2)) / math.pow( + f1, 2 + ) + 1 + if o >= 10: print("MORALE IS HIGH") - elif morale >= 5: + elif o >= 5: print("MORALE IS FAIR") else: print("MORALE IS POOR") - if not two_generals: + if bs != "YES": break - stats[player_index].morale = morale # type: ignore + oa[z] = o - stats[UNION].morale = get_morale(stats[UNION], stats[CONF]) - stats[CONF].morale = get_morale(stats[CONF], stats[UNION]) + o2 = oa[2] + o = oa[1] print("CONFEDERATE GENERAL---") # Actual off/def battle situation - if loaded_battle[5] == AttackState.OFFENSIVE: + if m == 3: print("YOU ARE ON THE OFFENSIVE") - elif loaded_battle[5] == AttackState.DEFENSIVE: + elif m == 1: print("YOU ARE ON THE DEFENSIVE") else: print("BOTH SIDES ARE ON THE OFFENSIVE") print() # Choose strategies - if not two_generals: + if bs != "YES": while True: - stats[CONF].strategy = int(input("YOUR STRATEGY ")) - if abs(stats[CONF].strategy - 3) < 3: + strategy_index = int(input("YOUR STRATEGY ")) + if abs(strategy_index - 3) < 3: break - print(f"STRATEGY {stats[CONF].strategy} NOT ALLOWED.") - if stats[CONF].strategy == 5: + print(f"STRATEGY {strategy_index} NOT ALLOWED.") + if strategy_index == 5: print("THE CONFEDERACY HAS SURRENDERED.") break # Union strategy is computer chosen if simulated_battle_index == 0: while True: - stats[UNION].strategy = int(input("UNION STRATEGY IS ")) - if stats[UNION].strategy > 0 and stats[UNION].strategy < 5: + union_strategy_index = int(input("UNION STRATEGY IS ")) + if union_strategy_index > 0 and union_strategy_index < 5: break print("ENTER 1, 2, 3, OR 4 (USUALLY PREVIOUS UNION STRATEGY)") else: s0 = 0 - random_nb = random.random() * 100 - for player_index in range(1, 5): - s0 += confederate_strategy_prob_distribution[player_index] + random_nb = math.random() * 100 + for i in range(1, 5): + s0 += sa[i] # If actual strategy info is in program data statements # then r-100 is extra weight given to that strategy. if random_nb < s0: break - stats[UNION].strategy = player_index - print(stats[UNION].strategy) + union_strategy_index = i + print(union_strategy_index) else: - for player_index in [1, 2]: - if player_index == 1: + for i in range(1, 3): + if i == 1: print("CONFEDERATE STRATEGY ? ", end="") while True: - stats[CONF].strategy = int(input()) - if abs(stats[CONF].strategy - 3) < 3: + strategy_index = int(input()) + if abs(strategy_index - 3) < 3: break - print(f"STRATEGY {stats[CONF].strategy} NOT ALLOWED.") + print(f"STRATEGY {strategy_index} NOT ALLOWED.") print("YOUR STRATEGY ? ", end="") - if player_index == 2: - stats[UNION].strategy = stats[CONF].strategy - stats[CONF].strategy = previous_strategy # type: ignore # noqa: F821 - if stats[UNION].strategy != 5: + if i == 2: + union_strategy_index = strategy_index + strategy_index = previous_strategy # noqa: F821 + if union_strategy_index != 5: break else: - previous_strategy = stats[CONF].strategy # noqa: F841 + previous_strategy = strategy_index # noqa: F841 print("UNION STRATEGY ? ", end="") - - update_army(stats[UNION], stats[CONF], use_factor=False) - + # Simulated losses - North + c6 = (2 * c2 / 5) * ( + 1 + 1 / (2 * (abs(union_strategy_index - strategy_index) + 1)) + ) + c6 = c6 * (1.28 + (5 * m2 / 6) / (ammunition[2] + 1)) + c6 = math.floor(c6 * (1 + 1 / o2) + 0.5) + # If loss > men present, rescale losses + e2 = 100 / o2 + if math.floor(c6 + e2) >= m6: + c6 = math.floor(13 * m6 / 20) + e2 = 7 * c6 / 13 + u2 = 1 # Calculate simulated losses print() print() print() print("\t\tCONFEDERACY\tUNION") - update_army(stats[CONF], stats[UNION], use_factor=True) + c5 = (2 * c1 / 5) * ( + 1 + 1 / (2 * (abs(union_strategy_index - strategy_index) + 1)) + ) + c5 = math.floor(c5 * (1 + 1 / o) * (1.28 + f1 / (ammunition[1] + 1)) + 0.5) + e = 100 / o + if c5 + 100 / o >= m1 * (1 + (p1 - t1) / (m3 + 1)): + c5 = math.floor(13 * m1 / 20 * (1 + (p1 - t1) / (m3 + 1))) + e = 7 * c5 / 13 + u = 1 if party == 1: - stats[UNION].casualties = math.floor( - 17 - * stats[UNION].army_c - * stats[CONF].army_c - / (stats[CONF].casualties * 20) - ) - stats[CONF].desertions = 5 * morale + c6 = math.floor(17 * c2 * c1 / (c5 * 20)) + e2 = 5 * o - print( - "CASUALTIES\t" - + str(stats[CONF].casualties) - + "\t\t" - + str(stats[UNION].casualties) - ) - print( - "DESERTIONS\t" - + str(math.floor(stats[CONF].desertions)) - + "\t\t" - + str(math.floor(stats[UNION].desertions)) - ) + print("CASUALTIES\t" + str(c5) + "\t\t" + str(c6)) + print("DESERTIONS\t" + str(math.floor(e)) + "\t\t" + str(math.floor(e2))) print() - if two_generals: - print("COMPARED TO THE ACTUAL CASUALTIES AT " + str(battle_name)) + if bs == "YES": + print("COMPARED TO THE ACTUAL CASUALTIES AT " + str(cs)) print( "CONFEDERATE: " - + str( - math.floor( - 100 * (stats[CONF].casualties / stats[CONF].army_c) + 0.5 - ) - ) + + str(math.floor(100 * (c5 / c1) + 0.5)) + "% OF THE ORIGINAL" ) print( "UNION: " - + str( - math.floor( - 100 * (stats[UNION].casualties / stats[UNION].army_c) + 0.5 - ) - ) + + str(math.floor(100 * (c6 / c2) + 0.5)) + "% OF THE ORIGINAL" ) print() # Find who won - if ( - stats[CONF].excessive_losses - and stats[UNION].excessive_losses - or ( - not stats[CONF].excessive_losses - and not stats[UNION].excessive_losses - and stats[CONF].casualties + stats[CONF].desertions - == stats[UNION].casualties + stats[CONF].desertions - ) - ): + if u == 1 and u2 == 1 or (u != 1 and u2 != 1 and c5 + e == c6 + e2): print("BATTLE OUTCOME UNRESOLVED") - confederacy_unresolved += 1 - elif stats[CONF].excessive_losses or ( - not stats[CONF].excessive_losses - and not stats[UNION].excessive_losses - and stats[CONF].casualties + stats[CONF].desertions - > stats[UNION].casualties + stats[CONF].desertions - ): - print(f"THE UNION WINS {battle_name}") + w0 += 1 + elif u == 1 or (u != 1 and u2 != 1 and c5 + e > c6 + e2): + print("THE UNION WINS " + str(cs)) if simulated_battle_index != 0: - confederacy_lost += 1 + line += 1 else: - print(f"THE CONFEDERACY WINS {battle_name}") + print("THE CONFEDERACY WINS " + str(cs)) if simulated_battle_index != 0: - confederacy_win += 1 + w += 1 # Lines 2530 to 2590 from original are unreachable. if simulated_battle_index != 0: - for i in [CONF, UNION]: - stats[i].t += stats[i].casualties + stats[i].desertions - stats[i].p += stats[i].army_c - stats[i].q += stats[i].get_cost() - stats[i].r += stats[i].army_m * (100 - stats[i].inflation) / 20 - stats[i].m += stats[i].army_m + t1 += c5 + e + t2 += c6 + e2 + p1 += c1 + p2 += c2 + q1 += food_array[1] + salaries[1] + ammunition[1] + q2 += food_array[2] + salaries[2] + ammunition[2] + r1 += m1 * (100 - i1) / 20 + r2 += m2 * (100 - i2) / 20 + m3 += m1 + m4 += m2 # Learn present strategy, start forgetting old ones - # present strategy of south gains 3*s, others lose s + # present startegy of south gains 3*s, others lose s # probability points, unless a strategy falls below 5 % . s = 3 s0 = 0 - for player_index in range(1, 5): - if confederate_strategy_prob_distribution[player_index] <= 5: + for i in range(1, 5): + if sa[i] <= 5: continue - confederate_strategy_prob_distribution[player_index] -= 5 + sa[i] -= 5 s0 += s - confederate_strategy_prob_distribution[stats[CONF].strategy] += s0 + sa[strategy_index] += s0 - stats[CONF].excessive_losses = False - stats[UNION].excessive_losses = False + u = 0 + u2 = 0 print("---------------") continue @@ -543,39 +450,27 @@ def main() -> None: print() print() print() - print( - f"THE CONFEDERACY HAS WON {confederacy_win} BATTLES AND LOST {confederacy_lost}" - ) - if stats[CONF].strategy == 5 or ( - stats[UNION].strategy != 5 and confederacy_win <= confederacy_lost - ): + print(f"THE CONFEDERACY HAS WON {w} BATTLES AND LOST {line}") + if strategy_index == 5 or (union_strategy_index != 5 and w <= line): print("THE UNION HAS WON THE WAR") else: print("THE CONFEDERACY HAS WON THE WAR") print() - if stats[CONF].r > 0: - print( - f"FOR THE {confederacy_win + confederacy_lost + confederacy_unresolved} BATTLES FOUGHT (EXCLUDING RERUNS)" - ) + if r1 > 0: + print(f"FOR THE {w + line + w0} BATTLES FOUGHT (EXCLUDING RERUNS)") print(" \t \t ") print("CONFEDERACY\t UNION") - print( - f"HISTORICAL LOSSES\t{math.floor(stats[CONF].p + 0.5)}\t{math.floor(stats[UNION].p + 0.5)}" - ) - print( - f"SIMULATED LOSSES\t{math.floor(stats[CONF].t + 0.5)}\t{math.floor(stats[UNION].t + 0.5)}" - ) + print(f"HISTORICAL LOSSES\t{math.floor(p1 + 0.5)}\t{math.floor(p2 + 0.5)}") + print(f"SIMULATED LOSSES\t{math.floor(t1 + 0.5)}\t{math.floor(t2 + 0.5)}") print() print( - f" % OF ORIGINAL\t{math.floor(100 * (stats[CONF].t / stats[CONF].p) + 0.5)}\t{math.floor(100 * (stats[UNION].t / stats[UNION].p) + 0.5)}" + f" % OF ORIGINAL\t{math.floor(100 * (t1 / p1) + 0.5)}\t{math.floor(100 * (t2 / p2) + 0.5)}" ) - if not two_generals: + if bs != "YES": print() print("UNION INTELLIGENCE SUGGEST THAT THE SOUTH USED") print("STRATEGIES 1, 2, 3, 4 IN THE FOLLOWING PERCENTAGES") - print( - f"{confederate_strategy_prob_distribution[CONF]} {confederate_strategy_prob_distribution[UNION]} {confederate_strategy_prob_distribution[3]} {confederate_strategy_prob_distribution[4]}" - ) + print(f"{sa[1]} {sa[2]} {sa[3]} {sa[4]}") if __name__ == "__main__": diff --git a/28_Combat/README.md b/28_Combat/README.md index e4463ab23..10918fc45 100644 --- a/28_Combat/README.md +++ b/28_Combat/README.md @@ -15,11 +15,6 @@ 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) diff --git a/28_Combat/perl/combat.pl b/28_Combat/perl/combat.pl deleted file mode 100755 index fc44a0e4c..000000000 --- a/28_Combat/perl/combat.pl +++ /dev/null @@ -1,202 +0,0 @@ -#!/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); -} diff --git a/28_Combat/python/combat.py b/28_Combat/python/combat.py index 0543b205a..d6eed5ebd 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(f"WE HAVE {str(MAX_UNITS)} SOLDIERS APIECE.") + print("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(f"ARMY {str(cpu_army)} ? ", end="") + print("ARMY " + str(cpu_army) + " ? ", end="") usr_army = int(input()) - print(f"NAVY {str(cpu_navy)} ? ", end="") + print("NAVY " + str(cpu_navy) + " ? ", end="") usr_navy = int(input()) - print(f"A. F. {str(cpu_air)} ? ", end="") + print("A. F. " + str(cpu_air) + " ? ", end="") usr_air = int(input()) if (usr_army + usr_navy + usr_air) <= MAX_UNITS: break @@ -38,6 +38,7 @@ 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: @@ -45,28 +46,32 @@ def attack_first() -> None: print("AND (3) FOR AIR FORCE.") print("?", end=" ") unit_type = int(input()) - if unit_type >= 1 and unit_type <= 3: + if not (unit_type < 1 or unit_type > 3): break - num_units = 0 while True: print("HOW MANY MEN") print("?", end=" ") num_units = int(input()) - 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) + 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)) ): break if unit_type == 1: if num_units < (usr_army / 3): - print(f"YOU LOST {str(num_units)} MEN FROM YOUR ARMY.") + print("YOU LOST " + str(num_units) + " MEN FROM YOUR ARMY.") usr_army = usr_army - num_units elif num_units < (2 * usr_army / 3): - print(f"YOU LOST {int(num_units / 3)} MEN, BUT I LOST {int(2 * cpu_army / 3)}") + print( + "YOU LOST " + + str(int(num_units / 3)) + + " MEN, BUT I LOST " + + str(int(2 * cpu_army / 3)) + ) usr_army = int(usr_army - (num_units / 3)) cpu_army = 0 else: @@ -80,7 +85,7 @@ def attack_first() -> None: print("YOUR ATTACK WAS STOPPED!") usr_navy = usr_navy - num_units elif num_units < 2 * cpu_navy / 3: - print(f"YOU DESTROYED {int(2 * cpu_navy / 3)} OF MY ARMY.") + print("YOU DESTROYED " + str(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") @@ -108,9 +113,10 @@ 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() + print("") print(" YOU ME") print("ARMY ", end="") print("%-14s%s\n" % (usr_army, cpu_army), end="") @@ -124,19 +130,18 @@ def attack_second() -> None: print("ARMY=1 NAVY=2 AIR FORCE=3") print("? ", end="") unit_type = int(input()) - if unit_type >= 1 and unit_type <= 3: + if not ((unit_type < 1) or (unit_type > 3)): break - num_units = 0 while True: print("HOW MANY MEN") print("? ", end="") num_units = int(input()) - 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) + 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)) ): break @@ -171,7 +176,7 @@ def attack_second() -> None: plane_crash_win = True if not plane_crash_win: - print() + print("") print("FROM THE RESULTS OF BOTH OF YOUR ATTACKS,") if plane_crash_win or ( diff --git a/29_Craps/lua/README.md b/29_Craps/lua/README.md index aac11dd0b..c063f42fd 100644 --- a/29_Craps/lua/README.md +++ b/29_Craps/lua/README.md @@ -1,17 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Lua](https://www.lua.org/) by Alex Conconi - ---- - -### Lua porting notes - -- The `craps_main` function contains the main game loop, which iteratively -plays craps rounds by calling `play_round` and tracks winnings and losings. -- Replaced the original routine that tries to scramble the random number -generator with a proper seed initializer in Lua: `math.randomseed(os.time())` -(as advised in the general porting notes). -- Added basic input validation to accept only positive integers for the -wager and the answer to the "If you want to play again print 5" question. -- "If you want to play again print 5 if not print 2" reads a bit odd but -we decided to leave it as is and stay true to the BASIC original version. \ No newline at end of file +Conversion to [Lua](https://www.lua.org/) diff --git a/29_Craps/lua/craps.lua b/29_Craps/lua/craps.lua deleted file mode 100644 index ddd1ce30b..000000000 --- a/29_Craps/lua/craps.lua +++ /dev/null @@ -1,149 +0,0 @@ ---[[ -Craps - -From: BASIC Computer Games (1978) -Edited by David H. Ahl - - This game simulates the games of craps played according to standard - Nevada craps table rules. That is: - 1. A 7 or 11 on the first roll wins - 2. A 2, 3, or 12 on the first roll loses - 3. Any other number rolled becomes your "point." You continue to roll; - if you get your point you win. If you roll a 7, you lose and the dice - change hands when this happens. - - This version of craps was modified by Steve North of Creative Computing. - It is based on an original which appeared one day one a computer at DEC. - - -Lua port by Alex Conconi, 2022 ---]] - - ---- Throw two dice and return their sum. -local function throw_dice() - return math.random(1, 6) + math.random(1, 6) -end - - ---- Print prompt and read a number > 0 from stdin. -local function input_number(prompt) - while true do - io.write(prompt) - local number = tonumber(io.stdin:read("*l")) - if number and number > 0 then - return number - else - print("Please enter a number greater than zero.") - end - end -end - - ---- Print custom balance message depending on balance value -local function print_balance(balance, under_msg, ahead_msg, even_msg) - if balance < 0 then - print(under_msg) - elseif balance > 0 then - print(ahead_msg) - else - print(even_msg) - end -end - - ---- Play a round and return winnings or losings. -local function play_round() - -- Input the wager - local wager = input_number("Input the amount of your wager: ") - - -- Roll the die for the first time. - print("I will now throw the dice") - local first_roll = throw_dice() - - -- A 7 or 11 on the first roll wins. - if first_roll == 7 or first_roll == 11 then - print(string.format("%d - natural.... a winner!!!!", first_roll)) - print(string.format("%d pays even money, you win %d dollars", first_roll, wager)) - return wager - end - - -- A 2, 3, or 12 on the first roll loses. - if first_roll == 2 or first_roll == 3 or first_roll == 12 then - if first_roll == 2 then - -- Special 'you lose' message for 'snake eyes' - print(string.format("%d - snake eyes.... you lose.", first_roll)) - else - -- Default 'you lose' message - print(string.format("%d - craps.... you lose.", first_roll)) - end - print(string.format("You lose %d dollars", wager)) - return -wager - end - - -- Any other number rolled becomes the "point". - -- Continue to roll until rolling a 7 or point. - print(string.format("%d is the point. I will roll again", first_roll)) - while true do - local second_roll = throw_dice() - if second_roll == first_roll then - -- Player gets point and wins - print(string.format("%d - a winner.........congrats!!!!!!!!", first_roll)) - print(string.format("%d at 2 to 1 odds pays you...let me see... %d dollars", first_roll, 2 * wager)) - return 2 * wager - end - if second_roll == 7 then - -- Player rolls a 7 and loses - print(string.format("%d - craps. You lose.", second_roll)) - print(string.format("You lose $ %d", wager)) - return -wager - end - -- Continue to roll - print(string.format("%d - no point. I will roll again", second_roll)) - end -end - - ---- Main game function. -local function craps_main() - -- Print the introduction to the game - print(string.rep(" ", 32) .. "Craps") - print(string.rep(" ", 14) .. "Creative Computing Morristown, New Jersey\n\n") - print("2,3,12 are losers; 4,5,6,8,9,10 are points; 7,11 are natural winners.") - - -- Initialize random number generator seed - math.randomseed(os.time()) - - -- Initialize balance to track winnings and losings - local balance = 0 - - -- Main game loop - local keep_playing = true - while keep_playing do - -- Play a round - balance = balance + play_round() - - -- If player's answer is 5, then stop playing - keep_playing = (input_number("If you want to play again print 5 if not print 2: ") == 5) - - -- Print an update on winnings or losings - print_balance( - balance, - string.format("You are now under $%d", -balance), - string.format("You are now ahead $%d", balance), - "You are now even at 0" - ) - end - - -- Game over, print the goodbye message - print_balance( - balance, - "Too bad, you are in the hole. Come again.", - "Congratulations---you came out a winner. Come again.", - "Congratulations---you came out even, not bad for an amateur" - ) -end - - ---- Run the game. -craps_main() diff --git a/29_Craps/python/craps.py b/29_Craps/python/craps.py index dd01fa5e1..9d265e4e7 100644 --- a/29_Craps/python/craps.py +++ b/29_Craps/python/craps.py @@ -20,7 +20,10 @@ def throw_dice() -> int: def main() -> None: print(" " * 33 + "Craps") - print(" " * 15 + "Creative Computing Morristown, New Jersey\n\n\n") + print(" " * 15 + "Creative Computing Morristown, New Jersey") + print() + print() + print() winnings = 0 print("2,3,12 are losers; 4,5,6,8,9,10 are points; 7,11 are natural winners.") diff --git a/29_Craps/rust/Cargo.lock b/29_Craps/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/29_Craps/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/29_Craps/rust/Cargo.toml b/29_Craps/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/29_Craps/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/29_Craps/rust/src/craps_game.rs b/29_Craps/rust/src/craps_game.rs deleted file mode 100644 index 1818c9c0f..000000000 --- a/29_Craps/rust/src/craps_game.rs +++ /dev/null @@ -1,141 +0,0 @@ -use crate::util; - -enum GameState { - ComeOut, - PointRolls, - GameOver, -} - -pub struct CrapsGame { - wallet: usize, - bet: usize, - point: u8, - state: GameState, -} - -impl CrapsGame { - pub fn new() -> Self { - let wallet = util::read_numeric("\nHow much money do you want to start with?"); - - CrapsGame { - wallet, - bet: 0, - point: 0, - state: GameState::ComeOut, - } - } - - pub fn tick(&mut self) -> bool { - use GameState::*; - - match self.state { - ComeOut => self.new_round(), - PointRolls => self.point_roll(), - GameOver => false, - } - } - - fn point_roll(&mut self) -> bool { - let point = self.point; - - println!("Rolling {point} wins. 7 loses."); - - self.prompt_roll(); - let roll = CrapsGame::roll(); - - if roll == point { - self.player_win(); - } else if roll == 7 { - self.player_lose(); - } - - true - } - - fn new_round(&mut self) -> bool { - println!("\nCome out roll."); - println!("7 and 11 win. 2, 3 and 12 lose.\n"); - - loop { - self.bet = util::read_numeric("Enter your bet:"); - - if self.bet <= self.wallet { - break; - } else { - println!("You don't have that much money!"); - } - } - - self.prompt_roll(); - let point = CrapsGame::roll(); - - match point { - 11 | 7 => { - self.player_win(); - } - 2 | 3 | 12 => { - self.player_lose(); - } - _ => { - self.point = point; - self.state = GameState::PointRolls - } - } - - true - } - - fn player_win(&mut self) { - let bet = self.bet; - - println!("You won ${bet}!"); - - self.wallet += bet; - self.print_wallet(); - - self.state = GameState::ComeOut; - } - - fn player_lose(&mut self) { - let bet = self.bet; - - println!("You lost ${bet}!"); - - self.wallet -= bet; - self.print_wallet(); - - if self.wallet == 0 { - self.game_over(); - } else { - self.state = GameState::ComeOut; - } - } - - fn print_wallet(&self) { - println!("\nYou have ${} in your wallet.", self.wallet); - } - - fn roll() -> u8 { - use rand::Rng; - - let roll = rand::thread_rng().gen_range(2..13); - println!("\nYou rolled {}.", roll); - - roll - } - - fn game_over(&mut self) { - self.state = GameState::GameOver; - } - - fn prompt_roll(&mut self) { - use util::Response::*; - - let response = util::prompt("Ready to roll?"); - - match response { - Yes => (), - No => self.game_over(), - } - } -} diff --git a/29_Craps/rust/src/main.rs b/29_Craps/rust/src/main.rs deleted file mode 100644 index f19e37182..000000000 --- a/29_Craps/rust/src/main.rs +++ /dev/null @@ -1,27 +0,0 @@ -mod craps_game; -mod util; -use crate::craps_game::CrapsGame; - -fn main() { - println!("~~Craps~~"); - println!("Creative Computing Morristown, New Jersey\n"); - - let mut quit = false; - - while !quit { - let mut game = CrapsGame::new(); - - loop { - if !game.tick() { - use util::Response::*; - - match util::prompt("New Game?") { - Yes => (), - No => quit = true, - } - - break; - } - } - } -} diff --git a/29_Craps/rust/src/util.rs b/29_Craps/rust/src/util.rs deleted file mode 100644 index 9fdd8b989..000000000 --- a/29_Craps/rust/src/util.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::io; - -pub enum Response { - Yes, - No, -} - -pub fn read_line() -> String { - let mut input = String::new(); - - io::stdin() - .read_line(&mut input) - .expect("Error reading line."); - - input -} - -pub fn read_numeric(message: &str) -> usize { - loop { - println!("{}", message); - - let mut ok = true; - - let input = read_line(); - - for c in input.trim().chars() { - if !c.is_numeric() { - println!("You can only enter a number!"); - ok = false; - break; - } - } - - if ok { - let input = input.trim().parse(); - - let _ = match input { - Ok(i) => return i, - Err(e) => { - println!("please input a number ({})", e); - } - }; - } - } -} - -pub fn prompt(msg: &str) -> Response { - use Response::*; - - let mut _r = Response::Yes; - - loop { - println!("\n{}", msg); - - let response = read_line().trim().to_uppercase(); - - match response.as_str() { - "YES" | "Y" => { - _r = Yes; - break; - } - "NO" | "N" => { - _r = No; - break; - } - _ => println!("Please input (Y)es or (N)o."), - }; - } - - _r -} diff --git a/30_Cube/README.md b/30_Cube/README.md index a257f1105..f99366a2c 100644 --- a/30_Cube/README.md +++ b/30_Cube/README.md @@ -16,35 +16,3 @@ http://www.vintage-basic.net/games.html #### Porting Notes (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 -chosen like this: - -```basic -380 LET A=INT(3*(RND(X))) -390 IF A<>0 THEN 410 -400 LET A=3 -``` - -where line 410 is the start of a similar block of code for the next coordinate. The behaviour of `RND(X)` depends on the -value of `X`. If `X` is greater than zero then it returns a random value between 0 and 1. If `X` is zero it returns the -last random value generated, or 0 if no value has yet been generated. - -If `X` is 1, therefore, the first line above set `A` to 0, 1, or 2. The next 2 lines replace a 0 with a 3. The -replacement values varies for the different coordinates with the result that the random selection is biased towards a -specific set of points. If `X` is 0, the `RND` calls all return 0, so the coordinates are the known. It appears that -this technique was probably used to allow testing the game with a well-known set of locations for the mines. However, in -the code as it comes to us, the value of `X` is never set and is thus 0, so the mine locations are never randomized. - -The C# port implements the biased randomized mine locations, as seems to be the original intent, but includes a -command-line switch to enable the deterministic execution as well. diff --git a/30_Cube/csharp/Cube.csproj b/30_Cube/csharp/Cube.csproj index 3870320c9..d3fe4757c 100644 --- a/30_Cube/csharp/Cube.csproj +++ b/30_Cube/csharp/Cube.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/30_Cube/csharp/Game.cs b/30_Cube/csharp/Game.cs deleted file mode 100644 index a06ec565e..000000000 --- a/30_Cube/csharp/Game.cs +++ /dev/null @@ -1,104 +0,0 @@ -namespace Cube; - -internal class Game -{ - private const int _initialBalance = 500; - private readonly IEnumerable<(int, int, int)> _seeds = new List<(int, int, int)> - { - (3, 2, 3), (1, 3, 3), (3, 3, 2), (3, 2, 3), (3, 1, 3) - }; - private readonly (float, float, float) _startLocation = (1, 1, 1); - private readonly (float, float, float) _goalLocation = (3, 3, 3); - - private readonly IReadWrite _io; - private readonly IRandom _random; - - public Game(IReadWrite io, IRandom random) - { - _io = io; - _random = random; - } - - public void Play() - { - _io.Write(Streams.Introduction); - - if (_io.ReadNumber("") != 0) - { - _io.Write(Streams.Instructions); - } - - PlaySeries(_initialBalance); - - _io.Write(Streams.Goodbye); - } - - private void PlaySeries(float balance) - { - while (true) - { - var wager = _io.ReadWager(balance); - - var gameWon = PlayGame(); - - if (wager.HasValue) - { - balance = gameWon ? (balance + wager.Value) : (balance - wager.Value); - if (balance <= 0) - { - _io.Write(Streams.Bust); - return; - } - _io.WriteLine(Formats.Balance, balance); - } - - if (_io.ReadNumber(Prompts.TryAgain) != 1) { return; } - } - } - - private bool PlayGame() - { - var mineLocations = _seeds.Select(seed => _random.NextLocation(seed)).ToHashSet(); - var currentLocation = _startLocation; - var prompt = Prompts.YourMove; - - while (true) - { - var newLocation = _io.Read3Numbers(prompt); - - if (!MoveIsLegal(currentLocation, newLocation)) { return Lose(Streams.IllegalMove); } - - currentLocation = newLocation; - - if (currentLocation == _goalLocation) { return Win(Streams.Congratulations); } - - if (mineLocations.Contains(currentLocation)) { return Lose(Streams.Bang); } - - prompt = Prompts.NextMove; - } - } - - private bool Lose(Stream text) - { - _io.Write(text); - return false; - } - - private bool Win(Stream text) - { - _io.Write(text); - return true; - } - - private bool MoveIsLegal((float, float, float) from, (float, float, float) to) - => (to.Item1 - from.Item1, to.Item2 - from.Item2, to.Item3 - from.Item3) switch - { - ( > 1, _, _) => false, - (_, > 1, _) => false, - (_, _, > 1) => false, - (1, 1, _) => false, - (1, _, 1) => false, - (_, 1, 1) => false, - _ => true - }; -} diff --git a/30_Cube/csharp/IOExtensions.cs b/30_Cube/csharp/IOExtensions.cs deleted file mode 100644 index 14f2a85e1..000000000 --- a/30_Cube/csharp/IOExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Cube; - -internal static class IOExtensions -{ - internal static float? ReadWager(this IReadWrite io, float balance) - { - io.Write(Streams.Wager); - if (io.ReadNumber("") == 0) { return null; } - - var prompt = Prompts.HowMuch; - - while(true) - { - var wager = io.ReadNumber(prompt); - if (wager <= balance) { return wager; } - - prompt = Prompts.BetAgain; - } - } -} diff --git a/30_Cube/csharp/Program.cs b/30_Cube/csharp/Program.cs deleted file mode 100644 index 803a569a5..000000000 --- a/30_Cube/csharp/Program.cs +++ /dev/null @@ -1,10 +0,0 @@ -global using Games.Common.IO; -global using Games.Common.Randomness; - -global using static Cube.Resources.Resource; - -using Cube; - -IRandom random = args.Contains("--non-random") ? new ZerosGenerator() : new RandomNumberGenerator(); - -new Game(new ConsoleIO(), random).Play(); diff --git a/30_Cube/csharp/README.md b/30_Cube/csharp/README.md index 7bea3d88b..4daabb5c1 100644 --- a/30_Cube/csharp/README.md +++ b/30_Cube/csharp/README.md @@ -1,12 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) - -#### Execution - -As noted in the main Readme file, the randomization code in the BASIC program has a switch (the variable `X`) that -allows the game to be run in a deterministic (non-random) mode. - -Running the C# port without command-line parameters will play the game with random mine locations. - -Running the port with a `--non-random` command-line switch will run the game with non-random mine locations. diff --git a/30_Cube/csharp/RandomExtensions.cs b/30_Cube/csharp/RandomExtensions.cs deleted file mode 100644 index ac05108e7..000000000 --- a/30_Cube/csharp/RandomExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Cube; - -internal static class RandomExtensions -{ - internal static (float, float, float) NextLocation(this IRandom random, (int, int, int) bias) - => (random.NextCoordinate(bias.Item1), random.NextCoordinate(bias.Item2), random.NextCoordinate(bias.Item3)); - - private static float NextCoordinate(this IRandom random, int bias) - { - var value = random.Next(3); - if (value == 0) { value = bias; } - return value; - } -} \ No newline at end of file diff --git a/30_Cube/csharp/Resources/Balance.txt b/30_Cube/csharp/Resources/Balance.txt deleted file mode 100644 index 1f6adffd8..000000000 --- a/30_Cube/csharp/Resources/Balance.txt +++ /dev/null @@ -1 +0,0 @@ -You now have {0} dollars. \ No newline at end of file diff --git a/30_Cube/csharp/Resources/Bang.txt b/30_Cube/csharp/Resources/Bang.txt deleted file mode 100644 index 1d9247887..000000000 --- a/30_Cube/csharp/Resources/Bang.txt +++ /dev/null @@ -1,4 +0,0 @@ -******BANG****** -You lose! - - diff --git a/30_Cube/csharp/Resources/BetAgain.txt b/30_Cube/csharp/Resources/BetAgain.txt deleted file mode 100644 index 47c9fb8c4..000000000 --- a/30_Cube/csharp/Resources/BetAgain.txt +++ /dev/null @@ -1 +0,0 @@ -Tried to fool me; bet again \ No newline at end of file diff --git a/30_Cube/csharp/Resources/Bust.txt b/30_Cube/csharp/Resources/Bust.txt deleted file mode 100644 index cd753d988..000000000 --- a/30_Cube/csharp/Resources/Bust.txt +++ /dev/null @@ -1 +0,0 @@ -You bust. diff --git a/30_Cube/csharp/Resources/Congratulations.txt b/30_Cube/csharp/Resources/Congratulations.txt deleted file mode 100644 index 3319c833a..000000000 --- a/30_Cube/csharp/Resources/Congratulations.txt +++ /dev/null @@ -1 +0,0 @@ -Congratulations! diff --git a/30_Cube/csharp/Resources/Goodbye.txt b/30_Cube/csharp/Resources/Goodbye.txt deleted file mode 100644 index 0aa641929..000000000 --- a/30_Cube/csharp/Resources/Goodbye.txt +++ /dev/null @@ -1,3 +0,0 @@ -Tough luck! - -Goodbye. diff --git a/30_Cube/csharp/Resources/HowMuch.txt b/30_Cube/csharp/Resources/HowMuch.txt deleted file mode 100644 index ff2bea20b..000000000 --- a/30_Cube/csharp/Resources/HowMuch.txt +++ /dev/null @@ -1 +0,0 @@ -How much \ No newline at end of file diff --git a/30_Cube/csharp/Resources/IllegalMove.txt b/30_Cube/csharp/Resources/IllegalMove.txt deleted file mode 100644 index ca8f96ba1..000000000 --- a/30_Cube/csharp/Resources/IllegalMove.txt +++ /dev/null @@ -1,2 +0,0 @@ - -Illegal move. You lose. diff --git a/30_Cube/csharp/Resources/Instructions.txt b/30_Cube/csharp/Resources/Instructions.txt deleted file mode 100644 index e82ae51e9..000000000 --- a/30_Cube/csharp/Resources/Instructions.txt +++ /dev/null @@ -1,24 +0,0 @@ -This is a game in which you will be playing against the -random decision od the computer. The field of play is a -cube of side 3. Any of the 27 locations can be designated -by inputing three numbers such as 2,3,1. At the start, -you are automatically at location 1,1,1. The object of -the game is to get to location 3,3,3. One minor detail: -the computer will pick, at random, 5 locations at which -it will play land mines. If you hit one of these locations -you lose. One other details: you may move only one space -in one direction each move. For example: from 1,1,2 you -may move to 2,1,2 or 1,1,3. You may not change -two of the numbers on the same move. If you make an illegal -move, you lose and the computer takes the money you may -have bet on that round. - - -All Yes or No questions will be answered by a 1 for Yes -or a 0 (zero) for no. - -When stating the amount of a wager, print only the number -of dollars (example: 250) You are automatically started with -500 dollars in your account. - -Good luck! diff --git a/30_Cube/csharp/Resources/Introduction.txt b/30_Cube/csharp/Resources/Introduction.txt deleted file mode 100644 index 6299d19bd..000000000 --- a/30_Cube/csharp/Resources/Introduction.txt +++ /dev/null @@ -1,6 +0,0 @@ - Cube - Creative Computing Morristown, New Jersey - - - -Do you want to see the instructions? (Yes--1,No--0) diff --git a/30_Cube/csharp/Resources/NextMove.txt b/30_Cube/csharp/Resources/NextMove.txt deleted file mode 100644 index 4cbe54967..000000000 --- a/30_Cube/csharp/Resources/NextMove.txt +++ /dev/null @@ -1 +0,0 @@ -Next move: \ No newline at end of file diff --git a/30_Cube/csharp/Resources/Resource.cs b/30_Cube/csharp/Resources/Resource.cs deleted file mode 100644 index c3ed10c71..000000000 --- a/30_Cube/csharp/Resources/Resource.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Cube.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Introduction => GetStream(); - public static Stream Instructions => GetStream(); - public static Stream Wager => GetStream(); - public static Stream IllegalMove => GetStream(); - public static Stream Bang => GetStream(); - public static Stream Bust => GetStream(); - public static Stream Congratulations => GetStream(); - public static Stream Goodbye => GetStream(); - } - - internal static class Prompts - { - public static string HowMuch => GetString(); - public static string BetAgain => GetString(); - public static string YourMove => GetString(); - public static string NextMove => GetString(); - public static string TryAgain => GetString(); - } - - internal static class Formats - { - public static string Balance => GetString(); - } - - 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/30_Cube/csharp/Resources/TryAgain.txt b/30_Cube/csharp/Resources/TryAgain.txt deleted file mode 100644 index 9ccf358a5..000000000 --- a/30_Cube/csharp/Resources/TryAgain.txt +++ /dev/null @@ -1 +0,0 @@ -Do you want to try again \ No newline at end of file diff --git a/30_Cube/csharp/Resources/Wager.txt b/30_Cube/csharp/Resources/Wager.txt deleted file mode 100644 index 04720a7a4..000000000 --- a/30_Cube/csharp/Resources/Wager.txt +++ /dev/null @@ -1 +0,0 @@ -Want to make a wager diff --git a/30_Cube/csharp/Resources/YourMove.txt b/30_Cube/csharp/Resources/YourMove.txt deleted file mode 100644 index 5ea0c5449..000000000 --- a/30_Cube/csharp/Resources/YourMove.txt +++ /dev/null @@ -1,2 +0,0 @@ - -It's your move: \ No newline at end of file diff --git a/30_Cube/csharp/ZerosGenerator.cs b/30_Cube/csharp/ZerosGenerator.cs deleted file mode 100644 index 4490f606f..000000000 --- a/30_Cube/csharp/ZerosGenerator.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Cube; - -internal class ZerosGenerator : IRandom -{ - public float NextFloat() => 0; - - public float PreviousFloat() => 0; - - public void Reseed(int seed) { } -} \ No newline at end of file diff --git a/30_Cube/python/cube.py b/30_Cube/python/cube.py index 260882dd1..393a494ee 100755 --- a/30_Cube/python/cube.py +++ b/30_Cube/python/cube.py @@ -1,10 +1,7 @@ #!/usr/bin/env python3 - -""" -CUBE - -Converted from BASIC to Python by Trevor Hobson -""" +# CUBE +# +# Converted from BASIC to Python by Trevor Hobson import random from typing import Tuple @@ -31,11 +28,7 @@ def play_game() -> None: for _ in range(5): while True: mine = mine_position() - if ( - mine not in mines - and mine != (1, 1, 1) - and mine != (3, 3, 3) - ): + if not (mine in mines or mine == (1, 1, 1) or mine == (3, 3, 3)): break mines.append(mine) wager = -1 diff --git a/30_Cube/rust/Cargo.lock b/30_Cube/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/30_Cube/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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.toml b/30_Cube/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/30_Cube/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/30_Cube/rust/src/game.rs b/30_Cube/rust/src/game.rs deleted file mode 100644 index 6b783b59e..000000000 --- a/30_Cube/rust/src/game.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::util; - -pub type Position = (u8, u8, u8); - -pub struct Game { - wallet: usize, - bet: Option, - landmines: Vec, - player: Position, -} - -impl Game { - pub fn new() -> Self { - Game { - wallet: 500, - bet: None, - landmines: util::get_landmines(), - player: (1, 1, 1), - } - } - - pub fn play(&mut self) -> bool { - self.bet = self.get_bet(); - - let mut first_move = true; - let mut result = (false, "******BANG!******\nYOU LOSE"); - - loop { - let msg = if first_move { - first_move = false; - "ITS YOUR MOVE" - } else { - "NEXT MOVE" - }; - - let (ok, p) = self.ask_position(msg); - - if ok { - if p == (3, 3, 3) { - result.0 = true; - result.1 = "CONGRATULATIONS!"; - break; - } else if self.landmines.contains(&p) { - break; - } else { - self.player = p; - } - } else { - result.1 = "ILLEGAL MOVE\nYOU LOSE."; - break; - } - } - - println!("{}", result.1); - self.calculate_wallet(result.0); - self.reset_game(); - - if self.wallet <= 0 { - println!("YOU ARE BROKE!"); - return false; - } - - return util::prompt_bool("DO YOU WANT TO TRY AGAIN?"); - } - - fn get_bet(&self) -> Option { - loop { - if util::prompt_bool("WANT TO MAKE A WAGER?") { - let b = util::prompt_number("HOW MUCH?"); - - if b != 0 && b <= self.wallet { - return Some(b); - } else { - println!("YOU CAN'T BET THAT!"); - } - } else { - return None; - }; - } - } - - fn ask_position(&self, msg: &str) -> (bool, Position) { - if let Some(p) = util::prompt_position(msg, self.player) { - return (true, p); - } - return (false, (0, 0, 0)); - } - - fn calculate_wallet(&mut self, win: bool) { - if let Some(b) = self.bet { - if win { - self.wallet += b; - } else { - self.wallet -= b; - } - self.bet = None; - println!("YOU NOW HAVE {} DOLLARS", self.wallet); - } - } - - fn reset_game(&mut self) { - self.player = (1, 1, 1); - self.landmines.clear(); - self.landmines = util::get_landmines(); - } -} diff --git a/30_Cube/rust/src/main.rs b/30_Cube/rust/src/main.rs deleted file mode 100644 index 94c3146e1..000000000 --- a/30_Cube/rust/src/main.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::game::Game; - -mod game; -mod util; - -fn main() { - println!("\n\n\t\tCUBE"); - println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); - - if util::prompt_bool("DO YOU WANT TO SEE THE INSTRUCTIONS? (YES--1,NO--0)") { - println!("\nThis is a game in which you will be playing against the"); - println!("random decisions of the computer. The field of play is a"); - println!("cube of side 3. Any of the 27 locations can be designated"); - println!("by inputing three numbers such as 2,3,1. At the start,"); - println!("you are automatically at location 1,1,1. The object of"); - println!("the game is to get to location 3,3,3. One minor detail:"); - println!("the computer will pick, at random, 5 locations at which"); - println!("it will plant land mines. If you hit one of these locations"); - println!("you lose. One other detail: You may move only one space"); - println!("in one direction each move. For example: From 1,1,2 you"); - println!("may move to 2,1,2 or 1,1,3. You may not change"); - println!("two of the numbers on the same move. If you make an illegal"); - println!("move, you lose and the computer takes the money you may"); - println!("have bet on that round.\n"); - println!("When stating the amount of a wager, print only the number"); - println!("of dollars (example: 250) you are automatically started with"); - println!("500 dollars in your account.\n"); - println!("Good luck!\n"); - } - - let mut game = Game::new(); - - loop { - if !game.play() { - println!("\nTOUGH LUCK\n\nGOODBYE!\n"); - break; - } - } -} diff --git a/30_Cube/rust/src/util.rs b/30_Cube/rust/src/util.rs deleted file mode 100644 index cb854beb8..000000000 --- a/30_Cube/rust/src/util.rs +++ /dev/null @@ -1,117 +0,0 @@ -use std::num::ParseIntError; - -use crate::game::Position; - -pub fn get_random_position() -> Position { - (get_random_axis(), get_random_axis(), get_random_axis()) -} - -fn get_random_axis() -> u8 { - rand::Rng::gen_range(&mut rand::thread_rng(), 1..=3) -} - -pub fn get_landmines() -> Vec { - let mut landmines = Vec::new(); - - for _ in 0..5 { - let mut m = get_random_position(); - while landmines.contains(&m) { - m = get_random_position(); - } - landmines.push(m); - } - - landmines -} - -fn read_line() -> Result { - let mut input = String::new(); - std::io::stdin() - .read_line(&mut input) - .expect("~~Failed reading line!~~"); - input.trim().parse::() -} - -pub fn prompt_bool(msg: &str) -> bool { - loop { - println!("{}", msg); - - if let Ok(n) = read_line() { - if n == 1 { - return true; - } else if n == 0 { - return false; - } - } - println!("ENTER YES--1 OR NO--0\n"); - } -} - -pub fn prompt_number(msg: &str) -> usize { - loop { - println!("{}", msg); - - if let Ok(n) = read_line() { - return n; - } - println!("ENTER A NUMBER\n"); - } -} - -pub fn prompt_position(msg: &str, prev_pos: Position) -> Option { - loop { - println!("{}", msg); - - let mut input = String::new(); - std::io::stdin() - .read_line(&mut input) - .expect("~~Failed reading line!~~"); - - let input: Vec<&str> = input.trim().split(",").collect(); - - let pp = [prev_pos.0, prev_pos.1, prev_pos.2]; - let mut pos = Vec::new(); - - if input.len() != 3 { - println!("YOU MUST ENTER 3 AXES!"); - } else { - for a in input { - if let Ok(n) = a.parse::() { - if n == 0 || n > 3 { - println!("YOU MUST ENTER AN AXIS BETWEEN 1 AND 3!"); - } else { - pos.push(n); - } - } else { - println!("INVALID LOCATION."); - } - } - - let mut moved = false; - for (i, p) in pos.iter().enumerate() { - let dt = ((*p as isize) - (pp[i] as isize)).abs(); - - if dt > 1 { - return None; - } - - if dt == 1 { - if moved { - return None; - } else { - moved = true; - } - } - } - } - - if pos.len() == 3 { - let pos = (pos[0], pos[1], pos[2]); - if pos == prev_pos { - println!("YOU ARE ALREADY THERE!"); - } else { - return Some(pos); - } - } - } -} diff --git a/31_Depth_Charge/python/depth_charge.py b/31_Depth_Charge/python/depth_charge.py index 6134f8ce9..c0180c79b 100644 --- a/31_Depth_Charge/python/depth_charge.py +++ b/31_Depth_Charge/python/depth_charge.py @@ -1,34 +1,31 @@ -""" -Original BASIC version as published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=55 - -Converted to Python by Anson VanDoren in 2021 -""" +# Original BASIC version as published in Basic Computer Games (1978) +# https://www.atariarchives.org/basicgames/showpage.php?page=55 +# +# Converted to Python by Anson VanDoren in 2021 import math import random -from typing import Tuple -def show_welcome() -> None: +def show_welcome(): # 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(f"{chr(27)}[2J") + print(chr(27) + "[2J") # Show the intro text, centered print("DEPTH CHARGE".center(45)) print("Creative Computing Morristown, New Jersey\n\n".center(45)) -def get_num_charges() -> Tuple[int, int]: +def get_num_charges(): print("Depth Charge game\n") while True: - search_area_str = input("Dimensions of search area? ") + search_area = input("Dimensions of search area? ") # Make sure the input is an integer try: - search_area = int(search_area_str) + search_area = int(search_area) break except ValueError: print("Must enter an integer number. Please try again...") @@ -37,16 +34,16 @@ def get_num_charges() -> Tuple[int, int]: return search_area, num_charges -def ask_for_new_game() -> None: +def ask_for_new_game(): answer = input("Another game (Y or N): ") if answer.lower().strip()[0] == "y": - main() + start_new_game() else: print("OK. Hope you enjoyed yourself") exit() -def show_shot_result(shot, location) -> None: +def show_shot_result(shot, location): result = "Sonar reports shot was " if shot[1] > location[1]: # y-direction result += "north" @@ -69,23 +66,23 @@ def show_shot_result(shot, location) -> None: return -def get_shot_input() -> Tuple[int, int, int]: +def get_shot_input(): while True: raw_guess = input("Enter coordinates: ") try: - xyz = raw_guess.split() + x, y, z = raw_guess.split() except ValueError: print("Please enter coordinates separated by spaces") print("Example: 3 2 1") continue try: - x, y, z = (int(num) for num in xyz) + x, y, z = (int(num) for num in [x, y, z]) return x, y, z except ValueError: print("Please enter whole numbers only") -def play_game(search_area, num_charges) -> None: +def play_game(search_area, num_charges): print("\nYou are the captain of the destroyer USS Computer.") print("An enemy sub has been causing you trouble. Your") print(f"mission is to destroy it. You have {num_charges} shots.") @@ -114,10 +111,10 @@ def play_game(search_area, num_charges) -> None: ask_for_new_game() -def main() -> None: +def start_new_game(): search_area, num_charges = get_num_charges() play_game(search_area, num_charges) if __name__ == "__main__": - main() + start_new_game() diff --git a/31_Depth_Charge/rust/Cargo.lock b/31_Depth_Charge/rust/Cargo.lock deleted file mode 100644 index 8be5f5fa6..000000000 --- a/31_Depth_Charge/rust/Cargo.lock +++ /dev/null @@ -1,243 +0,0 @@ -# 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.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 deleted file mode 100644 index 3a87396aa..000000000 --- a/31_Depth_Charge/rust/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "rust" -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 deleted file mode 100644 index f997fda36..000000000 --- a/31_Depth_Charge/rust/src/main.rs +++ /dev/null @@ -1,145 +0,0 @@ -/** 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 -*/ - -use std::io::Write; -use rand::Rng; - -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 g = input("DIMENSION OF SEARCH AREA: ").parse::().unwrap(); - - // 30 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" - // 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 - 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", - "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 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 #{}\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!" - print!("{}", format!("{}{}{}{}{}", - "\n", - "B O O M ! ! YOU FOUND IT IN ", - d, - " TRIES!\n", - "\n" - )); - // 400 PRINT : PRINT: INPUT "ANOTHER GAME (Y OR N)";A$ - if replay() { continue 'main; } - else { 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, - "\n" - )); - - replay(); - } - // 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 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 diff --git a/32_Diamond/csharp/Diamond.csproj b/32_Diamond/csharp/Diamond.csproj index 3870320c9..d3fe4757c 100644 --- a/32_Diamond/csharp/Diamond.csproj +++ b/32_Diamond/csharp/Diamond.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/32_Diamond/csharp/Pattern.cs b/32_Diamond/csharp/Pattern.cs deleted file mode 100644 index ce6d493ac..000000000 --- a/32_Diamond/csharp/Pattern.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Text; -using static Diamond.Resources.Resource; - -namespace Diamond; - -internal class Pattern -{ - private readonly IReadWrite _io; - - public Pattern(IReadWrite io) - { - _io = io; - io.Write(Streams.Introduction); - } - - public void Draw() - { - var diamondSize = _io.ReadNumber(Prompts.TypeNumber); - _io.WriteLine(); - - var diamondCount = (int)(60 / diamondSize); - - var diamondLines = new List(GetDiamondLines(diamondSize)).AsReadOnly(); - - for (int patternRow = 0; patternRow < diamondCount; patternRow++) - { - for (int diamondRow = 0; diamondRow < diamondLines.Count; diamondRow++) - { - var line = new StringBuilder(); - for (int patternColumn = 0; patternColumn < diamondCount; patternColumn++) - { - line.PadToLength((int)(patternColumn * diamondSize)).Append(diamondLines[diamondRow]); - } - _io.WriteLine(line); - } - } - } - - public static IEnumerable GetDiamondLines(float size) - { - for (var i = 1; i <= size; i += 2) - { - yield return GetLine(i); - } - - for (var i = size - 2; i >= 1; i -= 2) - { - yield return GetLine(i); - } - - string GetLine(float i) => - string.Concat( - new string(' ', (int)(size - i) / 2), - new string('C', Math.Min((int)i, 2)), - new string('!', Math.Max(0, (int)i - 2))); - } -} diff --git a/32_Diamond/csharp/Program.cs b/32_Diamond/csharp/Program.cs deleted file mode 100644 index 46dd67c5a..000000000 --- a/32_Diamond/csharp/Program.cs +++ /dev/null @@ -1,4 +0,0 @@ -global using Games.Common.IO; -using Diamond; - -new Pattern(new ConsoleIO()).Draw(); diff --git a/32_Diamond/csharp/Resources/Introduction.txt b/32_Diamond/csharp/Resources/Introduction.txt deleted file mode 100644 index e983fc9f8..000000000 --- a/32_Diamond/csharp/Resources/Introduction.txt +++ /dev/null @@ -1,5 +0,0 @@ - Diamond - Creative Computing Morristown, New Jersey - - - diff --git a/32_Diamond/csharp/Resources/Resource.cs b/32_Diamond/csharp/Resources/Resource.cs deleted file mode 100644 index d7051f5ca..000000000 --- a/32_Diamond/csharp/Resources/Resource.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Diamond.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Introduction => GetStream(); - } - - internal static class Prompts - { - public static string TypeNumber => GetString(); - } - - 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/32_Diamond/csharp/Resources/Rules.txt b/32_Diamond/csharp/Resources/Rules.txt deleted file mode 100644 index 2fd9177f4..000000000 --- a/32_Diamond/csharp/Resources/Rules.txt +++ /dev/null @@ -1,22 +0,0 @@ -Chomp is for 1 or more players (humans only). - -Here's how a board looks (this one is 5 by 7): - - 1 2 3 4 5 6 7 8 9 - 1 P * * * * * * - 2 * * * * * * * - 3 * * * * * * * - 4 * * * * * * * - 5 * * * * * * * - - -The board is a big cookie - R rows high and C columns -wide. You input R and C at the start. In the upper left -corner of the cookie is a poison square (P). The one who -chomps the poison square loses. To take a chomp, type the -row and column of one of the squares on the cookie. -All of the squares below and to the right of that square -(including that square, too) disappear -- Chomp!! -No fair chomping on squares that have already been chomped, -or that are outside the original dimensions of the cookie. - diff --git a/32_Diamond/csharp/Resources/TypeNumber.txt b/32_Diamond/csharp/Resources/TypeNumber.txt deleted file mode 100644 index d74d21fda..000000000 --- a/32_Diamond/csharp/Resources/TypeNumber.txt +++ /dev/null @@ -1,2 +0,0 @@ -For a pretty diamond pattern, -type in an odd number between 5 and 21 \ No newline at end of file diff --git a/32_Diamond/csharp/StringBuilderExtensions.cs b/32_Diamond/csharp/StringBuilderExtensions.cs deleted file mode 100644 index 3ada41460..000000000 --- a/32_Diamond/csharp/StringBuilderExtensions.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Text; - -namespace Diamond; - -internal static class StringBuilderExtensions -{ - internal static StringBuilder PadToLength(this StringBuilder builder, int length) => - builder.Append(' ', length - builder.Length); -} \ No newline at end of file diff --git a/32_Diamond/kotlin/README.md b/32_Diamond/kotlin/README.md index 83eaac65e..f43a5b700 100644 --- a/32_Diamond/kotlin/README.md +++ b/32_Diamond/kotlin/README.md @@ -1,12 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Kotlin](https://kotlinlang.org/), structure inspired from [the Java port](https://github.com/coding-horror/basic-computer-games/blob/main/32_Diamond/java/Diamond.java). - -### How to Run -1. Install [kotlin command line](https://kotlinlang.org/docs/command-line.html) compiler from JetBrains. -2. Compile with `kotlinc diamond.kt -include-runtime -d diamond.jar` -3. Run with `java -jar diamond.jar` - -### Changes from Original -This version validates that user input is correct. - +Conversion to [Kotlin](https://kotlinlang.org/) diff --git a/32_Diamond/kotlin/diamond.kt b/32_Diamond/kotlin/diamond.kt deleted file mode 100644 index 9db6125fb..000000000 --- a/32_Diamond/kotlin/diamond.kt +++ /dev/null @@ -1,154 +0,0 @@ - -/** - * Game of Diamond - *

    - * Based on the BASIC game of Diamond - * https://github.com/coding-horror/basic-computer-games/blob/main/32%20Diamond/diamond.bas - *

    - * - * Changes From Original: Input is validated. - * - * Converted from BASIC to Kotlin by Martin Marconcini (@Gryzor) - * Inspired in the Java code written by Darren Cardenas. - */ - - -fun main() { - Diamond().startGame() -} - -class Diamond { - init { - printIntro() - } - - fun startGame() { - var body: Int - var end: Int - var start: Int = 1 - var row: Int = 1 - var numPerRow: Int - var increment: Int = 2 - var lineContent: String - var prefixIndex: Int - - printPrompt() - - // Read the user input - val input = readLine() - - // Validate input - val userInput: Int = try { - input?.toInt() ?: -1 - } catch (e: NumberFormatException) { - -1 - } - if (!isValid(userInput)) { - printInvalidInput() - return - } - - // Calculate how many diamonds can horizontally fit in the given space - numPerRow = calculateDiamondsPerRow(userInput) - end = userInput - - // Loop throw rows of Diamonds - while (row <= numPerRow) { - body = start - while (canLoop(increment, body, end)) { - lineContent = "" - - // Add white spaces to the "left" of the leftmost diamond. - while (lineContent.length < ((userInput - body) / 2)) { - lineContent += " " - } - - // Begin loop through each column of diamonds - for (col in 1..numPerRow) { - prefixIndex = 1 - - // Begin loop that fills each diamond with characters (not whitespace) - for (fill in 1..body) { - // Right side of diamond, if the index is greater than the prefix, put a Symbol. - if (prefixIndex > PREFIX.length) { - lineContent += SYMBOL - } - // Left side of diamond, pick a Prefix character (-1 since it starts at 0) - else { - lineContent += PREFIX[prefixIndex - 1] - prefixIndex++ - } - }// End loop that fills each diamond with characters - - // Is Column finished? - if (col == numPerRow) { - break - } - // Column is not finished... - else { - // Add whitespace on the "right" side of the current diamond, and fill the "left" side of the - // next; doesn't fill the space to the right of the rightmost diamond. - while (lineContent.length < (userInput * col + (userInput - body) / 2)) { - lineContent += " " - } - - } - - }// End loop through each column of diamonds - - // Print the current Line - println(lineContent) - - // Increment the body that moves - body += increment - } //end While Loop throw rows of Diamonds - - // Increment the current Row of diamonds. - row++ - - if (start != 1) { - start = 1 - end = userInput - increment = 2 - } else { - // We're rendering the "bottom half" of the total rendering. - // Alter the parameters, and decrease the row number so the logic can loop again. - start = userInput - 2 - end = 1 - increment = -2 - row-- - } - } // End loop through each row of diamonds - } - - private fun canLoop(increment: Int, body: Int, end: Int): Boolean = if (increment < 0) body >= end else body <= end - - private fun calculateDiamondsPerRow(totalDiamonds: Int): Int = LINE_WIDTH / totalDiamonds - - private fun isValid(input: Int): Boolean = (input in 5..21) && (input % 2 != 0) - - private fun printInvalidInput() = println("Invalid input") - - private fun printPrompt() { - println( - """ - FOR A PRETTY DIAMOND PATTERN - TYPE IN AN ODD NUMBER BETWEEN 5 AND 21? - """.trimIndent() - ) - println() - } - - private fun printIntro() { - println(" ".repeat(32) + "DIAMOND") - println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - println() - println() - } - - companion object { - const val LINE_WIDTH = 60 - const val PREFIX = "CC" - const val SYMBOL = "!" - } -} diff --git a/32_Diamond/python/diamond.py b/32_Diamond/python/diamond.py index 3b261d36c..88713a88e 100644 --- a/32_Diamond/python/diamond.py +++ b/32_Diamond/python/diamond.py @@ -7,8 +7,16 @@ """ +def print_with_tab(space_count: int, msg: str) -> None: + if space_count > 0: + spaces = " " * space_count + else: + spaces = "" + print(spaces + msg) + + def print_diamond(begin_width, end_width, step, width, count) -> None: - edge_string = "CC" + edgeString = "CC" fill = "!" n = begin_width @@ -16,7 +24,10 @@ 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): - line_buffer += fill if a >= len(edge_string) else edge_string[a] + if a >= len(edgeString): + line_buffer += fill + else: + line_buffer += edgeString[a] line_buffer += " " * ( (width * (across + 1) + (width - n) // 2) - len(line_buffer) ) @@ -27,8 +38,11 @@ def print_diamond(begin_width, end_width, step, width, count) -> None: def main() -> None: - print(" " * 33, "DIAMOND") - print(" " * 15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_with_tab(33, "DIAMOND") + print_with_tab(15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() print("FOR A PRETTY DIAMOND PATTERN,") print("TYPE IN AN ODD NUMBER BETWEEN 5 AND 21") width = int(input()) @@ -36,7 +50,7 @@ def main() -> None: PAGE_WIDTH = 60 - count = PAGE_WIDTH // width + count = int(PAGE_WIDTH / width) for _down in range(count): print_diamond(1, width, 2, width, count) diff --git a/32_Diamond/rust/Cargo.lock b/32_Diamond/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/32_Diamond/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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/32_Diamond/rust/Cargo.toml b/32_Diamond/rust/Cargo.toml deleted file mode 100644 index 1ec696335..000000000 --- a/32_Diamond/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/32_Diamond/rust/README.md b/32_Diamond/rust/README.md deleted file mode 100644 index f84e546c2..000000000 --- a/32_Diamond/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) \ No newline at end of file diff --git a/32_Diamond/rust/src/lib.rs b/32_Diamond/rust/src/lib.rs deleted file mode 100644 index 3d2692c64..000000000 --- a/32_Diamond/rust/src/lib.rs +++ /dev/null @@ -1,182 +0,0 @@ -/* - lib.rs contains all the logic of the program -*/ - -use std::{error::Error, fmt::Display, str::FromStr, io::{self, Write}}; - -/// handles setup for the game -pub struct Config { - diamond_size: isize, -} -impl Config { - /// creates and returns a new Config from user input - pub fn new() -> Result> { - //DATA - let mut config: Config = Config { diamond_size: 0 }; - - //get data from user input - - //get num players - println!("FOR A PRETTY DIAMOND PATTERN,"); - //input looop - config.diamond_size = loop { - match get_number_from_input("TYPE IN AN ODD NUMBER BETWEEN 5 AND 31 ", 5, 31) { - Ok(num) => { - //ensure num is odd - if num%2 == 0 {continue;} - else {break num;} - }, - Err(e) => { - eprintln!("{}",e); - continue; - }, - } - }; - - //return new config - return Ok(config); - } -} - -/// run the program -pub fn run(config: &Config) -> Result<(), Box> { - //DATA - let line_width: isize = 60; - let padding: char = 'C'; - let pixel_width: isize = 1; - let filling: char = '!'; - let border: char = '#'; - - let width_of_full_diamonds_in_line = (line_width/config.diamond_size) * config.diamond_size; - - //print top border - println!("{}", n_chars(width_of_full_diamonds_in_line+2, border)); - - //print out diamonds - for row in 0..width_of_full_diamonds_in_line { - print_diamond_line(config.diamond_size, row, line_width, pixel_width, padding, filling, border); - } - - //print bottom border - println!("{}", n_chars(width_of_full_diamonds_in_line+2, border)); - - //return to main - Ok(()) -} - -/// prints the next line of diamonds -fn print_diamond_line(diamond_width: isize,row: isize, line_width:isize, pixel_width:isize, padding:char, filling:char, border:char) { - //DATA - let diamonds_per_row = (line_width/pixel_width) / diamond_width; - //let row = row % (diamonds_per_row - 1); - let padding_amount; //total amount of padding before and after the filling of each diamond in this row - let filling_amount; //amount of "diamond" in each diamond in this row - - //calculate padding - padding_amount = (2 * ( (row%(diamond_width-1)) - (diamond_width/2))).abs(); - //calculate filling - filling_amount = -padding_amount + diamond_width; - - //print border before every row - print!("{}", border); - - //for every diamond in this row: - for _diamond in 0..diamonds_per_row { - //print leading padding - print!("{}", n_chars( pixel_width * padding_amount/2, padding ) ); - //print filling - print!("{}", n_chars( pixel_width * filling_amount , filling ) ); - //print trailing padding - print!("{}", n_chars( pixel_width * padding_amount/2, padding ) ); - } - - //print border after every row - print!("{}", border); - //new line - println!(""); -} - -/// returns n of the passed character, put into a string -fn n_chars(n:isize, character: char) -> String { - let mut output = String::new(); - - for _i in 0..n { - output.push(character); - } - - output -} - - -/// gets a string from user input -fn get_string_from_user_input(prompt: &str) -> Result> { - //DATA - let mut raw_input = String::new(); - - //print prompt - print!("{}", prompt); - //make sure it's printed before getting input - io::stdout().flush().unwrap(); - - //read user input from standard input, and store it to raw_input, then return it or an error as needed - raw_input.clear(); //clear input - match io::stdin().read_line(&mut raw_input) { - Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())), - Err(err) => return Err(format!("ERROR: CANNOT READ INPUT!: {}", err).into()), - } -} - -/// generic function to get a number from the passed string (user input) -/// pass a min lower than the max to have minimun and maximun bounds -/// pass a min higher than the max to only have a minumum bound -/// pass a min equal to the max to only have a maximun bound -/// -/// Errors: -/// no number on user input -fn get_number_from_input(prompt: &str, min:T, max:T) -> Result> { - //DATA - let raw_input: String; - let processed_input: String; - - - //input looop - raw_input = loop { - match get_string_from_user_input(prompt) { - Ok(input) => break input, - Err(e) => { - eprintln!("{}",e); - continue; - }, - } - }; - - //filter out num-numeric characters from user input - processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect(); - - //from input, try to read a number - match processed_input.trim().parse() { - Ok(i) => { - //what bounds must the input fall into - if min < max { //have a min and max bound: [min,max] - if i >= min && i <= max {//is input valid, within bounds - return Ok(i); //exit the loop with the value i, returning it - } else { //print error message specific to this case - return Err(format!("ONLY BETWEEN {} AND {}, PLEASE!", min, max).into()); - } - } else if min > max { //only a min bound: [min, infinity) - if i >= min { - return Ok(i); - } else { - return Err(format!("NO LESS THAN {}, PLEASE!", min).into()); - } - } else { //only a max bound: (-infinity, max] - if i <= max { - return Ok(i); - } else { - return Err(format!("NO MORE THAN {}, PLEASE!", max).into()); - } - } - }, - Err(_e) => return Err(format!("Error: couldn't find a valid number in {}",raw_input).into()), - } -} \ No newline at end of file diff --git a/32_Diamond/rust/src/main.rs b/32_Diamond/rust/src/main.rs deleted file mode 100644 index 8aab73500..000000000 --- a/32_Diamond/rust/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::process; //allows for some better error handling - -mod lib; -use lib::Config; - -/// main function -/// responsibilities: -/// - Calling the command line logic with the argument values -/// - Setting up any other configuration -/// - Calling a run function in lib.rs -/// - Handling the error if run returns an error -fn main() { - //greet user - welcome(); - - // set up other configuration - let config = Config::new().unwrap_or_else(|err| { - eprintln!("Problem configuring program: {}", err); - process::exit(1); - }); - - // run the program - if let Err(e) = lib::run(&config) { - eprintln!("Application Error: {}", e); //use the eprintln! macro to output to standard error - process::exit(1); //exit the program with an error code - } - - //end of program - println!("THANKS FOR PLAYING!"); -} - -/// welcome message -fn welcome() { - print!(" - DIAMOND - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - - - "); -} diff --git a/33_Dice/lua/README.md b/33_Dice/lua/README.md index 610e38737..c063f42fd 100644 --- a/33_Dice/lua/README.md +++ b/33_Dice/lua/README.md @@ -1,16 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Lua](https://www.lua.org/) by Alex Conconi - ---- - -### Porting notes for Lua - -- This is a straightfoward port with only minor modifications for input -validation and text formatting. - -- The "Try again?" question accepts 'y', 'yes', 'n', 'no' (case insensitive), -whereas the original BASIC version defaults to no unless 'YES' is typed. - -- The "How many rolls?" question presents a more user friendly message -in case of invalid input. +Conversion to [Lua](https://www.lua.org/) diff --git a/33_Dice/lua/dice.lua b/33_Dice/lua/dice.lua deleted file mode 100644 index 17f9b8a6a..000000000 --- a/33_Dice/lua/dice.lua +++ /dev/null @@ -1,112 +0,0 @@ ---[[ -Dice - -From: BASIC Computer Games (1978) -Edited by David H. Ahl - - "Not exactly a game, this program simulates rolling - a pair of dice a large number of times and prints out - the frequency distribution. You simply input the - number of rolls. It is interesting to see how many - rolls are necessary to approach the theoretical - distribution: - - 2 1/36 2.7777...% - 3 2/36 5.5555...% - 4 3/36 8.3333...% - etc. - - "Daniel Freidus wrote this program while in the - seventh grade at Harrison Jr-Sr High School, - Harrison, New York." - - -Lua port by Alex Conconi, 2022. -]]-- - - -local function print_intro() - print("\n" .. string.rep(" ", 19) .. "Dice") - print("Creative Computing Morristown, New Jersey\n\n") - 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.") -end - - -local function ask_how_many_rolls() - while true do - -- Print prompt and read a valid number from stdin - print("\nHow many rolls?") - local num_rolls = tonumber(io.stdin:read("*l")) - if num_rolls then - return num_rolls - else - print("Please enter a valid number.") - end - end -end - - -local function ask_try_again() - while true do - -- Print prompt and read a yes/no answer from stdin, - -- accepting only 'yes', 'y', 'no' or 'n' (case insensitive) - print("\nTry again? ([y]es / [n]o)") - local answer = string.lower(io.stdin:read("*l")) - if answer == "yes" or answer == "y" then - return true - elseif answer == "no" or answer == "n" then - return false - else - print("Please answer '[y]es' or '[n]o'.") - end - end -end - - -local function roll_dice(num_rolls) - -- Initialize a table to track counts of roll outcomes - local counts = {} - for i=2, 12 do - counts[i] = 0 - end - - -- Roll the dice num_rolls times and update outcomes counts accordingly - for _=1, num_rolls do - local roll_total = math.random(1, 6) + math.random(1, 6) - counts[roll_total] = counts[roll_total] + 1 - end - - return counts -end - - -local function print_results(counts) - print("\nTotal Spots Number of Times") - for roll_total, count in pairs(counts) do - print(string.format(" %-14d%d", roll_total, count)) - end -end - - -local function dice_main() - print_intro() - - -- initialize the random number generator - math.randomseed(os.time()) - - -- main game loop - local keep_playing = true - while keep_playing do - local num_rolls = ask_how_many_rolls() - local counts = roll_dice(num_rolls) - print_results(counts) - keep_playing = ask_try_again() - end -end - - -dice_main() diff --git a/33_Dice/python/dice.py b/33_Dice/python/dice.py index 5c47f2b61..1529a7392 100644 --- a/33_Dice/python/dice.py +++ b/33_Dice/python/dice.py @@ -1,27 +1,30 @@ -""" -Dice - -From: BASIC Computer Games (1978) - Edited by David H. Ahl - -"Not exactly a game, this program simulates rolling - a pair of dice a large number of times and prints out - the frequency distribution. You simply input the - number of rolls. It is interesting to see how many - rolls are necessary to approach the theoretical - distribution: - - 2 1/36 2.7777...% - 3 2/36 5.5555...% - 4 3/36 8.3333...% - etc. - -"Daniel Freidus wrote this program while in the - seventh grade at Harrison Jr-Sr High School, - Harrison, New York." +######################################################## +# +# Dice +# +# From: BASIC Computer Games (1978) +# Edited by David H. Ahl +# +# "Not exactly a game, this program simulates rolling +# a pair of dice a large number of times and prints out +# the frequency distribution. You simply input the +# number of rolls. It is interesting to see how many +# rolls are necessary to approach the theoretical +# distribution: +# +# 2 1/36 2.7777...% +# 3 2/36 5.5555...% +# 4 3/36 8.3333...% +# etc. +# +# "Daniel Freidus wrote this program while in the +# seventh grade at Harrison Jr-Sr High School, +# Harrison, New York." +# +# Python port by Jeff Jetton, 2019 +# +######################################################## -Python port by Jeff Jetton, 2019 -""" import random @@ -45,7 +48,7 @@ def main() -> None: still_playing = True while still_playing: - print() + print("") n = int(input("How many rolls? ")) # Roll the dice n times @@ -61,7 +64,7 @@ def main() -> None: print(" %-14d%d" % (i, freq[i])) # Keep playing? - print() + print("") response = input("Try again? ") if len(response) > 0 and response.upper()[0] == "Y": # Clear out the frequency list diff --git a/33_Dice/rust/Cargo.lock b/33_Dice/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/33_Dice/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/33_Dice/rust/Cargo.toml b/33_Dice/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/33_Dice/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/33_Dice/rust/README.md b/33_Dice/rust/README.md deleted file mode 100644 index fc6468b9f..000000000 --- a/33_Dice/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) diff --git a/33_Dice/rust/src/main.rs b/33_Dice/rust/src/main.rs deleted file mode 100644 index 8c7e5885d..000000000 --- a/33_Dice/rust/src/main.rs +++ /dev/null @@ -1,85 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Dice -// -// From: BASIC Computer Games (1978) -// Edited by David H. Ahl -// -// "Not exactly a game, this program simulates rolling -// a pair of dice a large number of times and prints out -// the frequency distribution. You simply input the -// number of rolls. It is interesting to see how many -// rolls are necessary to approach the theoretical -// distribution: -// -// 2 1/36 2.7777...% -// 3 2/36 5.5555...% -// 4 3/36 8.3333...% -// etc. -// -// "Daniel Freidus wrote this program while in the -// seventh grade at Harrison Jr-Sr High School, -// Harrison, New York." -// -// Rust Port by Jay, 2022 -// -//////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -use rand::Rng; -use std::io::{self, Write}; - -fn main() { - let mut frequency: [i32; 13] = [0; 13]; - println!( - "{: >38}\n{: >57}\n\n", - "DICE", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" - ); - // DANNY FREIDUS - println!("THIS PROGRAM SIMULATES THE ROLLING OF A"); - println!("PAIR OF DICE."); - println!("YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO"); - println!("'ROLL' THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE"); - println!("A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000."); - let mut playing = true; - while playing { - let n = match readinput(&"HOW MANY ROLLS").trim().parse::() { - Ok(num) => num, - Err(_) => { - println!("PLEASE ENTER A NUMBER"); - continue; - } - }; - // Dice Rolled n times - for _i in 0..n { - let die_1 = rand::thread_rng().gen_range(1..=6); - let die_2 = rand::thread_rng().gen_range(1..=6); - let total = die_1 + die_2; - frequency[total] += 1; - } - - // Results tabel - println!("\nTOTAL SPOTS NUMBER OF TIMES"); - for i in 2..13 { - println!("{:^4}\t\t{}", i, frequency[i]); - } - - // Continue the game - let reply = readinput("TRY AGAIN").to_ascii_uppercase(); - if reply.starts_with("Y") || reply.eq("YES") { - frequency = [0; 13]; - } else { - playing = false; - } - } -} - -// function for getting input on same line -fn readinput(str: &str) -> String { - print!("\n{}? ", str); - let mut input = String::new(); - io::stdout().flush().unwrap(); - io::stdin() - .read_line(&mut input) - .expect("Failed to get Input"); - input -} diff --git a/34_Digits/README.md b/34_Digits/README.md index 6e82efda5..569122c8e 100644 --- a/34_Digits/README.md +++ b/34_Digits/README.md @@ -18,5 +18,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -- 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. +(please note any difficulties or challenges in porting here) diff --git a/34_Digits/csharp/Digits.csproj b/34_Digits/csharp/Digits.csproj index 3870320c9..d3fe4757c 100644 --- a/34_Digits/csharp/Digits.csproj +++ b/34_Digits/csharp/Digits.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/34_Digits/csharp/Game.cs b/34_Digits/csharp/Game.cs deleted file mode 100644 index 19f225b33..000000000 --- a/34_Digits/csharp/Game.cs +++ /dev/null @@ -1,80 +0,0 @@ -namespace Digits; - -internal class GameSeries -{ - private readonly IReadOnlyList _weights = new List { 0, 1, 3 }.AsReadOnly(); - - private readonly IReadWrite _io; - private readonly IRandom _random; - - public GameSeries(IReadWrite io, IRandom random) - { - _io = io; - _random = random; - } - - internal void Play() - { - _io.Write(Streams.Introduction); - - if (_io.ReadNumber(Prompts.ForInstructions) != 0) - { - _io.Write(Streams.Instructions); - } - - do - { - new Game(_io, _random).Play(); - } while (_io.ReadNumber(Prompts.WantToTryAgain) == 1); - - _io.Write(Streams.Thanks); - } -} - -internal class Game -{ - private readonly IReadWrite _io; - private readonly Guesser _guesser; - - public Game(IReadWrite io, IRandom random) - { - _io = io; - _guesser = new Guesser(random); - } - - public void Play() - { - var correctGuesses = 0; - - for (int round = 0; round < 3; round++) - { - var digits = _io.Read10Digits(Prompts.TenNumbers, Streams.TryAgain); - - correctGuesses = GuessDigits(digits, correctGuesses); - } - - _io.Write(correctGuesses switch - { - < 10 => Streams.YouWin, - 10 => Streams.ItsATie, - > 10 => Streams.IWin - }); - } - - private int GuessDigits(IEnumerable digits, int correctGuesses) - { - _io.Write(Streams.Headings); - - foreach (var digit in digits) - { - var guess = _guesser.GuessNextDigit(); - if (guess == digit) { correctGuesses++; } - - _io.WriteLine(Formats.GuessResult, guess, digit, guess == digit ? "Right" : "Wrong", correctGuesses); - - _guesser.ObserveActualDigit(digit); - } - - return correctGuesses; - } -} diff --git a/34_Digits/csharp/Guesser.cs b/34_Digits/csharp/Guesser.cs deleted file mode 100644 index 9cda59e91..000000000 --- a/34_Digits/csharp/Guesser.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Digits; - -internal class Guesser -{ - private readonly Memory _matrices = new(); - private readonly IRandom _random; - - public Guesser(IRandom random) - { - _random = random; - } - - public int GuessNextDigit() - { - var currentSum = 0; - var guess = 0; - - for (int i = 0; i < 3; i++) - { - var sum = _matrices.GetWeightedSum(i); - if (sum > currentSum || _random.NextFloat() >= 0.5) - { - currentSum = sum; - guess = i; - } - } - - return guess; - } - - public void ObserveActualDigit(int digit) => _matrices.ObserveDigit(digit); -} diff --git a/34_Digits/csharp/IOExtensions.cs b/34_Digits/csharp/IOExtensions.cs deleted file mode 100644 index cd6af7add..000000000 --- a/34_Digits/csharp/IOExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Digits; - -internal static class IOExtensions -{ - internal static IEnumerable Read10Digits(this IReadWrite io, string prompt, Stream retryText) - { - while (true) - { - var numbers = new float[10]; - io.ReadNumbers(prompt, numbers); - - if (numbers.All(n => n == 0 || n == 1 || n == 2)) - { - return numbers.Select(n => (int)n); - } - - io.Write(retryText); - } - } -} \ No newline at end of file diff --git a/34_Digits/csharp/Matrix.cs b/34_Digits/csharp/Matrix.cs deleted file mode 100644 index c07b45538..000000000 --- a/34_Digits/csharp/Matrix.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Digits; - -internal class Matrix -{ - private readonly int _weight; - private readonly int[,] _values; - - public Matrix(int width, int weight, Func seedFactory) - { - _weight = weight; - _values = new int[width, 3]; - - for (int i = 0; i < width; i++) - for (int j = 0; j < 3; j++) - { - _values[i, j] = seedFactory.Invoke(i, j); - } - - Index = width - 1; - } - - public int Index { get; set; } - - public int GetWeightedValue(int row) => _weight * _values[Index, row]; - - public int IncrementValue(int row) => _values[Index, row]++; -} \ No newline at end of file diff --git a/34_Digits/csharp/Memory.cs b/34_Digits/csharp/Memory.cs deleted file mode 100644 index a3023351a..000000000 --- a/34_Digits/csharp/Memory.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Digits; - -public class Memory -{ - private readonly Matrix[] _matrices; - - public Memory() - { - _matrices = new[] - { - new Matrix(27, 3, (_, _) => 1), - new Matrix(9, 1, (i, j) => i == 4 * j ? 2 : 3), - new Matrix(3, 0, (_, _) => 9) - }; - } - - public int GetWeightedSum(int row) => _matrices.Select(m => m.GetWeightedValue(row)).Sum(); - - public void ObserveDigit(int digit) - { - for (int i = 0; i < 3; i++) - { - _matrices[i].IncrementValue(digit); - } - - _matrices[0].Index = _matrices[0].Index % 9 * 3 + digit; - _matrices[1].Index = _matrices[0].Index % 9; - _matrices[2].Index = digit; - } -} \ No newline at end of file diff --git a/34_Digits/csharp/Program.cs b/34_Digits/csharp/Program.cs deleted file mode 100644 index 1b5dd2e0e..000000000 --- a/34_Digits/csharp/Program.cs +++ /dev/null @@ -1,6 +0,0 @@ -global using Digits; -global using Games.Common.IO; -global using Games.Common.Randomness; -global using static Digits.Resources.Resource; - -new GameSeries(new ConsoleIO(), new RandomNumberGenerator()).Play(); \ No newline at end of file diff --git a/34_Digits/csharp/Resources/ForInstructions.txt b/34_Digits/csharp/Resources/ForInstructions.txt deleted file mode 100644 index 1c16d5f4f..000000000 --- a/34_Digits/csharp/Resources/ForInstructions.txt +++ /dev/null @@ -1 +0,0 @@ -For instructions, type '1', else type '0' \ No newline at end of file diff --git a/34_Digits/csharp/Resources/GuessResult.txt b/34_Digits/csharp/Resources/GuessResult.txt deleted file mode 100644 index 4e233e037..000000000 --- a/34_Digits/csharp/Resources/GuessResult.txt +++ /dev/null @@ -1 +0,0 @@ - {0} {1} {2} {3} \ No newline at end of file diff --git a/34_Digits/csharp/Resources/Headings.txt b/34_Digits/csharp/Resources/Headings.txt deleted file mode 100644 index 8289cdf64..000000000 --- a/34_Digits/csharp/Resources/Headings.txt +++ /dev/null @@ -1,3 +0,0 @@ - -My guess Your no. Result No. right - diff --git a/34_Digits/csharp/Resources/IWin.txt b/34_Digits/csharp/Resources/IWin.txt deleted file mode 100644 index 491f69cf8..000000000 --- a/34_Digits/csharp/Resources/IWin.txt +++ /dev/null @@ -1,4 +0,0 @@ - -I guessed more than 1/3 of your numbers. -I win. - diff --git a/34_Digits/csharp/Resources/Instructions.txt b/34_Digits/csharp/Resources/Instructions.txt deleted file mode 100644 index f9ff2a16e..000000000 --- a/34_Digits/csharp/Resources/Instructions.txt +++ /dev/null @@ -1,11 +0,0 @@ - -Please take a piece of paper and write down -the digits '0', '1', or '2' thirty times at random. -Arrange them in three lines of ten digits each. -I will ask for then ten at a time. -I will always guess them first and then look at your -next number to see if I was right. By pure luck, -I ought to be right ten times. But I hope to do better -than that ***** - - diff --git a/34_Digits/csharp/Resources/Introduction.txt b/34_Digits/csharp/Resources/Introduction.txt deleted file mode 100644 index e4d2d93ee..000000000 --- a/34_Digits/csharp/Resources/Introduction.txt +++ /dev/null @@ -1,6 +0,0 @@ - Digits - Creative Computing Morristown, New Jersey - - - -This is a game of guessing. diff --git a/34_Digits/csharp/Resources/ItsATie.txt b/34_Digits/csharp/Resources/ItsATie.txt deleted file mode 100644 index 0e92fbf62..000000000 --- a/34_Digits/csharp/Resources/ItsATie.txt +++ /dev/null @@ -1,4 +0,0 @@ - -I guessed exactly 1/3 of your numbers. -It's a tie game. - diff --git a/34_Digits/csharp/Resources/Resource.cs b/34_Digits/csharp/Resources/Resource.cs deleted file mode 100644 index 2e9359557..000000000 --- a/34_Digits/csharp/Resources/Resource.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Digits.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Introduction => GetStream(); - public static Stream Instructions => GetStream(); - public static Stream TryAgain => GetStream(); - public static Stream ItsATie => GetStream(); - public static Stream IWin => GetStream(); - public static Stream YouWin => GetStream(); - public static Stream Thanks => GetStream(); - public static Stream Headings => GetStream(); - } - - internal static class Prompts - { - public static string ForInstructions => GetString(); - public static string TenNumbers => GetString(); - public static string WantToTryAgain => GetString(); - } - - internal static class Formats - { - public static string GuessResult => GetString(); - } - - 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/34_Digits/csharp/Resources/TenNumbers.txt b/34_Digits/csharp/Resources/TenNumbers.txt deleted file mode 100644 index ad03893a6..000000000 --- a/34_Digits/csharp/Resources/TenNumbers.txt +++ /dev/null @@ -1,2 +0,0 @@ - -Ten numbers, please \ No newline at end of file diff --git a/34_Digits/csharp/Resources/Thanks.txt b/34_Digits/csharp/Resources/Thanks.txt deleted file mode 100644 index 15d42e1b9..000000000 --- a/34_Digits/csharp/Resources/Thanks.txt +++ /dev/null @@ -1,2 +0,0 @@ - -Thanks for the game diff --git a/34_Digits/csharp/Resources/TryAgain.txt b/34_Digits/csharp/Resources/TryAgain.txt deleted file mode 100644 index 74bdca683..000000000 --- a/34_Digits/csharp/Resources/TryAgain.txt +++ /dev/null @@ -1,2 +0,0 @@ -Only use the digits '0', '1', or '2'. -Let's try again. diff --git a/34_Digits/csharp/Resources/WantToTryAgain.txt b/34_Digits/csharp/Resources/WantToTryAgain.txt deleted file mode 100644 index 38f4509db..000000000 --- a/34_Digits/csharp/Resources/WantToTryAgain.txt +++ /dev/null @@ -1 +0,0 @@ -Do you want to try again (1 for yes, 0 for no) \ No newline at end of file diff --git a/34_Digits/csharp/Resources/YouWin.txt b/34_Digits/csharp/Resources/YouWin.txt deleted file mode 100644 index 87b26b381..000000000 --- a/34_Digits/csharp/Resources/YouWin.txt +++ /dev/null @@ -1,4 +0,0 @@ - -I guessed less than 1/3 of your numbers. -You beat me. Congratulations ***** - diff --git a/34_Digits/perl/digits.pl b/34_Digits/perl/digits.pl deleted file mode 100755 index 2f49bd0e9..000000000 --- a/34_Digits/perl/digits.pl +++ /dev/null @@ -1,125 +0,0 @@ -#!/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"; diff --git a/34_Digits/python/Digits.py b/34_Digits/python/Digits.py index 16e2db7d8..f018c539e 100644 --- a/34_Digits/python/Digits.py +++ b/34_Digits/python/Digits.py @@ -1,5 +1,4 @@ import random -from typing import List def print_intro() -> None: @@ -31,7 +30,7 @@ def print_instructions() -> None: print() -def read_10_numbers() -> List[int]: +def read_10_numbers(): print("TEN NUMBERS, PLEASE ? ") numbers = [] @@ -48,7 +47,7 @@ def read_10_numbers() -> List[int]: return numbers -def read_continue_choice() -> bool: +def read_continue_choice(): print("\nDO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO) ? ") try: choice = int(input()) diff --git a/35_Even_Wins/python/evenwins.py b/35_Even_Wins/python/evenwins.py index b5a198298..b18806c74 100644 --- a/35_Even_Wins/python/evenwins.py +++ b/35_Even_Wins/python/evenwins.py @@ -1,36 +1,41 @@ -""" -This version of evenwins.bas based on game decscription and does *not* -follow the source. The computer chooses marbles at random. - -For simplicity, global variables are used to store the game state. -A good exercise would be to replace this with a class. -The code is not short, but hopefully it is easy for beginners to understand -and modify. - -Infinite loops of the style "while True:" are used to simplify some of the -code. The "continue" keyword is used in a few places to jump back to the top -of the loop. The "return" keyword is also used to break out of functions. -This is generally considered poor style, but in this case it simplifies the -code and makes it easier to read (at least in my opinion). A good exercise -would be to remove these infinite loops, and uses of continue, to follow a -more structured style. -""" - - -from dataclasses import dataclass -from typing import Literal, Tuple - -PlayerType = Literal["human", "computer"] - - -@dataclass -class MarbleCounts: - middle: int - human: int - computer: int - - -def print_intro() -> None: +# evenwins.py + +# +# This version of evenwins.bas based on game decscription and does *not* +# follow the source. The computer chooses marbles at random. +# +# For simplicity, global variables are used to store the game state. +# A good exercise would be to replace this with a class. +# +# The code is not short, but hopefully it is easy for beginners to understand +# and modify. +# +# Infinite loops of the style "while True:" are used to simplify some of the +# code. The "continue" keyword is used in a few places to jump back to the top +# of the loop. The "return" keyword is also used to break out of functions. +# This is generally considered poor style, but in this case it simplifies the +# code and makes it easier to read (at least in my opinion). A good exercise +# would be to remove these infinite loops, and uses of continue, to follow a +# more structured style. +# + +# global variables +marbles_in_middle = -1 +human_marbles = -1 +computer_marbles = -1 +whose_turn = "" + + +def serious_error(msg): + """ + Only call this function during development for serious errors that are due + to mistakes in the program. Should never be called during a regular game. + """ + print("serious_error: " + msg) + exit(1) + + +def welcome_screen(): print("Welcome to Even Wins!") print("Based on evenwins.bas from Creative Computing") print() @@ -45,17 +50,22 @@ def print_intro() -> None: print() -def marbles_str(n: int) -> str: - return "1 marble" if n == 1 else f"{n} marbles" +def marbles_str(n): + if n == 1: + return "1 marble" + return f"{n} marbles" -def choose_first_player() -> PlayerType: +def choose_first_player(): + global whose_turn while True: ans = input("Do you want to play first? (y/n) --> ") if ans == "y": - return "human" + whose_turn = "human" + return elif ans == "n": - return "computer" + whose_turn = "computer" + return else: print() print('Please enter "y" if you want to play first,') @@ -63,12 +73,18 @@ def choose_first_player() -> PlayerType: print() -def toggle_player(whose_turn: PlayerType) -> PlayerType: - return "computer" if whose_turn == "human" else "human" +def next_player(): + global whose_turn + if whose_turn == "human": + whose_turn = "computer" + elif whose_turn == "computer": + whose_turn = "human" + else: + serious_error(f"play_game: unknown player {whose_turn}") -def to_int(s: str) -> Tuple[bool, int]: - """Convert a string s to an int, if possible.""" +# Converts a string s to an int, if possible. +def to_int(s): try: n = int(s) return True, n @@ -76,104 +92,142 @@ def to_int(s: str) -> Tuple[bool, int]: return False, 0 -def print_board(marbles: MarbleCounts) -> None: +def print_board() -> None: + global marbles_in_middle + global human_marbles + global computer_marbles print() - print(f" marbles in the middle: {marbles.middle} " + marbles.middle * "*") - print(f" # marbles you have: {marbles.human}") - print(f"# marbles computer has: {marbles.computer}") + print(f" marbles in the middle: {marbles_in_middle} " + marbles_in_middle * "*") + print(f" # marbles you have: {human_marbles}") + print(f"# marbles computer has: {computer_marbles}") print() -def human_turn(marbles: MarbleCounts) -> None: - """get number in range 1 to min(4, marbles.middle)""" - max_choice = min(4, marbles.middle) +def human_turn(): + global marbles_in_middle + global human_marbles + + # get number in range 1 to min(4, marbles_in_middle) + max_choice = min(4, marbles_in_middle) print("It's your turn!") while True: s = input(f"Marbles to take? (1 - {max_choice}) --> ") ok, n = to_int(s) if not ok: - print(f"\n Please enter a whole number from 1 to {max_choice}\n") + print() + print(f" Please enter a whole number from 1 to {max_choice}") + print() continue if n < 1: - print("\n You must take at least 1 marble!\n") + print() + print(" You must take at least 1 marble!") + print() continue if n > max_choice: - print(f"\n You can take at most {marbles_str(max_choice)}\n") + print() + print(f" You can take at most {marbles_str(max_choice)}") + print() continue - print(f"\nOkay, taking {marbles_str(n)} ...") - marbles.middle -= n - marbles.human += n + print() + print(f"Okay, taking {marbles_str(n)} ...") + marbles_in_middle -= n + human_marbles += n return -def game_over(marbles: MarbleCounts) -> None: +def game_over(): + global marbles_in_middle + global human_marbles + global computer_marbles print() print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") print("!! All the marbles are taken: Game Over!") print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!") print() - print_board(marbles) - if marbles.human % 2 == 0: + print_board() + if human_marbles % 2 == 0: print("You are the winner! Congratulations!") else: print("The computer wins: all hail mighty silicon!") - print() + print("") -def computer_turn(marbles: MarbleCounts) -> None: +def computer_turn(): + global marbles_in_middle + global computer_marbles + global human_marbles + marbles_to_take = 0 print("It's the computer's turn ...") - r = marbles.middle - 6 * int(marbles.middle / 6) + r = marbles_in_middle - 6 * int(marbles_in_middle / 6) # line 500 - if int(marbles.human / 2) == marbles.human / 2: - 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: + if int(human_marbles / 2) == human_marbles / 2: # line 510 + if r < 1.5 or r > 5.3: # lines 710 and 720 + marbles_to_take = 1 + else: + marbles_to_take = r - 1 + + elif marbles_in_middle < 4.2: # line 580 + marbles_to_take = marbles_in_middle + elif r > 3.4: # line 530 if r < 4.7 or r > 3.5: marbles_to_take = 4 else: marbles_to_take = r + 1 print(f"Computer takes {marbles_str(marbles_to_take)} ...") - marbles.middle -= marbles_to_take - marbles.computer += marbles_to_take + marbles_in_middle -= marbles_to_take + computer_marbles += marbles_to_take + +def play_game(): + global marbles_in_middle + global human_marbles + global computer_marbles -def play_game(whose_turn: PlayerType) -> None: - marbles = MarbleCounts(middle=27, human=0, computer=0) - print_board(marbles) + # initialize the game state + marbles_in_middle = 27 + human_marbles = 0 + computer_marbles = 0 + print_board() while True: - if marbles.middle == 0: - game_over(marbles) + if marbles_in_middle == 0: + game_over() return elif whose_turn == "human": - human_turn(marbles) - print_board(marbles) - whose_turn = toggle_player(whose_turn) + human_turn() + print_board() + next_player() elif whose_turn == "computer": - computer_turn(marbles) - print_board(marbles) - whose_turn = toggle_player(whose_turn) + computer_turn() + print_board() + next_player() else: - raise Exception(f"whose_turn={whose_turn} is not 'human' or 'computer'") + serious_error(f"play_game: unknown player {whose_turn}") def main() -> None: - print_intro() + global whose_turn + + welcome_screen() while True: - whose_turn = choose_first_player() - play_game(whose_turn) + choose_first_player() + play_game() + # ask if the user if they want to play again print() - again = input("Would you like to play again? (y/n) --> ").lower() + again = input("Would you like to play again? (y/n) --> ") if again == "y": - print("\nOk, let's play again ...\n") + print() + print("Ok, let's play again ...") + print() else: - print("\nOk, thanks for playing ... goodbye!\n") + print() + print("Ok, thanks for playing ... goodbye!") + print() return diff --git a/35_Even_Wins/rust/Cargo.lock b/35_Even_Wins/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/35_Even_Wins/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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/35_Even_Wins/rust/Cargo.toml b/35_Even_Wins/rust/Cargo.toml deleted file mode 100644 index 1ec696335..000000000 --- a/35_Even_Wins/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/35_Even_Wins/rust/src/main.rs b/35_Even_Wins/rust/src/main.rs deleted file mode 100644 index 18a08a3a2..000000000 --- a/35_Even_Wins/rust/src/main.rs +++ /dev/null @@ -1,229 +0,0 @@ -use std::io; - -fn print_intro() { - println!( - "Welcome to Even Wins! -Based on evenwins.bas from Creative Computing - -Even Wins is a two-person game. You start with -27 marbles in the middle of the table. - -Players alternate taking marbles from the middle. -A player can take 1 to 4 marbles on their turn, and -turns cannot be skipped. The game ends when there are -no marbles left, and the winner is the one with an even -number of marbles. -" - ); -} - -#[derive(Debug)] -enum PlayerType { - Human, - Computer, -} - -#[derive(Debug)] -struct Game { - turn: PlayerType, - middle: u32, - human: u32, - computer: u32, - min_take: u32, - max_take: u32, -} - -impl Game { - fn get_max_take(&mut self) -> u32 { - if self.max_take > self.middle { - return self.middle; - } - return self.max_take; - } - - fn take(&mut self, num: u32) -> bool { - let max_take = self.get_max_take(); - if num > max_take { - println!("You can take at most {} marbles", max_take); - return false; - } - if num < self.min_take { - println!("You must take at least {} marble!", self.min_take); - return false; - } - - self.middle -= num; - match self.turn { - PlayerType::Computer => self.computer += num, - PlayerType::Human => self.human += num, - } - return true; - } - - fn next(&mut self) { - self.turn = match self.turn { - PlayerType::Computer => PlayerType::Human, - PlayerType::Human => PlayerType::Computer, - } - } - - fn info(&mut self) { - println!(""); - println!( - "marbles in the middle: {} **************************", - self.middle - ); - println!("# marbles you have: {}", self.human); - println!("# marbles computer has: {}", self.computer); - println!(""); - } - - fn wininfo(&mut self) { - if self.middle != 0 { - return; - } - println!("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n!! All the marbles are taken: Game Over!\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); - self.info(); - - if self.human % 2 == 0 { - println!("You are the winner! Congratulations!"); - } else { - println!("The computer wins: all hail mighty silicon!"); - } - - println!(""); - } -} - -fn human_play(game: &mut Game) { - println!("It's your turn!"); - loop { - let max_take = game.get_max_take(); - println!("Marbles to take? ({} - {}) --> ", game.min_take, max_take); - - let mut num = String::new(); - io::stdin() - .read_line(&mut num) - .expect("Failed to read line"); - - let _: u32 = match num.trim().to_uppercase().parse() { - Ok(num) => { - if game.take(num) { - println!("Okay, taking {} marble ...", num); - break; - }; - println!(""); - continue; - } - _ => { - println!("Please enter a whole number from 1 to 4"); - println!(""); - continue; - } - }; - } -} - -fn compute_play(game: &mut Game) { - println!("It's the computer's turn ..."); - - let marbles_to_take: u32; - - // the magic 6 and 1.5, 5.3 3.4 4.7 3.5 was copy from python implement - let r: f32 = (game.middle % 6) as f32; - if game.human % 2 == 0 { - if r < 1.5 || r > 5.3 { - marbles_to_take = 1; - } else { - marbles_to_take = (r - 1.0) as u32; - } - } else if game.middle <= 4 { - marbles_to_take = game.middle - } else if r > 3.4 { - if r < 4.7 || r > 3.5 { - marbles_to_take = 4; - } else { - marbles_to_take = 1; - } - } else { - marbles_to_take = (r + 1.0) as u32; - } - - game.take(marbles_to_take); - println!("Computer takes {} marble ...", marbles_to_take); -} - -fn run_game(turn: PlayerType) { - let mut game = Game { - turn: turn, - middle: 27, - computer: 0, - human: 0, - min_take: 1, - max_take: 4, - }; - - while game.middle > 0 { - match game.turn { - PlayerType::Computer => { - compute_play(&mut game); - } - PlayerType::Human => { - human_play(&mut game); - } - } - game.info(); - game.next(); - } - game.wininfo(); -} - -fn choose_first_player() -> PlayerType { - loop { - println!("Do you want to play first? (y/n) -->"); - - let mut flag = String::new(); - io::stdin() - .read_line(&mut flag) - .expect("Failed to read line"); - - match flag.trim().to_uppercase().as_str() { - "Y" => return PlayerType::Human, - "N" => return PlayerType::Computer, - _ => { - println!("Please enter \"y\" if you want to play first,\nor \"n\" if you want to play second.\n"); - } - }; - } -} - -fn choose_play_again() -> bool { - println!("Would you like to play again? (y/n) --> "); - let mut flag = String::new(); - io::stdin() - .read_line(&mut flag) - .expect("Failed to read line"); - - match flag.trim().to_uppercase().as_str() { - "Y" => { - println!("\nOk, let's play again ...\n"); - return true; - } - _ => { - println!("\nOk, thanks for playing ... goodbye!\n"); - return false; - } - } -} - -fn main() { - print_intro(); - loop { - let first = choose_first_player(); - run_game(first); - - if !choose_play_again() { - return; - } - } -} diff --git a/36_Flip_Flop/perl/flipflop.pl b/36_Flip_Flop/perl/flipflop.pl deleted file mode 100755 index 63e3f84e7..000000000 --- a/36_Flip_Flop/perl/flipflop.pl +++ /dev/null @@ -1,124 +0,0 @@ -#!/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); -} diff --git a/36_Flip_Flop/python/flipflop.py b/36_Flip_Flop/python/flipflop.py index 8ea7e5b1f..6472a58fa 100644 --- a/36_Flip_Flop/python/flipflop.py +++ b/36_Flip_Flop/python/flipflop.py @@ -61,7 +61,7 @@ def print_instructions() -> None: print("11 (ELEVEN).\n") -def main() -> None: +def main(): q = random.random() print("HERE IS THE STARTING LINE OF X'S.\n") @@ -75,9 +75,9 @@ def main() -> None: if legal_move: print(" ".join([str(i) for i in range(1, 11)])) print(" ".join(row[1:]) + "\n") - m_str = input("INPUT THE NUMBER\n") + m = input("INPUT THE NUMBER\n") try: - m = int(m_str) + m = int(m) if m > 11 or m < 0: raise ValueError() except ValueError: diff --git a/36_Flip_Flop/rust/Cargo.lock b/36_Flip_Flop/rust/Cargo.lock deleted file mode 100644 index 81365033b..000000000 --- a/36_Flip_Flop/rust/Cargo.lock +++ /dev/null @@ -1,82 +0,0 @@ -# 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/36_Flip_Flop/rust/Cargo.toml b/36_Flip_Flop/rust/Cargo.toml deleted file mode 100644 index 6989f4b29..000000000 --- a/36_Flip_Flop/rust/Cargo.toml +++ /dev/null @@ -1,10 +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] -rand = "0.8.5" -morristown = "0.1.3" diff --git a/36_Flip_Flop/rust/src/game.rs b/36_Flip_Flop/rust/src/game.rs deleted file mode 100644 index b0eab60a2..000000000 --- a/36_Flip_Flop/rust/src/game.rs +++ /dev/null @@ -1,125 +0,0 @@ -pub struct Game { - board: [char; 10], - last_move: u8, - entropy: f32, - tries: u8, -} - -impl Game { - pub fn new() -> Self { - Game { - board: ['X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'], - last_move: 0, - entropy: 0., - tries: 0, - } - } - - pub fn play(&mut self) -> bool { - self.reset_game(); - - println!("\nHERE IS THE STARTING LINE OF X'S.\n"); - println!("1 2 3 4 5 6 7 8 9 10"); - println!("X X X X X X X X X X\n"); - - let mut reset = false; - - loop { - self.tries += 1; - - match Game::get_number() { - 0 => self.reset_board(), - 11 => { - reset = true; - break; - } - n => { - self.flip(n); - - let other = self.get_other(n, n == self.last_move); - if other != n { - self.flip(other); - } - - println!("other: {}", other); - self.last_move = n; - } - } - self.draw(); - - if !self.board.iter().any(|c| *c == 'X') { - break; - } - } - - if !reset { - let t = self.tries; - - if t > 12 { - println!("TRY HARDER NEXT TIME. IT TOOK YOU {t} GUESSES."); - } else { - println!("VERY GOOD. IT TOOK YOU ONLY {t} GUESSES."); - } - - return morristown::prompt_bool("DO YOU WANT TO TRY ANOTHER PUZZLE?", false); - } - - true - } - - fn flip(&mut self, i: u8) { - if (1..=10).contains(&i) { - let i = (i - 1) as usize; - let char = &mut self.board[i]; - - match char { - 'X' => *char = '0', - '0' => *char = 'X', - _ => println!("INVALID BOARD CHARACTER!"), - } - } - } - - fn get_other(&self, m: u8, equals_last_move: bool) -> u8 { - let e = self.entropy; - let m = m as f32; - - let rate = if equals_last_move { - 0.592 * (1. / (e / m + e).tan()) / (m * 2. + e).sin() - m.cos() - } else { - (e + m / e - m).tan() - (e / m).sin() + 336. * (8. * m).sin() - }; - - (10. * (rate - rate.floor())).floor() as u8 - } - - fn draw(&self) { - println!("1 2 3 4 5 6 7 8 9 10"); - for c in self.board { - print!("{c} "); - } - println!(); - } - - fn get_number() -> u8 { - loop { - let n = morristown::prompt_number::("INPUT THE NUMBER?"); - if n > 11 { - println!("ILLEGAL ENTRY--TRY AGAIN."); - } else { - return n; - } - } - } - - fn reset_board(&mut self) { - self.board = ['X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X']; - } - - fn reset_game(&mut self) { - self.reset_board(); - self.last_move = 0; - self.entropy = rand::random(); - self.tries = 0; - } -} diff --git a/36_Flip_Flop/rust/src/main.rs b/36_Flip_Flop/rust/src/main.rs deleted file mode 100644 index f7c72c865..000000000 --- a/36_Flip_Flop/rust/src/main.rs +++ /dev/null @@ -1,24 +0,0 @@ -mod game; -use crate::game::Game; - -fn main() { - morristown::print_intro("FLIPFLOP"); - - println!("THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\n"); - println!("X X X X X X X X X X\n"); - println!("TO THIS:\n"); - println!("O O O O O O O O O O\n"); - println!("BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE"); - println!("LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON"); - println!("OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0"); - println!("(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE "); - println!("11 (ELEVEN)."); - - let mut game = Game::new(); - - loop { - if !game.play() { - break; - } - } -} diff --git a/37_Football/python/README.md b/37_Football/python/README.md index 1f375dd88..781945ec4 100644 --- a/37_Football/python/README.md +++ b/37_Football/python/README.md @@ -1,30 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Python](https://www.python.org/about/) - - -## Porting notes - -Variables: - -* E: score_limit -* H(2): Scores -* T(2): Team toggle -* T: team who currently possesses the ball -* L: Offset -* P: Who has the ball -* K: yards -* R: Runback current team in yards -* P$(20): Actions (see data.json) - -Functions: - -* `P$(I)`: Access index `I` of the `P` array -* ABS: abs (absolute value) -* RND(1): random() -* GOSUB: Execute a function - will jump back to this -* GOTO: Just jump - -Patterns: - -* `T=T(T)`: Toggle the team who currently has the ball diff --git a/37_Football/python/data.json b/37_Football/python/data.json deleted file mode 100644 index c387bc674..000000000 --- a/37_Football/python/data.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "players": [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], - "actions": ["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!!!!"] -} diff --git a/37_Football/python/football.py b/37_Football/python/football.py deleted file mode 100644 index c84c8df61..000000000 --- a/37_Football/python/football.py +++ /dev/null @@ -1,452 +0,0 @@ -""" -FOOTBALL - -A game. - -Ported to Python by Martin Thoma in 2022. -The JavaScript version by Oscar Toledo G. (nanochess) was used -""" -# NOTE: The newlines might be wrong - -import json -from math import floor -from pathlib import Path -from random import randint, random -from typing import List, Tuple - -with open(Path(__file__).parent / "data.json") as f: - data = json.load(f) - -player_data = [num - 1 for num in data["players"]] -actions = data["actions"] - - -aa: List[int] = [-100 for _ in range(20)] -ba: List[int] = [-100 for _ in range(20)] -ca: List[int] = [-100 for _ in range(40)] -score: List[int] = [0, 0] -ta: Tuple[int, int] = (1, 0) -wa: Tuple[int, int] = (-1, 1) -xa: Tuple[int, int] = (100, 0) -ya: Tuple[int, int] = (1, -1) -za: Tuple[int, int] = (0, 100) -marker: Tuple[str, str] = ("--->", "<---") -t: int = 0 -p: int = 0 -winning_score: int - - -def ask_bool(prompt: str) -> bool: - while True: - answer = input(prompt).lower() - if answer in ["yes", "y"]: - return True - elif answer in ["no", "n"]: - return False - - -def ask_int(prompt: str) -> int: - while True: - answer = input(prompt) - try: - return int(answer) - except Exception: - pass - - -def get_offense_defense() -> Tuple[int, int]: - while True: - input_str = input("INPUT OFFENSIVE PLAY, DEFENSIVE PLAY: ") - try: - p1, p2 = (int(n) for n in input_str.split(",")) - return p1, p2 - except Exception: - pass - - -def field_headers() -> None: - print("TEAM 1 [0 10 20 30 40 50 60 70 80 90 100] TEAM 2") - print("\n\n") - - -def separator() -> None: - print("+" * 72 + "\n") - - -def show_ball() -> None: - da: Tuple[int, int] = (0, 3) - print(" " * (da[t] + 5 + int(p / 2)) + marker[t] + "\n") - field_headers() - - -def show_scores() -> bool: - print() - print(f"TEAM 1 SCORE IS {score[0]}") - print(f"TEAM 2 SCORE IS {score[1]}") - print() - if score[t] >= winning_score: - print(f"TEAM {t+1} WINS*******************") - return True - return False - - -def loss_posession() -> None: - global t - print() - print(f"** LOSS OF POSSESSION FROM TEAM {t+1} TO TEAM {ta[t]+1}") - print() - separator() - print() - t = ta[t] - - -def touchdown() -> None: - print() - print(f"TOUCHDOWN BY TEAM {t+1} *********************YEA TEAM") - q = 7 - g = random() - if g <= 0.1: - q = 6 - print("EXTRA POINT NO GOOD") - else: - print("EXTRA POINT GOOD") - score[t] = score[t] + q - - -def print_header() -> None: - print(" " * 32 + "FOOTBALL") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") - print("PRESENTING N.F.U. FOOTBALL (NO FORTRAN USED)\n\n") - - -def print_instructions() -> None: - print( - """THIS IS A FOOTBALL GAME FOR TWO TEAMS IN WHICH PLAYERS MUST -PREPARE A TAPE WITH A DATA STATEMENT (1770 FOR TEAM 1, -1780 FOR TEAM 2) IN WHICH EACH TEAM SCRAMBLES NOS. 1-20 -THESE NUMBERS ARE THEN ASSIGNED TO TWENTY GIVEN PLAYS. -A LIST OF NOS. AND THEIR PLAYS IS PROVIDED WITH -BOTH TEAMS HAVING THE SAME PLAYS. THE MORE SIMILAR THE -PLAYS THE LESS YARDAGE GAINED. SCORES ARE GIVEN -WHENEVER SCORES ARE MADE. SCORES MAY ALSO BE OBTAINED -BY INPUTTING 99,99 FOR PLAY NOS. TO PUNT OR ATTEMPT A -FIELD GOAL, INPUT 77,77 FOR PLAY NUMBERS. QUESTIONS WILL BE -ASKED THEN. ON 4TH DOWN, YOU WILL ALSO BE ASKED WHETHER -YOU WANT TO PUNT OR ATTEMPT A FIELD GOAL. IF THE ANSWER TO -BOTH QUESTIONS IS NO IT WILL BE ASSUMED YOU WANT TO -TRY AND GAIN YARDAGE. ANSWER ALL QUESTIONS YES OR NO. -THE GAME IS PLAYED UNTIL PLAYERS TERMINATE (CONTROL-C). -PLEASE PREPARE A TAPE AND RUN. -""" - ) - - -def main() -> None: - global winning_score - print_header() - want_instructions = ask_bool("DO YOU WANT INSTRUCTIONS? ") - if want_instructions: - print_instructions() - print() - winning_score = ask_int("PLEASE INPUT SCORE LIMIT ON GAME: ") - for i in range(40): - index = player_data[i - 1] - if i < 20: - aa[index] = i - else: - ba[index] = i - 20 - ca[i] = index - offset = 0 - for t in [0, 1]: - print(f"TEAM {t+1} PLAY CHART") - print("NO. PLAY") - for i in range(20): - input_str = f"{ca[i + offset]}" - while len(input_str) < 6: - input_str += " " - input_str += actions[i] - print(input_str) - offset += 20 - t = 1 - print() - print("TEAR OFF HERE----------------------------------------------") - print("\n" * 10) - - field_headers() - print("TEAM 1 DEFEND 0 YD GOAL -- TEAM 2 DEFENDS 100 YD GOAL.") - t = randint(0, 1) - print() - print("THE COIN IS FLIPPED") - routine = 1 - while True: - if routine <= 1: - p = xa[t] - ya[t] * 40 - separator() - print(f"TEAM {t+1} RECEIVES KICK-OFF") - k = floor(26 * random() + 40) - if routine <= 2: - p = p - ya[t] * k - if routine <= 3: - if wa[t] * p >= za[t] + 10: - print("BALL WENT OUT OF ENDZONE --AUTOMATIC TOUCHBACK--") - p = za[t] - wa[t] * 20 - if routine <= 4: - routine = 5 - else: - print(f"BALL WENT {k} YARDS. NOW ON {p}") - show_ball() - - if routine <= 4: - want_runback = ask_bool(f"TEAM {t+1} DO YOU WANT TO RUNBACK? ") - - if want_runback: - k = floor(9 * random() + 1) - r = floor(((xa[t] - ya[t] * p + 25) * random() - 15) / k) - p = p - wa[t] * r - print(f"RUNBACK TEAM {t+1} {r} YARDS") - g = random() - if g < 0.25: - loss_posession() - routine = 4 - continue - elif ya[t] * p >= xa[t]: - touchdown() - if show_scores(): - return - t = ta[t] - routine = 1 - continue - elif wa[t] * p >= za[t]: - print(f"SAFETY AGAINST TEAM {t+1} **********************OH-OH") - score[ta[t]] = score[ta[t]] + 2 - if show_scores(): - return - - p = za[t] - wa[t] * 20 - want_punt = ask_bool( - f"TEAM {t+1} DO YOU WANT TO PUNT INSTEAD OF A KICKOFF? " - ) - if want_punt: - print(f"TEAM {t+1} WILL PUNT") - g = random() - if g < 0.25: - loss_posession() - routine = 4 - continue - - print() - separator() - k = floor(25 * random() + 35) - t = ta[t] - routine = 2 - continue - - touchdown() - if show_scores(): - return - t = ta[t] - routine = 1 - continue - else: - routine = 5 - continue - - else: - if wa[t] * p >= za[t]: - p = za[t] - wa[t] * 20 - - if routine <= 5: - d = 1 - s = p - - if routine <= 6: - print("=" * 72 + "\n") - print(f"TEAM {t+1} DOWN {d} ON {p}") - if d == 1: - if ya[t] * (p + ya[t] * 10) >= xa[t]: - c = 8 - else: - c = 4 - - if c != 8: - yards = 10 - (ya[t] * p - ya[t] * s) - print(" " * 27 + f"{yards} YARDS TO 1ST DOWN") - else: - yards = xa[t] - ya[t] * p - print(" " * 27 + f"{yards} YARDS") - - show_ball() - if d == 4: - routine = 8 - - if routine <= 7: - u = floor(3 * random() - 1) - while True: - p1, p2 = get_offense_defense() - if t != 1: - p2, p1 = p1, p2 - - if p1 == 99: - if show_scores(): - return - if p1 == 99: - continue - - if p1 < 1 or p1 > 20 or p2 < 1 or p2 > 20: - print("ILLEGAL PLAY NUMBER, CHECK AND ", end="") - continue - - break - p1 -= 1 - p2 -= 1 - - if d == 4 or p1 == 77: - want_punt = ask_bool(f"DOES TEAM {t+1} WANT TO PUNT? ") - - if want_punt: - print() - print(f"TEAM {t+1} WILL PUNT") - g = random() - if g < 0.25: - loss_posession() - routine = 4 - continue - - print() - separator() - k = floor(25 * random() + 35) - t = ta[t] - routine = 2 - continue - - attempt_field_goal = ask_bool( - f"DOES TEAM {t+1} WANT TO ATTEMPT A FIELD GOAL? " - ) - - if attempt_field_goal: - print() - print(f"TEAM {t+1} WILL ATTEMPT A FIELD GOAL") - g = random() - if g < 0.025: - loss_posession() - routine = 4 - continue - else: - f = floor(35 * random() + 20) - print() - print(f"KICK IS {f} YARDS LONG") - p = p - wa[t] * f - g = random() - if g < 0.35: - print("BALL WENT WIDE") - elif ya[t] * p >= xa[t]: - print( - f"FIELD GOLD GOOD FOR TEAM {t+1} *********************YEA" - ) - q = 3 - score[t] = score[t] + q - if show_scores(): - return - t = ta[t] - routine = 1 - continue - - print(f"FIELD GOAL UNSUCCESFUL TEAM {t+1}-----------------TOO BAD") - print() - separator() - if ya[t] * p < xa[t] + 10: - print() - print(f"BALL NOW ON {p}") - t = ta[t] - show_ball() - routine = 4 - continue - else: - t = ta[t] - routine = 3 - continue - - else: - routine = 7 - continue - - y = floor( - abs(aa[p1] - ba[p2]) / 19 * ((xa[t] - ya[t] * p + 25) * random() - 15) - ) - print() - if t == 1 and aa[p1] < 11 or t == 2 and ba[p2] < 11: - print("THE BALL WAS RUN") - elif u == 0: - print(f"PASS INCOMPLETE TEAM {t+1}") - y = 0 - else: - g = random() - if g <= 0.025 and y > 2: - print("PASS COMPLETED") - else: - print("QUARTERBACK SCRAMBLED") - - p = p - wa[t] * y - print() - print(f"NET YARDS GAINED ON DOWN {d} ARE {y}") - - g = random() - if g <= 0.025: - loss_posession() - routine = 4 - continue - elif ya[t] * p >= xa[t]: - touchdown() - if show_scores(): - return - t = ta[t] - routine = 1 - continue - elif wa[t] * p >= za[t]: - print() - print(f"SAFETY AGAINST TEAM {t+1} **********************OH-OH") - score[ta[t]] = score[ta[t]] + 2 - if show_scores(): - return - p = za[t] - wa[t] * 20 - want_punt = ask_bool( - f"TEAM {t+1} DO YOU WANT TO PUNT INSTEAD OF A KICKOFF? " - ) - if want_punt: - print() - print(f"TEAM {t+1} WILL PUNT") - g = random() - if g < 0.25: - loss_posession() - routine = 4 - continue - - print() - separator() - k = floor(25 * random() + 35) - t = ta[t] - routine = 2 - continue - - touchdown() - if show_scores(): - return - t = ta[t] - routine = 1 - elif ya[t] * p - ya[t] * s >= 10: - routine = 5 - else: - d += 1 - if d != 5: - routine = 6 - else: - print() - print(f"CONVERSION UNSUCCESSFUL TEAM {t+1}") - t = ta[t] - print() - separator() - routine = 5 - - -if __name__ == "__main__": - main() diff --git a/38_Fur_Trader/README.md b/38_Fur_Trader/README.md index 6b08911ae..8406487e7 100644 --- a/38_Fur_Trader/README.md +++ b/38_Fur_Trader/README.md @@ -15,10 +15,6 @@ 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) diff --git a/38_Fur_Trader/perl/README.md b/38_Fur_Trader/perl/README.md index c7001be76..e69c8b819 100644 --- a/38_Fur_Trader/perl/README.md +++ b/38_Fur_Trader/perl/README.md @@ -1,5 +1,3 @@ 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 deleted file mode 100755 index f1e6b01ad..000000000 --- a/38_Fur_Trader/perl/furtrader.pl +++ /dev/null @@ -1,265 +0,0 @@ -#!/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; -} diff --git a/38_Fur_Trader/python/furtrader.py b/38_Fur_Trader/python/furtrader.py index 0755c4100..f65bf5182 100755 --- a/38_Fur_Trader/python/furtrader.py +++ b/38_Fur_Trader/python/furtrader.py @@ -1,8 +1,7 @@ -#!/usr/bin/env python3 +#! /usr/bin/env python3 import random # for generating random numbers import sys # for system function, like exit() -from typing import List # global variables for storing player's status player_funds: float = 0 # no money @@ -23,7 +22,13 @@ FORT_NAMES = ["HOCHELAGA (MONTREAL)", "STADACONA (QUEBEC)", "NEW YORK"] -def show_introduction() -> None: +def print_at_column(column: int, words: str) -> None: + """Print the words at the specified column""" + spaces = " " * column # make a fat string of spaces + print(spaces + words) + + +def show_introduction(): """Show the player the introductory message""" print("YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN ") print("1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET") @@ -31,16 +36,16 @@ def show_introduction() -> None: 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() + print("") -def get_fort_choice() -> int: +def get_fort_choice(): """Show the player the choices of Fort, get their input, if the input is a valid choice (1,2,3) return it, otherwise keep prompting the user.""" result = 0 while result == 0: - print() + print("") 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.") @@ -63,9 +68,9 @@ def get_fort_choice() -> int: return result -def show_fort_comment(which_fort) -> None: +def show_fort_comment(which_fort): """Print the description for the fort""" - print() + print("") if which_fort == FORT_MONTREAL: print("YOU HAVE CHOSEN THE EASIEST ROUTE. HOWEVER, THE FORT") print("IS FAR FROM ANY SEAPORT. THE VALUE") @@ -82,17 +87,17 @@ 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(f"Internal error #1, fort {str(which_fort)} does not exist") + print("Internal error #1, fort " + str(which_fort) + " does not exist") sys.exit(1) # you have a bug - print() + print("") -def get_yes_or_no() -> str: +def get_yes_or_no(): """Prompt the player to enter 'YES' or 'NO'. Keep prompting until valid input is entered. Accept various spellings by only checking the first letter of input. Return a single letter 'Y' or 'N'""" - result = "" + result = 0 while result not in ("Y", "N"): print("ANSWER YES OR NO") player_choice = input(">> ") @@ -104,41 +109,43 @@ def get_yes_or_no() -> str: return result -def get_furs_purchase() -> List[int]: +def get_furs_purchase(): """Prompt the player for how many of each fur type they want. Accept numeric inputs, re-prompting on incorrect input values""" - results: List[int] = [] + results = [] - print(f"YOUR {str(MAX_FURS)} FURS ARE DISTRIBUTED AMONG THE FOLLOWING") + print("YOUR " + str(MAX_FURS) + " FURS ARE DISTRIBUTED AMONG THE FOLLOWING") print("KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.") - print() + print("") - while len(results) < len(FUR_NAMES): - print(f"HOW MANY {FUR_NAMES[len(results)]} DO YOU HAVE") + for i in range(len(FUR_NAMES)): + print("HOW MANY " + FUR_NAMES[i] + " DO YOU HAVE") count_str = input(">> ") try: count = int(count_str) results.append(count) - except Exception: # invalid input, prompt again by re-looping - pass + except Exception: + # invalid input, prompt again by re-looping + i -= 1 return results -def main() -> None: - print(" " * 31 + "FUR TRADER") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - print(" " * 15 + "(Ported to Python Oct 2012 krt@krt.com.au)") +if __name__ == "__main__": + + print_at_column(31, "FUR TRADER") + print_at_column(15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print_at_column(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": show_introduction() - player_funds: float = 600 # Initial player start money + player_funds = 600 # Initial player start money player_furs = [0, 0, 0, 0] # Player fur inventory print("DO YOU WISH TO TRADE FURS?") @@ -148,13 +155,13 @@ def main() -> None: game_state = "trading" elif game_state == "trading": - print() + print("") print("YOU HAVE $ %1.2f IN SAVINGS" % (player_funds)) - print(f"AND {str(MAX_FURS)} FURS TO BEGIN THE EXPEDITION") + print("AND " + str(MAX_FURS) + " FURS TO BEGIN THE EXPEDITION") player_furs = get_furs_purchase() if sum(player_furs) > MAX_FURS: - print() + print("") print("YOU MAY NOT HAVE THAT MANY FURS.") print("DO NOT TRY TO CHEAT. I CAN ADD.") print("YOU MUST START AGAIN.") @@ -171,7 +178,7 @@ def main() -> None: game_state = "travelling" elif game_state == "travelling": - print() + print("") if which_fort == FORT_MONTREAL: mink_price = ( int((0.2 * random.random() + 0.70) * 100 + 0.5) / 100 @@ -221,10 +228,13 @@ def main() -> None: print("NO ONE WILL BUY THEM.") player_furs[FUR_FOX] = 0 else: - print(f"Internal Error #3, Out-of-bounds event_picker{str(event_picker)}") + print( + "Internal Error #3, Out-of-bounds event_picker" + + str(event_picker) + ) sys.exit(1) # you have a bug - print() + print("") print("SUPPLIES AT FORT STADACONA COST $125.00.") print("YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.") player_funds -= 140 @@ -265,16 +275,19 @@ 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(f"Internal Error #4, Out-of-bounds event_picker{str(event_picker)}") + print( + "Internal Error #4, Out-of-bounds event_picker" + + str(event_picker) + ) sys.exit(1) # you have a bug - print() + print("") print("SUPPLIES AT NEW YORK COST $85.00.") print("YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.") player_funds -= 105 else: - print(f"Internal error #2, fort {str(which_fort)} does not exist") + print("Internal error #2, fort " + str(which_fort) + " does not exist") sys.exit(1) # you have a bug # Calculate sales @@ -283,7 +296,7 @@ def main() -> None: ermine_value = ermine_price * player_furs[FUR_ERMINE] mink_value = mink_price * player_furs[FUR_MINK] - print() + print("") print("YOUR BEAVER SOLD FOR $%6.2f" % (beaver_value)) print("YOUR FOX SOLD FOR $%6.2f" % (fox_value)) print("YOUR ERMINE SOLD FOR $%6.2f" % (ermine_value)) @@ -291,19 +304,15 @@ def main() -> None: player_funds += beaver_value + fox_value + ermine_value + mink_value - print() + print("") print( "YOU NOW HAVE $ %1.2f INCLUDING YOUR PREVIOUS SAVINGS" % (player_funds) ) - print() + print("") print("DO YOU WANT TO TRADE FURS NEXT YEAR?") should_trade = get_yes_or_no() if should_trade == "N": sys.exit(0) # STOP else: game_state = "trading" - - -if __name__ == "__main__": - main() diff --git a/39_Golf/README.md b/39_Golf/README.md index f8769f99b..262e7c386 100644 --- a/39_Golf/README.md +++ b/39_Golf/README.md @@ -14,10 +14,6 @@ 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) diff --git a/39_Golf/python/golf.py b/39_Golf/python/golf.py index d60bb60bb..9339c2367 100644 --- a/39_Golf/python/golf.py +++ b/39_Golf/python/golf.py @@ -129,8 +129,8 @@ def clear_console() -> None: class Point(NamedTuple): - x: int - y: int + X: int + Y: int class GameObjType(enum.Enum): @@ -183,14 +183,14 @@ class HoleGeometry(NamedTuple): @dataclass class Plot: - x: int - y: int - offline: int + X: int + Y: int + Offline: int def get_distance(pt1: Point, pt2: Point) -> float: """distance between 2 points""" - return math.sqrt(math.pow((pt2.x - pt1.x), 2) + math.pow((pt2.y - pt1.y), 2)) + return math.sqrt(math.pow((pt2.X - pt1.X), 2) + math.pow((pt2.Y - pt1.Y), 2)) def is_in_rectangle(pt: CircleGameObj, rect: RectGameObj) -> bool: @@ -392,9 +392,9 @@ def odds(x: int) -> bool: class Golf: - ball: Ball - hole_num: int = 0 - stroke_num: int = 0 + BALL: Ball + HOLE_NUM: int = 0 + STROKE_NUM: int = 0 handicap: int = 0 player_difficulty: int = 0 hole_geometry: HoleGeometry @@ -491,10 +491,10 @@ def set_difficulty_and_hole(self, j: int) -> None: self.new_hole() def new_hole(self) -> None: - self.hole_num += 1 - self.stroke_num = 0 + self.HOLE_NUM += 1 + self.STROKE_NUM = 0 - info: HoleInfo = CourseInfo[self.hole_num] + info: HoleInfo = CourseInfo[self.HOLE_NUM] yards: int = info.yards # from tee to cup @@ -517,19 +517,19 @@ def new_hole(self) -> None: GameObjType.ROUGH, ) - self.ball = Ball(0, yards, 0, GameObjType.BALL) + self.BALL = Ball(0, yards, 0, GameObjType.BALL) self.score_card_start_new_hole() self.hole_geometry = HoleGeometry(cup, green, fairway, rough, info.hazards) - print(f" |> {self.hole_num}") + print(f" |> {self.HOLE_NUM}") print(" | ") print(" | ") print(" ^^^^^^^^^^^^^^^") print( - f"Hole #{self.hole_num}. You are at the tee. Distance {info.yards} yards, par {info.par}." + f"Hole #{self.HOLE_NUM}. You are at the tee. Distance {info.yards} yards, par {info.par}." ) print(info.description) @@ -537,7 +537,7 @@ def new_hole(self) -> None: def set_putter_and_stroke(self, strength: float) -> None: putter = self.clubs[self.putt] - self.stroke((putter[1] * (strength / 10.0)), self.putt) + self.Stroke((putter[1] * (strength / 10.0)), self.putt) def ask_gauge(self, c: int) -> None: self.club = self.clubs[c] @@ -555,19 +555,23 @@ def ask_gauge(self, c: int) -> None: ) def make_stroke(self, strength: float, c: int) -> None: - self.stroke((self.club[1] * (strength / 10.0)), c) + self.Stroke((self.club[1] * (strength / 10.0)), c) def tee_up(self) -> None: # on the green? automatically select putter # otherwise Ask club and swing strength - if self.is_on_green(self.ball) and not self.is_in_hazard( - self.ball, GameObjType.SAND + if self.is_on_green(self.BALL) and not self.is_in_hazard( + self.BALL, GameObjType.SAND ): self.putt = 10 print("[PUTTER: average 10 yards]") - msg = "Keep your head down.\n" if odds(20) else "" + if odds(20): + msg = "Keep your head down.\n" + else: + msg = "" + self.ask( - f"{msg}Choose your putt potency. (1-10)", + msg + "Choose your putt potency. (1-10)", 1, 10, self.set_putter_and_stroke, @@ -575,13 +579,13 @@ def tee_up(self) -> None: else: self.ask("What club do you choose? (1-10)", 1, 10, self.ask_gauge) - def stroke(self, club_amt: float, club_index: int) -> None: - self.stroke_num += 1 + def Stroke(self, clubAmt: float, clubIndex: int) -> None: + self.STROKE_NUM += 1 flags = 0b000000000000 # fore! only when driving - if (self.stroke_num == 1) and (club_amt > 210) and odds(30): + if (self.STROKE_NUM == 1) and (clubAmt > 210) and odds(30): print('"...Fore !"') # dub @@ -592,37 +596,37 @@ def stroke(self, club_amt: float, club_index: int) -> None: # if you're in the rough, or sand, you really should be using a wedge if ( ( - self.is_in_rough(self.ball) - or self.is_in_hazard(self.ball, GameObjType.SAND) + self.is_in_rough(self.BALL) + or self.is_in_hazard(self.BALL, GameObjType.SAND) ) - and club_index not in {8, 9} + and not (clubIndex == 8 or clubIndex == 9) and odds(40) ): flags |= dub # trap difficulty if ( - self.is_in_hazard(self.ball, GameObjType.SAND) + self.is_in_hazard(self.BALL, GameObjType.SAND) and self.player_difficulty == 4 ) and odds(20): flags |= dub # hook/slice # There's 10% chance of a hook or slice - # if it's a known player_difficulty then increase chance to 30% - # if it's a putt & putting is a player_difficulty increase to 30% + # if it's a known playerDifficulty then increase chance to 30% + # if it's a putt & putting is a playerDifficulty increase to 30% - rand_hook_slice: bool + randHookSlice: bool if ( self.player_difficulty == 1 or self.player_difficulty == 2 - or (self.player_difficulty == 5 and self.is_on_green(self.ball)) + or (self.player_difficulty == 5 and self.is_on_green(self.BALL)) ): - rand_hook_slice = odds(30) + randHookSlice = odds(30) else: - rand_hook_slice = odds(10) + randHookSlice = odds(10) - if rand_hook_slice: + if randHookSlice: if self.player_difficulty == 1: if odds(80): flags |= hook @@ -633,10 +637,11 @@ def stroke(self, club_amt: float, club_index: int) -> None: flags |= slice_ else: flags |= hook - elif odds(50): - flags |= hook else: - flags |= slice_ + if odds(50): + flags |= hook + else: + flags |= slice_ # beginner's luck ! # If handicap is greater than 15, there's a 10% chance of avoiding all errors @@ -645,7 +650,7 @@ def stroke(self, club_amt: float, club_index: int) -> None: # ace # there's a 10% chance of an Ace on a par 3 - if CourseInfo[self.hole_num].par == 3 and odds(10) and self.stroke_num == 1: + if CourseInfo[self.HOLE_NUM].par == 3 and odds(10) and self.STROKE_NUM == 1: flags |= ace # distance: @@ -654,22 +659,29 @@ def stroke(self, club_amt: float, club_index: int) -> None: # If handicap is > 15, there's a 25% chance of reaching club average, # and 75% chance of falling short # The greater the handicap, the more the ball falls short - # If poor distance is a known player_difficulty, then reduce distance by 10% + # If poor distance is a known playerDifficulty, then reduce distance by 10% distance: float rnd = random.randint(1, 101) - 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 + if self.handicap < 15: + if rnd <= 25: + distance = clubAmt - (clubAmt * (self.handicap / 100.0)) + elif rnd > 25 and rnd <= 75: + distance = clubAmt + else: + distance = clubAmt + (clubAmt * 0.10) else: - distance = club_amt + (club_amt * 0.10) + if rnd <= 75: + distance = clubAmt - (clubAmt * (self.handicap / 100.0)) + else: + distance = clubAmt + if self.player_difficulty == 3 and odds(80): # poor distance - distance *= 0.80 + distance = distance * 0.80 if (flags & luck) == luck: - distance = club_amt + distance = clubAmt # angle # For all strokes, there's a possible "drift" of 4 degrees @@ -683,45 +695,43 @@ def stroke(self, club_amt: float, club_index: int) -> None: if (flags & luck) == luck: angle = 0 - plot = self.plot_ball(self.ball, distance, angle) + plot = self.plot_ball(self.BALL, distance, angle) # calculate a new location - if (flags & luck) == luck and plot.y > 0: - plot.y = 2 + if (flags & luck) == luck and plot.Y > 0: + plot.Y = 2 flags = self.find_ball( - Ball(plot.x, plot.y, plot.offline, GameObjType.BALL), flags + Ball(plot.X, plot.Y, plot.Offline, GameObjType.BALL), flags ) self.interpret_results(plot, flags) - def plot_ball(self, ball: Ball, stroke_distance: float, degrees_off: float) -> Plot: - cup_vector = Point(0, -1) - rad_from_cup = math.atan2(ball.Y, ball.X) - math.atan2( - cup_vector.y, cup_vector.x - ) - rad_from_ball = rad_from_cup - math.pi + def plot_ball(self, ball: Ball, strokeDistance: float, degreesOff: float) -> Plot: + cupVector = Point(0, -1) + radFromCup = math.atan2(ball.Y, ball.X) - math.atan2(cupVector.Y, cupVector.X) + radFromBall = radFromCup - math.pi - hypotenuse = stroke_distance - adjacent = math.cos(rad_from_ball + to_radians(degrees_off)) * hypotenuse + hypotenuse = strokeDistance + adjacent = math.cos(radFromBall + to_radians(degreesOff)) * hypotenuse opposite = math.sqrt(math.pow(hypotenuse, 2) - math.pow(adjacent, 2)) - new_pos: Point - if to_degrees_360(rad_from_ball + to_radians(degrees_off)) > 180: - new_pos = Point(int(ball.X - opposite), int(ball.Y - adjacent)) + newPos: Point + if to_degrees_360(radFromBall + to_radians(degreesOff)) > 180: + newPos = Point(int(ball.X - opposite), int(ball.Y - adjacent)) else: - new_pos = Point(int(ball.X + opposite), int(ball.Y - adjacent)) + newPos = Point(int(ball.X + opposite), int(ball.Y - adjacent)) - return Plot(new_pos.x, new_pos.y, int(opposite)) + return Plot(newPos.X, newPos.Y, int(opposite)) def interpret_results(self, plot: Plot, flags: int) -> None: - cup_distance: int = int( + cupDistance: int = int( get_distance( - Point(plot.x, plot.y), + Point(plot.X, plot.Y), Point(self.hole_geometry.cup.X, self.hole_geometry.cup.Y), ) ) - travel_distance: int = int( - get_distance(Point(plot.x, plot.y), Point(self.ball.X, self.ball.Y)) + travelDistance: int = int( + get_distance(Point(plot.X, plot.Y), Point(self.BALL.X, self.BALL.Y)) ) print(" ") @@ -729,12 +739,12 @@ def interpret_results(self, plot: Plot, flags: int) -> None: if (flags & ace) == ace: print("Hole in One! You aced it.") self.score_card_record_stroke(Ball(0, 0, 0, GameObjType.BALL)) - self.report_current_score() + self.ReportCurrentScore() return if (flags & in_trees) == in_trees: print("Your ball is lost in the trees. Take a penalty stroke.") - self.score_card_record_stroke(self.ball) + self.score_card_record_stroke(self.BALL) self.tee_up() return @@ -743,45 +753,54 @@ 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(f"{msg} Take a penalty stroke.") - self.score_card_record_stroke(self.ball) + print(msg + " Take a penalty stroke.") + self.score_card_record_stroke(self.BALL) self.tee_up() return if (flags & out_of_bounds) == out_of_bounds: print("Out of bounds. Take a penalty stroke.") - self.score_card_record_stroke(self.ball) + self.score_card_record_stroke(self.BALL) self.tee_up() return if (flags & dub) == dub: print("You dubbed it.") - self.score_card_record_stroke(self.ball) + self.score_card_record_stroke(self.BALL) self.tee_up() return if (flags & in_cup) == in_cup: - msg = "You holed it." if odds(50) else "It's in!" + if odds(50): + msg = "You holed it." + else: + msg = "It's in!" print(msg) - self.score_card_record_stroke(Ball(plot.x, plot.y, 0, GameObjType.BALL)) - self.report_current_score() + self.score_card_record_stroke(Ball(plot.X, plot.Y, 0, GameObjType.BALL)) + self.ReportCurrentScore() return - 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 & slice_) == slice_) and not ((flags & on_green) == on_green): + if (flags & out_of_bounds) == out_of_bounds: + bad = "badly" + else: + bad = "" + print(f"You sliced{bad}: {plot.Offline} yards offline.") - 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 ((flags & hook) == hook) and not ((flags & on_green) == on_green): + if (flags & out_of_bounds) == out_of_bounds: + bad = "badly" + else: + bad = "" + print(f"You hooked{bad}: {plot.Offline} yards offline.") - if self.stroke_num > 1: - prev_ball = self.score_card_get_previous_stroke() + if self.STROKE_NUM > 1: + prevBall = self.score_card_get_previous_stroke() d1 = get_distance( - Point(prev_ball.X, prev_ball.Y), + Point(prevBall.X, prevBall.Y), Point(self.hole_geometry.cup.X, self.hole_geometry.cup.Y), ) - d2 = cup_distance + d2 = cupDistance if d2 > d1: print("Too much club.") @@ -792,49 +811,55 @@ def interpret_results(self, plot: Plot, flags: int) -> None: print("You're in a sand trap.") if (flags & on_green) == on_green: - if cup_distance < 4: - pd = f"{str(cup_distance * 3)} feet" + if cupDistance < 4: + pd = str(cupDistance * 3) + " feet" else: - pd = f"{cup_distance} yards" + pd = f"{cupDistance} yards" print(f"You're on the green. It's {pd} from the pin.") if ((flags & on_fairway) == on_fairway) or ((flags & in_rough) == in_rough): print( - f"Shot went {travel_distance} yards. " - f"It's {cup_distance} yards from the cup." + f"Shot went {travelDistance} yards. " + f"It's {cupDistance} yards from the cup." ) - self.score_card_record_stroke(Ball(plot.x, plot.y, 0, GameObjType.BALL)) + self.score_card_record_stroke(Ball(plot.X, plot.Y, 0, GameObjType.BALL)) - self.ball = Ball(plot.x, plot.y, 0, GameObjType.BALL) + self.BALL = Ball(plot.X, plot.Y, 0, GameObjType.BALL) self.tee_up() - def report_current_score(self) -> None: - par = CourseInfo[self.hole_num].par - if len(self.score_card[self.hole_num]) == par + 1: + def ReportCurrentScore(self) -> None: + par = CourseInfo[self.HOLE_NUM].par + if len(self.score_card[self.HOLE_NUM]) == par + 1: print("A bogey. One above par.") - if len(self.score_card[self.hole_num]) == par: + if len(self.score_card[self.HOLE_NUM]) == par: print("Par. Nice.") - if len(self.score_card[self.hole_num]) == (par - 1): + if len(self.score_card[self.HOLE_NUM]) == (par - 1): print("A birdie! One below par.") - if len(self.score_card[self.hole_num]) == (par - 2): + if len(self.score_card[self.HOLE_NUM]) == (par - 2): print("An Eagle! Two below par.") - if len(self.score_card[self.hole_num]) == (par - 3): + if len(self.score_card[self.HOLE_NUM]) == (par - 3): print("Double Eagle! Unbelievable.") - total_par: int = sum(CourseInfo[i].par for i in range(1, self.hole_num + 1)) + totalPar: int = 0 + for i in range(1, self.HOLE_NUM + 1): + totalPar += CourseInfo[i].par + print(" ") print("-----------------------------------------------------") - hole_str = "holes" if self.hole_num > 1 else "hole" + if self.HOLE_NUM > 1: + hole_str = "holes" + else: + hole_str = "hole" print( - f" Total par for {self.hole_num} {hole_str} is: {total_par}. " + f" Total par for {self.HOLE_NUM} {hole_str} is: {totalPar}. " f"Your total is: {self.score_card_get_total()}." ) print("-----------------------------------------------------") print(" ") - if self.hole_num == 18: + if self.HOLE_NUM == 18: self.game_over() else: time.sleep(2) @@ -881,7 +906,10 @@ 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)) - return d < h.Radius and h.Type == hazard + result = False + if (d < h.Radius) and h.Type == hazard: + result = True + return result def is_in_hazard(self, ball: Ball, hazard: GameObjType) -> bool: result: bool = False @@ -902,13 +930,15 @@ def score_card_start_new_hole(self) -> None: def score_card_record_stroke(self, ball: Ball) -> None: clone = Ball(ball.X, ball.Y, 0, GameObjType.BALL) - self.score_card[self.hole_num].append(clone) + self.score_card[self.HOLE_NUM].append(clone) def score_card_get_previous_stroke(self) -> Ball: - return self.score_card[self.hole_num][len(self.score_card[self.hole_num]) - 1] + return self.score_card[self.HOLE_NUM][len(self.score_card[self.HOLE_NUM]) - 1] def score_card_get_total(self) -> int: - total: int = sum(len(h) for h in self.score_card) + total: int = 0 + for h in self.score_card: + total += len(h) return total def ask( @@ -931,8 +961,11 @@ def ask( success = False n = 0 - if success and n >= min_ and n <= max_: - callback(n) + if success: + if n >= min_ and n <= max_: + callback(n) + else: + self.ask(question, min_, max_, callback) else: self.ask(question, min_, max_, callback) @@ -953,7 +986,9 @@ def review_bag(self) -> None: print(" ") def quit_game(self) -> None: - print("\nLooks like rain. Goodbye!\n") + print("") + print("Looks like rain. Goodbye!") + print("") return def game_over(self) -> None: diff --git a/39_Golf/python/test_golf.py b/39_Golf/python/test_golf.py new file mode 100644 index 000000000..95b461d1c --- /dev/null +++ b/39_Golf/python/test_golf.py @@ -0,0 +1,88 @@ +import io +import math + +import pytest +from golf import ( + CircleGameObj, + GameObjType, + Golf, + Point, + RectGameObj, + get_distance, + is_in_rectangle, + odds, + to_degrees_360, + to_radians, +) + + +def test_odds() -> None: + n = 1000 + p = sum(odds(50) for i in range(n)) / n + assert abs(p - 0.5) < 0.1 + + +@pytest.mark.parametrize( + ("p1", "p2", "expected"), + [ + ((0, 0), (0, 0), 0), + ((0, 0), (1, 0), 1), + ((0, 0), (0, 1), 1), + ((0, 1), (0, 0), 1), + ((1, 0), (0, 0), 1), + ((0, 0), (2, 0), 2), + ((0, 0), (0, 2), 2), + ((0, 2), (0, 0), 2), + ((2, 0), (0, 0), 2), + ((0, 0), (1, 1), 2**0.5), + ((2, 3), (4, 5), (2**2 + 2**2) ** 0.5), + ], +) +def test_get_distance(p1, p2, expected): + assert get_distance(Point(*p1), Point(*p2)) == expected + + +@pytest.mark.parametrize( + ("pt", "rect", "expected"), + [ + ( + CircleGameObj(1, 1, 1, GameObjType.BALL), + RectGameObj(0, 0, 2, 2, GameObjType.GREEN), + True, + ), + ( + CircleGameObj(1, 1, 1, GameObjType.BALL), + RectGameObj(0, 0, 1, 1, GameObjType.GREEN), + False, + ), + ], +) +def test_is_in_rectangle(pt, rect, expected): + assert is_in_rectangle(pt, rect) == expected + + +@pytest.mark.parametrize( + ("angle", "radians"), + [ + (0, 0), + (180, math.pi), + (360, 2 * math.pi), + ], +) +def test_to_radians(angle, radians): + assert to_radians(angle) == radians + assert to_degrees_360(radians) == angle + + +def test_golf(monkeypatch, capsys): + handycap = 10 + difficulty = 4 + club = 10 + swing = 10 + monkeypatch.setattr( + "sys.stdin", + io.StringIO(f"10\na\n{handycap}\n{difficulty}\n{club}\n{swing}\nQUIT"), + ) + Golf() + out, err = capsys.readouterr() + assert err == "" diff --git a/40_Gomoko/gomoko.bas b/40_Gomoko/gomoko.bas index d57c10a1b..662cca132 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+E: Y=J+F: GOSUB 910 +540 X=I+F: Y=J+F: GOSUB 910 570 IF L=0 THEN 590 580 IF A(X,Y)=1 THEN 710 590 NEXT F: NEXT E diff --git a/40_Gomoko/python/Gomoko.py b/40_Gomoko/python/Gomoko.py index cc4930a3e..db3e02b71 100644 --- a/40_Gomoko/python/Gomoko.py +++ b/40_Gomoko/python/Gomoko.py @@ -2,6 +2,10 @@ from typing import Any, List, Tuple +def print_n_whitespaces(n: int) -> None: + print(" " * n, end="") + + def print_board(A: List[List[Any]], n: int) -> None: """PRINT THE BOARD""" for i in range(n): @@ -13,31 +17,42 @@ def print_board(A: List[List[Any]], n: int) -> None: def check_move(_I, _J, _N) -> bool: # 910 - return _I >= 1 and _I <= _N and _J >= 1 and _J <= _N + if _I < 1 or _I > _N or _J < 1 or _J > _N: + return False + return True def print_banner() -> None: - print(" " * 33 + "GOMOKU") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") - print("WELCOME TO THE ORIENTAL GAME OF GOMOKO.\n") + print_n_whitespaces(33) + print("GOMOKU") + print_n_whitespaces(15) + print("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'.\n") + 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.\n") + print("TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.") + print() def get_board_dimensions() -> int: n = 0 while True: n = int(input("WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)? ")) - if n >= 7 and n <= 19: + if n < 7 or n > 19: + print("I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.") + print() + else: break - print("I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.") - print() return n @@ -59,8 +74,10 @@ def initialize_board(n: int) -> List[List[int]]: # Initialize the board board = [] for _x in range(n): - sub_a = [0 for _y in range(n)] - board.append(sub_a) + subA = [] + for _y in range(n): + subA.append(0) + board.append(subA) return board @@ -82,49 +99,51 @@ def main() -> None: break elif not check_move(x, y, n): print("ILLEGAL MOVE. TRY AGAIN...") - 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 - ): + 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: 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/41_Guess/csharp/Game.cs b/41_Guess/csharp/Game.cs deleted file mode 100644 index 57ae071a8..000000000 --- a/41_Guess/csharp/Game.cs +++ /dev/null @@ -1,78 +0,0 @@ -namespace Guess; - -internal class Game -{ - private readonly IReadWrite _io; - private readonly IRandom _random; - - public Game(IReadWrite io, IRandom random) - { - _io = io; - _random = random; - } - - public void Play() - { - while (true) - { - _io.Write(Streams.Introduction); - - var limit = _io.ReadNumber(Prompts.Limit); - _io.WriteLine(); - - // There's a bug here that exists in the original code. - // If the limit entered is <= 0 then the program will crash. - var targetGuessCount = checked((int)Math.Log2(limit) + 1); - - PlayGuessingRounds(limit, targetGuessCount); - - _io.Write(Streams.BlankLines); - } - } - - private void PlayGuessingRounds(float limit, int targetGuessCount) - { - while (true) - { - _io.WriteLine(Formats.Thinking, limit); - - // There's a bug here that exists in the original code. If a non-integer is entered as the limit - // then it's possible for the secret number to be the next integer greater than the limit. - var secretNumber = (int)_random.NextFloat(limit) + 1; - - var guessCount = 0; - - while (true) - { - var guess = _io.ReadNumber(""); - if (guess <= 0) { return; } - guessCount++; - if (IsGuessCorrect(guess, secretNumber)) { break; } - } - - ReportResult(guessCount, targetGuessCount); - - _io.Write(Streams.BlankLines); - } - } - - private bool IsGuessCorrect(float guess, int secretNumber) - { - if (guess < secretNumber) { _io.Write(Streams.TooLow); } - if (guess > secretNumber) { _io.Write(Streams.TooHigh); } - - return guess == secretNumber; - } - - private void ReportResult(int guessCount, int targetGuessCount) - { - _io.WriteLine(Formats.ThatsIt, guessCount); - _io.WriteLine( - (guessCount - targetGuessCount) switch - { - < 0 => Strings.VeryGood, - 0 => Strings.Good, - > 0 => string.Format(Formats.ShouldHave, targetGuessCount) - }); - } -} \ No newline at end of file diff --git a/41_Guess/csharp/Guess.csproj b/41_Guess/csharp/Guess.csproj index 3870320c9..d3fe4757c 100644 --- a/41_Guess/csharp/Guess.csproj +++ b/41_Guess/csharp/Guess.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/41_Guess/csharp/Program.cs b/41_Guess/csharp/Program.cs deleted file mode 100644 index 73ab09dd0..000000000 --- a/41_Guess/csharp/Program.cs +++ /dev/null @@ -1,7 +0,0 @@ -global using Games.Common.IO; -global using Games.Common.Randomness; -global using static Guess.Resources.Resource; - -using Guess; - -new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); diff --git a/41_Guess/csharp/Resources/BlankLines.txt b/41_Guess/csharp/Resources/BlankLines.txt deleted file mode 100644 index 3f2ff2d6c..000000000 --- a/41_Guess/csharp/Resources/BlankLines.txt +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/41_Guess/csharp/Resources/Good.txt b/41_Guess/csharp/Resources/Good.txt deleted file mode 100644 index 989dfa38a..000000000 --- a/41_Guess/csharp/Resources/Good.txt +++ /dev/null @@ -1 +0,0 @@ -Good. \ No newline at end of file diff --git a/41_Guess/csharp/Resources/Introduction.txt b/41_Guess/csharp/Resources/Introduction.txt deleted file mode 100644 index ed6794920..000000000 --- a/41_Guess/csharp/Resources/Introduction.txt +++ /dev/null @@ -1,9 +0,0 @@ - Guess - Creative Computing Morristown, New Jersey - - - -This is a number guessing game. I'll think -of a number between 1 and any limit you want. -The you have to guess what it is. - diff --git a/41_Guess/csharp/Resources/Limit.txt b/41_Guess/csharp/Resources/Limit.txt deleted file mode 100644 index 62e698a60..000000000 --- a/41_Guess/csharp/Resources/Limit.txt +++ /dev/null @@ -1 +0,0 @@ -What limit do you want \ No newline at end of file diff --git a/41_Guess/csharp/Resources/Resource.cs b/41_Guess/csharp/Resources/Resource.cs deleted file mode 100644 index d42477e2e..000000000 --- a/41_Guess/csharp/Resources/Resource.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Guess.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Introduction => GetStream(); - public static Stream TooLow => GetStream(); - public static Stream TooHigh => GetStream(); - public static Stream BlankLines => GetStream(); - } - - internal static class Formats - { - public static string Thinking => GetString(); - public static string ThatsIt => GetString(); - public static string ShouldHave => GetString(); - } - - internal static class Prompts - { - public static string Limit => GetString(); - } - - internal static class Strings - { - public static string Good => GetString(); - public static string VeryGood => GetString(); - } - - 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/41_Guess/csharp/Resources/ShouldHave.txt b/41_Guess/csharp/Resources/ShouldHave.txt deleted file mode 100644 index 848035889..000000000 --- a/41_Guess/csharp/Resources/ShouldHave.txt +++ /dev/null @@ -1 +0,0 @@ -You should have been able to get it in only {0} \ No newline at end of file diff --git a/41_Guess/csharp/Resources/ThatsIt.txt b/41_Guess/csharp/Resources/ThatsIt.txt deleted file mode 100644 index 61f78c436..000000000 --- a/41_Guess/csharp/Resources/ThatsIt.txt +++ /dev/null @@ -1 +0,0 @@ -That's it! You got it in {0} tries. \ No newline at end of file diff --git a/41_Guess/csharp/Resources/Thinking.txt b/41_Guess/csharp/Resources/Thinking.txt deleted file mode 100644 index 8f1bbac7c..000000000 --- a/41_Guess/csharp/Resources/Thinking.txt +++ /dev/null @@ -1,2 +0,0 @@ -I'm thinking of a number between 1 and {0} -Now you try to guess what it is. \ No newline at end of file diff --git a/41_Guess/csharp/Resources/TooHigh.txt b/41_Guess/csharp/Resources/TooHigh.txt deleted file mode 100644 index bb4ee4edc..000000000 --- a/41_Guess/csharp/Resources/TooHigh.txt +++ /dev/null @@ -1 +0,0 @@ -Too high. Try a smaller answer. \ No newline at end of file diff --git a/41_Guess/csharp/Resources/TooLow.txt b/41_Guess/csharp/Resources/TooLow.txt deleted file mode 100644 index 4bc1776f3..000000000 --- a/41_Guess/csharp/Resources/TooLow.txt +++ /dev/null @@ -1 +0,0 @@ -Too low. Try a bigger answer. \ No newline at end of file diff --git a/41_Guess/csharp/Resources/VeryGood.txt b/41_Guess/csharp/Resources/VeryGood.txt deleted file mode 100644 index 606150c7e..000000000 --- a/41_Guess/csharp/Resources/VeryGood.txt +++ /dev/null @@ -1 +0,0 @@ -Very good. \ No newline at end of file diff --git a/41_Guess/python/guess.py b/41_Guess/python/guess.py index 8c1775f44..8786119be 100644 --- a/41_Guess/python/guess.py +++ b/41_Guess/python/guess.py @@ -1,22 +1,24 @@ -""" -Guess - -From: Basic Computer Games (1978) - - "In program Guess, the computer chooses a random - integer between 0 and any limit and any limit you - set. You must then try to guess the number the - computer has choosen using the clues provideed by - the computer. - You should be able to guess the number in one less - than the number of digits needed to represent the - number in binary notation - i.e. in base 2. This ought - to give you a clue as to the optimum search technique. - Guess converted from the original program in FOCAL - which appeared in the book "Computers in the Classroom" - by Walt Koetke of Lexington High School, Lexington, - Massaschusetts. -""" +######################################################## +# +# Guess +# +# From: Basic Computer Games (1978) +# +# "In program Guess, the computer chooses a random +# integer between 0 and any limit and any limit you +# set. You must then try to guess the number the +# computer has choosen using the clues provideed by +# the computer. +# You should be able to guess the number in one less +# than the number of digits needed to represent the +# number in binary notation - i.e. in base 2. This ought +# to give you a clue as to the optimum search technique. +# Guess converted from the original program in FOCAL +# which appeared in the book "Computers in the Classroom" +# by Walt Koetke of Lexington High School, Lexington, +# Massaschusetts. +# +######################################################## # Altough the introduction says that the computer chooses # a number between 0 and any limit, it actually chooses @@ -26,14 +28,13 @@ from math import log from random import random -from typing import Tuple def insert_whitespaces() -> None: print("\n\n\n\n\n") -def limit_set() -> Tuple[int, int]: +def limit_set(): print(" Guess") print("Creative Computing Morristown, New Jersey") print("\n\n\n") diff --git a/41_Guess/rust/Cargo.lock b/41_Guess/rust/Cargo.lock deleted file mode 100644 index 5329dedd1..000000000 --- a/41_Guess/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/42_Gunner/perl/gunner.pl b/42_Gunner/perl/gunner.pl deleted file mode 100755 index 9df20deb4..000000000 --- a/42_Gunner/perl/gunner.pl +++ /dev/null @@ -1,81 +0,0 @@ -#!/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; } - } -} diff --git a/42_Gunner/python/gunner.py b/42_Gunner/python/gunner.py index 6c6d19c72..ad421e7c1 100644 --- a/42_Gunner/python/gunner.py +++ b/42_Gunner/python/gunner.py @@ -50,29 +50,33 @@ 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: - print("OVER TARGET BY", abs(shot_proximity_int), "YARDS.") + 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.") else: print("\nBOOM !!!! YOU HAVE JUST BEEN DESTROYED BY THE ENEMY.\n\n\n") print("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!") return -def main() -> None: +if __name__ == "__main__": print(" " * 33 + "GUNNER") print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print("\n\n\n") + 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") @@ -81,11 +85,7 @@ def main() -> None: while True: gunner() - not_again = input("TRY AGAIN (Y OR N)? ").upper() != "Y" - if not_again: + Y = input("TRY AGAIN (Y OR N)? ") + if Y != "Y": print("\nOK. RETURN TO BASE CAMP.") break - - -if __name__ == "__main__": - main() diff --git a/43_Hammurabi/README.md b/43_Hammurabi/README.md index 937044c86..2e3d6397d 100644 --- a/43_Hammurabi/README.md +++ b/43_Hammurabi/README.md @@ -23,7 +23,8 @@ http://www.vintage-basic.net/games.html #### Porting Notes -- Though the file name and README both spell "Hammurabi" with two M's, the program itself consistently uses only one M. +(please note any difficulties or challenges in porting here) + #### External Links - C: https://github.com/beyonddream/hamurabi diff --git a/43_Hammurabi/csharp/View.cs b/43_Hammurabi/csharp/View.cs index e0c5b0545..fcfb4cd5c 100644 --- a/43_Hammurabi/csharp/View.cs +++ b/43_Hammurabi/csharp/View.cs @@ -133,7 +133,7 @@ public static void ShowGameResult(GameResult result) break; case PerformanceRating.Bad: Console.WriteLine("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV."); - Console.WriteLine("THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,"); + Console.WriteLine("THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND,"); Console.WriteLine("FRANKLY, HATE YOUR GUTS!!"); break; case PerformanceRating.Ok: diff --git a/43_Hammurabi/hammurabi.bas b/43_Hammurabi/hammurabi.bas index e41fe4fbd..8f0998f05 100644 --- a/43_Hammurabi/hammurabi.bas +++ b/43_Hammurabi/hammurabi.bas @@ -108,7 +108,7 @@ 900 PRINT "A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND" 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," +945 PRINT "THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND," 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" diff --git a/43_Hammurabi/javascript/hammurabi.js b/43_Hammurabi/javascript/hammurabi.js index ca4d471d6..6d878db97 100644 --- a/43_Hammurabi/javascript/hammurabi.js +++ b/43_Hammurabi/javascript/hammurabi.js @@ -233,7 +233,7 @@ async function main() print("ALSO BEEN DECLARED NATIONAL FINK!!!!\n"); } else if (p1 > 10 || l < 9) { print("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.\n"); - print("THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,\n"); + print("THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND,\n"); print("FRANKLY, HATE YOUR GUTS!!\n"); } else if (p1 > 3 || l < 10) { print("YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\n"); diff --git a/43_Hammurabi/perl/lib/BasicComputerGames/Hammurabi.pm b/43_Hammurabi/perl/lib/BasicComputerGames/Hammurabi.pm deleted file mode 100644 index cfcffb343..000000000 --- a/43_Hammurabi/perl/lib/BasicComputerGames/Hammurabi.pm +++ /dev/null @@ -1,472 +0,0 @@ -#!/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 diff --git a/43_Hammurabi/python/hamurabi.py b/43_Hammurabi/python/hamurabi.py index 46ef975d6..5c476ca9d 100644 --- a/43_Hammurabi/python/hamurabi.py +++ b/43_Hammurabi/python/hamurabi.py @@ -1,32 +1,31 @@ from random import random, seed -def gen_random() -> int: +def gen_random(): return int(random() * 5) + 1 -def bad_input_850() -> None: +def bad_input_850(): print("\nHAMURABI: I CANNOT DO WHAT YOU WISH.") print("GET YOURSELF ANOTHER STEWARD!!!!!") -def bad_input_710(grain_bushels: int) -> None: +def bad_input_710(S): print("HAMURABI: THINK AGAIN. YOU HAVE ONLY") - print(f"{grain_bushels} BUSHELS OF GRAIN. NOW THEN,") + print(S, "BUSHELS OF GRAIN. NOW THEN,") -def bad_input_720(acres: float) -> None: - print(f"HAMURABI: THINK AGAIN. YOU OWN ONLY {acres} ACRES. NOW THEN,") +def bad_input_720(A): + print("HAMURABI: THINK AGAIN. YOU OWN ONLY", A, "ACRES. NOW THEN,") -def national_fink() -> None: +def national_fink(): 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!!!!") -def b_input(promptstring: str) -> int: - """emulate BASIC input. It rejects non-numeric values""" +def b_input(promptstring): # emulate BASIC input. It rejects non-numeric values x = input(promptstring) while x.isalpha(): x = input("?REDO FROM START\n? ") @@ -62,7 +61,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 += 1 + year = year + 1 # year print( "IN YEAR", year, @@ -97,7 +96,9 @@ 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 - else: + elif ( + bushels_per_acre * plague <= grain_stores + ): # normal case, can afford it acres = acres + plague # increase the number of acres by Q grain_stores = ( grain_stores - bushels_per_acre * plague @@ -167,8 +168,15 @@ def main() -> None: # REM *** A BOUNTIFUL HARVEST! bushels_per_acre = C H = people * bushels_per_acre + eaten_rats = 0 + C = gen_random() - eaten_rats = int(grain_stores / C) if int(C / 2) == C / 2 else 0 + 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 + grain_stores = grain_stores - eaten_rats + H # deduct losses from stores C = gen_random() @@ -203,7 +211,7 @@ def main() -> None: national_fink() elif P1 > 10 or L < 9: print("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.") - print("THE PEOPLE (REMAINING) FIND YOU AN UNPLEASANT RULER, AND,") + print("THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND,") print("FRANKLY, HATE YOUR GUTS!!") elif P1 > 3 or L < 10: print("YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT") diff --git a/43_Hammurabi/python/test_hamurabi.py b/43_Hammurabi/python/test_hamurabi.py new file mode 100644 index 000000000..16377b1d0 --- /dev/null +++ b/43_Hammurabi/python/test_hamurabi.py @@ -0,0 +1,30 @@ +import io + +import hamurabi + + +def test_main(monkeypatch, capsys): + monkeypatch.setattr("sys.stdin", io.StringIO("100\n100\n100")) + hamurabi.main() + captured = capsys.readouterr() + actual_lines = captured.out.splitlines() + expected_lines = [ + "HAMURABI", # 0 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY", # 1 + "", # 2 + "", # 3 + "", # 4 + "", # 5 + "TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA", # 6 + "FOR A TEN-YEAR TERM OF OFFICE.", # 7 + "", # 8 + "", # 9 + "", # 10 + "", # 11 + "HAMURABI: I BEG TO REPORT TO YOU\n", # 12 + "IN YEAR 1 , 0 PEOPLE STARVED, 5 CAME TO THE CITY,\n", # 13 + "POPULATION IS NOW 100\n", # 14 + "THE CITY NOW OWNS 1000.0 ACRES.", # 15 + ] + for i, (actual, expected) in enumerate(zip(actual_lines, expected_lines)): + assert actual.strip() == expected.strip(), f"Line {i} is wrong" diff --git a/43_Hammurabi/rust/Cargo.lock b/43_Hammurabi/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/43_Hammurabi/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/43_Hammurabi/rust/Cargo.toml b/43_Hammurabi/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/43_Hammurabi/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/43_Hammurabi/rust/README.md b/43_Hammurabi/rust/README.md deleted file mode 100644 index fc6468b9f..000000000 --- a/43_Hammurabi/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 529a61451..000000000 --- a/43_Hammurabi/rust/src/main.rs +++ /dev/null @@ -1,262 +0,0 @@ -use std::io; -use rand::Rng; - -fn run() { - // Set up variables - 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 += immigrants; - if plague{ - 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() { - // 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 > grain { - insufficient_grain(grain); - continue; - } - // Everything checks out OK - if land_price * qty <= grain { - acres += qty ; - grain -= land_price * qty ; - bought_land = true; - break; - } - } else { - impossible_task(); - game_failed = true; - break 'main; - } - } - - if !bought_land { - loop { - println!("HOW MANY ACRES DO YOU WISH TO SELL? "); - if let Some(qty) = get_input() { - // Everything checks out OK - 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; - } - } - } - - loop { - println!("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? "); - if let Some(qty) = get_input() { - // Trying to use more grain than is in silos? - if qty > grain { - insufficient_grain(grain); - continue; - } - // Everything checks out OK - 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() { - // Trying to plant more acres than you own? - if qty > acres { - insufficient_land(acres); - continue; - } - // Enough grain for seed? - if qty / 2 > grain { - insufficient_grain(grain); - continue; - } - // Enough people to tend the crops? - if qty > (10 * population) { - insufficient_people(population); - continue; - } - // Everything checks out OK - planted = qty; - grain -= planted / 2; - break; - } else { - impossible_task(); - game_failed = true; - break 'main; - } - } - - // 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 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 += starved; - } - } - - 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!!"); - 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 { - println!(); - } - } - - 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(); -} diff --git a/44_Hangman/python/hangman.py b/44_Hangman/python/hangman.py index 59d443dbc..cbceb6a23 100755 --- a/44_Hangman/python/hangman.py +++ b/44_Hangman/python/hangman.py @@ -1,42 +1,44 @@ #!/usr/bin/env python3 - -""" -HANGMAN - -Converted from BASIC to Python by Trevor Hobson and Daniel Piron -""" +# HANGMAN +# +# Converted from BASIC to Python by Trevor Hobson and Daniel Piron import random -from typing import List class Canvas: """For drawing text-based figures""" - def __init__(self, width: int = 12, height: int = 12, fill: str = " ") -> None: + def __init__(self, width=12, height=12, fill=" "): self._buffer = [] for _ in range(height): - line = ["" for _ in range(width)] + line = [] + for _ in range(width): + line.append("") self._buffer.append(line) self.clear() - def clear(self, fill: str = " ") -> None: + def clear(self, fill=" "): for row in self._buffer: for x in range(len(row)): row[x] = fill - def render(self) -> str: - lines = ["".join(line) for line in self._buffer] + def render(self): + 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)) return "\n".join(lines) - def put(self, s: str, x: int, y: int) -> None: + def put(self, s, x, y): # In an effort to avoid distorting the drawn image, only write the # first character of the given string to the buffer. self._buffer[y][x] = s[0] -def init_gallows(canvas: Canvas) -> None: +def init_gallows(canvas): for i in range(12): canvas.put("X", 0, i) for i in range(7): @@ -44,7 +46,7 @@ def init_gallows(canvas: Canvas) -> None: canvas.put("X", 6, 1) -def draw_head(canvas: Canvas) -> None: +def draw_head(canvas): canvas.put("-", 5, 2) canvas.put("-", 6, 2) canvas.put("-", 7, 2) @@ -57,47 +59,47 @@ def draw_head(canvas: Canvas) -> None: canvas.put("-", 7, 4) -def draw_body(canvas: Canvas) -> None: +def draw_body(canvas): for i in range(5, 9, 1): canvas.put("X", 6, i) -def draw_right_arm(canvas: Canvas) -> None: +def draw_right_arm(canvas): for i in range(3, 7): canvas.put("\\", i - 1, i) -def draw_left_arm(canvas: Canvas) -> None: +def draw_left_arm(canvas): canvas.put("/", 10, 3) canvas.put("/", 9, 4) canvas.put("/", 8, 5) canvas.put("/", 7, 6) -def draw_right_leg(canvas: Canvas) -> None: +def draw_right_leg(canvas): canvas.put("/", 5, 9) canvas.put("/", 4, 10) -def draw_left_leg(canvas: Canvas) -> None: +def draw_left_leg(canvas): canvas.put("\\", 7, 9) canvas.put("\\", 8, 10) -def draw_left_hand(canvas: Canvas) -> None: +def draw_left_hand(canvas): canvas.put("\\", 10, 2) -def draw_right_hand(canvas: Canvas) -> None: +def draw_right_hand(canvas): canvas.put("/", 2, 2) -def draw_left_foot(canvas: Canvas) -> None: +def draw_left_foot(canvas): canvas.put("\\", 9, 11) canvas.put("-", 10, 11) -def draw_right_foot(canvas: Canvas) -> None: +def draw_right_foot(canvas): canvas.put("-", 2, 11) canvas.put("/", 3, 11) @@ -170,11 +172,11 @@ def draw_right_foot(canvas: Canvas) -> None: ] -def play_game(guess_target: str) -> None: +def play_game(guess_target): """Play one round of the game""" wrong_guesses = 0 guess_progress = ["-"] * len(guess_target) - guess_list: List[str] = [] + guess_list = [] gallows = Canvas() init_gallows(gallows) @@ -186,7 +188,7 @@ def play_game(guess_target: str) -> None: print("".join(guess_progress) + "\n") guess_letter = "" guess_word = "" - while not guess_letter: + while guess_letter == "": guess_letter = input("What is your guess? ").upper()[0] if not guess_letter.isalpha(): @@ -204,12 +206,12 @@ def play_game(guess_target: str) -> None: ] for i in indices: guess_progress[i] = guess_letter - if "".join(guess_progress) == guess_target: + if guess_progress == guess_target: print("You found the word!") break else: print("\n" + "".join(guess_progress) + "\n") - while not guess_word: + while guess_word == "": guess_word = input("What is your guess for the word? ").upper() if not guess_word.isalpha(): guess_word = "" @@ -228,7 +230,7 @@ def play_game(guess_target: str) -> None: print("Sorry, that letter isn't in the word.") if wrong_guesses == 10: - print(f"Sorry, you lose. The word was {guess_target}") + print("Sorry, you lose. The word was " + guess_target) break diff --git a/44_Hangman/ruby/hangman.rb b/44_Hangman/ruby/hangman.rb deleted file mode 100644 index b9ad8aa33..000000000 --- a/44_Hangman/ruby/hangman.rb +++ /dev/null @@ -1,280 +0,0 @@ -class Canvas - BUFFER = [] - def initialize width = 12, height = 12, fill = " " - for i in (0...height) do - line = [] - for i in (0...width) do - line << "" - end - BUFFER << line - end - - clear - end - - def render - lines = [] - for line in BUFFER do - lines << line.join("") - end - - return lines.join("\n") - end - - def put s, x, y - BUFFER[y][x] = s[0] - end - - private - def clear fill = " " - for row in BUFFER do - for x in (0...(row.length)) do - row[x] = fill - end - end - end -end - -def init_gallows canvas - for i in (0...12) do - canvas.put("X", 0, i) - end - - for i in (0...7) do - canvas.put("X", i, 0) - end - - canvas.put("X", 6, 1) -end - -def draw_head canvas - canvas.put("-", 5, 2) - canvas.put("-", 6, 2) - canvas.put("-", 7, 2) - canvas.put("(", 4, 3) - canvas.put(".", 5, 3) - canvas.put(".", 7, 3) - canvas.put(")", 8, 3) - canvas.put("-", 5, 4) - canvas.put("-", 6, 4) - canvas.put("-", 7, 4) -end - -def draw_body canvas - for i in (5...9) do - canvas.put("X", 6, i) - end -end - -def draw_right_arm canvas - for i in (3...8) do - canvas.put("\\", i - 1, i) - end -end - -def draw_left_arm canvas - canvas.put("/", 10, 3) - canvas.put("/", 9, 4) - canvas.put("/", 8, 5) - canvas.put("/", 7, 6) -end - -def draw_right_leg canvas - canvas.put("/", 5, 9) - canvas.put("/", 4, 10) -end - -def draw_left_leg canvas - canvas.put("\\", 7, 9) - canvas.put("\\", 8, 10) -end - -def draw_left_hand canvas - canvas.put("\\", 10, 2) -end - -def draw_right_hand canvas - canvas.put("/", 2, 2) -end - -def draw_left_foot canvas - canvas.put("\\", 9, 11) - canvas.put("-", 10, 11) -end - -def draw_right_foot canvas - canvas.put("-", 2, 11) - canvas.put("/", 3, 11) -end - -PHASES = [ - ["First, we draw a head", 'draw_head'], - ["Now we draw a body.", 'draw_body'], - ["Next we draw an arm.", 'draw_right_arm'], - ["this time it's the other arm.", 'draw_left_arm'], - ["Now, let's draw the right leg.", 'draw_right_leg'], - ["This time we draw the left leg.", 'draw_left_leg'], - ["Now we put up a hand.", 'draw_left_hand'], - ["Next the other hand.", 'draw_right_hand'], - ["Now we draw one foot", 'draw_left_foot'], - ["Here's the other foot -- you're hung!!", 'draw_right_foot'], -] - -WORDS = [ - "GUM", - "SIN", - "FOR", - "CRY", - "LUG", - "BYE", - "FLY", - "UGLY", - "EACH", - "FROM", - "WORK", - "TALK", - "WITH", - "SELF", - "PIZZA", - "THING", - "FEIGN", - "FIEND", - "ELBOW", - "FAULT", - "DIRTY", - "BUDGET", - "SPIRIT", - "QUAINT", - "MAIDEN", - "ESCORT", - "PICKAX", - "EXAMPLE", - "TENSION", - "QUININE", - "KIDNEY", - "REPLICA", - "SLEEPER", - "TRIANGLE", - "KANGAROO", - "MAHOGANY", - "SERGEANT", - "SEQUENCE", - "MOUSTACHE", - "DANGEROUS", - "SCIENTIST", - "DIFFERENT", - "QUIESCENT", - "MAGISTRATE", - "ERRONEOUSLY", - "LOUDSPEAKER", - "PHYTOTOXIC", - "MATRIMONIAL", - "PARASYMPATHOMIMETIC", - "THIGMOTROPISM", -] - -def play_game guess_target - wrong_guesses = 0 - guess_progress = ["-"] * guess_target.length - guess_list = [] - - gallows = Canvas.new - init_gallows(gallows) - - guess_count = 0 - while true - puts "Here are the letters you used:" - puts "#{guess_list.join(",")}\n" - puts "#{guess_progress.join("")}\n" - - guess_letter = "" - guess_word = "" - while guess_letter == "" - print "What is your guess? " - guess_letter = gets.chomp!.upcase[0] - if !guess_letter.match?(/[[:alpha:]]/) - guess_letter = "" - puts "Only letters are allowed!" - elsif guess_list.include?(guess_letter) - guess_letter = "" - puts "You guessed that letter before!" - end - end - - guess_list << guess_letter - guess_count += 1 - - if guess_target.include?(guess_letter) - indices = (0...guess_target.length).find_all { |i| guess_target[i,1] == guess_letter } - - for i in indices do - guess_progress[i] = guess_letter - end - - if guess_progress.join("") == guess_target - puts "You found the word!" - break - else - puts "\n#{guess_progress.join("")}\n" - - while guess_word == "" - print "What is your guess for the word? " - guess_word = gets.chomp!.upcase - if !guess_word.match?(/[[:alpha:]]/) - guess_word = "" - puts "Only words are allowed!" - end - end - - if guess_word == guess_target - puts "Right!! It took you #{guess_count} guesses!" - break - end - end - else - comment, draw_bodypart = PHASES[wrong_guesses] - - puts comment - method(draw_bodypart).call(gallows) - puts gallows.render() - - wrong_guesses += 1 - puts "Sorry, that letter isn't in the word." - - if wrong_guesses == 10 - puts "Sorry, you lose. The word was #{guess_target}" - break - end - end - end -end - - -def main - puts "#{(" " * 32)}HANGMAN" - - shuffled = WORDS.shuffle(random: Random.new) - current_word = 0 - word_count = shuffled.length - - keep_playing = true - while keep_playing - - play_game(shuffled[current_word]) - current_word += 1 - - if current_word == word_count - puts "You did all the words!!" - keep_playing = false - else - print "Want another word? (yes or no) " - a = gets.chomp!.upcase - keep_playing = true if a == 'Y' || a == 'y' || a == 'Yes' || a == 'YES' || a == 'yes' - end - end - puts "It's been fun! Bye for now." -end - -if __FILE__ == $0 - main -end \ No newline at end of file diff --git a/45_Hello/README.md b/45_Hello/README.md index 243efa700..87c47f65d 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. diff --git a/45_Hello/lua/hello.lua b/45_Hello/lua/hello.lua deleted file mode 100644 index 5628749bd..000000000 --- a/45_Hello/lua/hello.lua +++ /dev/null @@ -1,156 +0,0 @@ --- HELLO --- --- Converted from BASIC to Lua by Recanman - -local function tab(space) - local str = "" - - for _ = space, 1, -1 do - str = str .. " " - end - - return str -end - --- reused from Bagels.lua -function getInput(prompt) - io.write(prompt) - io.flush() - local input = io.read("l") - if not input then --- test for EOF - print("GOODBYE") - os.exit(0) - end - return input -end - -print(tab(33) .. "HELLO\n") -print(tab(15) .. "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n") -print("\n") -print("\n") -print("\n") - -print("HELLO. MY NAME IS CREATIVE COMPUTER.\n") -print("\n") -print("\n") - -print("WHAT'S YOUR NAME") -local ns = getInput("? ") - -print("\n") -print("HI THERE, " .. ns .. ", ARE YOU ENJOYING YOURSELF HERE") - -while true do - local bs = getInput("? ") - print("\n") - if bs == "YES" then - print("I'M GLAD TO HEAR THAT, " .. ns .. ".\n") - print("\n") - break - elseif bs == "NO" then - print("OH, I'M SORRY TO HEAR THAT, " .. ns .. ". MAYBE WE CAN\n") - print("BRIGHTEN UP YOUR VISIT A BIT.\n") - break - else - print("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE") - end -end - -local function main() - print("\n") - print("SAY, " .. ns .. ", I CAN SOLVED ALL KINDS OF PROBLEMS EXCEPT\n") - print("THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO\n") - print("YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)") - - while true do - local cs = getInput("? ") - print("\n") - - if cs ~= "SEX" and cs ~= "HEALTH" and cs ~= "MONEY" and cs ~= "JOB" then - print("OH, " .. ns .. ", YOUR ANSWER OF " .. cs .. " IS GREEK TO ME.\n") - elseif cs == "JOB" then - print("I CAN SYMPATHIZE WITH YOU " .. ns .. ". I HAVE TO WORK\n") - print("VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\n") - print("REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, " .. ns .. ",\n") - print("IS TO OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.\n") - elseif cs == "MONEY" then - print("SORRY, " .. ns .. ", I'M BROKE TOO. WHY DON'T YOU SELL\n") - print("ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\n") - print("SO YOU WON'T NEED SO MUCH MONEY?\n") - elseif cs == "HEALTH" then - print("MY ADVICE TO YOU " .. ns .. " IS:\n") - print(tab(5) .. "1. TAKE TWO ASPRIN\n") - print(tab(5) .. "2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\n") - print(tab(5) .. "3. GO TO BED (ALONE)\n") - elseif cs == "SEX" then - print("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE") - - while true do - local ds = getInput("? ") - print("\n") - - if ds == "TOO MUCH" then - print("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!\n") - print("IF IT BOTHERS YOU, " .. ns .. ", TAKE A COLD SHOWER.\n") - break - elseif ds == "TOO LITTLE" then - print("WHY ARE YOU HERE IN SUFFERN, " .. ns .. "? YOU SHOULD BE\n") - print("IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\n") - print("REAL ACTION.\n") - break - else - print("DON'T GET ALL SHOOK, " .. ns .. ", JUST ANSWER THE QUESTION\n") - print("WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT") - end - end - end - - print("\n") - print("ANY MORE PROBLEMS YOU WANT SOLVED, " .. ns) - - local es = getInput("? ") - - if es == "YES" then - print("WHAT KIND (SEX, MONEY, HEALTH, JOB)") - elseif es == "NO" then - print("THAT WILL BE $5.00 FOR THE ADVICE, " .. ns .. ".\n") - print("PLEASE LEAVE THE MONEY ON THE TERMINAL.\n") - print("\n") - print("\n") - print("\n") - - while true do - print("DID YOU LEAVE THE MONEY") - - local gs = getInput("? ") - print("\n") - - if gs == "YES" then - print("HEY, " .. ns .. "??? YOU LEFT NO MONEY AT ALL!\n") - print("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\n") - print("\n") - print("WHAT A RIP OFF, " .. ns .. "!!!\n") - print("\n") - break - elseif gs == "NO" then - print("THAT'S HONEST, " .. ns .. ", BUT HOW DO YOU EXPECT\n") - print("ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENT\n") - print("DON'T PAY THEIR BILLS?\n") - break - else - print("YOUR ANSWER OF '" .. gs .. "' CONFUSES ME, " .. ns .. ".\n") - print("PLEASE RESPOND WITH 'YES' OR 'NO'.\n") - end - end - - break - end - end - - print("\n") - print("TAKE A WALK, " .. ns .. ".\n") - print("\n") - print("\n") -end - -main() \ No newline at end of file diff --git a/45_Hello/python/hello.py b/45_Hello/python/hello.py index 661ea60a1..8875a86f5 100644 --- a/45_Hello/python/hello.py +++ b/45_Hello/python/hello.py @@ -9,10 +9,17 @@ """ import time -from typing import Optional, Tuple -def get_yes_or_no() -> Tuple[bool, Optional[bool], str]: +def print_with_tab(space_count: int, msg: str) -> None: + if space_count > 0: + spaces = " " * space_count + else: + spaces = "" + print(spaces + msg) + + +def get_yes_or_no(): msg = input() if msg.upper() == "YES": return True, True, msg @@ -22,7 +29,7 @@ def get_yes_or_no() -> Tuple[bool, Optional[bool], str]: return False, None, msg -def ask_enjoy_question(user_name: str) -> None: +def ask_enjoy_question(user_name): print(f"HI THERE, {user_name}, ARE YOU ENJOYING YOURSELF HERE?") while True: @@ -41,16 +48,17 @@ def ask_enjoy_question(user_name: str) -> None: print("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE?") -def prompt_for_problems(user_name: str) -> str: +def prompt_for_problems(user_name): print() print(f"SAY, {user_name}, 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)") - return input().upper() + problem_type = input().upper() + return problem_type -def prompt_too_much_or_too_little() -> Tuple[bool, Optional[bool]]: +def prompt_too_much_or_too_little(): answer = input().upper() if answer == "TOO MUCH": return True, True @@ -59,7 +67,7 @@ def prompt_too_much_or_too_little() -> Tuple[bool, Optional[bool]]: return False, None -def solve_sex_problem(user_name: str) -> None: +def solve_sex_problem(user_name): print("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE?") while True: valid, too_much = prompt_too_much_or_too_little() @@ -77,31 +85,31 @@ def solve_sex_problem(user_name: str) -> None: print("WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT?") -def solve_money_problem(user_name: str) -> None: +def solve_money_problem(user_name): print(f"SORRY, {user_name}, 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?") -def solve_health_problem(user_name: str) -> None: +def solve_health_problem(user_name): print(f"MY ADVICE TO YOU {user_name} IS:") print(" 1. TAKE TWO ASPRIN") print(" 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)") print(" 3. GO TO BED (ALONE)") -def solve_job_problem(user_name: str) -> None: +def solve_job_problem(user_name): print(f"I CAN SYMPATHIZE WITH YOU {user_name}. I HAVE TO WORK") print("VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES") print(f"REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, {user_name},") print("IS TO OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.") -def alert_unknown_problem_type(user_name: str, problem_type: str) -> None: +def alert_unknown_problem_type(user_name, problem_type): print(f"OH, {user_name}, YOUR ANSWER OF {problem_type} IS GREEK TO ME.") -def ask_question_loop(user_name: str) -> None: +def ask_question_loop(user_name): while True: problem_type = prompt_for_problems(user_name) if problem_type == "SEX": @@ -121,14 +129,15 @@ def ask_question_loop(user_name: str) -> None: valid, value, msg = get_yes_or_no() if valid: - if not value: + if value: + print("WHAT KIND (SEX, MONEY, HEALTH, JOB)") + break + else: return - print("WHAT KIND (SEX, MONEY, HEALTH, JOB)") - break print(f"JUST A SIMPLE 'YES' OR 'NO' PLEASE, {user_name}.") -def ask_for_fee(user_name: str) -> None: +def ask_for_fee(user_name): print() print(f"THAT WILL BE $5.00 FOR THE ADVICE, {user_name}.") print("PLEASE LEAVE THE MONEY ON THE TERMINAL.") @@ -157,21 +166,26 @@ def ask_for_fee(user_name: str) -> None: print("PLEASE RESPOND WITH 'YES' or 'NO'.") -def unhappy_goodbye(user_name: str) -> None: +def unhappy_goodbye(user_name): print() print(f"TAKE A WALK, {user_name}.") print() print() -def happy_goodbye(user_name: str) -> None: +def happy_goodbye(user_name): print(f"NICE MEETING YOU, {user_name}, HAVE A NICE DAY.") def main() -> None: - print(" " * 33 + "HELLO") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") - print("HELLO. MY NAME IS CREATIVE COMPUTER.\n\n") + print_with_tab(33, "HELLO") + print_with_tab(15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() + print("HELLO. MY NAME IS CREATIVE COMPUTER.") + print() + print() print("WHAT'S YOUR NAME?") user_name = input() print() @@ -182,7 +196,10 @@ def main() -> None: ask_for_fee(user_name) - unhappy_goodbye(user_name) + if False: + happy_goodbye(user_name) + else: + unhappy_goodbye(user_name) if __name__ == "__main__": diff --git a/45_Hello/ruby/hello.rb b/45_Hello/ruby/hello.rb deleted file mode 100644 index eb24d293d..000000000 --- a/45_Hello/ruby/hello.rb +++ /dev/null @@ -1,191 +0,0 @@ -class Hello - def start - puts "HELLO. MY NAME IS CREATIVE COMPUTER.\n\n" - print "WHAT'S YOUR NAME? " - user_name = gets.chomp! - - ask_enjoy_question(user_name) - - ask_question_loop(user_name) - - isHonest = ask_for_fee(user_name) - - if isHonest - happy_goodbye(user_name) - else - unhappy_goodbye(user_name) - end - end - private - def get_yes_or_no - msg = gets.chomp! - if msg.upcase() == "YES" - return true, true, msg - elsif msg.upcase() == "NO" - return true, false, msg - else - return false, false, msg - end - end - - def ask_enjoy_question user_name - print "\nHI THERE, #{user_name}, ARE YOU ENJOYING YOURSELF HERE? " - - while true - valid, value, msg = get_yes_or_no() - - if valid - if value - puts "\nI'M GLAD TO HEAR THAT, #{user_name}." - break - else - puts "\nOH, I'M SORRY TO HEAR THAT, #{user_name}. MAYBE WE CAN" - puts "BRIGHTEN UP YOUR VISIT A BIT." - break - end - else - puts "\n#{user_name}, I DON'T UNDERSTAND YOUR ANSWER OF '#{msg}'." - print "PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE? " - end - end - end - - def prompt_for_problems user_name - puts "\nSAY, #{user_name}, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT" - puts "THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO" - print "YOU HAVE? (ANSWER SEX, HEALTH, MONEY, OR JOB) " - - problem_type = gets.chomp! - return problem_type - end - - def prompt_too_much_or_too_little - answer = gets.chomp! - if answer.upcase() == "TOO MUCH" - return true, true - elsif answer.upcase() == "TOO LITTLE" - return true, false - else - return false, false - end - end - - def solve_sex_problem user_name - print "\nIS YOUR PROBLEM TOO MUCH OR TOO LITTLE? " - while true - valid, too_much = prompt_too_much_or_too_little() - if valid - if too_much - puts "\nYOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!" - puts "IF IT BOTHERS YOU, #{user_name}, TAKE A COLD SHOWER." - break - else - puts "\nWHY ARE YOU HERE IN SUFFERN, #{user_name}? YOU SHOULD BE" - puts "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME" - puts "REAL ACTION." - break - end - else - puts "\nDON'T GET ALL SHOOK, #{user_name}, JUST ANSWER THE QUESTION" - print "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT? " - end - end - end - - def solve_health_problem user_name - puts "\nMY ADVICE TO YOU #{user_name} IS:" - puts " 1. TAKE TWO ASPRIN" - puts " 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)" - puts " 3. GO TO BED (ALONE)" - end - - def solve_money_problem user_name - puts "\nSORRY, #{user_name}, I'M BROKE TOO. WHY DON'T YOU SELL" - puts "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING" - puts "SO YOU WON'T NEED SO MUCH MONEY?" - end - - def solve_job_problem user_name - puts "\nI CAN SYMPATHIZE WITH YOU #{user_name}. I HAVE TO WORK" - puts "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES" - puts "REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, #{user_name}," - puts "IS TO OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN." - end - - def alert_unknown_problem_type user_name, problem_type - puts "\nOH, #{user_name}, YOUR ANSWER OF #{problem_type} IS GREEK TO ME." - end - - def ask_question_loop user_name - while true - problem_type = prompt_for_problems(user_name) - if problem_type == "SEX" - solve_sex_problem(user_name) - elsif problem_type == "HEALTH" - solve_health_problem(user_name) - elsif problem_type == "MONEY" - solve_money_problem(user_name) - elsif problem_type == "JOB" - solve_job_problem(user_name) - else - alert_unknown_problem_type(user_name, problem_type) - end - - while true - print "\nANY MORE PROBLEMS YOU WANT SOLVED, #{user_name}? " - - valid, value, msg = get_yes_or_no() - if valid - if value - puts "\nWHAT KIND (SEX, MONEY, HEALTH, JOB)" - break - else - return - end - else - puts "\nJUST A SIMPLE 'YES' OR 'NO' PLEASE, #{user_name}." - end - end - end - end - - def ask_for_fee user_name - puts "\nTHAT WILL BE $5.00 FOR THE ADVICE, #{user_name}." - puts "PLEASE LEAVE THE MONEY ON THE TERMINAL." - sleep(3) - print "\n\nDID YOU LEAVE THE MONEY? " - - while true - valid, value, msg = get_yes_or_no() - if valid - if value - puts "\nHEY, #{user_name}, YOU LEFT NO MONEY AT ALL!" - puts "YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING." - puts "\nWHAT A RIP OFF, #{user_name}!!!" - return false - else - puts "\nTHAT'S HONEST, #{user_name}, BUT HOW DO YOU EXPECT" - puts "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS" - puts "DON'T PAY THEIR BILLS?" - return true - end - else - puts "\nYOUR ANSWER OF '#{msg}' CONFUSES ME, #{user_name}." - print "PLEASE RESPOND WITH 'YES' or 'NO'. " - end - end - end - - def unhappy_goodbye user_name - puts "\nTAKE A WALK, #{user_name}.\n\n" - end - - def happy_goodbye user_name - puts "\nNICE MEETING YOU, #{user_name}, HAVE A NICE DAY." - end -end - -if __FILE__ == $0 - hello = Hello.new - hello.start() -end \ No newline at end of file diff --git a/45_Hello/rust/Cargo.toml b/45_Hello/rust/Cargo.toml deleted file mode 100644 index 7d75412a6..000000000 --- a/45_Hello/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[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 deleted file mode 100644 index 310c5db32..000000000 --- a/45_Hello/rust/src/main.rs +++ /dev/null @@ -1,247 +0,0 @@ -/** 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 -} diff --git a/46_Hexapawn/README.md b/46_Hexapawn/README.md index 6376c0367..bbcf0ad67 100644 --- a/46_Hexapawn/README.md +++ b/46_Hexapawn/README.md @@ -15,10 +15,6 @@ 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) diff --git a/46_Hexapawn/python/hexapawn.py b/46_Hexapawn/python/hexapawn.py index f5cac438b..8c333447c 100644 --- a/46_Hexapawn/python/hexapawn.py +++ b/46_Hexapawn/python/hexapawn.py @@ -44,8 +44,8 @@ # BoardLayout matches the current board, as well as removing losing move # have been moved into methods of this class. +import collections import random -from typing import Iterator, List, NamedTuple, Optional, Tuple PAGE_WIDTH = 64 @@ -53,13 +53,9 @@ EMPTY_SPACE = 0 COMPUTER_PIECE = -1 - -class ComputerMove(NamedTuple): - board_index: int - move_index: int - m1: int - m2: int - +ComputerMove = collections.namedtuple( + "ComputerMove", ["board_index", "move_index", "m1", "m2"] +) wins = 0 losses = 0 @@ -72,7 +68,10 @@ def print_centered(msg: str) -> None: def print_header(title: str) -> None: print_centered(title) - print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() def print_instructions() -> None: @@ -111,7 +110,7 @@ def print_instructions() -> None: ) -def prompt_yes_no(msg: str) -> bool: +def prompt_yes_no(msg): while True: print(msg) response = input().upper() @@ -121,7 +120,7 @@ def prompt_yes_no(msg: str) -> bool: return False -def reverse_space_name(space_name: int) -> int: +def reverse_space_name(space_name): # reverse a space name in the range 1-9 left to right assert 1 <= space_name <= 9 @@ -129,38 +128,36 @@ def reverse_space_name(space_name: int) -> int: return reflections[space_name] -def is_space_in_center_column(space_name: int) -> bool: +def is_space_in_center_column(space_name): return reverse_space_name(space_name) == space_name class BoardLayout: - def __init__(self, cells: List[int], move_list: List[Tuple[int, int]]) -> None: + def __init__(self, cells, move_list): self.cells = cells self.moves = move_list - def _check_match_no_mirror(self, cell_list: List[int]) -> bool: + def _check_match_no_mirror(self, cell_list): return all( board_contents == cell_list[space_index] for space_index, board_contents in enumerate(self.cells) ) - def _check_match_with_mirror(self, cell_list: List[int]) -> bool: + def _check_match_with_mirror(self, cell_list): for space_index, board_contents in enumerate(self.cells): reversed_space_index = reverse_space_name(space_index + 1) - 1 if board_contents != cell_list[reversed_space_index]: return False return True - def check_match(self, cell_list: List[int]) -> Tuple[bool, Optional[bool]]: + def check_match(self, cell_list): if self._check_match_with_mirror(cell_list): return True, True elif self._check_match_no_mirror(cell_list): return True, False return False, None - def get_random_move( - self, reverse_board: Optional[bool] - ) -> Optional[Tuple[int, int, int]]: + def get_random_move(self, reverse_board): if not self.moves: return None move_index = random.randrange(len(self.moves)) @@ -196,7 +193,7 @@ def get_random_move( ] -def get_move(board_index: int, move_index: int) -> Tuple[int, int]: +def get_move(board_index, move_index): assert board_index >= 0 and board_index < len(boards) board = boards[board_index] @@ -205,7 +202,7 @@ def get_move(board_index: int, move_index: int) -> Tuple[int, int]: return board.moves[move_index] -def remove_move(board_index: int, move_index: int) -> None: +def remove_move(board_index, move_index): assert board_index >= 0 and board_index < len(boards) board = boards[board_index] @@ -214,11 +211,11 @@ def remove_move(board_index: int, move_index: int) -> None: del board.moves[move_index] -def init_board() -> List[int]: +def init_board(): return [COMPUTER_PIECE] * 3 + [EMPTY_SPACE] * 3 + [HUMAN_PIECE] * 3 -def print_board(board: List[int]) -> None: +def print_board(board) -> None: piece_dict = {COMPUTER_PIECE: "X", EMPTY_SPACE: ".", HUMAN_PIECE: "O"} space = " " * 10 @@ -234,7 +231,7 @@ def print_board(board: List[int]) -> None: print() -def get_coordinates() -> Tuple[int, int]: +def get_coordinates(): while True: try: print("YOUR MOVE?") @@ -249,15 +246,15 @@ def print_illegal() -> None: print("ILLEGAL MOVE.") -def board_contents(board: List[int], space_number: int) -> int: +def board_contents(board, space_number): return board[space_number - 1] -def set_board(board: List[int], space_number: int, new_value: int) -> None: +def set_board(board, space_number, new_value): board[space_number - 1] = new_value -def is_legal_human_move(board: List[int], m1: int, m2: int) -> bool: +def is_legal_human_move(board, m1, m2): if board_contents(board, m1) != HUMAN_PIECE: # Start space doesn't contain player's piece return False @@ -278,44 +275,56 @@ def is_legal_human_move(board: List[int], m1: int, m2: int) -> bool: # Destination is not open return False - return False if m2 - m1 < -4 else m1 != 7 or m2 != 3 + 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 -def player_piece_on_back_row(board: List[int]) -> bool: + +def player_piece_on_back_row(board): return any(board_contents(board, space) == HUMAN_PIECE for space in range(1, 4)) -def computer_piece_on_front_row(board: List[int]) -> bool: +def computer_piece_on_front_row(board): return any(board_contents(board, space) == COMPUTER_PIECE for space in range(7, 10)) -def all_human_pieces_captured(board: List[int]) -> bool: - return not list(get_human_spaces(board)) +def all_human_pieces_captured(board): + return len(list(get_human_spaces(board))) == 0 -def all_computer_pieces_captured(board: List[int]) -> bool: - return not list(get_computer_spaces(board)) +def all_computer_pieces_captured(board): + return len(list(get_computer_spaces(board))) == 0 -def human_win(last_computer_move: ComputerMove) -> None: +def human_win(last_computer_move): print("YOU WIN") remove_move(last_computer_move.board_index, last_computer_move.move_index) global losses losses += 1 -def computer_win(has_moves: bool) -> None: - msg = ("YOU CAN'T MOVE, SO " if not has_moves else "") + "I WIN" +def computer_win(has_moves): + if not has_moves: + msg = "YOU CAN'T MOVE, SO " + else: + msg = "" + msg += "I WIN" print(msg) global wins wins += 1 -def show_scores() -> None: - print(f"I HAVE WON {wins} AND YOU {losses} OUT OF {wins + losses} GAMES.\n") +def show_scores(): + print(f"I HAVE WON {wins} AND YOU {losses} OUT OF {wins + losses} GAMES.") + print() -def human_has_move(board: List[int]) -> bool: +def human_has_move(board): for i in get_human_spaces(board): if board_contents(board, i - 3) == EMPTY_SPACE: # can move piece forward @@ -329,14 +338,14 @@ def human_has_move(board: List[int]) -> bool: else: continue elif i < 7: - assert i in [4, 6] + assert (i == 4) or (i == 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 in [7, 9] + assert (i == 7) or (i == 9) # can capture computer piece at 5 return True else: @@ -344,31 +353,31 @@ def human_has_move(board: List[int]) -> bool: return False -def get_board_spaces() -> Iterator[int]: +def get_board_spaces(): """generates the space names (1-9)""" yield from range(1, 10) -def get_board_spaces_with(board: List[int], val: int) -> Iterator[int]: +def get_board_spaces_with(board, val): """generates spaces containing pieces of type val""" for i in get_board_spaces(): if board_contents(board, i) == val: yield i -def get_human_spaces(board: List[int]) -> Iterator[int]: +def get_human_spaces(board): yield from get_board_spaces_with(board, HUMAN_PIECE) -def get_empty_spaces(board: List[int]) -> Iterator[int]: +def get_empty_spaces(board): yield from get_board_spaces_with(board, EMPTY_SPACE) -def get_computer_spaces(board: List[int]) -> Iterator[int]: +def get_computer_spaces(board): yield from get_board_spaces_with(board, COMPUTER_PIECE) -def has_computer_move(board: List[int]) -> bool: +def has_computer_move(board): for i in get_computer_spaces(board): if board_contents(board, i + 3) == EMPTY_SPACE: # can move forward (down) @@ -380,20 +389,24 @@ def has_computer_move(board: List[int]) -> bool: board_contents(board, i + 4) == HUMAN_PIECE ): return True - 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 + 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 return False -def find_board_index_that_matches_board(board: List[int]) -> Tuple[int, Optional[bool]]: +def find_board_index_that_matches_board(board): for board_index, board_layout in enumerate(boards): matches, is_reversed = board_layout.check_match(board) if matches: @@ -404,7 +417,7 @@ def find_board_index_that_matches_board(board: List[int]) -> Tuple[int, Optional raise RuntimeError("ILLEGAL BOARD PATTERN.") -def pick_computer_move(board: List[int]) -> Optional[ComputerMove]: +def pick_computer_move(board): if not has_computer_move(board): return None @@ -421,7 +434,7 @@ def pick_computer_move(board: List[int]) -> Optional[ComputerMove]: return ComputerMove(board_index, move_index, m1, m2) -def get_human_move(board: List[int]) -> Tuple[int, int]: +def get_human_move(board): while True: m1, m2 = get_coordinates() @@ -431,12 +444,12 @@ def get_human_move(board: List[int]) -> Tuple[int, int]: return m1, m2 -def apply_move(board: List[int], m1: int, m2: int, piece_value: int) -> None: +def apply_move(board, m1, m2, piece_value): set_board(board, m1, EMPTY_SPACE) set_board(board, m2, piece_value) -def play_game() -> None: +def play_game(): last_computer_move = None board = init_board() @@ -451,13 +464,11 @@ def play_game() -> None: print_board(board) if player_piece_on_back_row(board) or all_computer_pieces_captured(board): - assert last_computer_move is not None human_win(last_computer_move) return computer_move = pick_computer_move(board) if computer_move is None: - assert last_computer_move is not None human_win(last_computer_move) return diff --git a/47_Hi-Lo/javascript/hi-lo.js b/47_Hi-Lo/javascript/hi-lo.js index 6964570d8..362e40a3f 100644 --- a/47_Hi-Lo/javascript/hi-lo.js +++ b/47_Hi-Lo/javascript/hi-lo.js @@ -86,7 +86,6 @@ async function main() print("\n"); print("PLAY AGAIN (YES OR NO)"); str = await input(); - str = str.toUpperCase(); if (str != "YES") break; } diff --git a/47_Hi-Lo/lua/hilo.lua b/47_Hi-Lo/lua/hilo.lua deleted file mode 100644 index 42284f28b..000000000 --- a/47_Hi-Lo/lua/hilo.lua +++ /dev/null @@ -1,86 +0,0 @@ -local function hilo (randomNum) - local numTries = 0 - math.randomseed(os.time()) - - local randomNum = math.random(1, 100) - print(randomNum) - - while numTries < 6 do - print("") - - io.write("YOUR GUESS? ") - - local guess = io.read("*n") - - numTries = numTries + 1 - - if guess < randomNum then - print("YOUR GUESS IS TOO LOW") - end - - if guess > randomNum then - print("YOUR GUESS IS TOO HIGH") - end - - if guess == randomNum then - print("GOT IT!!!!!!!!!! YOU WIN " .. randomNum .. " DOLLARS.") - break - end - end - - if numTries == 6 then - print("") - print("YOU BLEW IT...TOO BAD...THE NUMBER WAS " .. randomNum) - return 0 - else - return randomNum - end -end - -local THIRTY_FOUR_TABS=string.rep("\t",34) -print(THIRTY_FOUR_TABS, "HI LO") - -local FIFTEEN_TABS=string.rep("\t",15) -print(FIFTEEN_TABS, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - -local THREE_NEWLINES=string.rep("\n", 3) -print(THREE_NEWLINES) - -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.") - -local wonSoFar = 0 - -::continue:: -local won = 0 -local won = hilo(randomNum) -wonSoFar = won + wonSoFar -print("YOUR TOTAL WINNINGS ARE NOW " .. wonSoFar .. " DOLLARS.") - ---- This flush is here because if not then it will keep the newline in the ---- input buffer and cause the program to inadvertantly go to the ---- Invalid Answer! ---- part of the code which we don't want the program to do. Appears to be a ---- Lua-ism. - -io.stdin:flush() -io.write("PLAY AGAIN (YES OR NO)? ") -answer = io.read() - -while(not(answer == "YES" or answer == "NO")) do - io.write("Invalid Answer! Try again (YES/NO): ") - answer = io.read() -end - -if answer == "YES" then - goto continue -else - print("") - print("SO LONG. HOPE YOU ENJOYED YOURSELF!!!") - os.exit() -end \ No newline at end of file diff --git a/47_Hi-Lo/python/hilo.py b/47_Hi-Lo/python/hilo.py index 5850b3f7b..d0badf730 100755 --- a/47_Hi-Lo/python/hilo.py +++ b/47_Hi-Lo/python/hilo.py @@ -5,7 +5,7 @@ QUESTION_PROMPT = "? " -def main() -> None: +def play(): print("HI LO") print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") print("THIS IS THE GAME OF HI LO.\n") @@ -50,4 +50,4 @@ def main() -> None: if __name__ == "__main__": - main() + play() diff --git a/47_Hi-Lo/rust/Cargo.lock b/47_Hi-Lo/rust/Cargo.lock deleted file mode 100644 index 937c07c63..000000000 --- a/47_Hi-Lo/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/47_Hi-Lo/rust/Cargo.toml b/47_Hi-Lo/rust/Cargo.toml deleted file mode 100644 index d39f66411..000000000 --- a/47_Hi-Lo/rust/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "guessing_game" -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.3" \ No newline at end of file diff --git a/47_Hi-Lo/rust/README.md b/47_Hi-Lo/rust/README.md deleted file mode 100644 index fc6468b9f..000000000 --- a/47_Hi-Lo/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) diff --git a/47_Hi-Lo/rust/src/main.rs b/47_Hi-Lo/rust/src/main.rs deleted file mode 100644 index 0b821c3b8..000000000 --- a/47_Hi-Lo/rust/src/main.rs +++ /dev/null @@ -1,73 +0,0 @@ -use rand::Rng; -use std::io; - -fn main() { - println!( - "{: >39}\n{: >57}\n\n\n", - "HI LO", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" - ); - println!("THIS IS THE GAME OF HI LO.\n"); - println!("YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE"); - println!("HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS. IF YOU"); - println!("GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!"); - println!("THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY. HOWEVER,"); - println!("IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\n"); - - let mut total: u32 = 0; - loop { - let jackpot_amount = rand::thread_rng().gen_range(1..101); // generates a random number between 1 and 100 - for i in 0..6 { - println!("YOUR GUESS?"); - - let mut guess = String::new(); - - io::stdin() - .read_line(&mut guess) - .expect("Failed to read the line"); - - // this converts the input string into unsigned 32bit number and if the input entered is not a number - // it will again prompt the user to enter the guess number - let guess: u32 = match guess.trim().parse() { - Ok(num) => num, - Err(_) => { - println!("PLEASE ENTER A NUMBER VALUE.\n"); - continue; - } - }; - - // compare it with the jackpot amount - if guess == jackpot_amount { - println!("\nGOT IT!!!!!!!!!! YOU WIN {} DOLLARS.", jackpot_amount); - total += jackpot_amount; - println!("YOUR TOTAL WINNINGS ARE NOW {} DOLLARS.\n", total); - break; - } else if guess < jackpot_amount { - println!("YOUR GUESS IS TOO LOW.\n"); - } else { - println!("YOUR GUESS IS TOO HIGH.\n"); - } - - // if 6 tries are over make total jackpot amount to zero - if i == 5 { - total = 0; - println!( - "YOU BLEW IT...TOO BAD...THE NUMBER WAS {}\n", - jackpot_amount - ); - } - } - println!("PLAY AGAIN (YES OR NO)?"); - let mut tocontinue = String::new(); - io::stdin() - .read_line(&mut tocontinue) - .expect("Error Getting your input"); - let tocontinue = tocontinue.trim().to_ascii_uppercase(); - if tocontinue.eq("YES") { - println!("\n"); - continue; - } else { - println!("\nSO LONG. HOPE YOU ENJOYED YOURSELF!!!\n"); - break; - } - } -} diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 5b8c2204f..168435536 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -1,46 +1,43 @@ -from typing import Dict - - -def new_board() -> Dict[int, str]: - """ - Using a dictionary in python to store the board, - since we are not including all numbers within a given range. - """ - return { - 13: "!", - 14: "!", - 15: "!", - 22: "!", - 23: "!", - 24: "!", - 29: "!", - 30: "!", - 31: "!", - 32: "!", - 33: "!", - 34: "!", - 35: "!", - 38: "!", - 39: "!", - 40: "!", - 42: "!", - 43: "!", - 44: "!", - 47: "!", - 48: "!", - 49: "!", - 50: "!", - 51: "!", - 52: "!", - 53: "!", - 58: "!", - 59: "!", - 60: "!", - 67: "!", - 68: "!", - 69: "!", - 41: "O", - } +def new_board(): + # Using a dictionary in python to store the board, since we are not including all numbers within a given range. + board = {} + for i in [ + 13, + 14, + 15, + 22, + 23, + 24, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 38, + 39, + 40, + 42, + 43, + 44, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 58, + 59, + 60, + 67, + 68, + 69, + ]: + board[i] = "!" + board[41] = "O" + return board def print_instructions() -> None: @@ -76,7 +73,7 @@ def print_instructions() -> None: ) -def print_board(board: Dict[int, str]) -> None: +def print_board(board) -> None: """Prints the boards using indexes in the passed parameter""" print(" " * 2 + board[13] + board[14] + board[15]) print(" " * 2 + board[22] + board[23] + board[24]) @@ -121,15 +118,20 @@ def play_game() -> None: while not move(board): print("ILLEGAL MOVE! TRY AGAIN") - peg_count = sum(1 for key in board.keys() if board[key] == "!") - print(f"YOU HAD {str(peg_count)} PEGS REMAINING") + # 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") if peg_count == 1: print("BRAVO! YOU MADE A PERFECT SCORE!") print("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!") -def move(board: Dict[int, str]) -> bool: +def move(board): """Queries the user to move. Returns false if the user puts in an invalid input or move, returns true if the move was successful""" start_input = input("MOVE WHICH PIECE? ") @@ -152,8 +154,12 @@ def move(board: Dict[int, str]) -> bool: return False difference = abs(start - end) - center = int((end + start) / 2) - if difference in [2, 18] and board[center] == "!": + center = (end + start) / 2 + if ( + (difference == 2 or difference == 18) + and board[end] == "O" + and board[center] == "!" + ): board[start] = "O" board[center] = "O" board[end] = "!" @@ -169,21 +175,20 @@ def main() -> None: play_game() -def is_game_finished(board) -> bool: - """Check all locations and whether or not a move is possible at that location.""" +def is_game_finished(board): + # Checks all locations and whether or not a move is possible at that location. for pos in board.keys(): if board[pos] == "!": for space in [1, 9]: # Checks if the next location has a peg - next_to_peg = ((pos + space) in board) and board[pos + space] == "!" + nextToPeg = ((pos + space) in board) and board[pos + space] == "!" # Checks both going forward (+ location) or backwards (-location) - has_movable_space = ( - pos - space not in board - or board[pos - space] != "!" - or pos + space * 2 not in board - or board[pos + space * 2] != "!" + hasMovableSpace = ( + not ((pos - space) in board and board[pos - space] == "!") + ) or ( + not ((pos + space * 2) in board and board[pos + space * 2] == "!") ) - if next_to_peg and has_movable_space: + if nextToPeg and hasMovableSpace: return False return True diff --git a/49_Hockey/README.md b/49_Hockey/README.md index 98db22d58..3decfe1b1 100644 --- a/49_Hockey/README.md +++ b/49_Hockey/README.md @@ -15,11 +15,6 @@ 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) diff --git a/49_Hockey/python/README.md b/49_Hockey/python/README.md index 2d8807aa8..781945ec4 100644 --- a/49_Hockey/python/README.md +++ b/49_Hockey/python/README.md @@ -1,27 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Python](https://www.python.org/about/) - - -## Porting Notes - -Variables: - -* C: Do you want instructions? -* A$(7): Team name + player names (6 players) -* B$(7): Team name + player names (6 players) -* T6: Minutes per game -* R: REFEREE - -Functions: - -* REM: A line comment -* `INT(2*RND(X))+1`: X is constantly 1. That means that this expression is simpler expressed as `randint(1,2)` - ---- - -Looking at the JS implementation: - -* as[7] / bs[7]: The team name -* ha[8] : Score of team B -* ha[9] : Score of team A diff --git a/49_Hockey/python/hockey.py b/49_Hockey/python/hockey.py deleted file mode 100644 index c65d889e4..000000000 --- a/49_Hockey/python/hockey.py +++ /dev/null @@ -1,561 +0,0 @@ -""" -HOCKEY - -A simulation of an ice hockey game. - -The original author is Robert Puopolo; -modifications by Steve North of Creative Computing. - -Ported to Python by Martin Thoma in 2022 -""" - -from dataclasses import dataclass, field -from random import randint -from typing import List, Tuple - -NB_PLAYERS = 6 - - -@dataclass -class Team: - # TODO: It would be better to use a Player-class (name, goals, assits) - # and have the attributes directly at each player. This would avoid - # dealing with indices that much - # - # I'm also rather certain that I messed up somewhere with the indices - # - instead of using those, one could use actual player positions: - # LEFT WING, CENTER, RIGHT WING - # LEFT DEFENSE, RIGHT DEFENSE, GOALKEEPER - name: str - players: List[str] # 6 players - shots_on_net: int = 0 - goals: List[int] = field(default_factory=lambda: [0 for _ in range(NB_PLAYERS)]) - assists: List[int] = field(default_factory=lambda: [0 for _ in range(NB_PLAYERS)]) - score: int = 0 - - def show_lineup(self) -> None: - print(" " * 10 + f"{self.name} STARTING LINEUP") - for player in self.players: - print(player) - - -def ask_binary(prompt: str, error_msg: str) -> bool: - while True: - answer = input(prompt).lower() - if answer in ["y", "yes"]: - return True - if answer in ["n", "no"]: - return False - print(error_msg) - - -def get_team_names() -> Tuple[str, str]: - while True: - answer = input("ENTER THE TWO TEAMS: ") - if answer.count(",") == 1: - return answer.split(",") # type: ignore - print("separated by a single comma") - - -def get_pass() -> int: - while True: - answer = input("PASS? ") - try: - passes = int(answer) - if passes >= 0 and passes <= 3: - return passes - except ValueError: - print("ENTER A NUMBER BETWEEN 0 AND 3") - - -def get_minutes_per_game() -> int: - while True: - answer = input("ENTER THE NUMBER OF MINUTES IN A GAME ") - try: - minutes = int(answer) - if minutes >= 1: - return minutes - except ValueError: - print("ENTER A NUMBER") - - -def get_player_names(prompt: str) -> List[str]: - players = [] - print(prompt) - for i in range(1, 7): - player = input(f"PLAYER {i}: ") - players.append(player) - return players - - -def make_shot( - controlling_team: int, team_a: Team, team_b: Team, player_index: List[int], j: int -) -> Tuple[int, int, int, int]: - while True: - try: - s = int(input("SHOT? ")) - except ValueError: - continue - if s >= 1 and s <= 4: - break - if controlling_team == 1: - print(team_a.players[player_index[j - 1]]) - else: - print(team_b.players[player_index[j - 1]]) - g = player_index[j - 1] - g1 = 0 - g2 = 0 - if s == 1: - print(" LET'S A BOOMER GO FROM THE RED LINE!!\n") # line 400 - z = 10 - elif s == 2: - print(" FLIPS A WRISTSHOT DOWN THE ICE\n") # line 420 - # Probable missing line 430 in original - elif s == 3: - print(" BACKHANDS ONE IN ON THE GOALTENDER\n") - z = 25 - elif s == 4: - print(" SNAPS A LONG FLIP SHOT\n") - # line 460 - z = 17 - return z, g, g1, g2 - - -def print_header() -> None: - print(" " * 33 + "HOCKEY") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") - - -def instructions() -> None: - 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") - 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("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.") - - -def team1_action( - pass_value: int, player_index: List[int], team_a: Team, team_b: Team, j: int -) -> Tuple[int, int, int, int]: - if pass_value == 1: - print( - team_a.players[player_index[j - 2]] - + " LEADS " - + team_a.players[player_index[j - 1]] - + " WITH A PERFECT PASS.\n" - ) - print(team_a.players[player_index[j - 1]] + " CUTTING IN!!!\n") - scoring_player = player_index[j - 1] - goal_assistant1 = player_index[j - 2] - goal_assistant2 = 0 - z1 = 3 - elif pass_value == 2: - print( - team_a.players[player_index[j - 2]] - + " GIVES TO A STREAKING " - + team_a.players[player_index[j - 1]] - ) - print( - team_a.players[player_index[j - 3]] - + " COMES DOWN ON " - + team_b.players[4] - + " AND " - + team_b.players[3] - ) - scoring_player = player_index[j - 3] - goal_assistant1 = player_index[j - 1] - goal_assistant2 = player_index[j - 2] - z1 = 2 - elif pass_value == 3: - print("OH MY GOD!! A ' 4 ON 2 ' SITUATION\n") - print( - team_a.players[player_index[j - 3]] - + " LEADS " - + team_a.players[player_index[j - 2]] - + "\n" - ) - print(team_a.players[player_index[j - 2]] + " IS WHEELING THROUGH CENTER.\n") - print( - team_a.players[player_index[j - 2]] - + " GIVES AND GOEST WITH " - + team_a.players[player_index[j - 1]] - ) - print("PRETTY PASSING!\n") - print( - team_a.players[player_index[j - 1]] - + " DROPS IT TO " - + team_a.players[player_index[j - 4]] - ) - scoring_player = player_index[j - 4] - goal_assistant1 = player_index[j - 1] - goal_assistant2 = player_index[j - 2] - z1 = 1 - return scoring_player, goal_assistant1, goal_assistant2, z1 - - -def team2_action( - pass_value: int, player_index: List[int], team_a: Team, team_b: Team, j: int -) -> Tuple[int, int, int, int]: - if pass_value == 1: - print( - team_b.players[player_index[j - 1]] - + " HITS " - + team_b.players[player_index[j - 2]] - + " FLYING DOWN THE LEFT SIDE\n" - ) - scoring_player = player_index[j - 2] - goal_assistant1 = player_index[j - 1] - goal_assistant2 = 0 - 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( - team_b.players[player_index[j - 2]] - + " GIVES OFF TO " - + team_b.players[player_index[j - 1]] - ) - print( - team_b.players[player_index[j - 1]] - + " DROPS TO " - + team_b.players[player_index[j - 3]] - ) - scoring_player = player_index[j - 3] - goal_assistant1 = player_index[j - 1] - goal_assistant2 = player_index[j - 2] - z1 = 2 - elif pass_value == 3: - print(" A '3 ON 2 ' WITH A ' TRAILER '!\n") - print( - team_b.players[player_index[j - 4]] - + " GIVES TO " - + team_b.players[player_index[j - 2]] - + " WHO SHUFFLES IT OFF TO\n" - ) - print( - team_b.players[player_index[j - 1]] + " WHO FIRES A WING TO WING PASS TO \n" - ) - print(team_b.players[player_index[j - 3]] + " AS HE CUTS IN ALONE!!\n") - scoring_player = player_index[j - 3] - goal_assistant1 = player_index[j - 1] - goal_assistant2 = player_index[j - 2] - z1 = 1 - return scoring_player, goal_assistant1, goal_assistant2, z1 - - -def final_message(team_a: Team, team_b: Team, player_index: List[int]) -> None: - # Bells chime - print("THAT'S THE SIREN\n") - print("\n") - print(" " * 15 + "FINAL SCORE:\n") - if team_b.score <= team_a.score: - 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}\t:{team_a.score}\n") - print("\n") - print(" " * 10 + "SCORING SUMMARY\n") - print("\n") - print(" " * 25 + team_a.name + "\n") - print("\tNAME\tGOALS\tASSISTS\n") - print("\t----\t-----\t-------\n") - for i in range(1, 6): - print(f"\t{team_a.players[i]}\t{team_a.goals[i]}\t{team_a.assists[i]}\n") - print("\n") - print(" " * 25 + team_b.name + "\n") - print("\tNAME\tGOALS\tASSISTS\n") - print("\t----\t-----\t-------\n") - for t in range(1, 6): - print(f"\t{team_b.players[t]}\t{team_b.goals[t]}\t{team_b.assists[t]}\n") - print("\n") - print("SHOTS ON NET\n") - print(f"{team_a.name}: {team_a.shots_on_net}\n") - print(f"{team_b.name}: {team_b.shots_on_net}\n") - - -def main() -> None: - # Intro - print_header() - player_index: List[int] = [0 for _ in range(21)] - print("\n" * 3) - instructions() - - # Gather input - team_name_a, team_name_b = get_team_names() - print() - minutes_per_game = get_minutes_per_game() - print() - players_a = get_player_names(f"WOULD THE {team_name_a} COACH ENTER HIS TEAM") - print() - players_b = get_player_names(f"WOULD THE {team_name_b} COACH DO THE SAME") - team_a = Team(team_name_a, players_a) - team_b = Team(team_name_b, players_b) - print() - referee = input("INPUT THE REFEREE FOR THIS GAME: ") - print() - team_a.show_lineup() - print() - team_b.show_lineup() - print("WE'RE READY FOR TONIGHTS OPENING FACE-OFF.") - print( - f"{referee} WILL DROP THE PUCK BETWEEN " - f"{team_a.players[0]} AND {team_b.players[0]}" - ) - remaining_time = minutes_per_game - - # Play the game - while remaining_time > 0: - cont, remaining_time = simulate_game_round( - team_a, team_b, player_index, remaining_time - ) - remaining_time -= 1 - if cont == "break": - break - - # Outro - final_message(team_a, team_b, player_index) - - -def handle_hit( - controlling_team: int, - team_a: Team, - team_b: Team, - player_index: List[int], - goal_player: int, - goal_assistant1: int, - goal_assistant2: int, - hit_area: int, - z: int, -) -> int: - while True: - player_index[20] = randint(1, 100) - if player_index[20] % z != 0: - break - a2 = randint(1, 100) - if a2 % 4 == 0: - if controlling_team == 1: - print(f"SAVE {team_b.players[5]} -- REBOUND\n") - else: - print(f"SAVE {team_a.players[5]} -- FOLLOW up\n") - continue - else: - hit_area += 1 - if player_index[20] % z != 0: - if controlling_team == 1: - print(f"GOAL {team_a.name}\n") - team_a.score += 1 - else: - print(f"SCORE {team_b.name}\n") - team_b.score += 1 - # Bells in origninal - print("\n") - print("SCORE: ") - if team_b.score <= team_a.score: - 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") - 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( - f" ASSISTED BY: {team.players[goal_assistant1]}" - f" AND {team.players[goal_assistant2]}" - ) - else: - print(f" ASSISTED BY: {team.players[goal_assistant1]}") - team.assists[goal_assistant1] += 1 - team.assists[goal_assistant2] += 1 - else: - print(" UNASSISTED.\n") - team.goals[goal_player] += 1 - - return hit_area - - -def handle_miss( - controlling_team: int, - team_a: Team, - team_b: Team, - remaining_time: int, - goal_player: int, -) -> Tuple[str, int]: - 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") - 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"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") - remaining_time -= 1 - return ("continue", remaining_time) - if saving_player == 4: - print(f"PAD SAVE BY {team_b.players[5]} OFF THE STICK\n") - print( - f"OF {team_a.players[goal_player]} AND " - f"{team_b.players[5]} COVERS UP\n" - ) - return ("break", remaining_time) - if saving_player == 5: - print(f"WHISTLES ONE OVER THE HEAD OF {team_b.players[5]}\n") - remaining_time -= 1 - return ("continue", remaining_time) - if saving_player == 6: - print(f"{team_b.players[5]} MAKES A FACE SAVE!! AND HE IS HURT\n") - print(f"THE DEFENSEMAN {team_b.players[5]} COVERS UP FOR HIM\n") - return ("break", remaining_time) - else: - if saving_player == 1: - print(f"STICK SAVE BY {team_a.players[5]}\n") - print(f"AND CLEARED OUT BY {team_a.players[3]}\n") - remaining_time -= 1 - return ("continue", remaining_time) - if saving_player == 2: - print( - "OH MY GOD!! " - f"{team_b.players[goal_player]} RATTLES ONE OFF THE POST\n" - ) - print( - f"TO THE RIGHT OF {team_a.players[5]} AND " - f"{team_a.players[5]} COVERS " - ) - 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(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") - remaining_time -= 1 - return ("continue", remaining_time) - if saving_player == 5: - 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") - return ("break", remaining_time) - return ("continue", remaining_time) - - -def simulate_game_round( - team_a: Team, team_b: Team, player_index: List[int], remaining_time: int -) -> Tuple[str, int]: - controlling_team = randint(1, 2) - if controlling_team == 1: - print(f"{team_a.name} HAS CONTROL OF THE PUCK.") - else: - print(f"{team_b.name} HAS CONTROL.") - pass_value = get_pass() - for i in range(1, 4): - player_index[i] = 0 - - # Line 310: - while True: - 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 >= 1 - and ( - player_index[j - 1] == player_index[j - 3] - or player_index[j - 2] == player_index[j - 3] - ) - ): - break - if pass_value == 0: # line 350 - z, goal_player, goal_assistant1, goal_assistant2 = make_shot( - controlling_team, team_a, team_b, player_index, j - ) - else: - if controlling_team == 1: - goal_player, goal_assistant1, goal_assistant2, z1 = team1_action( - pass_value, player_index, team_a, team_b, j - ) - else: - goal_player, goal_assistant1, goal_assistant2, z1 = team2_action( - pass_value, player_index, team_a, team_b, j - ) - while True: - shot_type = int(input("SHOT? ")) - if shot_type >= 1 and shot_type <= 4: - break - if controlling_team == 1: - print(team_a.players[goal_player], end="") - else: - print(team_b.players[goal_player], end="") - if shot_type == 1: - print(" LET'S A BIG SLAP SHOT GO!!\n") - z = 4 - z += z1 - elif shot_type == 2: - print(" RIPS A WRIST SHOT OFF\n") - z = 2 - z += z1 - elif shot_type == 3: - print(" GETS A BACKHAND OFF\n") - z = 3 - z += z1 - elif shot_type == 4: - print(" SNAPS OFF A SNAP SHOT\n") - z = 2 - z += z1 - while True: - goal_area = int(input("AREA? ")) - if goal_area >= 1 and goal_area <= 4: - break - if controlling_team == 1: - team_a.shots_on_net += 1 - else: - team_b.shots_on_net += 1 - hit_area = randint(1, 5) - if goal_area == hit_area: - hit_area = handle_hit( - controlling_team, - team_a, - team_b, - player_index, - goal_player, - goal_assistant1, - goal_assistant2, - hit_area, - z, - ) - if goal_area != hit_area: - return handle_miss( - controlling_team, team_a, team_b, remaining_time, goal_player - ) - print("AND WE'RE READY FOR THE FACE-OFF\n") - return ("continue", remaining_time) - - -if __name__ == "__main__": - main() diff --git a/50_Horserace/java/Horserace.java b/50_Horserace/java/Horserace.java deleted file mode 100644 index 9a5a7651b..000000000 --- a/50_Horserace/java/Horserace.java +++ /dev/null @@ -1,313 +0,0 @@ -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 - *

    - * 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/50_Horserace/python/horserace.py b/50_Horserace/python/horserace.py index 075c4573a..a891597f8 100644 --- a/50_Horserace/python/horserace.py +++ b/50_Horserace/python/horserace.py @@ -1,7 +1,6 @@ import math import random import time -from typing import List, Tuple def basic_print(*zones, **kwargs) -> None: @@ -18,7 +17,7 @@ def basic_print(*zones, **kwargs) -> None: print(" " * identation + line, end=end) -def basic_input(prompt: str, type_conversion=None): +def basic_input(prompt, type_conversion=None): """BASIC INPUT command with optional type conversion""" while True: @@ -46,7 +45,7 @@ def basic_input(prompt: str, type_conversion=None): ] -def introduction() -> None: +def introduction(): """Print the introduction, and optional the instructions""" basic_print("HORSERACE", indent=31) @@ -67,17 +66,21 @@ def introduction() -> None: basic_print("") -def setup_players() -> List[str]: +def setup_players(): """Gather the number of players and their names""" # 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") - return [basic_input("") for _ in range(number_of_players)] + for _ in range(number_of_players): + player_names.append(basic_input("")) + return player_names -def setup_horses() -> List[float]: +def setup_horses(): """Generates random odds for each horse. Returns a list of odds, indexed by the order of the global HORSE_NAMES.""" @@ -98,14 +101,14 @@ def print_horse_odds(odds) -> None: basic_print("") -def get_bets(player_names: List[str]) -> List[Tuple[int, float]]: +def get_bets(player_names): """For each player, get the number of the horse to bet on, as well as the amount of money to bet""" basic_print("--------------------------------------------------") basic_print("PLACE YOUR BETS...HORSE # THEN AMOUNT") - bets: List[Tuple[int, float]] = [] + bets = [] for name in player_names: horse = basic_input(name, int) amount = None @@ -121,7 +124,7 @@ def get_bets(player_names: List[str]) -> List[Tuple[int, float]]: return bets -def get_distance(odd: float) -> int: +def get_distance(odd): """Advances a horse during one step of the racing simulation. The amount travelled is random, but scaled by the odds of the horse""" @@ -177,7 +180,7 @@ def print_race_state(total_distance, race_pos) -> None: basic_print("XXXXFINISHXXXX") -def simulate_race(odds) -> List[int]: +def simulate_race(odds): num_horses = len(HORSE_NAMES) # in spirit of the original implementation, using two arrays to diff --git a/50_Horserace/rust/Cargo.lock b/50_Horserace/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/50_Horserace/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/50_Horserace/rust/Cargo.toml b/50_Horserace/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/50_Horserace/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/50_Horserace/rust/src/game.rs b/50_Horserace/rust/src/game.rs deleted file mode 100644 index 079e397e2..000000000 --- a/50_Horserace/rust/src/game.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::{thread, time::Duration}; - -use crate::{horses::Horses, players::Players}; - -pub struct Game { - horses: Horses, - players: Players, -} - -impl Game { - pub fn new() -> Self { - Game { - horses: Horses::new(), - players: Players::new(), - } - } - - pub fn play(&mut self) -> bool { - self.horses.randomize_odds(); - self.horses.print_table(); - - self.players.make_bets(); - - println!("\n1 2 3 4 5 6 7 8"); - - for _ in 1..=7 { - self.horses.advance(); - self.draw(); - thread::sleep(Duration::from_secs(1)); - } - - let winner = self.horses.print_placements(); - self.players.process_winner(winner); - - return self.players.prompt_next_round(); - } - - pub fn draw(&self) { - println!("============="); - println!("XXXXSTARTXXXX"); - for row in 1..=28 { - let neighbors = self.horses.get_at(row); - - match neighbors.len() { - 0 => println!(), - 1 => println!("{}", neighbors[0].no), - _ => { - for h in neighbors { - print!("{} ", h.no); - } - println!(); - } - } - } - println!("XXXXFINISHXXXX"); - } -} diff --git a/50_Horserace/rust/src/horses.rs b/50_Horserace/rust/src/horses.rs deleted file mode 100644 index 825042aa2..000000000 --- a/50_Horserace/rust/src/horses.rs +++ /dev/null @@ -1,114 +0,0 @@ -use rand::Rng; - -pub struct Horse { - pub name: String, - pub no: u8, - pub odd: f32, - pub position: u8, -} - -impl Horse { - fn new(name: &str, no: u8) -> Self { - Horse { - name: name.to_string(), - no, - odd: 0., - position: 0, - } - } -} - -pub struct Horses { - horses: [Horse; 8], -} - -impl Horses { - pub fn new() -> Self { - Horses { - horses: [ - Horse::new("JOE MAW", 1), - Horse::new("L.B.J.", 2), - Horse::new("MR.WASHBURN", 3), - Horse::new("MISS KAREN", 4), - Horse::new("JOLLY", 5), - Horse::new("HORSE", 6), - Horse::new("JELLY DO NOT", 7), - Horse::new("MIDNIGHT", 8), - ], - } - } - - pub fn randomize_odds(&mut self) { - let mut odds = Vec::new(); - - for _ in 1..=8 { - odds.push(rand::thread_rng().gen_range(1.0..=10.)); - } - - let total: f32 = odds.iter().sum(); - - for (i, o) in odds.iter().enumerate() { - let o = total / o; - self.horses[i].odd = o; - } - } - - pub fn advance(&mut self) { - for h in self.horses.iter_mut() { - let distance = rand::thread_rng().gen_range(1..=100); - let scale = h.odd.ceil() as i32; - - let dt = if distance < 10 { - 1 - } else if distance < scale + 17 { - 2 - } else if distance < scale + 37 { - 3 - } else if distance < scale + 57 { - 4 - } else if distance < scale + 77 { - 5 - } else if distance < scale + 92 { - 6 - } else { - 7 - }; - - h.position += dt as u8; - } - } - - pub fn get_at(&self, row: usize) -> Vec<&Horse> { - self.horses - .iter() - .filter(|h| h.position == row as u8) - .collect() - } - - pub fn print_table(&self) { - println!("HORSE\t\tNUMBER\t\tODDS\t\t\n"); - for horse in self.horses.iter() { - let (h, n, o) = (horse.name.clone(), horse.no, horse.odd); - - if h.len() > 7 { - println!("{}\t{}\t\t{:.2} :1", h, n, o); - } else { - println!("{}\t\t{}\t\t{:.2} :1", h, n, o); - } - } - println!("-----------------------------------------\n") - } - - pub fn print_placements(&mut self) -> u8 { - self.horses.sort_by(|a, b| b.position.cmp(&a.position)); - - println!("\nTHE RACE RESULTS ARE:\n"); - - for (i, h) in self.horses.iter_mut().enumerate() { - println!("{} PLACE HORSE NO. {}\t\tAT {:.2} :1", i + 1, h.no, h.odd); - h.position = 0; - } - - self.horses[0].no - } -} diff --git a/50_Horserace/rust/src/main.rs b/50_Horserace/rust/src/main.rs deleted file mode 100644 index fc8a5d1af..000000000 --- a/50_Horserace/rust/src/main.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::{game::Game, util::PromptResult}; - -mod game; -mod horses; -mod players; -mod util; - -fn main() { - println!("\n\n\t\tHORSERACE"); - println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); - println!("WELCOME TO SOUTH PORTLAND HIGH RACETRACK\n\t\t...OWNED BY LAURIE CHEVALIER"); - - if let PromptResult::YesNo(yes) = util::prompt(Some(false), "DO YOU WANT DIRECTIONS?") { - if yes { - println!("UP TO 10 MAY PLAY. A TABLE OF ODDS WILL BE PRINTED. YOU"); - println!("MAY BET ANY AMOUNT UNDER $100,000 ON ONE HORSE."); - println!("DURING THE RACE, A HORSE WILL BE SHOWN BY ITS"); - println!("NUMBER. THE HORSES RACE DOWN THE PAPER!\n"); - } - } - - let mut game = Game::new(); - let mut again = true; - - while again { - again = game.play(); - } -} diff --git a/50_Horserace/rust/src/players.rs b/50_Horserace/rust/src/players.rs deleted file mode 100644 index 5aa891b71..000000000 --- a/50_Horserace/rust/src/players.rs +++ /dev/null @@ -1,156 +0,0 @@ -use crate::util::{self, PromptResult}; - -#[derive(Debug)] -pub struct Player { - pub name: String, - pub money: u32, - pub playing: bool, - pub horse_no: u8, - pub bet: u32, -} - -impl Player { - fn new(name: String) -> Self { - Player { - name, - money: 100000, - playing: true, - horse_no: 0, - bet: 0, - } - } -} - -#[derive(Debug)] -pub struct Players { - players: Vec, -} - -impl Players { - pub fn new() -> Self { - let players; - - loop { - if let PromptResult::Numeric(n) = util::prompt(Some(true), "HOW MANY WANT TO BET?") { - if n <= 0 { - println!("THERE CAN'T BE (LESS THAN) ZERO PLAYERS!"); - } else if n > 10 { - println!("THERE CAN'T BE MORE THAN TEN PLAYERS!"); - } else { - println!("WHEN ? APPEARS, TYPE NAME"); - players = Players::generate_players(n); - break; - } - } - } - - Players { players } - } - - pub fn make_bets(&mut self) { - println!("PLACE YOUR BETS...HORSE # THEN AMOUNT"); - - for p in self.players.iter_mut() { - if !p.playing { - continue; - } - - let name = format!("{}?", p.name); - - 'prompt: loop { - if let PromptResult::Normal(response) = util::prompt(None, name.as_str()) { - let response: Vec<&str> = response.trim().split(",").collect(); - - for (i, n) in response.iter().enumerate() { - if let Ok(n) = n.parse::() { - if n.is_negative() { - println!("YOU CAN'T ENTER A NEGATIVE NUMBER!") - } else { - match i { - 0 => { - if n > 8 { - println!("INVALID HORSE #") - } else { - p.horse_no = n as u8; - } - } - 1 => { - if n == 0 { - println!("YOU CAN'T BET NOTHING!"); - } else if n > p.money as i32 { - println!("YOU DON'T HAVE ENOUGH MONEY!") - } else { - p.bet = n as u32; - break 'prompt; - } - } - _ => println!("YOU CAN'T ENTER MORE THAN 2 NUMBERS!"), - } - } - } else { - println!("ONLY ENTER NUMBERS PLEASE!"); - } - } - } - } - } - } - - fn generate_players(n: i32) -> Vec { - let mut players: Vec = Vec::new(); - - for _ in 0..n { - loop { - if let PromptResult::Normal(name) = util::prompt(None, "?") { - let name = name.trim().to_uppercase(); - - if name.is_empty() { - println!("NAME CAN'T BE EMPTY!"); - } else if let Some(_) = players.iter().find(|p| p.name == name) { - println!("THERE IS ALREADY A PLAYER WITH THAT NAME!"); - } else { - players.push(Player::new(name)); - break; - } - } - } - } - - players - } - - pub fn process_winner(&mut self, no: u8) { - println!(); - for p in self.players.iter_mut() { - if !p.playing { - continue; - } - - if p.horse_no == no { - p.money += p.bet; - println!("{} WON ${}! THEY HAVE ${}.", p.name, p.bet, p.money); - } else { - p.money -= p.bet; - println!("{} LOST ${}. THEY HAVE ${} LEFT.", p.name, p.bet, p.money); - } - p.bet = 0; - p.horse_no = 0; - } - println!(); - } - - pub fn prompt_next_round(&mut self) -> bool { - for p in self.players.iter_mut() { - let msg = format!("{}, DO YOU WANT TO BET ON THE NEXT RACE?", p.name); - if let PromptResult::YesNo(yes) = util::prompt(Some(false), msg.as_str()) { - p.playing = yes; - } - } - - if let None = self.players.iter().find(|p| p.playing) { - return false; - } - - true - } -} diff --git a/50_Horserace/rust/src/util.rs b/50_Horserace/rust/src/util.rs deleted file mode 100644 index f1944bad3..000000000 --- a/50_Horserace/rust/src/util.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::io; - -pub enum PromptResult { - Normal(String), - YesNo(bool), - Numeric(i32), -} - -pub fn prompt(is_numeric: Option, msg: &str) -> PromptResult { - use PromptResult::*; - - println!("{msg}"); - - loop { - let mut input = String::new(); - - io::stdin() - .read_line(&mut input) - .expect("Failed to read input."); - - if let Some(is_numeric) = is_numeric { - let input = input.trim(); - - if is_numeric { - if let Ok(n) = input.parse::() { - return Numeric(n); - } - println!("PLEASE ENTER A VALID NUMBER!"); - } else { - match input.to_uppercase().as_str() { - "YES" | "Y" => return YesNo(true), - "NO" | "N" => return YesNo(false), - _ => println!("PLEASE ENTER (Y)ES OR (N)O."), - } - } - } else { - return Normal(input); - } - } -} diff --git a/51_Hurkle/python/hurkle.py b/51_Hurkle/python/hurkle.py index c8e2ca9bf..62cffecbf 100644 --- a/51_Hurkle/python/hurkle.py +++ b/51_Hurkle/python/hurkle.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 - -"""Ported to Python by @iamtraction""" +# +# Ported to Python by @iamtraction from random import random -def direction(A, B, X, Y) -> None: - """Print the direction hint for finding the hurkle.""" +def direction(A, B, X, Y): + """Prints the direction hint for finding the hurkle.""" print("GO ", end="") if Y < B: @@ -22,7 +22,7 @@ def direction(A, B, X, Y) -> None: print() -def main() -> None: +if __name__ == "__main__": print(" " * 33 + "HURKLE") print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") @@ -63,7 +63,3 @@ def main() -> None: continue print("\n\nLET'S PLAY AGAIN, HURKLE IS HIDING.\n") - - -if __name__ == "__main__": - main() diff --git a/51_Hurkle/rust/Cargo.lock b/51_Hurkle/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/51_Hurkle/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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.toml b/51_Hurkle/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/51_Hurkle/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/51_Hurkle/rust/src/game.rs b/51_Hurkle/rust/src/game.rs deleted file mode 100644 index 471889858..000000000 --- a/51_Hurkle/rust/src/game.rs +++ /dev/null @@ -1,103 +0,0 @@ -use std::io; - -use rand::Rng; - -type Position = (u8, u8); - -pub struct Game { - hurkle: Position, - tries: u8, -} - -impl Game { - pub fn new() -> Self { - let x: u8 = rand::thread_rng().gen_range(1..=10); - let y: u8 = rand::thread_rng().gen_range(1..=10); - let hurkle = (x, y); - - Game { hurkle, tries: 0 } - } - - pub fn update(&mut self) -> bool { - if self.tries >= 5 { - println!("SORRY, THAT'S {} GUESSES.", self.tries); - println!("THE HURKLE IS AT {}, {}", self.hurkle.0, self.hurkle.1); - return true; - } - self.tries += 1; - self.process_guess(self.get_guess()) - } - - fn get_guess(&self) -> Position { - let mut pos = (0, 0); - - 'guess: loop { - println!("GUESS # {}?", self.tries); - - let mut input = String::new(); - - io::stdin() - .read_line(&mut input) - .expect("**Failed to read line**"); - - let input: Vec<&str> = input.trim().split(",").collect(); - - let mut is_y = false; - for a in input { - match a.parse::() { - Ok(a) => { - if a > 10 || a == 0 { - println!("GUESS AXIS CANNOT BE ZERO OR LARGER THAN TEN!"); - break; - } - if is_y { - pos.1 = a; - break 'guess; - } else { - pos.0 = a; - is_y = true; - } - } - Err(e) => println!("{} - TRY AGAIN!", e.to_string().to_uppercase()), - } - } - } - - pos - } - - fn process_guess(&self, p: Position) -> bool { - if p == self.hurkle { - println!("\nYOU FOUND HIM IN {} GUESSES!", self.tries); - return true; - } - - let (x, y) = (p.0, p.1); - let (hx, hy) = (self.hurkle.0, self.hurkle.1); - - let mut dir_x = "WEST"; - let mut dir_y = "SOUTH"; - - let mut set_y_dir = || { - if y < hy { - dir_y = "NORTH"; - } else { - dir_y = ""; - } - }; - - if x > hx { - set_y_dir(); - } else if x < hx { - dir_x = "EAST"; - set_y_dir(); - } else { - dir_x = ""; - set_y_dir(); - } - - println!("GO {}{}\n", dir_y, dir_x); - - false - } -} diff --git a/51_Hurkle/rust/src/main.rs b/51_Hurkle/rust/src/main.rs deleted file mode 100644 index 70b07abd3..000000000 --- a/51_Hurkle/rust/src/main.rs +++ /dev/null @@ -1,29 +0,0 @@ -use game::Game; - -mod game; - -fn main() { - println!("\n\n\t\tHURKLE"); - println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); - - println!("A HURKLE IS HIDING ON A 10 BY 10 GRID. HOMEBASE"); - println!("ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,"); - println!("AND ANY POINT ON THE GRID IS DESIGNATED BY A"); - println!("PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST"); - println!("NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER"); - println!("IS THE VERTICAL POSITION. YOU MUST TRY TO"); - println!("GUESS THE HURKLE'S GRIDPOINT. YOU GET 5 TRIES."); - println!("AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE"); - println!("DIRECTION TO GO TO LOOK FOR THE HURKLE.\n"); - - loop { - let mut game = Game::new(); - - loop { - if game.update() { - println!("\nLET'S PLAY AGAIN. HURKLE IS HIDING."); - break; - } - } - } -} diff --git a/52_Kinema/python/kinema.py b/52_Kinema/python/kinema.py index 2a4831a77..65fbd08fb 100644 --- a/52_Kinema/python/kinema.py +++ b/52_Kinema/python/kinema.py @@ -20,7 +20,15 @@ EXPECTED_ACCURACY_PERCENT = 15 -def do_quiz() -> None: +def print_with_tab(spaces_count, msg) -> None: + if spaces_count > 0: + spaces = " " * spaces_count + else: + spaces = "" + print(spaces + msg) + + +def do_quiz(): print() print() num_questions_correct = 0 @@ -50,7 +58,7 @@ def do_quiz() -> None: print(" NOT BAD.") -def ask_player(question: str, answer) -> int: +def ask_player(question, answer): print(question) player_answer = float(input()) @@ -67,8 +75,11 @@ def ask_player(question: str, answer) -> int: def main() -> None: - print(" " * 33 + "KINEMA") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_with_tab(33, "KINEMA") + print_with_tab(15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() while True: do_quiz() diff --git a/52_Kinema/rust/Cargo.toml b/52_Kinema/rust/Cargo.toml deleted file mode 100644 index 3a87396aa..000000000 --- a/52_Kinema/rust/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[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 deleted file mode 100644 index 9ce5c29ed..000000000 --- a/52_Kinema/rust/src/main.rs +++ /dev/null @@ -1,114 +0,0 @@ -/** 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; 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 - 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 -} diff --git a/53_King/README.md b/53_King/README.md index 83fb61c33..411d4876e 100644 --- a/53_King/README.md +++ b/53_King/README.md @@ -1,10 +1,10 @@ ## King -This is one of the most comprehensive, difficult, and interesting games. (If you've never played one of these games, start with HAMMURABI.) +This is one of the most comprehensive, difficult, and interesting games. (If you’ve never played one of these games, start with HAMMURABI.) In this game, you are Premier of Setats Detinu, a small communist island 30 by 70 miles long. Your job is to decide upon the budget of your country and distribute money to your country from the communal treasury. -The money system is Rollods; 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. Part of your land is farm land but it also has an excellent mineral content and may be sold to foreign industry for strip mining. Industry import and support their own workers. Crops cost between 10 and 15 Rallods per square mile to plant, cultivate, and harvest. Your goal is to complete an eight-year term of office without major mishap. A word of warning: it isn't easy! +The money system is Rollods; 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. Part of your land is farm land but it also has an excellent mineral content and may be sold to foreign industry for strip mining. Industry import and support their own workers. Crops cost between 10 and 15 Rallods per square mile to plant, cultivate, and harvest. Your goal is to complete an eight-year term of office without major mishap. A word of warning: it isn’t easy! The author of this program is James A. Storer who wrote it while a student at Lexington High School. @@ -21,9 +21,7 @@ http://www.vintage-basic.net/games.html #### Porting Notes -Implementers should be aware that this game contains bugs. - -### Bug 1 +Implementers should be aware that this game contains at least one bug. On basic line 1450 @@ -43,53 +41,4 @@ A quick fix for this bug in the original code would be 1410 PRINT " YOU MADE";ABS(INT(V1-V2));"RALLODS FROM TOURIST TRADE." -### Bug 2 - -On basic line 1330 following was the variable T1 never assigned: - - 1330 PRINT " YOU HARVESTED ";INT(J-U2);"SQ. MILES OF CROPS." - 1340 IF U2=0 THEN 1370 - 1344 IF T1>=2 THEN 1370 - 1350 PRINT " (DUE TO "; - 1355 IF T1=0 THEN 1365 - 1360 PRINT "INCREASED "; - -Likely it should be the difference of the current years crop loss compared to the -last years crop loss. - -### Bug 3 - -On basic line 1997 it is: - - 1997 PRINT " AND 10,000 SQ. MILES OF FOREST LAND." - -but it should be: - - 1997 PRINT " AND 1,000 SQ. MILES OF FOREST LAND." - -### Bug 4 - -On basic line 1310 we see this: - - 1310 IF C=0 THEN 1324 - 1320 PRINT "OF ";INT(J);"SQ. MILES PLANTED,"; - 1324 ... - -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/csharp/Country.cs b/53_King/csharp/Country.cs deleted file mode 100644 index 1a37bcd88..000000000 --- a/53_King/csharp/Country.cs +++ /dev/null @@ -1,133 +0,0 @@ -namespace King; - -internal class Country -{ - private const int InitialLand = 1000; - - private readonly IReadWrite _io; - private readonly IRandom _random; - private float _rallods; - private float _countrymen; - private float _foreigners; - private float _arableLand; - private float _industryLand; - - public Country(IReadWrite io, IRandom random) - : this( - io, - random, - (int)(60000 + random.NextFloat(1000) - random.NextFloat(1000)), - (int)(500 + random.NextFloat(10) - random.NextFloat(10)), - 0, - InitialLand) - { - } - - public Country(IReadWrite io, IRandom random, float rallods, float countrymen, float foreigners, float land) - { - _io = io; - _random = random; - _rallods = rallods; - _countrymen = countrymen; - _foreigners = foreigners; - _arableLand = land; - } - - public string GetStatus(int landValue, int plantingCost) - => Resource.Status(_rallods, _countrymen, _foreigners, _arableLand, landValue, plantingCost); - - public float Countrymen => _countrymen; - public float Workers => _foreigners; - public bool HasWorkers => _foreigners > 0; - private float FarmLand => _arableLand; - public bool HasRallods => _rallods > 0; - public float Rallods => _rallods; - public float IndustryLand => InitialLand - _arableLand; - public int PreviousTourismIncome { get; private set; } - - public bool SellLand(int landValue, out float landSold) - { - if (_io.TryReadValue( - SellLandPrompt, - out landSold, - new ValidityTest(v => v <= FarmLand, () => SellLandError(FarmLand)))) - { - _arableLand = (int)(_arableLand - landSold); - _rallods = (int)(_rallods + landSold * landValue); - return true; - } - - return false; - } - - public bool DistributeRallods(out float rallodsGiven) - { - if (_io.TryReadValue( - GiveRallodsPrompt, - out rallodsGiven, - new ValidityTest(v => v <= _rallods, () => GiveRallodsError(_rallods)))) - { - _rallods = (int)(_rallods - rallodsGiven); - return true; - } - - return false; - } - - public bool PlantLand(int plantingCost, out float landPlanted) - { - if (_io.TryReadValue( - PlantLandPrompt, - out landPlanted, - new ValidityTest(v => v <= _countrymen * 2, PlantLandError1), - new ValidityTest(v => v <= FarmLand, PlantLandError2(FarmLand)), - new ValidityTest(v => v * plantingCost <= _rallods, PlantLandError3(_rallods)))) - { - _rallods -= (int)(landPlanted * plantingCost); - return true; - } - - return false; - } - - public bool ControlPollution(out float rallodsSpent) - { - if (_io.TryReadValue( - PollutionPrompt, - out rallodsSpent, - new ValidityTest(v => v <= _rallods, () => PollutionError(_rallods)))) - { - _rallods = (int)(_rallods - rallodsSpent); - return true; - } - - return false; - } - - public bool TrySpend(float amount, float landValue) - { - if (_rallods >= amount) - { - _rallods -= amount; - return true; - } - - _arableLand = (int)(_arableLand - (int)(amount - _rallods) / landValue); - _rallods = 0; - return false; - } - - public void RemoveTheDead(int deaths) => _countrymen = (int)(_countrymen - deaths); - - public void Migration(int migration) => _countrymen = (int)(_countrymen + migration); - - public void AddWorkers(int newWorkers) => _foreigners = (int)(_foreigners + newWorkers); - - public void SellCrops(int income) => _rallods = (int)(_rallods + income); - - public void EntertainTourists(int income) - { - PreviousTourismIncome = income; - _rallods = (int)(_rallods + income); - } -} diff --git a/53_King/csharp/Game.cs b/53_King/csharp/Game.cs deleted file mode 100644 index 6a91010ce..000000000 --- a/53_King/csharp/Game.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace King; - -internal class Game -{ - const int TermOfOffice = 8; - - private readonly IReadWrite _io; - private readonly IRandom _random; - - public Game(IReadWrite io, IRandom random) - { - _io = io; - _random = random; - } - - public void Play() - { - _io.Write(Title); - - var reign = SetUpReign(); - if (reign != null) - { - while (reign.PlayYear()); - } - - _io.WriteLine(); - _io.WriteLine(); - } - - private Reign? SetUpReign() - { - var response = _io.ReadString(InstructionsPrompt).ToUpper(); - - if (response.Equals("Again", StringComparison.InvariantCultureIgnoreCase)) - { - return _io.TryReadGameData(_random, out var reign) ? reign : null; - } - - if (!response.StartsWith("N", StringComparison.InvariantCultureIgnoreCase)) - { - _io.Write(InstructionsText(TermOfOffice)); - } - - _io.WriteLine(); - return new Reign(_io, _random); - } -} diff --git a/53_King/csharp/IOExtensions.cs b/53_King/csharp/IOExtensions.cs deleted file mode 100644 index dbb3079ad..000000000 --- a/53_King/csharp/IOExtensions.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using static King.Resources.Resource; - -namespace King; - -internal static class IOExtensions -{ - internal static bool TryReadGameData(this IReadWrite io, IRandom random, [NotNullWhen(true)] out Reign? reign) - { - if (io.TryReadValue(SavedYearsPrompt, v => v < Reign.MaxTerm, SavedYearsError(Reign.MaxTerm), out var years) && - io.TryReadValue(SavedTreasuryPrompt, out var rallods) && - io.TryReadValue(SavedCountrymenPrompt, out var countrymen) && - io.TryReadValue(SavedWorkersPrompt, out var workers) && - io.TryReadValue(SavedLandPrompt, v => v is > 1000 and <= 2000, SavedLandError, out var land)) - { - reign = new Reign(io, random, new Country(io, random, rallods, countrymen, workers, land), years + 1); - return true; - } - - reign = default; - return false; - } - - internal static bool TryReadValue(this IReadWrite io, string prompt, out float value, params ValidityTest[] tests) - { - while (true) - { - var response = value = io.ReadNumber(prompt); - if (response == 0) { return false; } - if (tests.All(test => test.IsValid(response, io))) { return true; } - } - } - - internal static bool TryReadValue(this IReadWrite io, string prompt, out float value) - => io.TryReadValue(prompt, _ => true, "", out value); - - internal static bool TryReadValue( - this IReadWrite io, - string prompt, - Predicate isValid, - string error, - out float value) - => io.TryReadValue(prompt, isValid, () => error, out value); - - internal static bool TryReadValue( - this IReadWrite io, - string prompt, - Predicate isValid, - Func getError, - out float value) - { - while (true) - { - value = io.ReadNumber(prompt); - if (value < 0) { return false; } - if (isValid(value)) { return true; } - - io.Write(getError()); - } - } -} diff --git a/53_King/csharp/King.csproj b/53_King/csharp/King.csproj index 3870320c9..d3fe4757c 100644 --- a/53_King/csharp/King.csproj +++ b/53_King/csharp/King.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/53_King/csharp/Program.cs b/53_King/csharp/Program.cs deleted file mode 100644 index 5aae4ccbc..000000000 --- a/53_King/csharp/Program.cs +++ /dev/null @@ -1,7 +0,0 @@ -global using Games.Common.IO; -global using Games.Common.Randomness; -global using King.Resources; -global using static King.Resources.Resource; -using King; - -new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); diff --git a/53_King/csharp/Reign.cs b/53_King/csharp/Reign.cs deleted file mode 100644 index 7a96a30fa..000000000 --- a/53_King/csharp/Reign.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace King; - -internal class Reign -{ - public const int MaxTerm = 8; - - private readonly IReadWrite _io; - private readonly IRandom _random; - private readonly Country _country; - private float _yearNumber; - - public Reign(IReadWrite io, IRandom random) - : this(io, random, new Country(io, random), 1) - { - } - - public Reign(IReadWrite io, IRandom random, Country country, float year) - { - _io = io; - _random = random; - _country = country; - _yearNumber = year; - } - - public bool PlayYear() - { - var year = new Year(_country, _random, _io); - - _io.Write(year.Status); - - var result = year.GetPlayerActions() ?? year.EvaluateResults() ?? IsAtEndOfTerm(); - if (result.IsGameOver) - { - _io.WriteLine(result.Message); - return false; - } - - return true; - } - - private Result IsAtEndOfTerm() - => _yearNumber == MaxTerm - ? Result.GameOver(EndCongratulations(MaxTerm)) - : Result.Continue; -} diff --git a/53_King/csharp/Resources/DeathsPollution.txt b/53_King/csharp/Resources/DeathsPollution.txt deleted file mode 100644 index bf28d9a76..000000000 --- a/53_King/csharp/Resources/DeathsPollution.txt +++ /dev/null @@ -1 +0,0 @@ - {0} countrymen died of carbon-monoxide and dust inhalation \ No newline at end of file diff --git a/53_King/csharp/Resources/DeathsStarvation.txt b/53_King/csharp/Resources/DeathsStarvation.txt deleted file mode 100644 index af275cf40..000000000 --- a/53_King/csharp/Resources/DeathsStarvation.txt +++ /dev/null @@ -1 +0,0 @@ - {0} countrymen died of starvation \ No newline at end of file diff --git a/53_King/csharp/Resources/Emigration.txt b/53_King/csharp/Resources/Emigration.txt deleted file mode 100644 index 01f67094e..000000000 --- a/53_King/csharp/Resources/Emigration.txt +++ /dev/null @@ -1 +0,0 @@ - {0} countrymen left the island. \ No newline at end of file diff --git a/53_King/csharp/Resources/EndAlso.txt b/53_King/csharp/Resources/EndAlso.txt deleted file mode 100644 index 084b9a823..000000000 --- a/53_King/csharp/Resources/EndAlso.txt +++ /dev/null @@ -1,3 +0,0 @@ -also had your left eye gouged out! -;have also gained a very bad reputation. -;have also been declared national fink. diff --git a/53_King/csharp/Resources/EndCongratulations.txt b/53_King/csharp/Resources/EndCongratulations.txt deleted file mode 100644 index ef1ff2038..000000000 --- a/53_King/csharp/Resources/EndCongratulations.txt +++ /dev/null @@ -1,10 +0,0 @@ - - -Congratulations!!!!!!!!!!!!!!!!!! -You have successfully completed your {0} 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. - - diff --git a/53_King/csharp/Resources/EndConsequences.txt b/53_King/csharp/Resources/EndConsequences.txt deleted file mode 100644 index 61ebfd253..000000000 --- a/53_King/csharp/Resources/EndConsequences.txt +++ /dev/null @@ -1,3 +0,0 @@ -You have been thrown out of office and are now -residing in prison.; -You have been assassinated. diff --git a/53_King/csharp/Resources/EndForeignWorkers.txt b/53_King/csharp/Resources/EndForeignWorkers.txt deleted file mode 100644 index 76c04c3d0..000000000 --- a/53_King/csharp/Resources/EndForeignWorkers.txt +++ /dev/null @@ -1,7 +0,0 @@ - - -The number of foreign workers has exceeded the number -of countrymen. As a minority, they have revolted and -taken over the country. -{0} - diff --git a/53_King/csharp/Resources/EndManyDead.txt b/53_King/csharp/Resources/EndManyDead.txt deleted file mode 100644 index 70cd95f05..000000000 --- a/53_King/csharp/Resources/EndManyDead.txt +++ /dev/null @@ -1,5 +0,0 @@ -{0} countrymen died in one year!!!!! -due to this extreme mismanagement, you have not only -been impeached and thrown out of office, but you -{1} - diff --git a/53_King/csharp/Resources/EndMoneyLeftOver.txt b/53_King/csharp/Resources/EndMoneyLeftOver.txt deleted file mode 100644 index e194a9fd7..000000000 --- a/53_King/csharp/Resources/EndMoneyLeftOver.txt +++ /dev/null @@ -1,7 +0,0 @@ - -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 resign. - - diff --git a/53_King/csharp/Resources/EndOneThirdDead.txt b/53_King/csharp/Resources/EndOneThirdDead.txt deleted file mode 100644 index e1761dfe4..000000000 --- a/53_King/csharp/Resources/EndOneThirdDead.txt +++ /dev/null @@ -1,7 +0,0 @@ - - -Over one third of the population has died since you -were elected to office. The people (remaining) -hate your guts. -{0} - diff --git a/53_King/csharp/Resources/FuneralExpenses.txt b/53_King/csharp/Resources/FuneralExpenses.txt deleted file mode 100644 index 3aff58ebe..000000000 --- a/53_King/csharp/Resources/FuneralExpenses.txt +++ /dev/null @@ -1 +0,0 @@ - You were forced to spend {0} rallods on funeral expenses \ No newline at end of file diff --git a/53_King/csharp/Resources/GiveRallodsError.txt b/53_King/csharp/Resources/GiveRallodsError.txt deleted file mode 100644 index df0d7cc00..000000000 --- a/53_King/csharp/Resources/GiveRallodsError.txt +++ /dev/null @@ -1 +0,0 @@ - Think again. You've only got {0} rallods in the treasury. diff --git a/53_King/csharp/Resources/GiveRallodsPrompt.txt b/53_King/csharp/Resources/GiveRallodsPrompt.txt deleted file mode 100644 index e8bd345b8..000000000 --- a/53_King/csharp/Resources/GiveRallodsPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -How many rallods will you distribute among your countrymen \ No newline at end of file diff --git a/53_King/csharp/Resources/Goodbye.txt b/53_King/csharp/Resources/Goodbye.txt deleted file mode 100644 index 67543c040..000000000 --- a/53_King/csharp/Resources/Goodbye.txt +++ /dev/null @@ -1,4 +0,0 @@ -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). diff --git a/53_King/csharp/Resources/Harvest.txt b/53_King/csharp/Resources/Harvest.txt deleted file mode 100644 index 287e0c427..000000000 --- a/53_King/csharp/Resources/Harvest.txt +++ /dev/null @@ -1,2 +0,0 @@ - you harvested {0} sq. miles of crops. -{1}making {2} rallods. diff --git a/53_King/csharp/Resources/HarvestReason.txt b/53_King/csharp/Resources/HarvestReason.txt deleted file mode 100644 index 82faccb53..000000000 --- a/53_King/csharp/Resources/HarvestReason.txt +++ /dev/null @@ -1 +0,0 @@ - (Due to increased air and water pollution from foreign industry.) diff --git a/53_King/csharp/Resources/Immigration.txt b/53_King/csharp/Resources/Immigration.txt deleted file mode 100644 index 30d8b6b37..000000000 --- a/53_King/csharp/Resources/Immigration.txt +++ /dev/null @@ -1 +0,0 @@ - {0} countrymen came to the island. \ No newline at end of file diff --git a/53_King/csharp/Resources/InstructionsPrompt.txt b/53_King/csharp/Resources/InstructionsPrompt.txt deleted file mode 100644 index 0d311b605..000000000 --- a/53_King/csharp/Resources/InstructionsPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -Do you want instructions \ No newline at end of file diff --git a/53_King/csharp/Resources/InstructionsText.txt b/53_King/csharp/Resources/InstructionsText.txt deleted file mode 100644 index c576123b3..000000000 --- a/53_King/csharp/Resources/InstructionsText.txt +++ /dev/null @@ -1,17 +0,0 @@ - - - -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 country'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 if 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 {0} year term of office. -Good luck! diff --git a/53_King/csharp/Resources/LandPlanted.txt b/53_King/csharp/Resources/LandPlanted.txt deleted file mode 100644 index e52529aac..000000000 --- a/53_King/csharp/Resources/LandPlanted.txt +++ /dev/null @@ -1 +0,0 @@ -Of {0} sq. miles planted, \ No newline at end of file diff --git a/53_King/csharp/Resources/PlantLandError1.txt b/53_King/csharp/Resources/PlantLandError1.txt deleted file mode 100644 index ef959f9fb..000000000 --- a/53_King/csharp/Resources/PlantLandError1.txt +++ /dev/null @@ -1 +0,0 @@ - Sorry, but each countryman can only plant 2 sq. miles. \ No newline at end of file diff --git a/53_King/csharp/Resources/PlantLandError2.txt b/53_King/csharp/Resources/PlantLandError2.txt deleted file mode 100644 index e5844aa1c..000000000 --- a/53_King/csharp/Resources/PlantLandError2.txt +++ /dev/null @@ -1 +0,0 @@ - Sorry, but you've only {0} sq. miles of farm land. \ No newline at end of file diff --git a/53_King/csharp/Resources/PlantLandError3.txt b/53_King/csharp/Resources/PlantLandError3.txt deleted file mode 100644 index 38264442e..000000000 --- a/53_King/csharp/Resources/PlantLandError3.txt +++ /dev/null @@ -1 +0,0 @@ - Think again, You've only {0} rallods left in the treasury. diff --git a/53_King/csharp/Resources/PlantLandPrompt.txt b/53_King/csharp/Resources/PlantLandPrompt.txt deleted file mode 100644 index f2fe448ef..000000000 --- a/53_King/csharp/Resources/PlantLandPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -How many square miles do you wish to plant \ No newline at end of file diff --git a/53_King/csharp/Resources/PollutionError.txt b/53_King/csharp/Resources/PollutionError.txt deleted file mode 100644 index f99644e3b..000000000 --- a/53_King/csharp/Resources/PollutionError.txt +++ /dev/null @@ -1 +0,0 @@ - Think again. You only have {0} rallods remaining. diff --git a/53_King/csharp/Resources/PollutionPrompt.txt b/53_King/csharp/Resources/PollutionPrompt.txt deleted file mode 100644 index 252fb3339..000000000 --- a/53_King/csharp/Resources/PollutionPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -How many rallods do you wish to spend on pollution control \ No newline at end of file diff --git a/53_King/csharp/Resources/Resource.cs b/53_King/csharp/Resources/Resource.cs deleted file mode 100644 index 5ea09e1ce..000000000 --- a/53_King/csharp/Resources/Resource.cs +++ /dev/null @@ -1,112 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace King.Resources; - -internal static class Resource -{ - private static bool _sellLandErrorShown; - - public static Stream Title => GetStream(); - - public static string InstructionsPrompt => GetString(); - public static string InstructionsText(int years) => string.Format(GetString(), years); - - public static string Status( - float rallods, - float countrymen, - float workers, - float land, - float landValue, - float plantingCost) - => string.Format( - workers == 0 ? StatusWithWorkers : StatusSansWorkers, - rallods, - (int)countrymen, - (int)workers, - (int)land, - landValue, - plantingCost); - - private static string StatusWithWorkers => GetString(); - private static string StatusSansWorkers => GetString(); - - public static string SellLandPrompt => GetString(); - public static string SellLandError(float farmLand) - { - var error = string.Format(GetString(), farmLand, _sellLandErrorShown ? "" : SellLandErrorReason); - _sellLandErrorShown = true; - return error; - } - private static string SellLandErrorReason => GetString(); - - public static string GiveRallodsPrompt => GetString(); - public static string GiveRallodsError(float rallods) => string.Format(GetString(), rallods); - - public static string PlantLandPrompt => GetString(); - public static string PlantLandError1 => GetString(); - public static string PlantLandError2(float farmLand) => string.Format(GetString(), farmLand); - public static string PlantLandError3(float rallods) => string.Format(GetString(), rallods); - - public static string PollutionPrompt => GetString(); - public static string PollutionError(float rallods) => string.Format(GetString(), rallods); - - public static string DeathsStarvation(float deaths) => string.Format(GetString(), (int)deaths); - public static string DeathsPollution(int deaths) => string.Format(GetString(), deaths); - public static string FuneralExpenses(int expenses) => string.Format(GetString(), expenses); - public static string InsufficientReserves => GetString(); - - public static string WorkerMigration(int newWorkers) => string.Format(GetString(), newWorkers); - public static string Migration(int migration) - => string.Format(migration < 0 ? Emigration : Immigration, Math.Abs(migration)); - public static string Emigration => GetString(); - public static string Immigration => GetString(); - - public static string LandPlanted(float landPlanted) - => landPlanted > 0 ? string.Format(GetString(), (int)landPlanted) : ""; - public static string Harvest(int yield, int income, bool hasIndustry) - => string.Format(GetString(), yield, HarvestReason(hasIndustry), income); - private static string HarvestReason(bool hasIndustry) => hasIndustry ? GetString() : ""; - - public static string TourismEarnings(int income) => string.Format(GetString(), income); - public static string TourismDecrease(IRandom random) => string.Format(GetString(), TourismReason(random)); - private static string TourismReason(IRandom random) => GetStrings()[random.Next(5)]; - - private static string EndAlso(IRandom random) - => random.Next(10) switch - { - <= 3 => GetStrings()[0], - <= 6 => GetStrings()[1], - _ => GetStrings()[2] - }; - - public static string EndCongratulations(int termLength) => string.Format(GetString(), termLength); - private static string EndConsequences(IRandom random) => GetStrings()[random.Next(2)]; - public static string EndForeignWorkers(IRandom random) => string.Format(GetString(), EndConsequences(random)); - public static string EndManyDead(int deaths, IRandom random) => string.Format(GetString(), deaths, EndAlso(random)); - public static string EndMoneyLeftOver() => GetString(); - public static string EndOneThirdDead(IRandom random) => string.Format(GetString(), EndConsequences(random)); - - public static string SavedYearsPrompt => GetString(); - public static string SavedYearsError(int years) => string.Format(GetString(), years); - public static string SavedTreasuryPrompt => GetString(); - public static string SavedCountrymenPrompt => GetString(); - public static string SavedWorkersPrompt => GetString(); - public static string SavedLandPrompt => GetString(); - public static string SavedLandError => GetString(); - - public static string Goodbye => GetString(); - - private static string[] GetStrings([CallerMemberName] string? name = null) => GetString(name).Split(';'); - - 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/53_King/csharp/Resources/SavedCountrymenPrompt.txt b/53_King/csharp/Resources/SavedCountrymenPrompt.txt deleted file mode 100644 index 120718d29..000000000 --- a/53_King/csharp/Resources/SavedCountrymenPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -How many countrymen \ No newline at end of file diff --git a/53_King/csharp/Resources/SavedLandError.txt b/53_King/csharp/Resources/SavedLandError.txt deleted file mode 100644 index 9ac66dad2..000000000 --- a/53_King/csharp/Resources/SavedLandError.txt +++ /dev/null @@ -1,2 +0,0 @@ - Come on, you started with 1000 sq. miles of farm land - and 10,000 sq. miles of forest land diff --git a/53_King/csharp/Resources/SavedLandPrompt.txt b/53_King/csharp/Resources/SavedLandPrompt.txt deleted file mode 100644 index e8afdf723..000000000 --- a/53_King/csharp/Resources/SavedLandPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -How many square miles of land \ No newline at end of file diff --git a/53_King/csharp/Resources/SavedTreasuryPrompt.txt b/53_King/csharp/Resources/SavedTreasuryPrompt.txt deleted file mode 100644 index f4a50f58f..000000000 --- a/53_King/csharp/Resources/SavedTreasuryPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -How much did you have in the treasury \ No newline at end of file diff --git a/53_King/csharp/Resources/SavedWorkersPrompt.txt b/53_King/csharp/Resources/SavedWorkersPrompt.txt deleted file mode 100644 index b88a9c107..000000000 --- a/53_King/csharp/Resources/SavedWorkersPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -How many workers \ No newline at end of file diff --git a/53_King/csharp/Resources/SavedYearsError.txt b/53_King/csharp/Resources/SavedYearsError.txt deleted file mode 100644 index 1c8c3c992..000000000 --- a/53_King/csharp/Resources/SavedYearsError.txt +++ /dev/null @@ -1 +0,0 @@ - Come on, your term in office is only {0} years. diff --git a/53_King/csharp/Resources/SavedYearsPrompt.txt b/53_King/csharp/Resources/SavedYearsPrompt.txt deleted file mode 100644 index afbda229e..000000000 --- a/53_King/csharp/Resources/SavedYearsPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -How many years had you been in office when interrupted \ No newline at end of file diff --git a/53_King/csharp/Resources/SellLandError.txt b/53_King/csharp/Resources/SellLandError.txt deleted file mode 100644 index 83e0266c2..000000000 --- a/53_King/csharp/Resources/SellLandError.txt +++ /dev/null @@ -1,2 +0,0 @@ -*** Think again. You only have {0} square miles of farm land. -{1} \ No newline at end of file diff --git a/53_King/csharp/Resources/SellLandErrorReason.txt b/53_King/csharp/Resources/SellLandErrorReason.txt deleted file mode 100644 index 836352bbf..000000000 --- a/53_King/csharp/Resources/SellLandErrorReason.txt +++ /dev/null @@ -1,4 +0,0 @@ - -(Foreign industry will only buy farm land because -forest land is uneconomical to strip mine due to trees, -thicker top soil, etc.) diff --git a/53_King/csharp/Resources/SellLandPrompt.txt b/53_King/csharp/Resources/SellLandPrompt.txt deleted file mode 100644 index 8d01c2c23..000000000 --- a/53_King/csharp/Resources/SellLandPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -How many square miles do you wish to sell to industry \ No newline at end of file diff --git a/53_King/csharp/Resources/StatusSansWorkers.txt b/53_King/csharp/Resources/StatusSansWorkers.txt deleted file mode 100644 index 7efb84e76..000000000 --- a/53_King/csharp/Resources/StatusSansWorkers.txt +++ /dev/null @@ -1,6 +0,0 @@ - -You now have {0} rallods in the treasury. - {1} countrymen, and {3} sq. miles of land. -This year industry will buy land for {4} rallods per square mile. -Land currently costs {5} rallods per square mile to plant. - diff --git a/53_King/csharp/Resources/StatusWithWorkers.txt b/53_King/csharp/Resources/StatusWithWorkers.txt deleted file mode 100644 index e7bc5c4a8..000000000 --- a/53_King/csharp/Resources/StatusWithWorkers.txt +++ /dev/null @@ -1,6 +0,0 @@ - -You now have {0} rallods in the treasury. - {1} countrymen, {2} foreign workers and {3} sq. miles of land. -This year industry will buy land for {4} rallods per square mile. -Land currently costs {5} rallods per square mile to plant. - diff --git a/53_King/csharp/Resources/Title.txt b/53_King/csharp/Resources/Title.txt deleted file mode 100644 index f9f7854da..000000000 --- a/53_King/csharp/Resources/Title.txt +++ /dev/null @@ -1,5 +0,0 @@ - King - Creative Computing Morristown, New Jersey - - - diff --git a/53_King/csharp/Resources/TourismDecrease.txt b/53_King/csharp/Resources/TourismDecrease.txt deleted file mode 100644 index dcb45fc70..000000000 --- a/53_King/csharp/Resources/TourismDecrease.txt +++ /dev/null @@ -1 +0,0 @@ - Decrease because {0} \ No newline at end of file diff --git a/53_King/csharp/Resources/TourismEarnings.txt b/53_King/csharp/Resources/TourismEarnings.txt deleted file mode 100644 index db9251dd5..000000000 --- a/53_King/csharp/Resources/TourismEarnings.txt +++ /dev/null @@ -1 +0,0 @@ - You made {0} rallods from tourist trade. \ No newline at end of file diff --git a/53_King/csharp/Resources/TourismReason.txt b/53_King/csharp/Resources/TourismReason.txt deleted file mode 100644 index b3535c3dc..000000000 --- a/53_King/csharp/Resources/TourismReason.txt +++ /dev/null @@ -1,5 +0,0 @@ -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. diff --git a/53_King/csharp/Resources/WorkerMigration.txt b/53_King/csharp/Resources/WorkerMigration.txt deleted file mode 100644 index d2f3b378e..000000000 --- a/53_King/csharp/Resources/WorkerMigration.txt +++ /dev/null @@ -1 +0,0 @@ - {0} workers came to the country and \ No newline at end of file diff --git a/53_King/csharp/Result.cs b/53_King/csharp/Result.cs deleted file mode 100644 index 185f4617a..000000000 --- a/53_King/csharp/Result.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace King; - -internal record struct Result (bool IsGameOver, string Message) -{ - internal static Result GameOver(string message) => new(true, message); - internal static Result Continue => new(false, ""); -} diff --git a/53_King/csharp/ValidityTest.cs b/53_King/csharp/ValidityTest.cs deleted file mode 100644 index f1aeb5ec6..000000000 --- a/53_King/csharp/ValidityTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace King; - -internal class ValidityTest -{ - private readonly Predicate _isValid; - private readonly Func _getError; - - public ValidityTest(Predicate isValid, string error) - : this(isValid, () => error) - { - } - - public ValidityTest(Predicate isValid, Func getError) - { - _isValid = isValid; - _getError = getError; - } - - public bool IsValid(float value, IReadWrite io) - { - if (_isValid(value)) { return true; } - - io.Write(_getError()); - return false; - } -} \ No newline at end of file diff --git a/53_King/csharp/Year.cs b/53_King/csharp/Year.cs deleted file mode 100644 index 8e6bb0b41..000000000 --- a/53_King/csharp/Year.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System.Text; - -namespace King; - -internal class Year -{ - private readonly Country _country; - private readonly IRandom _random; - private readonly IReadWrite _io; - private readonly int _plantingCost; - private readonly int _landValue; - - private float _landSold; - private float _rallodsDistributed; - private float _landPlanted; - private float _pollutionControlCost; - - private float _citizenSupport; - private int _deaths; - private float _starvationDeaths; - private int _pollutionDeaths; - private int _migration; - - public Year(Country country, IRandom random, IReadWrite io) - { - _country = country; - _random = random; - _io = io; - - _plantingCost = random.Next(10, 15); - _landValue = random.Next(95, 105); - } - - public string Status => _country.GetStatus(_landValue, _plantingCost); - - public Result? GetPlayerActions() - { - var playerSoldLand = _country.SellLand(_landValue, out _landSold); - var playerDistributedRallods = _country.DistributeRallods(out _rallodsDistributed); - var playerPlantedLand = _country.HasRallods && _country.PlantLand(_plantingCost, out _landPlanted); - var playerControlledPollution = _country.HasRallods && _country.ControlPollution(out _pollutionControlCost); - - return playerSoldLand || playerDistributedRallods || playerPlantedLand || playerControlledPollution - ? null - : Result.GameOver(Goodbye); - } - - public Result? EvaluateResults() - { - var rallodsUnspent = _country.Rallods; - - _io.WriteLine(); - _io.WriteLine(); - - return EvaluateDeaths() - ?? EvaluateMigration() - ?? EvaluateAgriculture() - ?? EvaluateTourism() - ?? DetermineResult(rallodsUnspent); - } - - public Result? EvaluateDeaths() - { - var supportedCountrymen = _rallodsDistributed / 100; - _citizenSupport = supportedCountrymen - _country.Countrymen; - _starvationDeaths = -_citizenSupport; - if (_starvationDeaths > 0) - { - if (supportedCountrymen < 50) { return Result.GameOver(EndOneThirdDead(_random)); } - _io.WriteLine(DeathsStarvation(_starvationDeaths)); - } - - var pollutionControl = _pollutionControlCost >= 25 ? _pollutionControlCost / 25 : 1; - _pollutionDeaths = (int)(_random.Next((int)_country.IndustryLand) / pollutionControl); - if (_pollutionDeaths > 0) - { - _io.WriteLine(DeathsPollution(_pollutionDeaths)); - } - - _deaths = (int)(_starvationDeaths + _pollutionDeaths); - if (_deaths > 0) - { - var funeralCosts = _deaths * 9; - _io.WriteLine(FuneralExpenses(funeralCosts)); - - if (!_country.TrySpend(funeralCosts, _landValue)) - { - _io.WriteLine(InsufficientReserves); - } - - _country.RemoveTheDead(_deaths); - } - - return null; - } - - private Result? EvaluateMigration() - { - if (_landSold > 0) - { - var newWorkers = (int)(_landSold + _random.NextFloat(10) - _random.NextFloat(20)); - if (!_country.HasWorkers) { newWorkers += 20; } - _io.Write(WorkerMigration(newWorkers)); - _country.AddWorkers(newWorkers); - } - - _migration = - (int)(_citizenSupport / 10 + _pollutionControlCost / 25 - _country.IndustryLand / 50 - _pollutionDeaths / 2); - _io.WriteLine(Migration(_migration)); - _country.Migration(_migration); - - return null; - } - - private Result? EvaluateAgriculture() - { - var ruinedCrops = (int)Math.Min(_country.IndustryLand * (_random.NextFloat() + 1.5f) / 2, _landPlanted); - var yield = (int)(_landPlanted - ruinedCrops); - var income = (int)(yield * _landValue / 2f); - - _io.Write(LandPlanted(_landPlanted)); - _io.Write(Harvest(yield, income, _country.IndustryLand > 0)); - - _country.SellCrops(income); - - return null; - } - - private Result? EvaluateTourism() - { - var reputationValue = (int)((_country.Countrymen - _migration) * 22 + _random.NextFloat(500)); - var industryAdjustment = (int)(_country.IndustryLand * 15); - var tourismIncome = Math.Abs(reputationValue - industryAdjustment); - - _io.WriteLine(TourismEarnings(tourismIncome)); - if (industryAdjustment > 0 && tourismIncome < _country.PreviousTourismIncome) - { - _io.Write(TourismDecrease(_random)); - } - - _country.EntertainTourists(tourismIncome); - - return null; - } - - private Result? DetermineResult(float rallodsUnspent) - { - if (_deaths > 200) { return Result.GameOver(EndManyDead(_deaths, _random)); } - if (_country.Countrymen < 343) { return Result.GameOver(EndOneThirdDead(_random)); } - if (rallodsUnspent / 100 > 5 && _starvationDeaths >= 2) { return Result.GameOver(EndMoneyLeftOver()); } - if (_country.Workers > _country.Countrymen) { return Result.GameOver(EndForeignWorkers(_random)); } - return null; - } -} diff --git a/53_King/king_variable_update.bas b/53_King/king_variable_update.bas index 0ae19de45..7f88e1014 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, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR" + 22 PRINT "DETINU, RALLODS 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,8 +66,7 @@ 380 PLANTING_AREA=0 390 MONEY_SPENT_ON_POLLUTION_CONTROL=0 395 RALLODS=0 -399 GOTO 600 - +399 GOTO 1000 400 RALLODS=INT(RALLODS-WELFARE) 410 PRINT "HOW MANY SQUARE MILES DO YOU WISH TO PLANT"; @@ -89,7 +88,7 @@ 490 MONEY_SPENT_ON_POLLUTION_CONTROL=0 495 RALLODS=0 -499 GOTO 600 +499 GOTO 1000 500 RALLODS=RALLODS-MONEY_SPENT_ON_PLANTING diff --git a/53_King/python/README.md b/53_King/python/README.md index b96c2f42c..781945ec4 100644 --- a/53_King/python/README.md +++ b/53_King/python/README.md @@ -1,44 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Python](https://www.python.org/about/) - - -## Porting notes - -Variables: - -* A: Available rallods (money) -* B: Current countrymen -* C: foreign_workers -* C1: foreign_workers_influx -* D: Available land (farmland=D-1000) -* F1: polution_deaths (last round) -* B5: died_contrymen (starvation + pollution) -* H: sm_sell_to_industry -* I: distributed_rallods -* J: planted_sq in a round -* K: pollution_control_spendings in a round -* X5: years in office -* N5: YEARS_IN_TERM - how many years one term in office has -* P1: population_change (positive means people come, negative means people leave) -* W: land_buy_price -* V9: planting_cost -* U2: crop_loss -* V1-V2: Earnings from tourist trade -* V3: tourism_earnings -* T1: crop_loss_last_year -* W: land_buy_price -* X: only show an error message once - -Functions: - -* `RND(1)`: `random.random()` -* `INT(...)`: `int(...)` -* `ABS(...)`: `abs(...)` - -Bugs: See [53 King README](../README.md) - -Implicit knowledge: - -* `COST_OF_LIVING`: One countryman needs 100 for food. Otherwise they will die of starvation -* `COST_OF_FUNERAL`: A funeral costs 9 diff --git a/53_King/python/king.py b/53_King/python/king.py deleted file mode 100644 index 0bf85016c..000000000 --- a/53_King/python/king.py +++ /dev/null @@ -1,447 +0,0 @@ -""" -KING - -A strategy game where the player is the king. - -Ported to Python by Martin Thoma in 2022 -""" - -import sys -from dataclasses import dataclass -from random import randint, random - -FOREST_LAND = 1000 -INITIAL_LAND = FOREST_LAND + 1000 -COST_OF_LIVING = 100 -COST_OF_FUNERAL = 9 -YEARS_IN_TERM = 8 -POLLUTION_CONTROL_FACTOR = 25 - - -def ask_int(prompt) -> int: - while True: - try: - return int(input(prompt)) - except ValueError: - continue - - -@dataclass -class GameState: - rallods: int = -1 - countrymen: int = -1 - land: int = INITIAL_LAND - foreign_workers: int = 0 - years_in_office: int = 0 - - # previous year stats - crop_loss_last_year: int = 0 - - # current year stats - died_contrymen: int = 0 - pollution_deaths: int = 0 - population_change: int = 0 - - # current year - market situation (in rallods per square mile) - planting_cost: int = -1 - land_buy_price: int = -1 - - tourism_earnings: int = 0 - - def set_market_conditions(self) -> None: - self.land_buy_price = randint(95, 105) - self.planting_cost = randint(10, 15) - - @property - def farmland(self) -> int: - return self.land - FOREST_LAND - - @property - def settled_people(self) -> int: - return self.countrymen - self.population_change - - def sell_land(self, amount: int) -> None: - assert amount <= self.farmland - self.land -= amount - self.rallods += self.land_buy_price * amount - - def distribute_rallods(self, distribute: int) -> None: - self.rallods -= distribute - - def spend_pollution_control(self, spend: int) -> None: - self.rallods -= spend - - def plant(self, sq_to_plant: int) -> None: - self.rallods -= sq_to_plant * self.planting_cost - - def print_status(self) -> None: - print(f"\n\nYOU NOW HAVE {self.rallods} RALLODS IN THE TREASURY.") - print(f"{int(self.countrymen)} COUNTRYMEN, ", end="") - if self.foreign_workers > 0: - print(f"{int(self.foreign_workers)} FOREIGN WORKERS, ", end="") - print(f"AND {self.land} SQ. MILES OF LAND.") - print( - f"THIS YEAR INDUSTRY WILL BUY LAND FOR {self.land_buy_price} " - "RALLODS PER SQUARE MILE." - ) - print( - f"LAND CURRENTLY COSTS {self.planting_cost} RALLODS " - "PER SQUARE MILE TO PLANT.\n" - ) - - def handle_deaths( - self, distributed_rallods: int, pollution_control_spendings: int - ) -> None: - starved_countrymen = max( - 0, int(self.countrymen - distributed_rallods / COST_OF_LIVING) - ) - - if starved_countrymen > 0: - print(f"{starved_countrymen} COUNTRYMEN DIED OF STARVATION") - - self.pollution_deaths = int(random() * (INITIAL_LAND - self.land)) - if pollution_control_spendings >= POLLUTION_CONTROL_FACTOR: - self.pollution_deaths = int( - self.pollution_deaths - / (pollution_control_spendings / POLLUTION_CONTROL_FACTOR) - ) - if self.pollution_deaths > 0: - print( - f"{self.pollution_deaths} COUNTRYMEN DIED OF CARBON-MONOXIDE " - f"AND DUST INHALATION" - ) - - self.died_contrymen = starved_countrymen + self.pollution_deaths - if self.died_contrymen > 0: - funeral_cost = self.died_contrymen * COST_OF_FUNERAL - print(f" YOU WERE FORCED TO SPEND {funeral_cost} RALLODS ON ") - print("FUNERAL EXPENSES.") - self.rallods -= funeral_cost - if self.rallods < 0: - print(" INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD") - self.land += int(self.rallods / self.land_buy_price) - self.rallods = 0 - self.countrymen -= self.died_contrymen - - def handle_tourist_trade(self) -> None: - V1 = int(self.settled_people * 22 + random() * 500) - V2 = int((INITIAL_LAND - self.land) * 15) - 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 ", end="") - reason = randint(0, 10) - if reason <= 2: - print("FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.") - elif reason <= 4: - print("AIR POLLUTION IS KILLING GAME BIRD POPULATION.") - elif reason <= 6: - print("MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.") - elif reason <= 8: - print("UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.") - else: - print("HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.") - - # NOTE: The following two lines had a bug in the original game: - self.tourism_earnings = abs(int(V1 - V2)) - self.rallods += self.tourism_earnings - - def handle_harvest(self, planted_sq: int) -> None: - crop_loss = int((INITIAL_LAND - self.land) * ((random() + 1.5) / 2)) - if self.foreign_workers != 0: - print(f"OF {planted_sq} SQ. MILES PLANTED,") - if planted_sq <= crop_loss: - crop_loss = planted_sq - harvested = int(planted_sq - crop_loss) - print(f" YOU HARVESTED {harvested} SQ. MILES OF CROPS.") - unlucky_harvesting_worse = crop_loss - self.crop_loss_last_year - if crop_loss != 0: - print(" (DUE TO ", end="") - if unlucky_harvesting_worse > 2: - print("INCREASED ", end="") - print("AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)") - revenue = int((planted_sq - crop_loss) * (self.land_buy_price / 2)) - print(f"MAKING {revenue} RALLODS.") - self.crop_loss_last_year = crop_loss - self.rallods += revenue - - def handle_foreign_workers( - self, - sm_sell_to_industry: int, - distributed_rallods: int, - polltion_control_spendings: int, - ) -> None: - foreign_workers_influx = 0 - if sm_sell_to_industry != 0: - foreign_workers_influx = int( - sm_sell_to_industry + (random() * 10) - (random() * 20) - ) - if self.foreign_workers <= 0: - foreign_workers_influx += 20 - print(f"{foreign_workers_influx} WORKERS CAME TO THE COUNTRY AND") - - surplus_distributed = distributed_rallods / COST_OF_LIVING - self.countrymen - population_change = int( - (surplus_distributed / 10) - + (polltion_control_spendings / POLLUTION_CONTROL_FACTOR) - - ((INITIAL_LAND - self.land) / 50) - - (self.died_contrymen / 2) - ) - print(f"{abs(population_change)} COUNTRYMEN ", end="") - if population_change < 0: - print("LEFT ", end="") - else: - print("CAME TO ", end="") - print("THE ISLAND") - self.countrymen += population_change - 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!!!!!") - print("\n\n\nDUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY") - print("BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU") - message = randint(0, 10) - if message <= 3: - print("ALSO HAD YOUR LEFT EYE GOUGED OUT!") - if message <= 6: - print("HAVE ALSO GAINED A VERY BAD REPUTATION.") - if message <= 10: - print("HAVE ALSO BEEN DECLARED NATIONAL FINK.") - sys.exit() - - def handle_third_died(self) -> None: - 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.") - self.end_game() - - def handle_money_mismanagement(self) -> None: - 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.") - sys.exit() - - def handle_too_many_foreigners(self) -> None: - print("\n\nTHE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER") - print("OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND") - print("TAKEN OVER THE COUNTRY.") - self.end_game() - - def end_game(self) -> None: - if random() <= 0.5: - print("YOU HAVE BEEN ASSASSINATED.") - else: - print("YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW") - print("RESIDING IN PRISON.") - sys.exit() - - def handle_congratulations(self) -> None: - print("\n\nCONGRATULATIONS!!!!!!!!!!!!!!!!!!") - print(f"YOU HAVE SUCCESFULLY COMPLETED YOUR {YEARS_IN_TERM} 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.") - sys.exit() - - -def print_header() -> None: - print(" " * 34 + "KING") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") - - -def print_instructions() -> None: - print( - f"""\n\n\nCONGRATULATIONS! 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 {COST_OF_LIVING} -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 {YEARS_IN_TERM} YEAR TERM OF OFFICE. -GOOD LUCK!""" - ) - - -def ask_how_many_sq_to_plant(state: GameState) -> int: - while True: - sq = ask_int("HOW MANY SQUARE MILES DO YOU WISH TO PLANT? ") - if sq < 0: - continue - elif sq > 2 * state.countrymen: - print(" SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.") - elif sq > state.farmland: - print( - f" SORRY, BUT YOU ONLY HAVE {state.farmland} " - "SQ. MILES OF FARM LAND." - ) - elif sq * state.planting_cost > state.rallods: - print( - f" THINK AGAIN. YOU'VE ONLY {state.rallods} RALLODS " - "LEFT IN THE TREASURY." - ) - else: - return sq - - -def ask_pollution_control(state: GameState) -> int: - while True: - rallods = ask_int( - "HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL? " - ) - if rallods > state.rallods: - print(f" THINK AGAIN. YOU ONLY HAVE {state.rallods} RALLODS REMAINING.") - elif rallods < 0: - continue - else: - return rallods - - -def ask_sell_to_industry(state: GameState) -> int: - had_first_err = False - first = """(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE -FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES, -THICKER TOP SOIL, ETC.)""" - err = f"""*** THINK AGAIN. YOU ONLY HAVE {state.farmland} SQUARE MILES OF FARM LAND.""" - while True: - sm = input("HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY? ") - try: - sm_sell = int(sm) - except ValueError: - if not had_first_err: - print(first) - had_first_err = True - print(err) - continue - if sm_sell > state.farmland: - print(err) - elif sm_sell < 0: - continue - else: - return sm_sell - - -def ask_distribute_rallods(state: GameState) -> int: - while True: - rallods = ask_int( - "HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN? " - ) - if rallods < 0: - continue - elif rallods > state.rallods: - print( - f" THINK AGAIN. YOU'VE ONLY {state.rallods} RALLODS IN THE TREASURY" - ) - else: - return rallods - - -def resume() -> GameState: - while True: - years = ask_int("HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED? ") - if years < 0: - sys.exit() - if years >= YEARS_IN_TERM: - print(f" COME ON, YOUR TERM IN OFFICE IS ONLY {YEARS_IN_TERM} YEARS.") - else: - break - treasury = ask_int("HOW MUCH DID YOU HAVE IN THE TREASURY? ") - if treasury < 0: - sys.exit() - countrymen = ask_int("HOW MANY COUNTRYMEN? ") - if countrymen < 0: - sys.exit() - workers = ask_int("HOW MANY WORKERS? ") - if workers < 0: - sys.exit() - while True: - land = ask_int("HOW MANY SQUARE MILES OF LAND? ") - if land < 0: - sys.exit() - if land > INITIAL_LAND: - farm_land = INITIAL_LAND - FOREST_LAND - print(f" COME ON, YOU STARTED WITH {farm_land:,} SQ. MILES OF FARM LAND") - print(f" AND {FOREST_LAND:,} SQ. MILES OF FOREST LAND.") - if land > FOREST_LAND: - break - return GameState( - rallods=treasury, - countrymen=countrymen, - foreign_workers=workers, - years_in_office=years, - ) - - -def main() -> None: - print_header() - want_instructions = input("DO YOU WANT INSTRUCTIONS? ").upper() - if want_instructions == "AGAIN": - state = resume() - else: - state = GameState( - rallods=randint(59000, 61000), - countrymen=randint(490, 510), - planting_cost=randint(10, 15), - ) - if want_instructions != "NO": - print_instructions() - - while True: - state.set_market_conditions() - state.print_status() - - # Users actions - sm_sell_to_industry = ask_sell_to_industry(state) - state.sell_land(sm_sell_to_industry) - - distributed_rallods = ask_distribute_rallods(state) - state.distribute_rallods(distributed_rallods) - - planted_sq = ask_how_many_sq_to_plant(state) - state.plant(planted_sq) - polltion_control_spendings = ask_pollution_control(state) - state.spend_pollution_control(polltion_control_spendings) - - # Run the year - state.handle_deaths(distributed_rallods, polltion_control_spendings) - state.handle_foreign_workers( - sm_sell_to_industry, distributed_rallods, polltion_control_spendings - ) - state.handle_harvest(planted_sq) - state.handle_tourist_trade() - - if state.died_contrymen > 200: - state.handle_too_many_deaths() - if state.countrymen < 343: - state.handle_third_died() - elif ( - 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() - elif YEARS_IN_TERM - 1 == state.years_in_office: - state.handle_congratulations() - else: - state.years_in_office += 1 - state.died_contrymen = 0 - - -if __name__ == "__main__": - main() diff --git a/53_King/python/king_variable_update.py b/53_King/python/king_variable_update.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/53_King/rust/Cargo.lock b/53_King/rust/Cargo.lock deleted file mode 100644 index db44c2e7a..000000000 --- a/53_King/rust/Cargo.lock +++ /dev/null @@ -1,16 +0,0 @@ -# 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 deleted file mode 100644 index c4f9c9132..000000000 --- a/53_King/rust/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[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/README.md b/53_King/rust/README.md deleted file mode 100644 index 529da33b7..000000000 --- a/53_King/rust/README.md +++ /dev/null @@ -1,28 +0,0 @@ -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. diff --git a/53_King/rust/src/main.rs b/53_King/rust/src/main.rs deleted file mode 100644 index 90b2aac67..000000000 --- a/53_King/rust/src/main.rs +++ /dev/null @@ -1,577 +0,0 @@ -#![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); - } - } - } -} diff --git a/54_Letter/python/letter.py b/54_Letter/python/letter.py index ca4599eec..77c87c7f1 100644 --- a/54_Letter/python/letter.py +++ b/54_Letter/python/letter.py @@ -15,6 +15,15 @@ BELLS_ON_SUCCESS = False +def print_with_tab(space_count: int, msg: str) -> None: + if space_count > 0: + spaces = " " * space_count + else: + spaces = "" + + print(spaces + msg) + + def print_instructions() -> None: print("LETTER GUESSING GAME") print() @@ -23,7 +32,7 @@ def print_instructions() -> None: print("AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.") -def play_game() -> None: +def play_game(): target_value = random.randint(ord("A"), ord("Z")) num_guesses = 0 print() @@ -43,8 +52,8 @@ def play_game() -> None: print("GOOD JOB !!!!!") if BELLS_ON_SUCCESS: - bell_str = chr(7) * 15 - print(bell_str) + bellStr = chr(7) * 15 + print(bellStr) print() print("LET'S PLAY AGAIN.....") @@ -58,8 +67,11 @@ def play_game() -> None: def main() -> None: - print(" " * 33 + "LETTER") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_with_tab(33, "LETTER") + print_with_tab(15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() print_instructions() diff --git a/54_Letter/rust/Cargo.lock b/54_Letter/rust/Cargo.lock deleted file mode 100644 index 6a34e6ec8..000000000 --- a/54_Letter/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/54_Letter/rust/Cargo.toml b/54_Letter/rust/Cargo.toml deleted file mode 100644 index 83652ff05..000000000 --- a/54_Letter/rust/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "letter" -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.4" - diff --git a/54_Letter/rust/README.md b/54_Letter/rust/README.md deleted file mode 100644 index fc6468b9f..000000000 --- a/54_Letter/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) diff --git a/54_Letter/rust/src/main.rs b/54_Letter/rust/src/main.rs deleted file mode 100644 index 0ae3534c8..000000000 --- a/54_Letter/rust/src/main.rs +++ /dev/null @@ -1,46 +0,0 @@ -use rand::Rng; -use std::cmp::Ordering; -use std::io; - -fn main() { - println!( - "{: >40}\n{: >57}\n\n\n", - "LETTER", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" - ); - println!("LETTER GUESSING GAME\n"); - println!("I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z."); - println!("TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES"); - println!("AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER."); - - loop { - let gen_character = rand::thread_rng().gen_range('A'..='Z'); // generates a random character between A and Z - let gen_character = String::from(gen_character); - println!("\nO.K., I HAVE A LETTER. START GUESSING."); - for i in 0..999999 { - println!("\nWHAT IS YOUR GUESS?"); - - let mut guess = String::new(); - - io::stdin() - .read_line(&mut guess) - .expect("Failed to read the line"); - println!("{}", gen_character); - let guess = guess.trim().to_ascii_uppercase(); - match guess.cmp(&gen_character) { - Ordering::Less => println!("\nTOO LOW. TRY A HIGHER LETTER."), - Ordering::Greater => println!("\nTOO HIGH. TRY A LOWER LETTER."), - Ordering::Equal => { - println!("\nYOU GOT IT IN {} GUESSES!!", i + 1); - if i >= 4 { - println!("BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\n"); - } else { - println!("{}", std::iter::repeat("💖").take(15).collect::()); - println!("GOOD JOB !!!!!"); - } - break; - } - } - } - println!("\nLET'S PLAY AGAIN....."); - } -} diff --git a/55_Life/README.md b/55_Life/README.md index 195bd7956..1834c1e68 100644 --- a/55_Life/README.md +++ b/55_Life/README.md @@ -37,11 +37,4 @@ 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) diff --git a/55_Life/python/life.py b/55_Life/python/life.py index 8707d5015..b473632ea 100644 --- a/55_Life/python/life.py +++ b/55_Life/python/life.py @@ -6,7 +6,6 @@ Ported by Dave LeCompte """ -from typing import Dict PAGE_WIDTH = 64 @@ -27,11 +26,11 @@ def print_header(title) -> None: print() -def get_pattern() -> Dict[int, str]: +def get_pattern(): print("ENTER YOUR PATTERN:") c = 0 - pattern: Dict[int, str] = {} + pattern = {} while True: line = input() if line == "DONE": @@ -44,7 +43,7 @@ def get_pattern() -> Dict[int, str]: # staying in. if line[0] == ".": - line = f" {line[1:]}" + line = " " + line[1:] pattern[c] = line c += 1 @@ -64,7 +63,7 @@ def main() -> None: max_x = MAX_HEIGHT - 1 max_y = MAX_WIDTH - 1 - a = [[0 for _ in range(MAX_WIDTH)] for _ in range(MAX_HEIGHT)] + a = [[0 for y in range(MAX_WIDTH)] for x in range(MAX_HEIGHT)] p = 0 g = 0 invalid = False @@ -81,7 +80,11 @@ def main() -> None: print() print() while True: - inv_str = "INVALID!" if invalid else "" + if invalid: + inv_str = "INVALID!" + else: + inv_str = "" + print(f"GENERATION: {g}\tPOPULATION: {p} {inv_str}") next_min_x = MAX_HEIGHT - 1 @@ -95,8 +98,8 @@ def main() -> None: print() for x in range(min_x, max_x + 1): - print() - line_list = [" "] * MAX_WIDTH + print + line = [" "] * MAX_WIDTH for y in range(min_y, max_y + 1): if a[x][y] == 2: a[x][y] = 0 @@ -106,14 +109,15 @@ def main() -> None: elif a[x][y] != 1: continue - line_list[y] = "*" + # line 261 + line[y] = "*" next_min_x = min(x, next_min_x) next_max_x = max(x, next_max_x) next_min_y = min(y, next_min_y) next_max_y = max(y, next_max_y) - print("".join(line_list)) + print("".join(line)) # line 295 for _ in range(max_x + 1, MAX_HEIGHT): @@ -147,7 +151,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] in [1, 2]: + if a[i][j] == 1 or a[i][j] == 2: count += 1 if a[x][y] == 0: if count == 3: diff --git a/55_Life/rust/Cargo.lock b/55_Life/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/55_Life/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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/55_Life/rust/Cargo.toml b/55_Life/rust/Cargo.toml deleted file mode 100644 index 1ec696335..000000000 --- a/55_Life/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/55_Life/rust/README.md b/55_Life/rust/README.md deleted file mode 100644 index 19f2d09da..000000000 --- a/55_Life/rust/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# Conway's Life - -Original from David Ahl's _Basic Computer Games_, downloaded from http://www.vintage-basic.net/games.html. - -Ported to Rust by Jon Fetter-Degges - -Developed and tested on Rust 1.64.0 - -## How to Run - -Install Rust using the instructions at [rust-lang.org](https://www.rust-lang.org/tools/install). - -At a command or shell prompt in the `rust` subdirectory, enter `cargo run`. - -## Differences from Original Behavior - -* The simulation stops if all cells die. -* `.` at the beginning of an input line is supported but optional. -* Input of more than 66 columns is rejected. Input will automatically terminate after 20 rows. Beyond these bounds, the original -implementation would have marked the board as invalid, and beyond 68 cols/24 rows it would have had an out of bounds array access. -* The check for the string "DONE" at the end of input is case-independent. -* The program pauses for half a second between each generation. diff --git a/55_Life/rust/src/main.rs b/55_Life/rust/src/main.rs deleted file mode 100644 index 50aa4927d..000000000 --- a/55_Life/rust/src/main.rs +++ /dev/null @@ -1,275 +0,0 @@ -// Rust implementation of the "Basic Computer Games" version of Conway's Life -// -// Jon Fetter-Degges -// October 2022 - -// I am a Rust newbie. Corrections and suggestions are welcome. - -use std::{cmp, fmt, io, thread, time}; - -// The BASIC implementation uses integers to represent the state of each cell: 1 is -// alive, 2 is about to die, 3 is about to be born, 0 is dead. Here, we'll use an enum -// instead. -// Deriving Copy (which requires Clone) allows us to use this enum value in assignments, -// and deriving Eq (or PartialEq) allows us to use the == operator. These need to be -// explicitly specified because some enums may have associated data that makes copies and -// comparisons more complicated or expensive. -#[derive(Clone, Copy, PartialEq, Eq)] -enum CellState { - Empty, - Alive, - AboutToDie, - AboutToBeBorn, -} - -// Support direct printing of the cell. In this program cells will only be Alive or Empty -// when they are printed. -impl fmt::Display for CellState { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let rep = match *self { - CellState::Empty => ' ', - CellState::Alive => '*', - CellState::AboutToDie => 'o', - CellState::AboutToBeBorn => '.', - }; - write!(f, "{}", rep) - } -} - -// Following the BASIC implementation, we will bound the board at 24 rows x 70 columns. -// The board is an array of CellState. Using an array of arrays gives us bounds checking -// in both dimensions. -const HEIGHT: usize = 24; -const WIDTH: usize = 70; - -struct Board { - cells: [[CellState; WIDTH]; HEIGHT], - min_row: usize, - max_row: usize, - min_col: usize, - max_col: usize, - population: usize, - generation: usize, - invalid: bool, -} - -impl Board { - fn new() -> Board { - Board { - cells: [[CellState::Empty; WIDTH]; HEIGHT], - min_row: 0, - max_row: 0, - min_col: 0, - max_col: 0, - population: 0, - generation: 0, - invalid: false, - } - } -} - -fn main() { - println!(); println!(); println!(); - println!("{:33}{}", " ", "Life"); - println!("{:14}{}", " ", "Creative Computing Morristown, New Jersey"); - println!("Enter your pattern: "); - let mut board = parse_pattern(get_pattern()); - loop { - finish_cell_transitions(&mut board); - print_board(&board); - mark_cell_transitions(&mut board); - if board.population == 0 { - break; // this isn't in the original implementation but it seemed better than - // spewing blank screens - } - delay(); - } -} - -fn get_pattern() -> Vec> { - let max_line_len = WIDTH - 4; - let max_line_count = HEIGHT - 4; - let mut lines = Vec::new(); - loop { - let mut line = String::new(); - // read_line reads into the buffer (appending if it's not empty). It returns the - // number of characters read, including the newline. This will be 0 on EOF. - // unwrap() will panic and terminate the program if there is an error reading - // from stdin. That's reasonable behavior in this case. - let nread = io::stdin().read_line(&mut line).unwrap(); - let line = line.trim_end(); - if nread == 0 || line.eq_ignore_ascii_case("DONE") { - return lines; - } - // Handle Unicode by converting the string to a vector of characters up front. We - // do this here because we check the number of characters several times, so we - // might as well just do the Unicode parsing once. - let line = Vec::from_iter(line.chars()); - if line.len() > max_line_len { - println!("Line too long - the maximum is {max_line_len} characters."); - continue; - } - lines.push(line); - if lines.len() == max_line_count { - println!("Maximum line count reached. Starting simulation."); - return lines; - } - } -} - -fn parse_pattern(rows: Vec>) -> Board { - // This function assumes that the input pattern in rows is in-bounds. If the pattern - // is too large, this function will panic. get_pattern checks the size of the input, - // so it is safe to call this function with its results. - - let mut board = Board::new(); - - // The BASIC implementation puts the pattern roughly in the center of the board, - // assuming that there are no blank rows at the beginning or end, or blanks entered - // at the beginning or end of every row. It wouldn't be hard to check for that, but - // for now we'll preserve the original behavior. - let nrows = rows.len(); - // If rows is empty, the call to max will return None. The unwrap_or then provides a - // default value - let ncols = rows.iter().map(|l| l.len()).max().unwrap_or(0); - - // The min and max values here are unsigned. If nrows >= 24 or ncols >= 68, these - // assignments will panic - they do not wrap around unless we use a function with - // that specific behavior. Again, we expect bounds checking on the input before this - // function is called. - board.min_row = 11 - nrows / 2; - board.min_col = 33 - ncols / 2; - board.max_row = board.min_row + nrows - 1; - board.max_col = board.min_col + ncols - 1; - - // Loop over the rows provided. enumerate() augments the iterator with an index. - for (row_index, pattern) in rows.iter().enumerate() { - let row = board.min_row + row_index; - // Now loop over the non-empty cells in the current row. filter_map takes a - // closure that returns an Option. If the Option is None, filter_map filters out - // that entry from the for loop. If it's Some(x), filter_map executes the loop - // body with the value x. - for col in pattern.iter().enumerate().filter_map(|(col_index, chr)| { - if *chr == ' ' || (*chr == '.' && col_index == 0) { - None - } else { - Some(board.min_col + col_index) - } - }) { - board.cells[row][col] = CellState::Alive; - board.population += 1; - } - } - - board -} - -fn finish_cell_transitions(board: &mut Board) { - // In the BASIC implementation, this happens in the same loop that prints the board. - // We're breaking it out to improve separation of concerns. - let mut min_row = HEIGHT - 1; - let mut max_row = 0usize; - let mut min_col = WIDTH - 1; - let mut max_col = 0usize; - for row_index in board.min_row-1..=board.max_row+1 { - let mut any_alive_this_row = false; - for col_index in board.min_col-1..=board.max_col+1 { - let cell = &mut board.cells[row_index][col_index]; - if *cell == CellState::AboutToBeBorn { - *cell = CellState::Alive; - board.population += 1; - } else if *cell == CellState::AboutToDie { - *cell = CellState::Empty; - board.population -= 1; - } - if *cell == CellState::Alive { - any_alive_this_row = true; - min_col = cmp::min(min_col, col_index); - max_col = cmp::max(max_col, col_index); - } - } - if any_alive_this_row { - min_row = cmp::min(min_row, row_index); - max_row = cmp::max(max_row, row_index); - } - } - // If anything is alive within two cells of the boundary, mark the board invalid and - // clamp the bounds. We need a two-cell margin because we'll count neighbors on cells - // one space outside the min/max, and when we count neighbors we go out by an - // additional space. - if min_row < 2 { - min_row = 2; - board.invalid = true; - } - if max_row > HEIGHT - 3 { - max_row = HEIGHT - 3; - board.invalid = true; - } - if min_col < 2 { - min_col = 2; - board.invalid = true; - } - if max_col > WIDTH - 3 { - max_col = WIDTH - 3; - board.invalid = true; - } - - board.min_row = min_row; - board.max_row = max_row; - board.min_col = min_col; - board.max_col = max_col; -} - -fn print_board(board: &Board) { - println!(); println!(); println!(); - print!("Generation: {} Population: {}", board.generation, board.population); - if board.invalid { - print!(" Invalid!"); - } - println!(); - for row_index in 0..HEIGHT { - for col_index in 0..WIDTH { - // This print uses the Display implementation for cell_state, above. - print!("{}", board.cells[row_index][col_index]); - } - println!(); - } -} - -fn count_neighbors(board: &Board, row_index: usize, col_index: usize) -> i32 { - // Simply loop over all the immediate neighbors of a cell. We assume that the row and - // column indices are not on (or outside) the boundary of the arrays; if they are, - // the function will panic instead of going out of bounds. - let mut count = 0; - for i in row_index-1..=row_index+1 { - for j in col_index-1..=col_index+1 { - if i == row_index && j == col_index { - continue; - } - if board.cells[i][j] == CellState::Alive || board.cells[i][j] == CellState::AboutToDie { - count += 1; - } - } - } - count -} - -fn mark_cell_transitions(board: &mut Board) { - for row_index in board.min_row-1..=board.max_row+1 { - for col_index in board.min_col-1..=board.max_col+1 { - let neighbors = count_neighbors(board, row_index, col_index); - // Borrow a mutable reference to the array cell - let this_cell_state = &mut board.cells[row_index][col_index]; - *this_cell_state = match *this_cell_state { - CellState::Empty if neighbors == 3 => CellState::AboutToBeBorn, - CellState::Alive if !(2..=3).contains(&neighbors) => CellState::AboutToDie, - _ => *this_cell_state, - } - } - } - board.generation += 1; -} - -fn delay() { - thread::sleep(time::Duration::from_millis(500)); -} diff --git a/56_Life_for_Two/README.md b/56_Life_for_Two/README.md index 5ce081d37..3cc22c9e3 100644 --- a/56_Life_for_Two/README.md +++ b/56_Life_for_Two/README.md @@ -6,7 +6,6 @@ There are two players; the game is played on a 5x5 board and each player has a s The # and * are regarded as the same except when deciding whether to generate a live cell. An empty cell having two `#` and one `*` for neighbors will generate a `#`, i.e. the live cell generated belongs to the player who has the majority of the 3 live cells surrounding the empty cell where life is to be generated, for example: -``` | | 1 | 2 | 3 | 4 | 5 | |:-:|:-:|:-:|:-:|:-:|:-:| | 1 | | | | | | @@ -14,10 +13,9 @@ The # and * are regarded as the same except when deciding whether to generate a | 3 | | | | # | | | 4 | | | # | | | | 5 | | | | | | -``` A new cell will be generated at (3,3) which will be a `#` since there are two `#` and one `*` surrounding. The board will then become: -``` + | | 1 | 2 | 3 | 4 | 5 | |:-:|:-:|:-:|:-:|:-:|:-:| | 1 | | | | | | @@ -25,8 +23,8 @@ A new cell will be generated at (3,3) which will be a `#` since there are two `# | 3 | | | # | # | | | 4 | | | | | | | 5 | | | | | | -``` -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.) + +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.) The board is then adjusted to the next generation and printed out. @@ -45,21 +43,6 @@ 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) - -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/csharp/Board.cs b/56_Life_for_Two/csharp/Board.cs deleted file mode 100644 index f3cb0329c..000000000 --- a/56_Life_for_Two/csharp/Board.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Collections; -using System.Text; - -namespace LifeforTwo; - -internal class Board : IEnumerable -{ - private readonly Piece[,] _cells = new Piece[7, 7]; - private readonly Dictionary _cellCounts = - new() { [Piece.None] = 0, [Piece.Player1] = 0, [Piece.Player2] = 0 }; - - public Piece this[Coordinates coordinates] - { - get => this[coordinates.X, coordinates.Y]; - set => this[coordinates.X, coordinates.Y] = value; - } - - private Piece this[int x, int y] - { - get => _cells[x, y]; - set - { - if (!_cells[x, y].IsEmpty) { _cellCounts[_cells[x, y]] -= 1; } - _cells[x, y] = value; - _cellCounts[value] += 1; - } - } - - public int Player1Count => _cellCounts[Piece.Player1]; - public int Player2Count => _cellCounts[Piece.Player2]; - - internal bool IsEmptyAt(Coordinates coordinates) => this[coordinates].IsEmpty; - - internal void ClearCell(Coordinates coordinates) => this[coordinates] = Piece.NewNone(); - internal void AddPlayer1Piece(Coordinates coordinates) => this[coordinates] = Piece.NewPlayer1(); - internal void AddPlayer2Piece(Coordinates coordinates) => this[coordinates] = Piece.NewPlayer2(); - - public override string ToString() - { - var builder = new StringBuilder(); - - for (var y = 0; y <= 6; y++) - { - builder.AppendLine(); - for (var x = 0; x <= 6; x++) - { - builder.Append(GetCellDisplay(x, y)); - } - } - - return builder.ToString(); - } - - private string GetCellDisplay(int x, int y) => - (x, y) switch - { - (0 or 6, _) => $" {y % 6} ", - (_, 0 or 6) => $" {x % 6} ", - _ => $" {this[x, y]} " - }; - - public IEnumerator GetEnumerator() - { - for (var x = 1; x <= 5; x++) - { - for (var y = 1; y <= 5; y++) - { - yield return new(x, y); - } - } - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} diff --git a/56_Life_for_Two/csharp/Coordinates.cs b/56_Life_for_Two/csharp/Coordinates.cs deleted file mode 100644 index 09bd3dd4a..000000000 --- a/56_Life_for_Two/csharp/Coordinates.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace LifeforTwo; - -internal record Coordinates (int X, int Y) -{ - public static bool TryCreate((float X, float Y) values, out Coordinates coordinates) - { - if (values.X <= 0 || values.X > 5 || values.Y <= 0 || values.Y > 5) - { - coordinates = new(0, 0); - return false; - } - - coordinates = new((int)values.X, (int)values.Y); - return true; - } - - public static Coordinates operator +(Coordinates coordinates, int value) => - new (coordinates.X + value, coordinates.Y + value); - - public IEnumerable GetNeighbors() - { - yield return new(X - 1, Y); - yield return new(X + 1, Y); - yield return new(X, Y - 1); - yield return new(X, Y + 1); - yield return new(X - 1, Y - 1); - yield return new(X + 1, Y - 1); - yield return new(X - 1, Y + 1); - yield return new(X + 1, Y + 1); - } -} diff --git a/56_Life_for_Two/csharp/Game.cs b/56_Life_for_Two/csharp/Game.cs deleted file mode 100644 index de6cb5a5f..000000000 --- a/56_Life_for_Two/csharp/Game.cs +++ /dev/null @@ -1,26 +0,0 @@ -internal class Game -{ - private readonly IReadWrite _io; - - public Game(IReadWrite io) - { - _io = io; - } - - public void Play() - { - _io.Write(Streams.Title); - - var life = new Life(_io); - - _io.Write(life.FirstGeneration); - - foreach (var generation in life) - { - _io.WriteLine(); - _io.Write(generation); - } - - _io.WriteLine(life.Result ?? "No result"); - } -} diff --git a/56_Life_for_Two/csharp/Generation.cs b/56_Life_for_Two/csharp/Generation.cs deleted file mode 100644 index b96ee4786..000000000 --- a/56_Life_for_Two/csharp/Generation.cs +++ /dev/null @@ -1,89 +0,0 @@ -internal class Generation -{ - private readonly Board _board; - - public Generation(Board board) - { - _board = board; - CountNeighbours(); - } - - public Board Board => _board; - - public int Player1Count => _board.Player1Count; - public int Player2Count => _board.Player2Count; - - public string? Result => - (Player1Count, Player2Count) switch - { - (0, 0) => Strings.Draw, - (_, 0) => string.Format(Formats.Winner, 1), - (0, _) => string.Format(Formats.Winner, 2), - _ => null - }; - - public static Generation Create(IReadWrite io) - { - var board = new Board(); - - SetInitialPieces(1, coord => board.AddPlayer1Piece(coord)); - SetInitialPieces(2, coord => board.AddPlayer2Piece(coord)); - - return new Generation(board); - - void SetInitialPieces(int player, Action setPiece) - { - io.WriteLine(Formats.InitialPieces, player); - for (var i = 1; i <= 3; i++) - { - setPiece(io.ReadCoordinates(board)); - } - } - } - - public Generation CalculateNextGeneration() - { - var board = new Board(); - - foreach (var coordinates in _board) - { - board[coordinates] = _board[coordinates].GetNext(); - } - - return new(board); - } - - public void AddPieces(IReadWrite io) - { - var player1Coordinate = io.ReadCoordinates(1, _board); - var player2Coordinate = io.ReadCoordinates(2, _board); - - if (player1Coordinate == player2Coordinate) - { - io.Write(Streams.SameCoords); - // This is a bug existing in the original code. The line should be _board[_coordinates[_player]] = 0; - _board.ClearCell(player1Coordinate + 1); - } - else - { - _board.AddPlayer1Piece(player1Coordinate); - _board.AddPlayer2Piece(player2Coordinate); - } - } - - private void CountNeighbours() - { - foreach (var coordinates in _board) - { - var piece = _board[coordinates]; - if (piece.IsEmpty) { continue; } - - foreach (var neighbour in coordinates.GetNeighbors()) - { - _board[neighbour] = _board[neighbour].AddNeighbour(piece); - } - } - } - - public override string ToString() => _board.ToString(); -} \ No newline at end of file diff --git a/56_Life_for_Two/csharp/IOExtensions.cs b/56_Life_for_Two/csharp/IOExtensions.cs deleted file mode 100644 index d7db9bf49..000000000 --- a/56_Life_for_Two/csharp/IOExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -internal static class IOExtensions -{ - internal static Coordinates ReadCoordinates(this IReadWrite io, int player, Board board) - { - io.Write(Formats.Player, player); - return io.ReadCoordinates(board); - } - - internal static Coordinates ReadCoordinates(this IReadWrite io, Board board) - { - while (true) - { - io.WriteLine("X,Y"); - var values = io.Read2Numbers("&&&&&&\r"); - if (Coordinates.TryCreate(values, out var coordinates) && board.IsEmptyAt(coordinates)) - { - return coordinates; - } - io.Write(Streams.IllegalCoords); - } - } -} \ No newline at end of file diff --git a/56_Life_for_Two/csharp/Life.cs b/56_Life_for_Two/csharp/Life.cs deleted file mode 100644 index 7848a3487..000000000 --- a/56_Life_for_Two/csharp/Life.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections; - -internal class Life : IEnumerable -{ - private readonly IReadWrite _io; - - public Life(IReadWrite io) - { - _io = io; - FirstGeneration = Generation.Create(io); - } - - public Generation FirstGeneration { get; } - public string? Result { get; private set; } - - public IEnumerator GetEnumerator() - { - var current = FirstGeneration; - while (current.Result is null) - { - current = current.CalculateNextGeneration(); - yield return current; - - if (current.Result is null) { current.AddPieces(_io); } - } - - Result = current.Result; - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} \ No newline at end of file diff --git a/56_Life_for_Two/csharp/LifeforTwo.csproj b/56_Life_for_Two/csharp/LifeforTwo.csproj index 3870320c9..d3fe4757c 100644 --- a/56_Life_for_Two/csharp/LifeforTwo.csproj +++ b/56_Life_for_Two/csharp/LifeforTwo.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/56_Life_for_Two/csharp/Piece.cs b/56_Life_for_Two/csharp/Piece.cs deleted file mode 100644 index 20e5adba0..000000000 --- a/56_Life_for_Two/csharp/Piece.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; - -namespace LifeforTwo; - -public struct Piece -{ - public const int None = 0x0000; - public const int Player1 = 0x0100; - public const int Player2 = 0x1000; - private const int PieceMask = Player1 | Player2; - private const int NeighbourValueOffset = 8; - - private static readonly ImmutableHashSet _willBePlayer1 = - new[] { 0x0003, 0x0102, 0x0103, 0x0120, 0x0130, 0x0121, 0x0112, 0x0111, 0x0012 }.ToImmutableHashSet(); - private static readonly ImmutableHashSet _willBePlayer2 = - new[] { 0x0021, 0x0030, 0x1020, 0x1030, 0x1011, 0x1021, 0x1003, 0x1002, 0x1012 }.ToImmutableHashSet(); - - private int _value; - - private Piece(int value) => _value = value; - - public int Value => _value & PieceMask; - public bool IsEmpty => (_value & PieceMask) == None; - - public static Piece NewNone() => new(None); - public static Piece NewPlayer1() => new(Player1); - public static Piece NewPlayer2() => new(Player2); - - public Piece AddNeighbour(Piece neighbour) - { - _value += neighbour.Value >> NeighbourValueOffset; - return this; - } - - public Piece GetNext() => new( - _value switch - { - _ when _willBePlayer1.Contains(_value) => Player1, - _ when _willBePlayer2.Contains(_value) => Player2, - _ => None - }); - - public override string ToString() => - (_value & PieceMask) switch - { - Player1 => "*", - Player2 => "#", - _ => " " - }; - - public static implicit operator Piece(int value) => new(value); - public static implicit operator int(Piece piece) => piece.Value; -} \ No newline at end of file diff --git a/56_Life_for_Two/csharp/Program.cs b/56_Life_for_Two/csharp/Program.cs deleted file mode 100644 index 4c399811c..000000000 --- a/56_Life_for_Two/csharp/Program.cs +++ /dev/null @@ -1,5 +0,0 @@ -global using Games.Common.IO; -global using static LifeforTwo.Resources.Resource; -global using LifeforTwo; - -new Game(new ConsoleIO()).Play(); diff --git a/56_Life_for_Two/csharp/Resources/Draw.txt b/56_Life_for_Two/csharp/Resources/Draw.txt deleted file mode 100644 index 9b9fd8fc8..000000000 --- a/56_Life_for_Two/csharp/Resources/Draw.txt +++ /dev/null @@ -1,2 +0,0 @@ - -A draw \ No newline at end of file diff --git a/56_Life_for_Two/csharp/Resources/IllegalCoords.txt b/56_Life_for_Two/csharp/Resources/IllegalCoords.txt deleted file mode 100644 index ff01dfcbf..000000000 --- a/56_Life_for_Two/csharp/Resources/IllegalCoords.txt +++ /dev/null @@ -1 +0,0 @@ -Illegal coords. Retype diff --git a/56_Life_for_Two/csharp/Resources/InitialPieces.txt b/56_Life_for_Two/csharp/Resources/InitialPieces.txt deleted file mode 100644 index abbadf16e..000000000 --- a/56_Life_for_Two/csharp/Resources/InitialPieces.txt +++ /dev/null @@ -1,2 +0,0 @@ - -Player {0} - 3 live pieces \ No newline at end of file diff --git a/56_Life_for_Two/csharp/Resources/Player.txt b/56_Life_for_Two/csharp/Resources/Player.txt deleted file mode 100644 index f920e489d..000000000 --- a/56_Life_for_Two/csharp/Resources/Player.txt +++ /dev/null @@ -1,3 +0,0 @@ - - -Player {0} \ No newline at end of file diff --git a/56_Life_for_Two/csharp/Resources/Resource.cs b/56_Life_for_Two/csharp/Resources/Resource.cs deleted file mode 100644 index c6f59d3b9..000000000 --- a/56_Life_for_Two/csharp/Resources/Resource.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace LifeforTwo.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Title => GetStream(); - public static Stream IllegalCoords => GetStream(); - public static Stream SameCoords => GetStream(); - } - - internal static class Formats - { - public static string InitialPieces => GetString(); - public static string Player => GetString(); - public static string Winner => GetString(); - } - - internal static class Strings - { - public static string Draw => GetString(); - } - - 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/56_Life_for_Two/csharp/Resources/SameCoords.txt b/56_Life_for_Two/csharp/Resources/SameCoords.txt deleted file mode 100644 index 8af7b066d..000000000 --- a/56_Life_for_Two/csharp/Resources/SameCoords.txt +++ /dev/null @@ -1 +0,0 @@ -Same coord. Set to 0 diff --git a/56_Life_for_Two/csharp/Resources/Title.txt b/56_Life_for_Two/csharp/Resources/Title.txt deleted file mode 100644 index 0e3404a72..000000000 --- a/56_Life_for_Two/csharp/Resources/Title.txt +++ /dev/null @@ -1,6 +0,0 @@ - Life2 - Creative Computing Morristown, New Jersey - - - - U.B. Life Game diff --git a/56_Life_for_Two/csharp/Resources/Winner.txt b/56_Life_for_Two/csharp/Resources/Winner.txt deleted file mode 100644 index e35c54407..000000000 --- a/56_Life_for_Two/csharp/Resources/Winner.txt +++ /dev/null @@ -1,2 +0,0 @@ - -Player {0} is the winner \ No newline at end of file diff --git a/56_Life_for_Two/java/LifeForTwo.java b/56_Life_for_Two/java/LifeForTwo.java deleted file mode 100644 index 1f68e7944..000000000 --- a/56_Life_for_Two/java/LifeForTwo.java +++ /dev/null @@ -1,305 +0,0 @@ -import java.util.*; -import java.util.stream.IntStream; - -/** - * Life for Two - *

    - * The original BASIC program uses a grid with an extras border of cells all around, - * probably to simplify calculations and manipulations. This java program has the exact - * grid size and instead uses boundary check conditions in the logic. - *

    - * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) - */ -public class LifeForTwo { - - final static int GRID_SIZE = 5; - - //Pair of offset which when added to the current cell's coordinates, - // give the coordinates of the neighbours - final static int[] neighbourCellOffsets = { - -1, 0, - 1, 0, - 0, -1, - 0, 1, - -1, -1, - 1, -1, - -1, 1, - 1, 1 - }; - - //The best term that I could come with to describe these numbers was 'masks' - //They act like indicators to decide which player won the cell. The value is the score of the cell after all the - // generation calculations. - final static List maskPlayer1 = List.of(3, 102, 103, 120, 130, 121, 112, 111, 12); - final static List maskPlayer2 = List.of(21, 30, 1020, 1030, 1011, 1021, 1003, 1002, 1012); - - public static void main(String[] args) { - printIntro(); - Scanner scan = new Scanner(System.in); - scan.useDelimiter("\\D"); - - int[][] grid = new int[GRID_SIZE][GRID_SIZE]; - - initializeGrid(grid); - - //Read the initial 3 moves for each player - for (int b = 1; b <= 2; b++) { - System.out.printf("\nPLAYER %d - 3 LIVE PIECES.%n", b); - for (int k1 = 1; k1 <= 3; k1++) { - var player1Coordinates = readUntilValidCoordinates(scan, grid); - grid[player1Coordinates.x - 1][player1Coordinates.y - 1] = (b == 1 ? 3 : 30); - } - } - - printGrid(grid); - - calculatePlayersScore(grid); //Convert 3, 30 to 100, 1000 - - resetGridForNextGen(grid); - computeCellScoresForOneGen(grid); - - var playerScores = calculatePlayersScore(grid); - resetGridForNextGen(grid); - - boolean gameOver = false; - while (!gameOver) { - printGrid(grid); - if (playerScores.getPlayer1Score() == 0 && playerScores.getPlayer2Score() == 0) { - System.out.println("\nA DRAW"); - gameOver = true; - } else if (playerScores.getPlayer2Score() == 0) { - System.out.println("\nPLAYER 1 IS THE WINNER"); - gameOver = true; - } else if (playerScores.getPlayer1Score() == 0) { - System.out.println("\nPLAYER 2 IS THE WINNER"); - gameOver = true; - } else { - System.out.print("PLAYER 1 "); - Coordinate player1Move = readCoordinate(scan); - System.out.print("PLAYER 2 "); - Coordinate player2Move = readCoordinate(scan); - if (!player1Move.equals(player2Move)) { - grid[player1Move.x - 1][player1Move.y - 1] = 100; - grid[player2Move.x - 1][player2Move.y - 1] = 1000; - } - //In the original, B is assigned 99 when both players choose the same cell - //and that is used to control the flow - computeCellScoresForOneGen(grid); - playerScores = calculatePlayersScore(grid); - resetGridForNextGen(grid); - } - } - - } - - private static void initializeGrid(int[][] grid) { - for (int[] row : grid) { - Arrays.fill(row, 0); - } - } - - private static void computeCellScoresForOneGen(int[][] grid) { - for (int i = 0; i < GRID_SIZE; i++) { - for (int j = 0; j < GRID_SIZE; j++) { - if (grid[i][j] >= 100) { - calculateScoreForOccupiedCell(grid, i, j); - } - } - } - } - - private static Scores calculatePlayersScore(int[][] grid) { - int m2 = 0; - int m3 = 0; - for (int i = 0; i < GRID_SIZE; i++) { - for (int j = 0; j < GRID_SIZE; j++) { - if (grid[i][j] < 3) { - grid[i][j] = 0; - } else { - if (maskPlayer1.contains(grid[i][j])) { - m2++; - } else if (maskPlayer2.contains(grid[i][j])) { - m3++; - } - } - } - } - return new Scores(m2, m3); - } - - private static void resetGridForNextGen(int[][] grid) { - for (int i = 0; i < GRID_SIZE; i++) { - for (int j = 0; j < GRID_SIZE; j++) { - if (grid[i][j] < 3) { - grid[i][j] = 0; - } else { - if (maskPlayer1.contains(grid[i][j])) { - grid[i][j] = 100; - } else if (maskPlayer2.contains(grid[i][j])) { - grid[i][j] = 1000; - } else { - grid[i][j] = 0; - } - } - } - } - } - - private static void calculateScoreForOccupiedCell(int[][] grid, int i, int j) { - var b = 1; - if (grid[i][j] > 999) { - b = 10; - } - for (int k = 0; k < 15; k += 2) { - //check bounds - var neighbourX = i + neighbourCellOffsets[k]; - var neighbourY = j + neighbourCellOffsets[k + 1]; - if (neighbourX >= 0 && neighbourX < GRID_SIZE && - neighbourY >= 0 && neighbourY < GRID_SIZE) { - grid[neighbourX][neighbourY] = grid[neighbourX][neighbourY] + b; - } - - } - } - - private static void printGrid(int[][] grid) { - System.out.println(); - printRowEdge(); - System.out.println(); - for (int i = 0; i < grid.length; i++) { - System.out.printf("%d ", i + 1); - for (int j = 0; j < grid[i].length; j++) { - System.out.printf(" %c ", mapChar(grid[i][j])); - } - System.out.printf(" %d", i + 1); - System.out.println(); - } - printRowEdge(); - System.out.println(); - } - - private static void printRowEdge() { - System.out.print("0 "); - IntStream.range(1, GRID_SIZE + 1).forEach(i -> System.out.printf(" %s ", i)); - System.out.print(" 0"); - } - - private static char mapChar(int i) { - if (i == 3 || i == 100) { - return '*'; - } - if (i == 30 || i == 1000) { - return '#'; - } - return ' '; - } - - private static Coordinate readUntilValidCoordinates(Scanner scanner, int[][] grid) { - boolean coordinateInRange = false; - Coordinate coordinate = null; - while (!coordinateInRange) { - coordinate = readCoordinate(scanner); - if (coordinate.x <= 0 || coordinate.x > GRID_SIZE - || coordinate.y <= 0 || coordinate.y > GRID_SIZE - || grid[coordinate.x - 1][coordinate.y - 1] != 0) { - System.out.println("ILLEGAL COORDS. RETYPE"); - } else { - coordinateInRange = true; - } - } - return coordinate; - } - - private static Coordinate readCoordinate(Scanner scanner) { - Coordinate coordinate = null; - int x, y; - boolean valid = false; - - System.out.println("X,Y"); - System.out.print("XXXXXX\r"); - System.out.print("$$$$$$\r"); - System.out.print("&&&&&&\r"); - - while (!valid) { - try { - System.out.print("? "); - y = scanner.nextInt(); - x = scanner.nextInt(); - valid = true; - coordinate = new Coordinate(x, y); - } catch (InputMismatchException e) { - System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); - valid = false; - } finally { - scanner.nextLine(); - } - } - return coordinate; - } - - private static void printIntro() { - System.out.println(" LIFE2"); - System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); - System.out.println("\n\n"); - - System.out.println("\tU.B. LIFE GAME"); - } - - private static class Coordinate { - private final int x, y; - - public Coordinate(int x, int y) { - this.x = x; - this.y = y; - } - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - @Override - public String toString() { - return "Coordinate{" + - "x=" + x + - ", y=" + y + - '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Coordinate that = (Coordinate) o; - return x == that.x && y == that.y; - } - - @Override - public int hashCode() { - return Objects.hash(x, y); - } - } - - private static class Scores { - private final int player1Score; - private final int player2Score; - - public Scores(int player1Score, int player2Score) { - this.player1Score = player1Score; - this.player2Score = player2Score; - } - - public int getPlayer1Score() { - return player1Score; - } - - public int getPlayer2Score() { - return player2Score; - } - } - - -} diff --git a/56_Life_for_Two/lifefortwo.bas b/56_Life_for_Two/lifefortwo.bas index 4faf1f127..e970ef6df 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 999 -575 PRINT: PRINT "PLAYER";B;"IS THE WINNER":GOTO 999 +574 PRINT: PRINT "A DRAW":GOTO 800 +575 PRINT: PRINT "PLAYER";B;"IS THE WINNER":GOTO 800 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 7b3b41a3c..e69c8b819 100644 --- a/56_Life_for_Two/perl/README.md +++ b/56_Life_for_Two/perl/README.md @@ -1,21 +1,3 @@ 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 deleted file mode 100644 index 0c50cdef7..000000000 --- a/56_Life_for_Two/perl/lifefortwo.pl +++ /dev/null @@ -1,215 +0,0 @@ -#!/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; -} diff --git a/56_Life_for_Two/python/life_for_two.py b/56_Life_for_Two/python/life_for_two.py deleted file mode 100644 index c9910f994..000000000 --- a/56_Life_for_Two/python/life_for_two.py +++ /dev/null @@ -1,157 +0,0 @@ -''' -LIFE FOR TWO - -Competitive Game of Life (two or more players). - -Ported by Sajid Sarker (2022). -''' - -# Global Variable Initialisation -# Initialise the board -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] -ga = [0, -1, 0, 1, 0, 0, -1, 0, 1, -1, -1, 1, -1, -1, 1, 1, 1] -m2 = 0 -m3 = 0 - - -# Helper Functions -def tab(number) -> str: - t = "" - while len(t) < number: - t += " " - return t - - -def display_header() -> None: - 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 -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(f"\nPLAYER {b} - 3 LIVE PIECES.") - for _ in range(1, 4): - query_player(b) - gn[gx[b]][gy[b]] = p1 - - -def modify_board() -> None: - # Players take turns to add symbols and modify the board - for b in range(1, 3): - print(f"PLAYER {b} ") - query_player(b) - if b == 99: - break - if b <= 2: - gn[gx[1]][gy[1]] = 100 - gn[gx[2]][gy[2]] = 1000 - - -def simulate_board() -> None: - # Simulate the board for one step - for j in range(1, 6): - for k in range(1, 6): - if gn[j][k] > 99: - b = 1 if gn[j][k] <= 999 else 10 - for o1 in range(1, 16, 2): - gn[j + ga[o1] - 1][k + ga[o1 + 1] - 1] += b - # gn[j+ga[o1]][k+ga[o1+1]-1] = gn[j+ga[o1]][k+ga[o1+1]]+b - - -def display_board() -> None: - # Draws the board with all symbols - m2, m3 = 0, 0 - for j in range(7): - print("") - for k in range(7): - if j in [0, 6]: - if k != 6: - print(f" {str(k)} ", end="") - else: - print(" 0 ", end="") - elif k in [0, 6]: - print(f" {str(j)} ", end="") - elif gn[j][k] < 3: - 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 -def query_player(b) -> None: - # Query player for symbol placement coordinates - while True: - print("X,Y\nXXXXXX\n$$$$$$\n&&&&&&") - a_ = input("??") - 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 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)\ - and gy[b] in range(1, 6)\ - and gn[gx[b]][gy[b]] == 0: - break - print("ILLEGAL COORDS. RETYPE") - if b != 1: - if gx[1] == gx[2] and gy[1] == gy[2]: - print("SAME COORD. SET TO 0") - gn[gx[b] + 1][gy[b] + 1] = 0 - b = 99 - - -# Game Functions -def check_winner(m2, m3) -> None: - # Check if the game has been won - if m2 == 0 and m3 == 0: - print("\nA DRAW\n") - return - if m3 == 0: - print("\nPLAYER 1 IS THE WINNER\n") - return - if m2 == 0: - print("\nPLAYER 2 IS THE WINNER\n") - return - - -# Program Flow -def main() -> None: - display_header() - setup_board() - display_board() - while True: - print("\n") - simulate_board() - display_board() - check_winner(m2, m3) - modify_board() - - -if __name__ == "__main__": - main() diff --git a/57_Literature_Quiz/javascript/literature-quiz-node.mjs b/57_Literature_Quiz/javascript/literature-quiz-node.mjs new file mode 100644 index 000000000..5dadd50b9 --- /dev/null +++ b/57_Literature_Quiz/javascript/literature-quiz-node.mjs @@ -0,0 +1,90 @@ +import * as readline from 'readline' + +// start reusable code +async function input(prompt = "") { + const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout + }) + + return new Promise((resolve, _) => { + rl.setPrompt(prompt) + // show user the question + rl.prompt() + // listen for user answer, + // callback is triggered as soon as user hits enter key + rl.on('line', answer => { + rl.close() + // resolve the promise, with the input the user entered + resolve(answer) + }) + }) +} + +function println(message = "", align = "left"){ + let padColCount = 0 + if(align === "center"){ + // calculate the amount of spaces required to center the message + // process.stdout.columns is the number of spaces per line in the terminal + padColCount = Math.round(process.stdout.columns / 2 + message.length / 2) + } + console.log(message.padStart(padColCount, " ")) +} +// end reusable code + + +function equalIgnoreCase(correct, provided){ + return correct.toString().toLowerCase() === provided.toString().toLowerCase() +} + +async function evaluateQuestion(question, answerOptions, correctAnswer, correctMessage, wrongMessage){ + // ask the user to answer the given question + // this is a blocking wait + const answer = await input(question + "\n" + answerOptions + "\n") + const isCorrect = equalIgnoreCase(correctAnswer, answer) + println(isCorrect ? correctMessage : wrongMessage) + return isCorrect ? 1 : 0 +} + +async function main(){ + let score = 0 + println("LITERATURE QUIZ", "center") + println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY", "center") + println();println();println() + + score += await evaluateQuestion("IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT?", + "1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO", 3, + "VERY GOOD! HERE'S ANOTHER.", "SORRY...FIGARO WAS HIS NAME.") + println() + + score += await evaluateQuestion("FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?", + "1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S", 2, + "PRETTY GOOD!", "TOO BAD...IT WAS ELMER FUDD'S GARDEN.") + println() + + score += await evaluateQuestion("IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED", + "1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO", 4, + "YEA! YOU'RE A REAL LITERATURE GIANT.", + "BACK TO THE BOOKS,...TOTO WAS HIS NAME.") + println() + + score += await evaluateQuestion("WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE", + "1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY", 3, + "GOOD MEMORY!", "OH, COME ON NOW...IT WAS SNOW WHITE.") + + println();println() + + if(score === 4) { + println("WOW! THAT'S SUPER! YOU REALLY KNOW YOUR NURSERY\n"+ + "YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\n"+ + "LITERATURE (HA, HA, HA)") + } else if(score <= 2){ + println("UGH. THAT WAS DEFINITELY NOT TOO SWIFT. BACK TO\n" + + "NURSERY SCHOOL FOR YOU, MY FRIEND.") + } else { + println("NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\n"+ + "READING THE NURSERY GREATS.") + } +} + +main() diff --git a/57_Literature_Quiz/javascript/litquiz.mjs b/57_Literature_Quiz/javascript/litquiz.mjs deleted file mode 100644 index 89daef928..000000000 --- a/57_Literature_Quiz/javascript/litquiz.mjs +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env node - -import { println, input } from '../../00_Common/javascript/common.mjs'; - -function printAlign(message = "", align = "left") { - // process.stdout.columns is the number of spaces per line in the terminal - const maxWidth = process.stdout.columns - if (align === "center") { - // calculate the amount of spaces required to center the message - const padColCount = Math.round((process.stdout.columns-message.length)/2); - const padding = padColCount <= 0 ? '' : ' '.repeat(padColCount); - println(padding, message); - } else if (align === "right") { - const padColCount = Math.round(process.stdout.columns-message.length); - const padding = padColCount <= 0 ? '' : ' '.repeat(padColCount); - println(padding, message); - } else { - println(message); - } -} - -function equalIgnoreCase(correct, provided){ - return correct.toString().toLowerCase() === provided.toString().toLowerCase() -} - -async function evaluateQuestion(question, answerOptions, correctAnswer, correctMessage, wrongMessage){ - // ask the user to answer the given question - println(question); - println(answerOptions.map((answer, index) => `${index+1})${answer}`).join(', ')); - // this is a blocking wait - const answer = await input('?') - const isCorrect = equalIgnoreCase(correctAnswer, answer) - println(isCorrect ? correctMessage : wrongMessage) - return isCorrect ? 1 : 0 -} - -async function main(){ - let score = 0 - - printAlign("LITERATURE QUIZ", "center") - printAlign("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY", "center") - println("\n\n") - - 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("\n\n"); - - score += await evaluateQuestion("IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT?", - [ "TIGGER", "CICERO", "FIGARO", "GUIPETTO"], 3, - "VERY GOOD! HERE'S ANOTHER.", "SORRY...FIGARO WAS HIS NAME.") - println() - - score += await evaluateQuestion("FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?", - [ "MR. NIXON'S", "ELMER FUDD'S", "CLEM JUDD'S", "STROMBOLI'S" ], 2, - "PRETTY GOOD!", "TOO BAD...IT WAS ELMER FUDD'S GARDEN.") - println() - - score += await evaluateQuestion("IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED", - [ "CICERO", "TRIXIA", "KING", "TOTO" ], 4, - "YEA! YOU'RE A REAL LITERATURE GIANT.", - "BACK TO THE BOOKS,...TOTO WAS HIS NAME.") - println() - - score += await evaluateQuestion("WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE", - [ "SLEEPING BEAUTY", "CINDERELLA", "SNOW WHITE", "WENDY" ], 3, - "GOOD MEMORY!", "OH, COME ON NOW...IT WAS SNOW WHITE.") - - println("\n") - - if(score === 4) { - println("WOW! THAT'S SUPER! YOU REALLY KNOW YOUR NURSERY\n"+ - "YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\n"+ - "LITERATURE (HA, HA, HA)") - } else if(score <= 2){ - println("UGH. THAT WAS DEFINITELY NOT TOO SWIFT. BACK TO\n" + - "NURSERY SCHOOL FOR YOU, MY FRIEND.") - } else { - println("NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\n"+ - "READING THE NURSERY GREATS.") - } -} - -main() diff --git a/57_Literature_Quiz/python/litquiz.py b/57_Literature_Quiz/python/litquiz.py index 9af123989..d9e581d31 100644 --- a/57_Literature_Quiz/python/litquiz.py +++ b/57_Literature_Quiz/python/litquiz.py @@ -6,19 +6,20 @@ Ported by Dave LeCompte """ -from typing import List, NamedTuple - PAGE_WIDTH = 64 -class Question(NamedTuple): - question: str - answer_list: List[str] - correct_number: int - incorrect_message: str - correct_message: str +class Question: + def __init__( + self, question, answer_list, correct_number, incorrect_message, correct_message + ): + self.question = question + self.answer_list = answer_list + self.correct_number = correct_number + self.incorrect_message = incorrect_message + self.correct_message = correct_message - def ask(self) -> bool: + def ask(self): print(self.question) options = [f"{i+1}){self.answer_list[i]}" for i in range(len(self.answer_list))] @@ -68,6 +69,7 @@ def ask(self) -> bool: def print_centered(msg: str) -> None: spaces = " " * ((64 - len(msg)) // 2) + print(spaces + msg) diff --git a/57_Literature_Quiz/rust/Cargo.lock b/57_Literature_Quiz/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/57_Literature_Quiz/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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.toml b/57_Literature_Quiz/rust/Cargo.toml deleted file mode 100644 index 1ec696335..000000000 --- a/57_Literature_Quiz/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/57_Literature_Quiz/rust/README.md b/57_Literature_Quiz/rust/README.md deleted file mode 100644 index fc6468b9f..000000000 --- a/57_Literature_Quiz/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index a9e3923e5..000000000 --- a/57_Literature_Quiz/rust/src/main.rs +++ /dev/null @@ -1,127 +0,0 @@ -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); - -} - - - diff --git a/58_Love/python/love.py b/58_Love/python/love.py index 2bb93c68c..a15237ba4 100644 --- a/58_Love/python/love.py +++ b/58_Love/python/love.py @@ -1,22 +1,24 @@ -""" -LOVE - -From: BASIC Computer Games (1978) - Edited by David H. Ahl - -"This program is designed to reproduce Robert Indiana's great art - work 'Love' with a message of your choice up to 60 characters long. - -"The [DATA variable is] an alternating count of the number - of characters and blanks which form the design. These data give - the correct proportions for a standard 10 character per inch - Teletype or line printer. - -"The LOVE program was created by David Ahl." - - -Python port by Jeff Jetton, 2019 -""" +###################################################################### +# +# LOVE +# +# From: BASIC Computer Games (1978) +# Edited by David H. Ahl +# +# "This program is designed to reproduce Robert Indiana's great art +# work 'Love' with a message of your choice up to 60 characters long. +# +# "The [DATA variable is] an alternating count of the number +# of characters and blanks which form the design. These data give +# the correct proportions for a standard 10 character per inch +# Teletype or line printer. +# +# "The LOVE program was created by David Ahl." +# +# +# Python port by Jeff Jetton, 2019 +# +###################################################################### # Image data. Each top-level element is a row. Each row element @@ -106,7 +108,7 @@ def main() -> None: position += length print(line_text) - print() + print("") if __name__ == "__main__": diff --git a/58_Love/rust/Cargo.lock b/58_Love/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/58_Love/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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.toml b/58_Love/rust/Cargo.toml deleted file mode 100644 index 1ec696335..000000000 --- a/58_Love/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/58_Love/rust/README.md b/58_Love/rust/README.md deleted file mode 100644 index 4cd904309..000000000 --- a/58_Love/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 5e8e18d72..000000000 --- a/58_Love/rust/src/main.rs +++ /dev/null @@ -1,92 +0,0 @@ -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!(); - } -} diff --git a/59_Lunar_LEM_Rocket/README.md b/59_Lunar_LEM_Rocket/README.md index 98db7aed6..91fe1cd63 100644 --- a/59_Lunar_LEM_Rocket/README.md +++ b/59_Lunar_LEM_Rocket/README.md @@ -23,45 +23,6 @@ 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) - -### 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. diff --git a/59_Lunar_LEM_Rocket/javascript/lunar.js b/59_Lunar_LEM_Rocket/javascript/lunar.js index 43a0e892c..69306aa28 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,000 LBS.\n"); + print("CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,500 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 301336150..b12037187 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,000 LBS." +100 PRINT "CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,500 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 228093e91..d9a94885d 100644 --- a/59_Lunar_LEM_Rocket/python/lunar.py +++ b/59_Lunar_LEM_Rocket/python/lunar.py @@ -6,9 +6,8 @@ Ported by Dave LeCompte """ +import collections import math -from dataclasses import dataclass -from typing import Any, NamedTuple PAGE_WIDTH = 64 @@ -33,10 +32,7 @@ BURN_LEFT = FUEL_RIGHT + COLUMN_WIDTH BURN_RIGHT = BURN_LEFT + BURN_WIDTH - -class PhysicalState(NamedTuple): - velocity: float - altitude: float +PhysicalState = collections.namedtuple("PhysicalState", ["velocity", "altitude"]) def print_centered(msg: str) -> None: @@ -46,25 +42,30 @@ def print_centered(msg: str) -> None: def print_header(title: str) -> None: print_centered(title) - print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() + +def add_rjust(line, s, pos): + # adds a new field to a line right justified to end at pos -def add_rjust(line: str, s: Any, pos: int) -> str: - """Add a new field to a line right justified to end at pos""" - s_str = str(s) - slen = len(s_str) + s = str(s) + slen = len(s) if len(line) + slen > pos: new_len = pos - slen line = line[:new_len] if len(line) + slen < pos: spaces = " " * (pos - slen - len(line)) line = line + spaces - return line + s_str + return line + s -def add_ljust(line: str, s: str, pos: int) -> str: - """Add a new field to a line left justified starting at pos""" - s = s +def add_ljust(line, s, pos): + # adds a new field to a line left justified starting at pos + + s = str(s) if len(line) > pos: line = line[:pos] if len(line) < pos: @@ -74,30 +75,59 @@ def add_ljust(line: str, s: str, pos: int) -> str: def print_instructions() -> None: - """Somebody had a bad experience with Xerox.""" + # Somebody had a bad experience with Xerox. + print("THIS IS A COMPUTER SIMULATION OF AN APOLLO LUNAR") - print("LANDING CAPSULE.\n\n") + 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.\n") + print("XEROX) SO YOU HAVE TO LAND THE CAPSULE MANUALLY.") + print() 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,000 LBS.\n\n\n") - print("GOOD LUCK\n") - - -def format_line_for_report( - t: Any, - miles: Any, - feet: Any, - velocity: Any, - fuel: Any, - burn_rate: str, - is_header: bool, -) -> str: + 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") + print() + + +def show_landing(sim_clock, capsule): + w = 3600 * capsule.v + print( + f"ON MOON AT {sim_clock.elapsed_time:.2f} SECONDS - IMPACT VELOCITY {w:.2f} MPH" + ) + if w < 1.2: + print("PERFECT LANDING!") + elif w < 10: + print("GOOD LANDING (COULD BE BETTER)") + elif w <= 60: + 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(f"IN FACT, YOU BLASTED A NEW LUNAR CRATER {w*.227:.2f} FEET DEEP!") + end_sim() + + +def show_out_of_fuel(sim_clock, capsule): + print(f"FUEL OUT AT {sim_clock.elapsed_time} SECONDS") + delta_t = ( + -capsule.v + math.sqrt(capsule.v**2 + 2 * capsule.a * capsule.g) + ) / capsule.g + capsule.v += capsule.g * delta_t + sim_clock.advance(delta_t) + show_landing(sim_clock, capsule) + + +def format_line_for_report(t, miles, feet, velocity, fuel, burn_rate, is_header) -> str: line = add_rjust("", t, SECONDS_RIGHT) line = add_rjust(line, miles, ALT_MI_RIGHT) line = add_rjust(line, feet, ALT_FT_RIGHT) @@ -110,65 +140,58 @@ def format_line_for_report( return line -class SimulationClock: - def __init__(self, elapsed_time: float, time_until_next_prompt: float) -> None: - self.elapsed_time = elapsed_time - self.time_until_next_prompt = time_until_next_prompt - - def time_for_prompt(self) -> bool: - return self.time_until_next_prompt < 1e-3 - - def advance(self, delta_t: float) -> None: - self.elapsed_time += delta_t - self.time_until_next_prompt -= delta_t - - -@dataclass class Capsule: - altitude: float = 120 # in miles above the surface - velocity: float = 1 # downward - m: float = 33000 # mass_with_fuel - n: float = 16500 # mass_without_fuel - g: float = 1e-3 - z: float = 1.8 - fuel_per_second: float = 0 - - def remaining_fuel(self) -> float: + def __init__( + self, + altitude=120, + velocity=1, + mass_with_fuel=33000, + mass_without_fuel=16500, + g=1e-3, + z=1.8, + ): + self.a = altitude # in miles above the surface + self.v = velocity # downward + self.m = mass_with_fuel + self.n = mass_without_fuel + self.g = g + self.z = z + self.fuel_per_second = 0 + + def remaining_fuel(self): return self.m - self.n - def is_out_of_fuel(self) -> bool: + def is_out_of_fuel(self): return self.remaining_fuel() < 1e-3 - def update_state( - self, sim_clock: SimulationClock, delta_t: float, new_state: PhysicalState - ) -> None: + def update_state(self, sim_clock, delta_t, new_state): sim_clock.advance(delta_t) self.m = self.m - delta_t * self.fuel_per_second - self.altitude = new_state.altitude - self.velocity = new_state.velocity + self.a = new_state.altitude + self.v = new_state.velocity - def fuel_time_remaining(self) -> float: + def fuel_time_remaining(self): # extrapolates out how many seconds we have at the current fuel burn rate assert self.fuel_per_second > 0 return self.remaining_fuel() / self.fuel_per_second - def predict_motion(self, delta_t: float) -> PhysicalState: + def predict_motion(self, delta_t): # Perform an Euler's Method numerical integration of the equations of motion. q = delta_t * self.fuel_per_second / self.m # new velocity new_velocity = ( - self.velocity + self.v + self.g * delta_t + self.z * (-q - q**2 / 2 - q**3 / 3 - q**4 / 4 - q**5 / 5) ) # new altitude new_altitude = ( - self.altitude + self.a - self.g * delta_t**2 / 2 - - self.velocity * delta_t + - self.v * delta_t + self.z * delta_t * (q / 2 + q**2 / 6 + q**3 / 12 + q**4 / 20 + q**5 / 30) @@ -176,11 +199,11 @@ def predict_motion(self, delta_t: float) -> PhysicalState: return PhysicalState(altitude=new_altitude, velocity=new_velocity) - def make_state_display_string(self, sim_clock: SimulationClock) -> str: + def make_state_display_string(self, sim_clock) -> str: seconds = sim_clock.elapsed_time - miles = int(self.altitude) - feet = int(5280 * (self.altitude - miles)) - velocity = int(3600 * self.velocity) + miles = int(self.a) + feet = int(5280 * (self.a - miles)) + velocity = int(3600 * self.v) fuel = int(self.remaining_fuel()) burn_rate = " ? " @@ -188,45 +211,27 @@ def make_state_display_string(self, sim_clock: SimulationClock) -> str: seconds, miles, feet, velocity, fuel, burn_rate, False ) - def prompt_for_burn(self, sim_clock: SimulationClock) -> None: + def prompt_for_burn(self, sim_clock): msg = self.make_state_display_string(sim_clock) self.fuel_per_second = float(input(msg)) sim_clock.time_until_next_prompt = 10 -def show_landing(sim_clock: SimulationClock, capsule: Capsule) -> None: - w = 3600 * capsule.velocity - print( - f"ON MOON AT {sim_clock.elapsed_time:.2f} SECONDS - IMPACT VELOCITY {w:.2f} MPH" - ) - if w < 1.2: - print("PERFECT LANDING!") - elif w < 10: - print("GOOD LANDING (COULD BE BETTER)") - elif w <= 60: - 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(f"IN FACT, YOU BLASTED A NEW LUNAR CRATER {w*.227:.2f} FEET DEEP!") - end_sim() +class SimulationClock: + def __init__(self, elapsed_time, time_until_next_prompt): + self.elapsed_time = elapsed_time + self.time_until_next_prompt = time_until_next_prompt + def time_for_prompt(self): + return self.time_until_next_prompt < 1e-3 -def show_out_of_fuel(sim_clock: SimulationClock, capsule: Capsule) -> None: - print(f"FUEL OUT AT {sim_clock.elapsed_time} SECONDS") - delta_t = ( - -capsule.velocity - + math.sqrt(capsule.velocity**2 + 2 * capsule.altitude * capsule.g) - ) / capsule.g - capsule.velocity += capsule.g * delta_t - sim_clock.advance(delta_t) - show_landing(sim_clock, capsule) + def advance(self, delta_t): + self.elapsed_time += delta_t + self.time_until_next_prompt -= delta_t -def process_final_tick( - delta_t: float, sim_clock: SimulationClock, capsule: Capsule -) -> None: +def process_final_tick(delta_t, sim_clock, capsule): # When we extrapolated our position based on our velocity # and delta_t, we overshot the surface. For better # accuracy, we will back up and do shorter time advances. @@ -237,20 +242,20 @@ def process_final_tick( return # line 35 average_vel = ( - capsule.velocity + capsule.v + math.sqrt( - capsule.velocity**2 + capsule.v**2 + 2 - * capsule.altitude + * capsule.a * (capsule.g - capsule.z * capsule.fuel_per_second / capsule.m) ) ) / 2 - delta_t = capsule.altitude / average_vel + delta_t = capsule.a / average_vel new_state = capsule.predict_motion(delta_t) capsule.update_state(sim_clock, delta_t, new_state) -def handle_flyaway(sim_clock: SimulationClock, capsule: Capsule) -> bool: +def handle_flyaway(sim_clock, capsule): """ The user has started flying away from the moon. Since this is a lunar LANDING simulation, we wait until the capsule's velocity is @@ -263,11 +268,11 @@ def handle_flyaway(sim_clock: SimulationClock, capsule: Capsule) -> bool: w = (1 - capsule.m * capsule.g / (capsule.z * capsule.fuel_per_second)) / 2 delta_t = ( capsule.m - * capsule.velocity + * capsule.v / ( capsule.z * capsule.fuel_per_second - * math.sqrt(w**2 + capsule.velocity / capsule.z) + * math.sqrt(w**2 + capsule.v / capsule.z) ) ) + 0.05 @@ -279,16 +284,22 @@ def handle_flyaway(sim_clock: SimulationClock, capsule: Capsule) -> bool: capsule.update_state(sim_clock, delta_t, new_state) - if (new_state.velocity > 0) or (capsule.velocity <= 0): + if (new_state.velocity > 0) or (capsule.v <= 0): # return to normal sim return False -def end_sim() -> None: - print("\n\n\nTRY AGAIN??\n\n\n") +def end_sim(): + print() + print() + print() + print("TRY AGAIN??") + print() + print() + print() -def run_simulation() -> None: +def run_simulation(): print() print( format_line_for_report("SEC", "MI", "FT", "MPH", "LB FUEL", "BURN RATE", True) @@ -323,8 +334,11 @@ def run_simulation() -> None: process_final_tick(delta_t, sim_clock, capsule) return - if capsule.velocity > 0 and new_state.velocity < 0: - if landed := handle_flyaway(sim_clock, capsule): + if capsule.v > 0 and new_state.velocity < 0: + # moving away from the moon + + landed = handle_flyaway(sim_clock, capsule) + if landed: process_final_tick(delta_t, sim_clock, capsule) return diff --git a/60_Mastermind/README.md b/60_Mastermind/README.md index 05383f106..9aba2691c 100644 --- a/60_Mastermind/README.md +++ b/60_Mastermind/README.md @@ -28,130 +28,20 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html -### How the computer deduces your guess. - -The computer takes the number of black pegs and white pegs that the user reports -and uses that information as a target. It then assumes its guess is the answer -and proceeds to compare the black and white pegs against all remaining possible -answers. For each set of black and white pegs it gets in these comparisons, if -they don't match what the user reported, then they can not be part of the solution. -This can be a non-intuitive assumption, so we'll walk through it with a three color, -three position example (27 possible solutions.) - -Let's just suppose our secret code we're hiding from the computer is `BWB` - -First let's point out the commutative property of comparing two codes for their -black and white pegs. A black peg meaning correct color and correct position, and -a white peg meaning correct color and wrong position. If the computer guesses -`RBW` then the black/white peg report is 0 black, 2 white. But if `RBW` is the -secret code and the computer guesses `BWB` the reporting for `BWB` is going to be -the same, 0 black, 2 white. - -Now lets look at a table with the reporting for every possible guess the computer -can make while our secret code is `BWB`. - -| Guess | Black | White | | Guess | Black | White | | Guess | Black | White | -|-------|-------|-------|-----|-------|-------|-------|-----|-------|-------|-------| -| BBB | 2 | 0 | | WBB | 1 | 2 | | RBB | 1 | 1 | -| BBW | 1 | 2 | | WBW | 0 | 2 | | RBW | 0 | 2 | -| BBR | 1 | 1 | | WBR | 0 | 2 | | RBR | 0 | 1 | -| BWB | 3 | 0 | | WWB | 2 | 0 | | RWB | 2 | 0 | -| BWW | 2 | 0 | | WWW | 1 | 0 | | RWW | 1 | 0 | -| BWR | 2 | 0 | | WWR | 1 | 0 | | RWR | 1 | 0 | -| BRB | 2 | 0 | | WRB | 1 | 1 | | RRB | 1 | 0 | -| BRW | 1 | 1 | | WRW | 0 | 1 | | RRW | 0 | 1 | -| BRR | 1 | 0 | | WRR | 0 | 1 | | RRR | 0 | 0 | - -The computer has guessed `RBW` and the report on it is 0 black, 2 white. The code -used to eliminate other solutions looks like this: +#### Porting Notes + +in [#613](https://github.com/coding-horror/basic-computer-games/pull/613) `1060 IF B1<>B OR W1<>W THEN I(X)=0` -which says set `RBW` as the secret and compare it to all remaining solutions and -get rid of any that don't match the same black and white report, 0 black and 2 white. -So let's do that. - -Remember, `RBW` is pretending to be the secret code here. These are the remaining -solutions reporting their black and white pegs against `RBW`. - -| Guess | Black | White | | Guess | Black | White | | Guess | Black | White | -|-------|-------|-------|-----|-------|-------|-------|-----|-------|-------|-------| -| BBB | 1 | 0 | | WBB | 1 | 1 | | RBB | 2 | 0 | -| BBW | 2 | 0 | | WBW | 2 | 0 | | RBW | 3 | 0 | -| BBR | 1 | 1 | | WBR | 1 | 2 | | RBR | 2 | 0 | -| BWB | 0 | 2 | | WWB | 0 | 2 | | RWB | 1 | 2 | -| BWW | 1 | 1 | | WWW | 1 | 0 | | RWW | 2 | 0 | -| BWR | 0 | 3 | | WWR | 1 | 1 | | RWR | 1 | 1 | -| BRB | 0 | 2 | | WRB | 0 | 3 | | RRB | 1 | 1 | -| 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** match 0 black and 2 white. - -| Guess | Black | White | | Guess | Black | White | | Guess | Black | White | -|----------|-------|-------|-----|----------|-------|-------|-----|----------|-------|-------| -| ~~~BBB~~ | 1 | 0 | | ~~~WBB~~ | 1 | 1 | | ~~~RBB~~ | 2 | 0 | -| ~~~BBW~~ | 2 | 0 | | ~~~WBW~~ | 2 | 0 | | ~~~RBW~~ | 3 | 0 | -| ~~~BBR~~ | 1 | 1 | | ~~~WBR~~ | 1 | 2 | | ~~~RBR~~ | 2 | 0 | -| BWB | 0 | 2 | | WWB | 0 | 2 | | ~~~RWB~~ | 1 | 2 | -| ~~~BWW~~ | 1 | 1 | | ~~~WWW~~ | 1 | 0 | | ~~~RWW~~ | 2 | 0 | -| ~~~BWR~~ | 0 | 3 | | ~~~WWR~~ | 1 | 1 | | ~~~RWR~~ | 1 | 1 | -| BRB | 0 | 2 | | ~~~WRB~~ | 0 | 3 | | ~~~RRB~~ | 1 | 1 | -| ~~~BRW~~ | 1 | 2 | | ~~~WRW~~ | 1 | 1 | | ~~~RRW~~ | 2 | 0 | -| BRR | 0 | 2 | | WRR | 0 | 2 | | ~~~RRR~~ | 1 | 0 | - - That wipes out all but five solutions. Notice how the entire right column of solutions - is eliminated, including our original guess of `RBW`, therefore eliminating any - special case to specifically eliminate this guess from the solution set when we first find out - its not the answer. - - Continuing on, we have the following solutions left of which our secret code, `BWB` - is one of them. Remember our commutative property explained previously. - -| Guess | Black | White | -|-------|-------|-------| -| BWB | 0 | 2 | -| BRB | 0 | 2 | -| BRR | 0 | 2 | -| WWB | 0 | 2 | -| WRR | 0 | 2 | - -So for its second pick, the computer will randomly pick one of these remaining solutions. Let's pick -the middle one, `BRR`, and perform the same ritual. Our user reports to the computer -that it now has 1 black, 0 whites when comparing to our secret code `BWB`. Let's -now compare `BRR` to the remaining five solutions and eliminate any that **DON'T** -report 1 black and 0 whites. - -| Guess | Black | White | -|----------|-------|-------| -| BWB | 1 | 0 | -| ~~~BRB~~ | 2 | 0 | -| ~~~BRR~~ | 3 | 0 | -| ~~~WWB~~ | 0 | 1 | -| ~~~WRR~~ | 2 | 0 | - -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. -This is because it is winnowing down the solutions -logarithmically on average. You noticed on the first pass, it wiped out 22 -solutions. If it was doing this logarithmically the worst case guess would -still eliminate 18 of the solutions leaving 9 (32). So we have as -a guideline: - - Log(# of Colors)TotalPossibilities - -but TotalPossibilities = (# of Colors)# of Positions - -so you end up with the number of positions as a guess limit. If you consider the -simplest non-trivial puzzle, two colors with two positions, and you guess BW or -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. - -#### 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.) +was changed to: + +`1060 IF B1>B OR W1>W THEN I(X)=0` + +This was done because of a bug: + +Originally, after guessing and getting feedback, the computer would look through every possible combination, and for all that haven't previously been marked as impossible it would check whether or not the black and white pins that that combination should get are not-equal to what its previous guess got and, if they are equal, the combination would be marked as possible, and if they aren't equal then the combination would be marked as impossible. This results in a bug where the computer eliminates the correct answer as a possible solution after the first guess, unless the first guess just happens to be correct. + +this was discussed in more detail in [issue #611](https://github.com/coding-horror/basic-computer-games/issues/611) + +additionally, it's recommended that you have the computer elimate it's previous guess as possible unless that guess was correct. (the rust port does this) diff --git a/60_Mastermind/csharp/Program.cs b/60_Mastermind/csharp/Program.cs index 13f525d7c..596b552dc 100644 --- a/60_Mastermind/csharp/Program.cs +++ b/60_Mastermind/csharp/Program.cs @@ -152,7 +152,7 @@ bool ComputerTakesTurn() if (isCandidate[index]) { var (candidateBlacks, candidateWhites) = guess.Compare(candidate); - if (blacks != candidateBlacks || whites != candidateWhites) + if (blacks > candidateBlacks || whites > candidateWhites) isCandidate[index] = false; } } diff --git a/60_Mastermind/java/Mastermind.java b/60_Mastermind/java/Mastermind.java deleted file mode 100644 index a8b7d4223..000000000 --- a/60_Mastermind/java/Mastermind.java +++ /dev/null @@ -1,423 +0,0 @@ -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.List; -import java.util.Objects; -import java.util.Random; -import java.util.Scanner; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -/** - * A port of the BASIC Mastermind game in java. - * - * Differences between this and the original BASIC: - * Uses a number base conversion approach to converting solution ids to - * color code strings. The original performs an inefficient add by 1 - * with carry technique where every carry increments the next positions - * color id. - * - * Implements a ceiling check on the number of positions in a secret code - * to not run out of memory. Because of the algorithm that the computer - * uses to deduce the players secret code, it searches through the entire - * possible spectrum of solutions. This can be a very large number because - * it's (number of colors) ^ (number of positions). The original will - * happily try to allocate all the memory on the system if this number is - * too large. If it did successfully allocate the memory on a large solution - * set then it would also take too long to compute code strings via its - * technique mentioned in the previous note. - * - * An extra message is given at the start to alert the player to the - * BOARD and QUIT commands. - */ -public class Mastermind { - final Random random = new Random(); - // some less verbose printing methods - static private void pf(String s, Object... o){ System.out.printf(s, o);} - static private void pl(String s){System.out.println(s);} - static private void pl(){System.out.println();} - - public static void main(String[] args) { - title(); - Mastermind game = setup(); - game.play(); - } - - /** - * The eight possible color codes. - */ - private enum Color { - B("BLACK"), W("WHITE"), R("RED"), G("GREEN"), - O("ORANGE"), Y("YELLOW"), P("PURPLE"), T("TAN"); - public final String name; - - Color(String name) { - this.name = name; - } - } - - /** - * Represents a guess and the subsequent number of colors in the correct - * position (blacks), and the number of colors present but not in the correct - * position (whites.) - */ - private record Guess(int guessNum, String guess, int blacks, int whites){} - - - private void play() { - IntStream.rangeClosed(1,rounds).forEach(this::playRound); - pl("GAME OVER"); - pl("FINAL SCORE: "); - pl(getScore()); - } - - /** - * Builder-ish pattern for creating Mastermind game - * @return Mastermind game object - */ - private static Mastermind setup() { - int numOfColors; - pf("NUMBER OF COLORS? > "); - numOfColors = getPositiveNumberUpTo(Color.values().length); - int maxPositions = getMaxPositions(numOfColors); - pf("NUMBER OF POSITIONS (MAX %d)? > ", maxPositions); - int positions = getPositiveNumberUpTo(maxPositions); - pf("NUMBER OF ROUNDS? > "); - int rounds = getPositiveNumber(); - pl("ON YOUR TURN YOU CAN ENTER 'BOARD' TO DISPLAY YOUR PREVIOUS GUESSES,"); - pl("OR 'QUIT' TO GIVE UP."); - return new Mastermind(numOfColors, positions, rounds, 10); - } - - /** - * Computes the number of allowable positions to prevent the total possible - * solution set that the computer has to check to a reasonable number, and - * to prevent out of memory errors. - * - * The computer guessing algorithm uses a BitSet which has a limit of 2^31 - * bits (Integer.MAX_VALUE bits). Since the number of possible solutions to - * any mastermind game is (numColors) ^ (numPositions) we need find the - * maximum number of positions by finding the Log|base-NumOfColors|(2^31) - * - * @param numOfColors number of different colors - * @return max number of positions in the secret code. - */ - private static int getMaxPositions(int numOfColors){ - return (int)(Math.log(Integer.MAX_VALUE)/Math.log(numOfColors)); - } - - final int numOfColors, positions, rounds, possibilities; - int humanMoves, computerMoves; - final BitSet solutionSet; - final Color[] colors; - final int maxTries; - - // A recording of human guesses made during the round for the BOARD command. - final List guesses = new ArrayList<>(); - - // A regular expression to validate user guess strings - final String guessValidatorRegex; - - public Mastermind(int numOfColors, int positions, int rounds, int maxTries) { - this.numOfColors = numOfColors; - this.positions = positions; - this.rounds = rounds; - this.maxTries = maxTries; - this.humanMoves = 0; - this.computerMoves = 0; - String colorCodes = Arrays.stream(Color.values()) - .limit(numOfColors) - .map(Color::toString) - .collect(Collectors.joining()); - // regex that limits the number of color codes and quantity for a guess. - this.guessValidatorRegex = "^[" + colorCodes + "]{" + positions + "}$"; - this.colors = Color.values(); - this.possibilities = (int) Math.round(Math.pow(numOfColors, positions)); - pf("TOTAL POSSIBILITIES =% d%n", possibilities); - this.solutionSet = new BitSet(possibilities); - displayColorCodes(numOfColors); - } - - private void playRound(int round) { - pf("ROUND NUMBER % d ----%n%n",round); - humanTurn(); - computerTurn(); - pl(getScore()); - } - - private void humanTurn() { - guesses.clear(); - String secretCode = generateColorCode(); - pl("GUESS MY COMBINATION. \n"); - int guessNumber = 1; - while (true) { // User input loop - pf("MOVE #%d GUESS ?", guessNumber); - final String guess = getWord(); - if (guess.equals(secretCode)) { - guesses.add(new Guess(guessNumber, guess, positions, 0)); - pf("YOU GUESSED IT IN %d MOVES!%n", guessNumber); - humanMoves++; - pl(getScore()); - return; - } else if ("BOARD".equals(guess)) { displayBoard(); - } else if ("QUIT".equals(guess)) { quit(secretCode); - } else if (!validateGuess(guess)) { pl(guess + " IS UNRECOGNIZED."); - } else { - Guess g = evaluateGuess(guessNumber, guess, secretCode); - pf("YOU HAVE %d BLACKS AND %d WHITES.%n", g.blacks(), g.whites()); - guesses.add(g); - humanMoves++; - guessNumber++; - } - if (guessNumber > maxTries) { - pl("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!"); - pl("THE ACTUAL COMBINATION WAS: " + secretCode); - return; - } - } - } - - private void computerTurn(){ - while (true) { - pl("NOW I GUESS. THINK OF A COMBINATION."); - pl("HIT RETURN WHEN READY:"); - solutionSet.set(0, possibilities); // set all bits to true - getInput("RETURN KEY", Scanner::nextLine, Objects::nonNull); - int guessNumber = 1; - while(true){ - if (solutionSet.cardinality() == 0) { - // user has given wrong information, thus we have cancelled out - // any remaining possible valid solution. - pl("YOU HAVE GIVEN ME INCONSISTENT INFORMATION."); - pl("TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL."); - break; - } - // Randomly pick an untried solution. - int solution = solutionSet.nextSetBit(generateSolutionID()); - if (solution == -1) { - solution = solutionSet.nextSetBit(0); - } - String guess = solutionIdToColorCode(solution); - pf("MY GUESS IS: %s BLACKS, WHITES ? ",guess); - int[] bAndWPegs = getPegCount(positions); - if (bAndWPegs[0] == positions) { - pf("I GOT IT IN % d MOVES!%n", guessNumber); - computerMoves+=guessNumber; - return; - } - // wrong guess, first remove this guess from solution set - solutionSet.clear(solution); - int index = 0; - // Cycle through remaining solution set, marking any solutions as invalid - // that don't exactly match what the user said about our guess. - while ((index = solutionSet.nextSetBit(index)) != -1) { - String solutionStr = solutionIdToColorCode(index); - Guess possibleSolution = evaluateGuess(0, solutionStr, guess); - if (possibleSolution.blacks() != bAndWPegs[0] || - possibleSolution.whites() != bAndWPegs[1]) { - solutionSet.clear(index); - } - index++; - } - guessNumber++; - } - } - } - - // tally black and white pegs - private Guess evaluateGuess(int guessNum, String guess, String secretCode) { - int blacks = 0, whites = 0; - char[] g = guess.toCharArray(); - char[] sc = secretCode.toCharArray(); - // An incremented number that marks this position as having been counted - // as a black or white peg already. - char visited = 0x8000; - // Cycle through guess letters and check for color and position match - // with the secretCode. If both match, mark it black. - // Else cycle through remaining secretCode letters and check if color - // matches. If this matches, a preventative check must be made against - // the guess letter matching the secretCode letter at this position in - // case it would be counted as a black in one of the next passes. - for (int j = 0; j < positions; j++) { - if (g[j] == sc[j]) { - blacks++; - g[j] = visited++; - sc[j] = visited++; - } - for (int k = 0; k < positions; k++) { - if (g[j] == sc[k] && g[k] != sc[k]) { - whites++; - g[j] = visited++; - sc[k] = visited++; - } - } - } - return new Guess(guessNum, guess, blacks, whites); - } - - private boolean validateGuess(String guess) { - return guess.length() == positions && guess.matches(guessValidatorRegex); - } - - private String getScore() { - return "SCORE:%n\tCOMPUTER \t%d%n\tHUMAN \t%d%n" - .formatted(computerMoves, humanMoves); - } - - private void printGuess(Guess g){ - pf("% 3d%9s% 15d% 10d%n",g.guessNum(),g.guess(),g.blacks(),g.whites()); - } - - private void displayBoard() { - pl(); - pl("BOARD"); - pl("MOVE GUESS BLACK WHITE"); - guesses.forEach(this::printGuess); - pl(); - } - - private void quit(String secretCode) { - pl("QUITTER! MY COMBINATION WAS: " + secretCode); - pl("GOOD BYE"); - System.exit(0); - } - - /** - * Generates a set of color codes randomly. - */ - private String generateColorCode() { - int solution = generateSolutionID(); - return solutionIdToColorCode(solution); - } - - /** - * From the total possible number of solutions created at construction, choose - * one randomly. - * - * @return one of many possible solutions - */ - private int generateSolutionID() { - return random.nextInt(0, this.possibilities); - } - - /** - * Given the number of colors and positions in a secret code, decode one of - * those permutations, a solution number, into a string of letters - * representing colored pegs. - * - * The pattern can be decoded easily as a number with base `numOfColors` and - * `positions` representing the digits. For example if numOfColors is 5 and - * positions is 3 then the pattern is converted to a number that is base 5 - * with three digits. Each digit then maps to a particular color. - * - * @param solution one of many possible solutions - * @return String representing this solution's color combination. - */ - private String solutionIdToColorCode(final int solution) { - StringBuilder secretCode = new StringBuilder(); - int pos = possibilities; - int remainder = solution; - for (int i = positions - 1; i > 0; i--) { - pos = pos / numOfColors; - secretCode.append(colors[remainder / pos].toString()); - remainder = remainder % pos; - } - secretCode.append(colors[remainder].toString()); - return secretCode.toString(); - } - - private static void displayColorCodes(int numOfColors) { - pl("\n\nCOLOR LETTER\n===== ======"); - Arrays.stream(Color.values()) - .limit(numOfColors) - .map(c -> c.name + " ".repeat(13 - c.name.length()) + c) - .forEach(Mastermind::pl); - pl();pl(); - } - - private static void title() { - pl(""" - MASTERMIND - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY%n%n%n - """); - } - - ///////////////////////////////////////////////////////// - // User input functions from here on - - /** - * Base input function to be called from a specific input function. - * Re-prompts upon unexpected or invalid user input. - * Discards any remaining input in the line of user entered input once - * it gets what it wants. - * @param descriptor Describes explicit type of input expected - * @param extractor The method performed against a Scanner object to parse - * the type of input. - * @param conditional A test that the input meets a minimum validation. - * @param Input type returned. - * @return input type for this line of user input. - */ - private static T getInput(String descriptor, - Function extractor, - Predicate conditional) { - - Scanner scanner = new Scanner(System.in); - while (true) { - try { - T input = extractor.apply(scanner); - if (conditional.test(input)) { - return input; - } - } catch (Exception ex) { - try { - // If we are here then a call on the scanner was most likely unable to - // parse the input. We need to flush whatever is leftover from this - // line of interactive user input so that we can re-prompt for new input. - scanner.nextLine(); - } catch (Exception ns_ex) { - // if we are here then the input has been closed, or we received an - // EOF (end of file) signal, usually in the form of a ctrl-d or - // in the case of Windows, a ctrl-z. - pl("END OF INPUT, STOPPING PROGRAM."); - System.exit(1); - } - } - pf("!%s EXPECTED - RETRY INPUT LINE%n? ", descriptor); - } - } - - private static int getPositiveNumber() { - return getInput("NUMBER", Scanner::nextInt, num -> num > 0); - } - - private static int getPositiveNumberUpTo(long to) { - return getInput( - "NUMBER FROM 1 TO " + to, - Scanner::nextInt, - num -> num > 0 && num <= to); - } - - private static int[] getPegCount(int upperBound) { - int[] nums = {Integer.MAX_VALUE, Integer.MAX_VALUE}; - while (true) { - String input = getInput( - "NUMBER, NUMBER", - Scanner::nextLine, - s -> s.matches("\\d+[\\s,]+\\d+$")); - String[] numbers = input.split("[\\s,]+"); - nums[0] = Integer.parseInt(numbers[0].trim()); - nums[1] = Integer.parseInt(numbers[1].trim()); - if (nums[0] <= upperBound && nums[1] <= upperBound && - nums[0] >= 0 && nums[1] >= 0) { - return nums; - } - pf("NUMBERS MUST BE FROM 0 TO %d.%n? ", upperBound); - } - } - - private static String getWord() { - return getInput("WORD", Scanner::next, word -> !"".equals(word)); - } -} diff --git a/60_Mastermind/javascript/mastermind.js b/60_Mastermind/javascript/mastermind.js index 1fbd13ec2..5c91575bf 100644 --- a/60_Mastermind/javascript/mastermind.js +++ b/60_Mastermind/javascript/mastermind.js @@ -343,7 +343,7 @@ async function main() copy_hs(); convert_qa(); get_number(); - if (b1 != b || w1 != w) + if (b1 > b || w1 > w) ia[x] = 0; } } diff --git a/60_Mastermind/mastermind.bas b/60_Mastermind/mastermind.bas index e6d548935..215cdd186 100644 --- a/60_Mastermind/mastermind.bas +++ b/60_Mastermind/mastermind.bas @@ -113,7 +113,7 @@ 1035 GOSUB 6500 1040 GOSUB 4000 1050 GOSUB 4500 -1060 IF B1<>B OR W1<>W THEN I(X)=0 +1060 IF B1>B OR W1>W THEN I(X)=0 1070 NEXT X 1080 NEXT M 1090 PRINT "I USED UP ALL MY MOVES!" diff --git a/60_Mastermind/python/mastermind.py b/60_Mastermind/python/mastermind.py index 8fcecc624..94b923856 100644 --- a/60_Mastermind/python/mastermind.py +++ b/60_Mastermind/python/mastermind.py @@ -1,226 +1,271 @@ -import random -import sys -from typing import List, Union, Tuple - - -# define some parameters for the game which should not be modified. -def setup_game() -> Tuple[int, int, int, int]: - print(""" - MASTERMIND - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - - - - """) - # get user inputs for game conditions - num_colors: int = len(COLOR_LETTERS) + 1 - while num_colors > len(COLOR_LETTERS): - num_colors = int(input("Number of colors (max 8): ")) # C9 in BASIC - num_positions = int(input("Number of positions: ")) # P9 in BASIC - num_rounds = int(input("Number of rounds: ")) # R9 in BASIC - possibilities = num_colors**num_positions - - print(f"Number of possibilities {possibilities}") - print("Color\tLetter") - print("=====\t======") - for element in range(0, num_colors): - print(f"{COLORS[element]}\t{COLORS[element][0]}") - return num_colors, num_positions, num_rounds, possibilities - - -# Global variables -COLORS = ["BLACK", "WHITE", "RED", "GREEN", "ORANGE", "YELLOW", "PURPLE", "TAN"] -COLOR_LETTERS = "BWRGOYPT" -NUM_COLORS, NUM_POSITIONS, NUM_ROUNDS, POSSIBILITIES = setup_game() -human_score = 0 -computer_score = 0 - - -def main() -> None: - current_round = 1 - while current_round <= NUM_ROUNDS: - print(f"Round number {current_round}") - human_turn() - computer_turn() - current_round += 1 - print_score(is_final_score=True) - sys.exit() - - -def human_turn() -> None: - global human_score - num_moves = 1 - guesses: List[List[Union[str, int]]] = [] - print("Guess my combination ...") - secret_combination = int(POSSIBILITIES * random.random()) - answer = possibility_to_color_code(secret_combination) - while True: - print(f"Move # {num_moves} Guess : ") - user_command = input("Guess ") - if user_command == "BOARD": - print_board(guesses) # 2000 - elif user_command == "QUIT": # 2500 - print(f"QUITTER! MY COMBINATION WAS: {answer}") - print("GOOD BYE") - quit() - elif len(user_command) != NUM_POSITIONS: # 410 - print("BAD NUMBER OF POSITIONS") - else: - invalid_letters = get_invalid_letters(user_command) - if invalid_letters > "": - print(f"INVALID GUESS: {invalid_letters}") - else: - guess_results = compare_two_positions(user_command, answer) - if guess_results[1] == NUM_POSITIONS: # correct guess - print(f"You guessed it in {num_moves} moves!") - human_score = human_score + num_moves - print_score() - return # from human turn, triumphant - else: - print(f"You have {guess_results[1]} blacks and {guess_results[2]} whites") - guesses.append(guess_results) - num_moves += 1 - - if num_moves > 10: # RAN OUT OF MOVES - print("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!") - print(f"THE ACTUAL COMBINATION WAS: {answer}") - human_score = human_score + num_moves - print_score() - return # from human turn, defeated - - -def computer_turn() -> None: - global computer_score - while True: - all_possibilities = [1] * POSSIBILITIES - num_moves = 1 - print("NOW I GUESS. THINK OF A COMBINATION.") - input("HIT RETURN WHEN READY: ") - while True: - possible_guess = find_first_solution_of(all_possibilities) - if possible_guess < 0: # no solutions left :( - print("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.") - print("TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.") - break # out of inner while loop, restart computer turn - - computer_guess = possibility_to_color_code(possible_guess) - print(f"My guess is: {computer_guess}") - blacks_str, whites_str = input( - "ENTER BLACKS, WHITES (e.g. 1,2): " - ).split(",") - blacks = int(blacks_str) - whites = int(whites_str) - if blacks == NUM_POSITIONS: # Correct guess - print(f"I GOT IT IN {num_moves} MOVES") - computer_score = computer_score + num_moves - print_score() - return # from computer turn - - # computer guessed wrong, deduce which solutions to eliminate. - for i in range(0, POSSIBILITIES): - if all_possibilities[i] == 0: # already ruled out - continue - possible_answer = possibility_to_color_code(i) - comparison = compare_two_positions( - possible_answer, computer_guess - ) - if (blacks != comparison[1]) or (whites != comparison[2]): - all_possibilities[i] = 0 - - if num_moves == 10: - print("I USED UP ALL MY MOVES!") - print("I GUESS MY CPU IS JUST HAVING AN OFF DAY.") - computer_score = computer_score + num_moves - print_score() - return # from computer turn, defeated. - num_moves += 1 - - -def find_first_solution_of(all_possibilities: List[int]) -> int: - """Scan through all_possibilities for first remaining non-zero marker, - starting from some random position and wrapping around if needed. - If not found return -1.""" - start = int(POSSIBILITIES * random.random()) - for i in range(0, POSSIBILITIES): - solution = (i + start) % POSSIBILITIES - if all_possibilities[solution]: - return solution - return -1 - - -# 470 -def get_invalid_letters(user_command) -> str: - """Makes sure player input consists of valid colors for selected game configuration.""" - valid_colors = COLOR_LETTERS[:NUM_COLORS] - invalid_letters = "" - for letter in user_command: - if letter not in valid_colors: - invalid_letters = invalid_letters + letter - return invalid_letters - - -# 2000 -def print_board(guesses) -> None: - """Print previous guesses within the round.""" - print("Board") - print("Move\tGuess\tBlack White") - for idx, guess in enumerate(guesses): - print(f"{idx + 1}\t{guess[0]}\t{guess[1]} {guess[2]}") - - -def possibility_to_color_code(possibility: int) -> str: - """Accepts a (decimal) number representing one permutation in the realm of - possible secret codes and returns the color code mapped to that permutation. - This algorithm is essentially converting a decimal number to a number with - a base of #num_colors, where each color code letter represents a digit in - that #num_colors base.""" - color_code: str = "" - pos: int = NUM_COLORS ** NUM_POSITIONS # start with total possibilities - remainder = possibility - for _ in range(NUM_POSITIONS - 1, 0, -1): # process all but the last digit - pos = pos // NUM_COLORS - color_code += COLOR_LETTERS[remainder // pos] - remainder = remainder % pos - color_code += COLOR_LETTERS[remainder] # last digit is what remains - return color_code - - -# 4500 -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).""" - 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 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:] - increment = increment + 2 - else: # correct color and placement - blacks = blacks + 1 - # THIS IS DEVIOUSLY CLEVER - guess = guess[:pos] + chr(increment + 1) + guess[pos + 1:] - answer = answer[:pos] + chr(increment) + answer[pos + 1:] - increment = increment + 2 - return [initial_guess, blacks, whites] - - -# 5000 + logic from 1160 -def print_score(is_final_score: bool = False) -> None: - """Print score after each turn ends, including final score at end of game.""" - if is_final_score: - print("GAME OVER") - print("FINAL SCORE:") - else: - print("SCORE:") - print(f" COMPUTER {computer_score}") - print(f" HUMAN {human_score}") - - -if __name__ == "__main__": - main() +import random +import sys +from typing import List, Union + +# Global variables +colors = ["BLACK", "WHITE", "RED", "GREEN", "ORANGE", "YELLOW", "PURPLE", "TAN"] +color_letters = "BWRGOYPT" +num_positions = 0 +num_colors = 100 +human_score = 0 +computer_score = 0 + + +def main() -> None: + global colors, color_letters, num_positions, num_colors, human_score, computer_score + colors = ["BLACK", "WHITE", "RED", "GREEN", "ORANGE", "YELLOW", "PURPLE", "TAN"] + color_letters = "BWRGOYPT" + + num_colors = 100 + human_score = 0 + computer_score = 0 + + # get user inputs for game conditions + print("Mastermind") + print("Creative Computing Morristown, New Jersey") + while num_colors > 8: + num_colors = int(input("Number of colors (max 8): ")) # C9 in BASIC + num_positions = int(input("Number of positions: ")) # P9 in BASIC + num_rounds = int(input("Number of rounds: ")) # R9 in BASIC + possibilities = num_colors**num_positions + all_possibilities = [1] * possibilities + + print(f"Number of possibilities {possibilities}") + print("Color\tLetter") + print("=====\t======") + for element in range(0, num_colors): + print(f"{colors[element]}\t{colors[element][0]}") + + current_round = 1 + + while current_round <= num_rounds: + print(f"Round number {current_round}") + num_moves = 1 + guesses: List[List[Union[str, int]]] = [] + turn_over = False + print("Guess my combination ...") + answer = int(possibilities * random.random()) + numeric_answer = [-1] * num_positions + for _ in range(0, answer): + numeric_answer = get_possibility(numeric_answer) + # human_readable_answer = make_human_readable(numeric_answer, color_letters) + while num_moves < 10 and not turn_over: + print(f"Move # {num_moves} Guess : ") + user_command = input("Guess ") + if user_command == "BOARD": + print_board(guesses) # 2000 + elif user_command == "QUIT": # 2500 + human_readable_answer = make_human_readable( + numeric_answer, color_letters + ) + print(f"QUITTER! MY COMBINATION WAS: {human_readable_answer}") + print("GOOD BYE") + quit() + elif len(user_command) != num_positions: # 410 + print("BAD NUMBER OF POSITIONS") + else: + invalid_letters = get_invalid_letters(user_command) + if invalid_letters > "": + print(f"INVALID GUESS: {invalid_letters}") + else: + guess_results = compare_two_positions( + user_command, make_human_readable(numeric_answer, color_letters) + ) + print(f"Results: {guess_results}") + if guess_results[1] == num_positions: # correct guess + turn_over = True + print(f"You guessed it in {num_moves} moves!") + human_score = human_score + num_moves + print_score(computer_score, human_score) + else: + print( + "You have {} blacks and {} whites".format( + guess_results[1], guess_results[2] + ) + ) + num_moves = num_moves + 1 + guesses.append(guess_results) + if not turn_over: # RAN OUT OF MOVES + print("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!") + print( + "THE ACTUAL COMBINATION WAS: {}".format( + make_human_readable(numeric_answer, color_letters) + ) + ) + human_score = human_score + num_moves + print_score(computer_score, human_score) + + # COMPUTER TURN + guesses = [] + turn_over = False + inconsistent_information = False + while not turn_over and not inconsistent_information: + all_possibilities = [1] * possibilities + num_moves = 1 + inconsistent_information = False + print("NOW I GUESS. THINK OF A COMBINATION.") + input("HIT RETURN WHEN READY: ") + while num_moves < 10 and not turn_over and not inconsistent_information: + found_guess = False + computer_guess = int(possibilities * random.random()) + if ( + all_possibilities[computer_guess] == 1 + ): # random guess is possible, use it + found_guess = True + guess = computer_guess + else: + for i in range(computer_guess, possibilities): + if all_possibilities[i] == 1: + found_guess = True + guess = i + break + if not found_guess: + for i in range(0, computer_guess): + if all_possibilities[i] == 1: + found_guess = True + guess = i + break + if not found_guess: # inconsistent info from user + print("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.") + print("TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.") + turn_over = True + inconsistent_information = True + else: + numeric_guess = [-1] * num_positions + for _ in range(0, guess): + numeric_guess = get_possibility(numeric_guess) + human_readable_guess = make_human_readable( + numeric_guess, color_letters + ) + print(f"My guess is: {human_readable_guess}") + blacks_str, whites_str = input( + "ENTER BLACKS, WHITES (e.g. 1,2): " + ).split(",") + blacks = int(blacks_str) + whites = int(whites_str) + if blacks == num_positions: # Correct guess + print(f"I GOT IT IN {num_moves} MOVES") + turn_over = True + computer_score = computer_score + num_moves + print_score(computer_score, human_score) + else: + num_moves += 1 + for i in range(0, possibilities): + if all_possibilities[i] == 0: # already ruled out + continue + numeric_possibility = [-1] * num_positions + for _ in range(0, i): + numeric_possibility = get_possibility( + numeric_possibility + ) + human_readable_possibility = make_human_readable( + numeric_possibility, color_letters + ) # 4000 + comparison = compare_two_positions( + human_readable_possibility, human_readable_guess + ) + print(comparison) + if (blacks > comparison[1]) or (whites > comparison[2]): # type: ignore + all_possibilities[i] = 0 + if not turn_over: # COMPUTER DID NOT GUESS + print("I USED UP ALL MY MOVES!") + print("I GUESS MY CPU IS JUST HAVING AN OFF DAY.") + computer_score = computer_score + num_moves + print_score(computer_score, human_score) + current_round += 1 + print_score(computer_score, human_score, is_final_score=True) + sys.exit() + + +# 470 +def get_invalid_letters(user_command): + """Makes sure player input consists of valid colors for selected game configuration.""" + valid_colors = color_letters[:num_colors] + invalid_letters = "" + for letter in user_command: + if letter not in valid_colors: + invalid_letters = invalid_letters + letter + return invalid_letters + + +# 2000 +def print_board(guesses) -> None: + """Prints previous guesses within the round.""" + print("Board") + print("Move\tGuess\tBlack White") + for idx, guess in enumerate(guesses): + print(f"{idx + 1}\t{guess[0]}\t{guess[1]} {guess[2]}") + + +# 3500 +# Easily the place for most optimization, since they generate every possibility +# every time when checking for potential solutions +# From the original article: +# "We did try a version that kept an actual list of all possible combinations +# (as a string array), which was significantly faster than this versionn but +# which ate tremendous amounts of memory." +def get_possibility(possibility): + # print(possibility) + if possibility[0] > -1: # 3530 + current_position = 0 # Python arrays are zero-indexed + while True: + if possibility[current_position] < num_colors - 1: # zero-index again + possibility[current_position] += 1 + return possibility + else: + possibility[current_position] = 0 + current_position += 1 + else: # 3524 + possibility = [0] * num_positions + return possibility + + +# 4500 +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 + 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 + whites = whites + 1 + answer = answer[:pos2] + chr(increment) + answer[pos2 + 1 :] + guess = guess[:pos] + chr(increment + 1) + guess[pos + 1 :] + increment = increment + 2 + else: # correct color and placement + blacks = blacks + 1 + # THIS IS DEVIOUSLY CLEVER + guess = guess[:pos] + chr(increment + 1) + guess[pos + 1 :] + answer = answer[:pos] + chr(increment) + answer[pos + 1 :] + increment = increment + 2 + return [initial_guess, blacks, whites] + + +# 5000 + logic from 1160 +def print_score(computer_score, human_score, is_final_score: bool = False) -> None: + """Prints score after each turn ends, including final score at end of game.""" + if is_final_score: + print("GAME OVER") + print("FINAL SCORE:") + else: + print("SCORE:") + print(f" COMPUTER {computer_score}") + print(f" HUMAN {human_score}") + + +# 4000, 5500, 6000 subroutines are all identical +def make_human_readable(num: List[int], color_letters) -> str: + """Make the numeric representation of a position human readable.""" + retval = "" + for i in range(0, len(num)): + retval = retval + color_letters[int(num[i])] + return retval + + +if __name__ == "__main__": + main() diff --git a/09_Battle/rust/Cargo.toml b/60_Mastermind/rust/Cargo.toml similarity index 100% rename from 09_Battle/rust/Cargo.toml rename to 60_Mastermind/rust/Cargo.toml diff --git a/60_Mastermind/rust/Mastermind/Cargo.toml b/60_Mastermind/rust/Mastermind/Cargo.toml deleted file mode 100644 index 83729722a..000000000 --- a/60_Mastermind/rust/Mastermind/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "mastermind" -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/60_Mastermind/rust/Mastermind/README.md b/60_Mastermind/rust/Mastermind/README.md deleted file mode 100644 index 7e85f9a15..000000000 --- a/60_Mastermind/rust/Mastermind/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) diff --git a/60_Mastermind/rust/Mastermind/src/main.rs b/60_Mastermind/rust/Mastermind/src/main.rs deleted file mode 100644 index 92fc852a5..000000000 --- a/60_Mastermind/rust/Mastermind/src/main.rs +++ /dev/null @@ -1,420 +0,0 @@ -use rand::{Rng, prelude::{thread_rng, ThreadRng}}; -use std::{io, fmt::Display, str::FromStr}; - -//DATA -const COLORS: [&str;8] = ["Black ", "White ","Red ","Green ","Orange ","Yellow ", "Purple ", "Tan "]; //all available colors -const LETTERS: &str = "BWRGOYPT"; //letters representing the above colors - -struct CODE { - code: Vec, //maybe use a char array later, idk - -} -impl CODE { - /** - * create generic, empty code - */ - fn new() -> CODE { - return CODE{code: Vec::new()}; - } - /** - * generates and returns a random CODE with the given parameters - */ - fn new_random(rng: &mut ThreadRng, num_colors: usize, num_positions: usize) -> CODE { - //data - let mut code = CODE{code: Vec::new()}; - //generate random combination of colors - for _i in 0..num_positions { - code.code.push(rng.gen_range(0..num_colors)); - } - return code; - } - /** - * converts input_int from base 10 to base num_colors to generate the code - * input_int must be between 0 and num_colors.pow(num_positions) - */ - fn new_from_int(mut input_int: usize, num_colors: usize, num_positions: usize) -> CODE { - //DATA - let mut converted_number:Vec<_> = Vec::new(); - assert!(2 <= num_colors && num_colors <= 36); //if num_colors is outside of this range, things break later on - - //convert input_int into a code by effectively converting input_int from base 10 to base n where n is num_colors, uses some fancy stuff to do this - loop { - converted_number.push(std::char::from_digit((input_int % num_colors) as u32, num_colors as u32).unwrap()); // - input_int /= num_colors; - if input_int == 0 {break} - } - - while converted_number.len() < num_positions {converted_number.push('0');} // fill remaining space with zero's - let converted_number: Vec<_> = converted_number.iter().rev().map(|e| e.to_digit(num_colors as u32).unwrap() as usize).collect(); //reverse the vector and convert it to integers - return CODE{code: converted_number}; - } - /** - * returns a code parsed from the passed string - */ - fn new_from_string(input_string: String, num_colors: usize) -> Option { - let valid_chars = &LETTERS[0..num_colors]; - //DATA - let new_code = CODE{ - code: - input_string.to_ascii_uppercase().chars() //get an iterator with all the chars in input string converted to uppercase - .filter( |c| { valid_chars.contains(*c)}) //remove chars that aren't in LETTERS - .map( |x| -> usize {valid_chars.find(x).expect("invalid character")})//convert all the chars into usizes representing their index in LETTERS - .collect() //wrap this iterator up into a vector - }; - //if code is empty, return None, otherwise return Some(code) - if new_code.code.is_empty() {return None;} - else {return Some(new_code);} - } - - /** - * returns a string containing the code represented as characters - */ - fn _as_human_readible_chars(&self) -> String { - return self.code.iter().map(|i|->char{LETTERS.chars().nth(*i).expect("index out of bounds")}).collect(); - } - /** - * returns a string containing the code represented as words - */ - fn _as_human_readible_words(&self) -> String { - return self.code.iter().map(|i|->&str{COLORS.iter().nth(*i).expect("index out of bounds")}).collect(); - } -} -struct GUESS { - code: CODE, - blacks: usize, - whites: usize, -} -impl GUESS { - /** - * create a new guess, and evaluate it - */ - fn new(code: CODE) -> GUESS { - return GUESS{code:code, blacks:0,whites:0 }; - } - - /** - * evaulates itself for the number of black and white pegs it should have for a given answer - */ - fn evaluate(&mut self, answer:&CODE) { - //data - let mut consumed = vec![false;answer.code.len()]; - - if self.code.code.len() != answer.code.len() { - panic!("only codes of the same length can be compared"); - } - - for i in 0..answer.code.len() { - if self.code.code[i] == answer.code[i] { //correct value correct place - self.blacks += 1; - consumed[i] = true; - } - else { - //check for correct value incorrect place, don't count positions that are already exact matches - for j in 0..answer.code.len() { - if !consumed[j] && self.code.code[i] == answer.code[j] && self.code.code[j] != answer.code[j] { - self.whites += 1; - consumed[j] = true; - break; - } - } - } - } - } -} - -fn main() { - //DATA - let mut rng = thread_rng(); - let num_colors: usize; - let num_positions: usize; - let num_rounds: usize; - let num_guesses: usize; - let total_posibilities: usize; - - let mut human_score: usize = 0; - let mut computer_score: usize = 0; - - //print welcome message - welcome(); - - //ask user for a number of colors, positions, and rounds - num_colors = get_number_from_user_input("NUMBER OF COLORS", "", 1, COLORS.len()); - num_positions = get_number_from_user_input("NUMBER OF POSITIONS", "", 2, 10); - num_rounds = get_number_from_user_input("NUMBER OF ROUNDS", "", 1, 10); - num_guesses = get_number_from_user_input("NUMBER OF GUESSES", "", 10, 0); - - - //print number of posibilities - total_posibilities = num_colors.pow(num_positions as u32); - println!("\nTOTAL POSSIBILITIES = {}\n", total_posibilities); - - //print color letter table - print_color_letter_table(num_colors); - - //game loop - for round_num in 1..=num_rounds { - //data - let mut num_moves: usize = 1; - let mut answer: CODE; - let mut guess: GUESS; - let mut guesses: Vec = Vec::new(); - let mut all_possibilities = vec![true; total_posibilities]; - - - //print round number - println!("\n\nROUND NUMBER: {}", round_num); - - //human player is code-breaker, computer is code-maker - //generate a combination - answer = CODE::new_random(&mut rng, num_colors, num_positions); - //println!("CODE: {:?}", answer._as_human_readible_chars()); //this is for troubleshooting, prints the code converted back into characters - - //round loop - loop { - //loop condition - if num_moves > num_guesses { - println!("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!"); - println!("THE ACTUAL COMBINATION WAS: {}", answer._as_human_readible_chars()); - human_score += num_moves; - print_scores(human_score,computer_score); - break; - } - - //input loop - guess = GUESS::new(loop { - println!("\nMOVE # {} GUESS: ", num_moves); - - //get player move - let mut raw_input = String::new(); //temp variable to store user input - io::stdin().read_line(&mut raw_input).expect("CANNOT READ INPUT!"); //read user input from standard input and store it to raw_input - - //attempt to parse input - if raw_input.trim().eq_ignore_ascii_case("board") { - //print the board state - print_board(&guesses); - continue; //run loop again - } - else if raw_input.trim().eq_ignore_ascii_case("quit") { - //quit the game - println!("QUITTER! MY COMBINATION WAS: {}\nGOOD BYE", answer._as_human_readible_words()); - return; //exit the game - } - else { - //parse input for a code - match CODE::new_from_string(raw_input, num_colors) { - Some(code) => { - //ensure code is correct length - if code.code.len() != num_positions { // if not - println!("BAD NUMBER OF POSITIONS."); - continue; //run loop again - } - else {break code;}//break with the code - }, - None => continue, //run loop again - } - } - }); - - //evaluate guess - guess.evaluate(&answer); - let blacks = guess.blacks; - let whites = guess.whites; - //add guess to the list of guesses - guesses.push(guess); - - //tell human the results - if blacks >= num_positions { //guessed it correctly - println!("YOU GUESSED IT IN {} MOVES!", num_moves); - human_score += num_moves; - print_scores(human_score,computer_score); - break; //break from loop - } else { //didn't - println!("YOU HAVE {} BLACKS AND {} WHITES.", blacks, whites); - //increment moves - num_moves += 1; - } - } - - //computer is code-breaker, human player is code-maker - println!("\nNOW I GUESS. THINK OF A COMBINATION.\nHIT RETURN WHEN READY: "); - //prompt user to give a valid combination #730 - //input loop - answer = loop { - let mut raw_input = String::new(); //temp variable to store user input - io::stdin().read_line(&mut raw_input).expect("CANNOT READ INPUT!"); //read user input from standard input and store it to raw_input - - //attempt to create a code from the user input, if successful break the loop returning the code - if let Some(code) = CODE::new_from_string(raw_input, num_colors) { - if code.code.len() == num_positions {break code;} //exit loop with code - else {println!("CODE MUST HAVE {} POSITIONS", num_positions);continue;} //tell them to try again - } - - println!("INVALID CODE. TRY AGAIN"); //if unsuccessful, this is printed and the loop runs again - }; - - //reset some things in preparation for computer play - guesses.clear(); - num_moves = 0; - //let num_colors = *answer.code.iter().max().unwrap(); //figure out the number of colors from the code | Commented bc we're enforcing that the computer cracks the same size code as the human - //let num_positions = answer.code.len(); //figure out the number of positions from the code | Commented bc we're enforcing that the computer cracks the same size code as the human - - //round loop - loop { - //loop condition - if num_moves > num_guesses { - println!("I USED UP ALL MY MOVES!"); - println!("I GUESS MY CPU IS JUST HAVING AN OFF DAY."); - computer_score += num_moves; - print_scores(human_score,computer_score); - break; - } - - //randomly generate a guess //770 - let mut guess_int = rng.gen_range(0..total_posibilities); - guess = GUESS::new(CODE::new()); - //if it's possible, use it //780 - if all_possibilities[guess_int] { - guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess - } - else {//if it's not possible: - // search all possibilities after guess, use first valid one //790 - for g in guess_int..total_posibilities { - if all_possibilities[g] { - guess_int=g; - guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess - break; - } - } - //if none was found - // search all possibilities before guess, use first valid one //820 - if guess.code.code.is_empty() { - for g in (0..guess_int).rev() { - if all_possibilities[g] { - guess_int=g; - guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess - break; - } - } - } - // if none where found, tell the user and start over #850 - if guess.code.code.is_empty() { - println!("YOU HAVE GIVEN ME INCONSISTENT INFORMATION."); - println!("PLAY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL."); - return; //exit game - }; - } - - //convert guess into something readible #890 - //print it #940 - println!("MY GUESS IS: {}", guess.code._as_human_readible_chars()); - //ask user for feedback, #980 - let blacks=get_number_from_user_input("BLACKS: ", "", 0, num_positions); - let whites=get_number_from_user_input("WHITES: ", "", 0, num_positions); - - //if we got it, end #990 - if blacks >= num_positions { //guessed it correctly - println!("I GOT IT IN {} MOVES!", num_moves); - computer_score += num_moves; - print_scores(human_score,computer_score); - break; //break from loop - } else { //didn't - all_possibilities[guess_int] = false; - //if we didn't, eliminate the combinations that don't work - //we know the number of black and white pegs for a valid answer, so eleminate all that get different amounts - all_possibilities.iter_mut().enumerate().for_each(|b| { - if *b.1 { //filter out ones we already know aren't possible - let mut tmp_guess = GUESS::new(CODE::new_from_int(b.0, num_colors, num_positions)); - tmp_guess.evaluate(&guess.code); //compare with computer guess - if blacks != tmp_guess.blacks || whites != tmp_guess.whites { //if number of blacks/whites is different, set it to false - *b.1 = false; - } - } - }); - - //increment moves - num_moves += 1; - } - - - } - - } -} - -/** - * print the welcome message - */ -fn welcome() { - println!(" - MASTERMIND - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - - - "); -} - -/** - * print scores - */ -fn print_scores(human_score:usize, computer_score:usize) { - println!("SCORE\n\tCOMPUTER: {}\n\tHUMAN: {}", computer_score, human_score); -} - -/** - * print the color - letter table - * only prints the first num_colors pairs - */ -fn print_color_letter_table(num_colors: usize) { - println!("COLOR\tLETTER"); - println!("=====\t======"); - for i in 0..num_colors { - println!("{}\t{}", COLORS[i], &LETTERS[i..i+1]); - } -} - -fn print_board(guesses: &Vec) { - println!("BOARD"); - println!("MOVE\tGUESS\t\tBLACK\tWhite"); - for guess in guesses.iter().enumerate() { - println!("{}\t{}\t\t{}\t{}", guess.0,guess.1.code._as_human_readible_chars(),guess.1.blacks,guess.1.whites); - } -} - -/** - * gets a number from user input - * pass an empty &str for error_message if you don't want one printed - * pass a min lower than the max to have minimun and maximun bounds - * pass a min higher than the max to only have a minumum bound - * pass a min equal to the max to only have a maximun bound - */ -fn get_number_from_user_input(prompt: &str, error_message: &str, min:T, max:T) -> T { - //DATA - let mut raw_input = String::new(); // temporary variable for user input that can be parsed later - - //input loop - return loop { - - //print prompt - println!("{}", prompt); - //read user input from standard input, and store it to raw_input - raw_input.clear(); //clear input - io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); - - //from input, try to read a number - if let Ok(i) = raw_input.trim().parse() { - //what bounds must the input fall into - if min < max { //have a min and max bound: [min,max] - if i >= min && i <= max {//is input valid, within bounds - break i; //exit the loop with the value i, returning it - } else {println!("ONLY BETWEEN {} AND {}, PLEASE!", min, max);} //print error message specific to this case - } else if min > max { //only a min bound: [min, infinity) - if i >= min {break i;} else {println!("NO LESS THAN {}, PLEASE!", min);} - } else { //only a max bound: (-infinity, max] - if i <= max {break i;} else {println!("NO MORE THAN {}, PLEASE!", max);} - } - continue; //continue to the next loop iteration - }; - //this is only reached if a number couldn't be parsed from the input - if !error_message.is_empty() {println!("{}",error_message);} //if they gave an error message to use, print it - }; -} diff --git a/60_Mastermind/rust/Mastermind_refactored_for_conventions/Cargo.toml b/60_Mastermind/rust/Mastermind_refactored_for_conventions/Cargo.toml deleted file mode 100644 index 14762c87e..000000000 --- a/60_Mastermind/rust/Mastermind_refactored_for_conventions/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "mastermind_refactored_for_conventions" -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" \ No newline at end of file diff --git a/60_Mastermind/rust/Mastermind_refactored_for_conventions/README.md b/60_Mastermind/rust/Mastermind_refactored_for_conventions/README.md deleted file mode 100644 index 7e85f9a15..000000000 --- a/60_Mastermind/rust/Mastermind_refactored_for_conventions/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) diff --git a/60_Mastermind/rust/Mastermind_refactored_for_conventions/src/lib.rs b/60_Mastermind/rust/Mastermind_refactored_for_conventions/src/lib.rs deleted file mode 100644 index 1fd92d62a..000000000 --- a/60_Mastermind/rust/Mastermind_refactored_for_conventions/src/lib.rs +++ /dev/null @@ -1,463 +0,0 @@ -/* - lib.rs contains all the logic of the program -*/ -use rand::{Rng, prelude::thread_rng}; //rng -use std::error::Error; //better errors -use std::io::{self, Write}; //io interactions -use std::{str::FromStr, fmt::Display}; //traits - -//DATA -const COLORS: [&str;8] = ["Black ", "White ","Red ","Green ","Orange ","Yellow ", "Purple ", "Tan "]; //all available colors -const LETTERS: &str = "BWRGOYPT"; //letters representing the above colors - -/// handles setup for the game -pub struct Config { - num_colors: usize, - num_positions: usize, - num_rounds: usize, - num_guesses: usize, - total_possibilities: usize, -} -impl Config { - /// creates and returns a new Config from user input - pub fn new() -> Result> { - //DATA - let mut config: Config = Config { - num_colors: 0, - num_positions: 0, - num_rounds: 0, - num_guesses: 0, - total_possibilities: 0, - }; - - //get data from user input - //input loop - loop {match get_number_from_input("NUMBER OF COLORS: ", 2, COLORS.len()) { - Ok(num) => { - config.num_colors = num; - break; - }, - Err(e) => eprintln!("{}",e), - }} - //input loop - loop {match get_number_from_input("NUMBER OF POSITIONS: ", 2, 10) { - Ok(num) => { - config.num_positions = num; - break; - }, - Err(e) => eprintln!("{}",e), - }} - //input loop - loop {match get_number_from_input("NUMBER OF ROUNDS: ", 1, 10) { - Ok(num) => { - config.num_rounds = num; - break; - }, - Err(e) => eprintln!("{}",e), - }} - //input loop - loop {match get_number_from_input("NUMBER OF GUESSES: ", 10, 0) { - Ok(num) => { - config.num_guesses = num; - break; - }, - Err(e) => eprintln!("{}",e), - }} - //calc total posibilities - config.total_possibilities = config.num_colors.pow(config.num_positions as u32); - - //return new config - return Ok(config); - } -} - -/// run the program -pub fn run(config: &Config) -> Result<(), Box> { - //DATA - let mut human_score: usize = 0; - let mut computer_score: usize = 0; - - //print number of possibilities - println!("\nTOTAL POSSIBILITIES = {}\n", config.total_possibilities); - - //print color letter table - print_color_letter_table(config.num_colors); - - //for every round - for round in 1..=config.num_rounds { - //print round number - println!("\n\nROUND NUMBER: {}", round); - - //computer as code-maker - if let Some(score) = play_round_computer_codemaker(config) { - human_score += score; - } else {break;} - - //human as code-maker - if let Some(score) = play_round_human_codemaker(config) { - computer_score += score; - } else {break;} - - //print scores - print_scores(human_score,computer_score); - } - - //return to main - Ok(()) -} - -/// run a round with computer as code-maker -/// returns the number of turns it takes the human to guess the secret code -fn play_round_computer_codemaker(config: &Config) -> Option { - //DATA - let mut rng = thread_rng(); - let mut guesses: Vec = Vec::new(); - let secret: Code; - - //generate secret - secret = Code::new_from_int(rng.gen_range(0..config.num_colors.pow(config.num_positions.try_into().unwrap())), config); - - //round loop - for human_moves in 1..=config.num_guesses { - //get guess from user input - //input loop - let mut guess = loop { - //get input - let user_input = get_string_from_user_input(format!("\nMOVE # {} GUESS: ", human_moves).as_str()).expect("something went wrong getting user guess"); - - //parse input - if user_input.trim().eq_ignore_ascii_case("board") { //print the board state - print_board(&guesses); - continue; //run input loop again - } else if user_input.trim().eq_ignore_ascii_case("quit") { //quit the game - println!("QUITTER! MY COMBINATION WAS: {}\nGOOD BYE", secret.as_human_readible_chars()); - return None; //exit the game - } else { - //parse input for a code - match Code::new_from_string(&user_input, &config) { - Ok(code) => { - //ensure code is correct length - if code.code.len() != config.num_positions { // if not - println!("BAD NUMBER OF POSITIONS."); - continue; //run loop again - } - else {break code;}//break with the code - }, - Err(e) => {eprintln!("{}",e); continue;}, //run loop again - } - } - }; - - //evaluate guess - guess.evaluate(&secret).expect("something went wrong evaluating user guess"); - - //tell user the results - if guess.black_pins >= config.num_positions { //guessed it correctly - println!("YOU GUESSED IT IN {} MOVES!", human_moves); - return Some(human_moves); //exit function - } else { //didn't - println!("YOU HAVE {} BLACKS AND {} WHITES.", guess.black_pins, guess.white_pins); - } - - //add guess to the list of guesses - guesses.push(guess); - } - - //only runs if user doesn't guess the code - println!("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!"); - println!("THE ACTUAL COMBINATION WAS: {}", secret.as_human_readible_chars()); - return Some(config.num_guesses); //max score gain per round -} - -/// run a round with human as code-maker -/// returns the number of turns it takes the computer to guess the secret code -fn play_round_human_codemaker(config: &Config) -> Option{ - //DATA - let mut rng = thread_rng(); - let mut all_possibilities = vec![true; config.total_possibilities]; - let _secret: Code; - - - //get a secret code from user input - println!("\nNOW I GUESS. THINK OF A COMBINATION.\nHIT RETURN WHEN READY: "); - // input loop - _secret = loop { - //get input - let user_input = get_string_from_user_input("").expect("something went wrong getting secret from user"); - - //parse input - if let Ok(code) = Code::new_from_string(&user_input, config) { - if code.code.len() == config.num_positions {break code;} //exit loop with code - else {println!("CODE MUST HAVE {} POSITIONS", config.num_positions);continue;} //tell them to try again - } - println!("INVALID CODE. TRY AGAIN"); //if unsuccessful, this is printed and the loop runs again - }; - - //round loop - for computer_moves in 1..=config.num_guesses { - let mut guess: Code = Code::new(); - - //randomly generate a guess //770 - let mut guess_int = rng.gen_range(0..config.total_possibilities); - // if possible, use it //780 - if all_possibilities[guess_int] { - guess = Code::new_from_int(guess_int, &config); //create guess - } - else {// if not possible: - // search all possibilities after guess, use first valid one //790 - for g in guess_int..config.total_possibilities { - if all_possibilities[g] { - guess_int=g; - guess = Code::new_from_int(guess_int, &config); //create guess - break; - } - } - // if none was found - // search all possibilities before guess, use first valid one //820 - if guess.code.is_empty() { - for g in (0..guess_int).rev() { - if all_possibilities[g] { - guess_int=g; - guess = Code::new_from_int(guess_int, &config); //create guess - break; - } - } - } - - // if none where found, tell the user and start over #850 - if guess.code.is_empty() { - println!("YOU HAVE GIVEN ME INCONSISTENT INFORMATION."); - println!("PLAY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL."); - return None; //exit game - }; - } - - //convert guess into something readible #890 - //print it #940 - println!("MY GUESS IS: {}", guess.as_human_readible_chars()); - - //ask user for feedback, #980 - // input loop for black pegs - loop {match get_number_from_input("BLACKS: ", 0, config.num_positions) { - Ok(num) => { - guess.black_pins = num; - break; - }, - Err(e) => eprintln!("{}",e), - }} - // input loop for white pegs - loop {match get_number_from_input("WHITES: ", 0, config.num_positions) { - Ok(num) => { - guess.white_pins = num; - break; - }, - Err(e) => eprintln!("{}",e), - }} - - //if computer guessed it, end #990 - if guess.black_pins >= config.num_positions { //guessed it correctly - println!("I GOT IT IN {} MOVES!", computer_moves); - return Some(computer_moves); //exit function - } else { //didn't - all_possibilities[guess_int] = false; - //if we didn't, eliminate the combinations that don't work - //we know the number of black and white pegs for a valid answer, so eleminate all that get different amounts - all_possibilities.iter_mut().enumerate().for_each(|b| { - if *b.1 { //filter out ones we already know aren't possible - let mut tmp_guess = Code::new_from_int(b.0, &config); - tmp_guess.evaluate(&guess).expect("something went wrong evaluation the computer's guess"); //compare with computer guess - if (guess.black_pins != tmp_guess.black_pins) || (guess.white_pins != tmp_guess.white_pins) { //if number of blacks/whites is different, set it to false - *b.1 = false; - } - } - }); - } - } - - //only runs if computer doesn't guess the code - println!("I USED UP ALL MY MOVES!"); - println!("I GUESS MY CPU IS JUST HAVING AN OFF DAY."); - return Some(config.num_guesses); //max moves the computer could've taken -} - -struct Code { - code: Vec, - black_pins: usize, - white_pins: usize, -} -impl Code { - /// create generic, empty code - fn new() -> Code { - return Code{code: Vec::new(), black_pins:0, white_pins:0}; - } - /// converts input_int from base 10 to base num_colors to generate the code - /// input_int must be between 0 and num_colors.pow(num_positions) - fn new_from_int(mut input_int: usize, config: &Config) -> Code { - //DATA - let mut converted_number:Vec<_> = Vec::new(); - assert!(2 <= config.num_colors && config.num_colors <= 36); //if num_colors is outside of this range, things break later on - - //convert input_int into a code by effectively converting input_int from base 10 to base n where n is num_colors, uses some fancy stuff to do this - loop { - converted_number.push(std::char::from_digit((input_int % config.num_colors).try_into().unwrap(), config.num_colors.try_into().unwrap()).unwrap()); // - input_int /= config.num_colors; - if input_int == 0 {break} - } - - while converted_number.len() < config.num_positions {converted_number.push('0');} // fill remaining space with zero's - let converted_number: Vec<_> = converted_number.iter().rev().map(|e| e.to_digit(config.num_colors.try_into().unwrap()).unwrap() .try_into().unwrap()).collect(); //reverse the vector and convert it to integers - return Code{code: converted_number, black_pins:0, white_pins:0}; - } - /// returns a code parsed from the passed string - fn new_from_string(input_string: &str, config: &Config) -> Result> { - let valid_chars = &LETTERS[0..config.num_colors]; - //DATA - let new_code = Code{ - code: { - input_string.to_ascii_uppercase().chars() //get an iterator with all the chars in input string converted to uppercase - .filter( |c| { valid_chars.contains(*c)}) //remove chars that aren't in LETTERS - .map( |x| -> usize {valid_chars.find(x).expect("invalid character")})//convert all the chars into usizes representing their index in LETTERS - .collect() //wrap this iterator up into a vector - }, - black_pins: 0, - white_pins: 0, - }; - //if code is empty, return None, otherwise return Some(code) - if new_code.code.is_empty() {return Err(String::from("Input String did not contain enough valid characters").into());} - else {return Ok(new_code);} - } - - /// returns a string containing the code represented as characters - fn as_human_readible_chars(&self) -> String { - return self.code.iter().map(|i|->char{LETTERS.chars().nth(*i).expect("index out of bounds")}).collect(); - } - - /** - * evaulates itself for the number of black and white pegs it should have when compared to a given secret - */ - fn evaluate(&mut self, secret:&Code) -> Result<(),Box> { - //data - let mut consumed = vec![false;secret.code.len()]; - - if self.code.len() != secret.code.len() { - return Err(String::from("only codes of the same length can be compared").into()); - } - - for i in 0..secret.code.len() { - if self.code[i] == secret.code[i] { //correct value correct place - self.black_pins += 1; - consumed[i] = true; - } - else { - //check for correct value incorrect place, don't count positions that are already exact matches - for j in 0..secret.code.len() { - if !consumed[j] && self.code[i] == secret.code[j] && self.code[j] != secret.code[j] { - self.white_pins += 1; - consumed[j] = true; - break; - } - } - } - } - - return Ok(()) - } -} - - - -/// print scores -fn print_scores(human_score:usize, computer_score:usize) { - println!("SCORE\n\tCOMPUTER: {}\n\tHUMAN: {}", computer_score, human_score); -} -/// print the color - letter table -/// only prints the first num_colors pairs -fn print_color_letter_table(num_colors:usize) { - println!("COLOR\tLETTER"); - println!("=====\t======"); - for i in 0..num_colors { - println!("{}\t{}", COLORS[i], &LETTERS[i..i+1]); - } -} -/// prints the board state, previous guesses and the number of black/white pins for each -fn print_board(guesses: &[Code]) { - println!("BOARD"); - println!("MOVE\tGUESS\t\tBLACK\tWhite"); - for guess in guesses.iter().enumerate() { - println!("{}\t{}\t\t{}\t{}", guess.0,guess.1.as_human_readible_chars(),guess.1.black_pins,guess.1.white_pins); - } -} - - - -/// gets a string from user input -fn get_string_from_user_input(prompt: &str) -> Result> { - //DATA - let mut raw_input = String::new(); - - //print prompt - print!("{}", prompt); - //make sure it's printed before getting input - io::stdout().flush().expect("couldn't flush stdout"); - - //read user input from standard input, and store it to raw_input, then return it or an error as needed - raw_input.clear(); //clear input - match io::stdin().read_line(&mut raw_input) { - Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())), - Err(err) => return Err(format!("ERROR: CANNOT READ INPUT!: {}", err).into()), - } -} -/// generic function to get a number from the passed string (user input) -/// pass a min lower than the max to have minimun and maximun bounds -/// pass a min higher than the max to only have a minumum bound -/// pass a min equal to the max to only have a maximun bound -/// -/// Errors: -/// no number on user input -fn get_number_from_input(prompt: &str, min:T, max:T) -> Result> { - //DATA - let raw_input: String; - let processed_input: String; - - - //input looop - raw_input = loop { - match get_string_from_user_input(prompt) { - Ok(input) => break input, - Err(e) => { - eprintln!("{}",e); - continue; - }, - } - }; - - //filter out num-numeric characters from user input - processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect(); - - //from input, try to read a number - match processed_input.trim().parse() { - Ok(i) => { - //what bounds must the input fall into - if min < max { //have a min and max bound: [min,max] - if i >= min && i <= max {//is input valid, within bounds - return Ok(i); //exit the loop with the value i, returning it - } else { //print error message specific to this case - return Err(format!("ONLY BETWEEN {} AND {}, PLEASE!", min, max).into()); - } - } else if min > max { //only a min bound: [min, infinity) - if i >= min { - return Ok(i); - } else { - return Err(format!("NO LESS THAN {}, PLEASE!", min).into()); - } - } else { //only a max bound: (-infinity, max] - if i <= max { - return Ok(i); - } else { - return Err(format!("NO MORE THAN {}, PLEASE!", max).into()); - } - } - }, - Err(_e) => return Err(format!("Error: couldn't find a valid number in {}",raw_input).into()), - } -} diff --git a/60_Mastermind/rust/Mastermind_refactored_for_conventions/src/main.rs b/60_Mastermind/rust/Mastermind_refactored_for_conventions/src/main.rs deleted file mode 100644 index 5a5d01295..000000000 --- a/60_Mastermind/rust/Mastermind_refactored_for_conventions/src/main.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::process;//allows for some better error handling - -mod lib; //allows access to lib.rs -use lib::Config; - -/// main function -/// responsibilities: -/// - Calling the command line logic with the argument values -/// - Setting up any other configuration -/// - Calling a run function in lib.rs -/// - Handling the error if run returns an error -fn main() { - //greet user - welcome(); - - // set up other configuration - let mut config = Config::new().unwrap_or_else(|err| { - eprintln!("Problem configuring program: {}", err); - process::exit(1); - }); - - // run the program - if let Err(e) = lib::run(&mut config) { - eprintln!("Application Error: {}", e); //use the eprintln! macro to output to standard error - process::exit(1); //exit the program with an error code - } - - //end of program - println!("THANKS FOR PLAYING!"); -} - -/// print the welcome message -fn welcome() { - println!(" - MASTERMIND - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - - - "); -} diff --git a/24_Chemist/rust/README.md b/60_Mastermind/rust/README.md similarity index 100% rename from 24_Chemist/rust/README.md rename to 60_Mastermind/rust/README.md diff --git a/60_Mastermind/rust/src/main.rs b/60_Mastermind/rust/src/main.rs new file mode 100644 index 000000000..5bef7f975 --- /dev/null +++ b/60_Mastermind/rust/src/main.rs @@ -0,0 +1,421 @@ +use rand::{Rng, prelude::{thread_rng, ThreadRng}}; +use std::{io, fmt::Display, str::FromStr}; + +//DATA +const COLORS: [&str;8] = ["Black ", "White ","Red ","Green ","Orange ","Yellow ", "Purple ", "Tan "]; //all available colors +const LETTERS: &str = "BWRGOYPT"; //letters representing the above colors + +struct CODE { + code: Vec, //maybe use a char array later, idk + +} +impl CODE { + /** + * create generic, empty code + */ + fn new() -> CODE { + return CODE{code: Vec::new()}; + } + /** + * generates and returns a random CODE with the given parameters + */ + fn new_random(rng: &mut ThreadRng, num_colors: usize, num_positions: usize) -> CODE { + //data + let mut code = CODE{code: Vec::new()}; + //generate random combination of colors + for _i in 0..num_positions { + code.code.push(rng.gen_range(0..num_colors)); + } + return code; + } + /** + * converts input_int from base 10 to base num_colors to generate the code + * input_int must be between 0 and num_colors.pow(num_positions) + */ + fn new_from_int(mut input_int: usize, num_colors: usize, num_positions: usize) -> CODE { + //DATA + let mut converted_number:Vec<_> = Vec::new(); + assert!(2 <= num_colors && num_colors <= 36); //if num_colors is outside of this range, things break later on + + //convert input_int into a code by effectively converting input_int from base 10 to base n where n is num_colors, uses some fancy stuff to do this + loop { + converted_number.push(std::char::from_digit((input_int % num_colors) as u32, num_colors as u32).unwrap()); // + input_int /= num_colors; + if input_int == 0 {break} + } + + while converted_number.len() < num_positions {converted_number.push('0');} // fill remaining space with zero's + let converted_number: Vec<_> = converted_number.iter().rev().map(|e| e.to_digit(num_colors as u32).unwrap() as usize).collect(); //reverse the vector and convert it to integers + return CODE{code: converted_number}; + } + /** + * returns a code parsed from the passed string + */ + fn new_from_string(input_string: String, num_colors: usize) -> Option { + let valid_chars = &LETTERS[0..num_colors]; + //DATA + let new_code = CODE{ + code: + input_string.to_ascii_uppercase().chars() //get an iterator with all the chars in input string converted to uppercase + .filter( |c| { valid_chars.contains(*c)}) //remove chars that aren't in LETTERS + .map( |x| -> usize {valid_chars.find(x).expect("invalid character")})//convert all the chars into usizes representing their index in LETTERS + .collect() //wrap this iterator up into a vector + }; + //if code is empty, return None, otherwise return Some(code) + if new_code.code.is_empty() {return None;} + else {return Some(new_code);} + } + + /** + * returns a string containing the code represented as characters + */ + fn _as_human_readible_chars(&self) -> String { + return self.code.iter().map(|i|->char{LETTERS.chars().nth(*i).expect("index out of bounds")}).collect(); + } + /** + * returns a string containing the code represented as words + */ + fn _as_human_readible_words(&self) -> String { + return self.code.iter().map(|i|->&str{COLORS.iter().nth(*i).expect("index out of bounds")}).collect(); + } +} +struct GUESS { + code: CODE, + blacks: usize, + whites: usize, +} +impl GUESS { + /** + * create a new guess, and evaluate it + */ + fn new(code: CODE) -> GUESS { + return GUESS{code:code, blacks:0,whites:0 }; + } + + /** + * evaulates itself for the number of black and white pegs it should have for a given answer + */ + fn evaluate(&mut self, answer:&CODE) { + //data + let mut consumed = vec![false;answer.code.len()]; + + if self.code.code.len() != answer.code.len() { + panic!("only codes of the same length can be compared"); + } + + for i in 0..answer.code.len() { + if self.code.code[i] == answer.code[i] { //correct value correct place + self.blacks += 1; + consumed[i] = true; + } + else { + //check for correct value incorrect place, don't count positions that are already exact matches + for j in 0..answer.code.len() { + if !consumed[j] && self.code.code[i] == answer.code[j] && self.code.code[j] != answer.code[j] { + self.whites += 1; + consumed[j] = true; + break; + } + } + } + } + } +} + +fn main() { + //DATA + let mut rng = thread_rng(); + let num_colors: usize; + let num_positions: usize; + let num_rounds: usize; + let num_guesses: usize; + let total_posibilities: usize; + + let mut human_score: usize = 0; + let mut computer_score: usize = 0; + + //print welcome message + welcome(); + + //ask user for a number of colors, positions, and rounds + num_colors = get_number_from_user_input("NUMBER OF COLORS", "", 1, COLORS.len()); + num_positions = get_number_from_user_input("NUMBER OF POSITIONS", "", 2, 10); + num_rounds = get_number_from_user_input("NUMBER OF ROUNDS", "", 1, 10); + num_guesses = get_number_from_user_input("NUMBER OF GUESSES", "", 10, 0); + + + //print number of posibilities + total_posibilities = num_colors.pow(num_positions as u32); + println!("\nTOTAL POSSIBILITIES = {}\n", total_posibilities); + + //print color letter table + print_color_letter_table(num_colors); + + //game loop + for round_num in 1..=num_rounds { + //data + let mut num_moves: usize = 1; + let mut answer: CODE; + let mut guess: GUESS; + let mut guesses: Vec = Vec::new(); + let mut all_possibilities = vec![true; total_posibilities]; + + + //print round number + println!("\n\nROUND NUMBER: {}", round_num); + + //human player is code-breaker, computer is code-maker + //generate a combination + answer = CODE::new_random(&mut rng, num_colors, num_positions); + //println!("CODE: {:?}", answer._as_human_readible_chars()); //this is for troubleshooting, prints the code converted back into characters + + //round loop + loop { + //loop condition + if num_moves > num_guesses { + println!("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!"); + println!("THE ACTUAL COMBINATION WAS: {}", answer._as_human_readible_chars()); + human_score += num_moves; + print_scores(human_score,computer_score); + break; + } + + //input loop + guess = GUESS::new(loop { + println!("\nMOVE # {} GUESS: ", num_moves); + + //get player move + let mut raw_input = String::new(); //temp variable to store user input + io::stdin().read_line(&mut raw_input).expect("CANNOT READ INPUT!"); //read user input from standard input and store it to raw_input + + //attempt to parse input + if raw_input.trim().eq_ignore_ascii_case("board") { + //print the board state + print_board(&guesses); + continue; //run loop again + } + else if raw_input.trim().eq_ignore_ascii_case("quit") { + //quit the game + println!("QUITTER! MY COMBINATION WAS: {}\nGOOD BYE", answer._as_human_readible_words()); + return; //exit the game + } + else { + //parse input for a code + match CODE::new_from_string(raw_input, num_colors) { + Some(code) => { + //ensure code is correct length + if code.code.len() != num_positions { // if not + println!("BAD NUMBER OF POSITIONS."); + continue; //run loop again + } + else {break code;}//break with the code + }, + None => continue, //run loop again + } + } + }); + + //evaluate guess + guess.evaluate(&answer); + let blacks = guess.blacks; + let whites = guess.whites; + //add guess to the list of guesses + guesses.push(guess); + + //tell human the results + if blacks >= num_positions { //guessed it correctly + println!("YOU GUESSED IT IN {} MOVES!", num_moves); + human_score += num_moves; + print_scores(human_score,computer_score); + break; //break from loop + } else { //didn't + println!("YOU HAVE {} BLACKS AND {} WHITES.", blacks, whites); + //increment moves + num_moves += 1; + } + } + + //computer is code-breaker, human player is code-maker + println!("\nNOW I GUESS. THINK OF A COMBINATION.\nHIT RETURN WHEN READY: "); + //prompt user to give a valid combination #730 + //input loop + answer = loop { + let mut raw_input = String::new(); //temp variable to store user input + io::stdin().read_line(&mut raw_input).expect("CANNOT READ INPUT!"); //read user input from standard input and store it to raw_input + + //attempt to create a code from the user input, if successful break the loop returning the code + if let Some(code) = CODE::new_from_string(raw_input, num_colors) { + if code.code.len() == num_positions {break code;} //exit loop with code + else {println!("CODE MUST HAVE {} POSITIONS", num_positions);continue;} //tell them to try again + } + + println!("INVALID CODE. TRY AGAIN"); //if unsuccessful, this is printed and the loop runs again + }; + + //reset some things in preparation for computer play + guesses.clear(); + num_moves = 0; + //let num_colors = *answer.code.iter().max().unwrap(); //figure out the number of colors from the code | Commented bc we're enforcing that the computer cracks the same size code as the human + //let num_positions = answer.code.len(); //figure out the number of positions from the code | Commented bc we're enforcing that the computer cracks the same size code as the human + + //round loop + loop { + //loop condition + if num_moves > num_guesses { + println!("I USED UP ALL MY MOVES!"); + println!("I GUESS MY CPU IS JUST HAVING AN OFF DAY."); + computer_score += num_moves; + print_scores(human_score,computer_score); + break; + } + + //randomly generate a guess //770 + let mut guess_int = rng.gen_range(0..total_posibilities); + guess = GUESS::new(CODE::new()); + //if it's possible, use it //780 + if all_possibilities[guess_int] { + guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess + } + else {//if it's not possible: + // search all possibilities after guess, use first valid one //790 + for g in guess_int..total_posibilities { + if all_possibilities[g] { + guess_int=g; + guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess + break; + } + } + //if none was found + // search all possibilities before guess, use first valid one //820 + if guess.code.code.is_empty() { + for g in (0..guess_int).rev() { + if all_possibilities[g] { + guess_int=g; + guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess + break; + } + } + } + // if none where found, tell the user and start over #850 + if guess.code.code.is_empty() { + println!("YOU HAVE GIVEN ME INCONSISTENT INFORMATION."); + println!("PLAY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL."); + return; //exit game + }; + } + + //convert guess into something readible #890 + //print it #940 + println!("MY GUESS IS: {}", guess.code._as_human_readible_chars()); + //ask user for feedback, #980 + let blacks=get_number_from_user_input("BLACKS: ", "", 0, num_positions); + let whites=get_number_from_user_input("WHITES: ", "", 0, num_positions); + + //if we got it, end #990 + if blacks >= num_positions { //guessed it correctly + println!("I GOT IT IN {} MOVES!", num_moves); + computer_score += num_moves; + print_scores(human_score,computer_score); + break; //break from loop + } else { //didn't + all_possibilities[guess_int] = false; + //if we didn't, eliminate the combinations that don't work + //we know the number of black and white pegs for a valid answer, so eleminate all that get different amounts + all_possibilities.iter_mut().enumerate().for_each(|b| { + if *b.1 { //filter out ones we already know aren't possible + let mut tmp_guess = GUESS::new(CODE::new_from_int(b.0, num_colors, num_positions)); + tmp_guess.evaluate(&answer); + if blacks > tmp_guess.blacks || whites > tmp_guess.whites { //if number of blacks/whites is different, set it to false + *b.1 = false; + } + } + }); + + //increment moves + num_moves += 1; + } + + + } + + } +} + +/** + * print the welcome message + */ +fn welcome() { + println!(" + MASTERMIND + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + "); +} + +/** + * print scores + */ +fn print_scores(human_score:usize, computer_score:usize) { + println!("SCORE\n\tCOMPUTER: {}\n\tHUMAN: {}", computer_score, human_score); +} + +/** + * print the color - letter table + * only prints the first num_colors pairs + */ +fn print_color_letter_table(num_colors: usize) { + println!("COLOR\tLETTER"); + println!("=====\t======"); + for i in 0..num_colors { + println!("{}\t{}", COLORS[i], &LETTERS[i..i+1]); + } +} + +fn print_board(guesses: &Vec) { + println!("BOARD"); + println!("MOVE\tGUESS\t\tBLACK\tWhite"); + for guess in guesses.iter().enumerate() { + println!("{}\t{}\t\t{}\t{}", guess.0,guess.1.code._as_human_readible_chars(),guess.1.blacks,guess.1.whites); + } + +} + +/** + * gets a number from user input + * pass an empty &str for error_message if you don't want one printed + * pass a min lower than the max to have minimun and maximun bounds + * pass a min higher than the max to only have a minumum bound + * pass a min equal to the max to only have a maximun bound + */ +fn get_number_from_user_input(prompt: &str, error_message: &str, min:T, max:T) -> T { + //DATA + let mut raw_input = String::new(); // temporary variable for user input that can be parsed later + + //input loop + return loop { + + //print prompt + println!("{}", prompt); + //read user input from standard input, and store it to raw_input + raw_input.clear(); //clear input + io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!"); + + //from input, try to read a number + if let Ok(i) = raw_input.trim().parse() { + //what bounds must the input fall into + if min < max { //have a min and max bound: [min,max] + if i >= min && i <= max {//is input valid, within bounds + break i; //exit the loop with the value i, returning it + } else {println!("ONLY BETWEEN {} AND {}, PLEASE!", min, max);} //print error message specific to this case + } else if min > max { //only a min bound: [min, infinity) + if i >= min {break i;} else {println!("NO LESS THAN {}, PLEASE!", min);} + } else { //only a max bound: (-infinity, max] + if i <= max {break i;} else {println!("NO MORE THAN {}, PLEASE!", max);} + } + continue; //continue to the next loop iteration + }; + //this is only reached if a number couldn't be parsed from the input + if !error_message.is_empty() {println!("{}",error_message);} //if they gave an error message to use, print it + }; +} diff --git a/61_Math_Dice/python/mathdice.py b/61_Math_Dice/python/mathdice.py index 4081e0cca..99220e713 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/61_Math_Dice/rust/Cargo.lock b/61_Math_Dice/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/61_Math_Dice/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/python/mugwump.py b/62_Mugwump/python/mugwump.py index cc719c172..6eb63ccc8 100644 --- a/62_Mugwump/python/mugwump.py +++ b/62_Mugwump/python/mugwump.py @@ -1,6 +1,5 @@ from math import sqrt from random import randint -from typing import List, Tuple def introduction() -> None: @@ -19,7 +18,7 @@ def introduction() -> None: ) -def generate_mugwumps(n: int = 4) -> List[List[int]]: +def generate_mugwumps(n=4): mugwumps = [] for _ in range(n): current = [randint(0, 9), randint(0, 9)] @@ -27,15 +26,16 @@ def generate_mugwumps(n: int = 4) -> List[List[int]]: return mugwumps -def reveal_mugwumps(mugwumps: List[List[int]]) -> None: +def reveal_mugwumps(mugwumps): print("Sorry, that's 10 tries. Here's where they're hiding.") for idx, mugwump in enumerate(mugwumps, 1): if mugwump[0] != -1: print(f"Mugwump {idx} is at {mugwump[0]},{mugwump[1]}") -def calculate_distance(guess: Tuple[int, int], mugwump: List[int]) -> float: - return sqrt(((mugwump[0] - guess[0]) ** 2) + ((mugwump[1] - guess[1]) ** 2)) +def calculate_distance(guess, mugwump): + d = sqrt(((mugwump[0] - guess[0]) ** 2) + ((mugwump[1] - guess[1]) ** 2)) + return d def play_again() -> None: @@ -47,7 +47,7 @@ def play_again() -> None: exit() -def play_round() -> None: +def play_round(): mugwumps = generate_mugwumps() turns = 1 score = 0 diff --git a/62_Mugwump/rust/Cargo.lock b/62_Mugwump/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/62_Mugwump/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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.toml b/62_Mugwump/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/62_Mugwump/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/62_Mugwump/rust/src/coordinate.rs b/62_Mugwump/rust/src/coordinate.rs deleted file mode 100644 index f13eb2406..000000000 --- a/62_Mugwump/rust/src/coordinate.rs +++ /dev/null @@ -1,41 +0,0 @@ -#![allow(dead_code)] - -#[derive(Debug)] -pub struct Coordinate { - x: u8, - y: u8, - pub state: CoordState, - pub mugwump_number: u8, -} - -impl Coordinate { - pub fn new(pos: (u8, u8), has_mugwump: bool, mugwump_number: i32) -> Self { - let mut mug_no = 0; - - let state = if has_mugwump { - mug_no = mugwump_number; - CoordState::HasMugwump - } else { - CoordState::Normal - }; - - Coordinate { - x: pos.0, - y: pos.1, - state, - mugwump_number: mug_no as u8, - } - } - - pub fn get_pos(&self) -> (u8, u8) { - (self.x, self.y) - } -} - -#[derive(Debug, PartialEq)] -pub enum CoordState { - Normal, - HasMugwump, - Checked, - FoundMugwump, -} diff --git a/62_Mugwump/rust/src/draw.rs b/62_Mugwump/rust/src/draw.rs deleted file mode 100644 index d7fac325e..000000000 --- a/62_Mugwump/rust/src/draw.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::coordinate::{CoordState, Coordinate}; - -pub fn draw_board(coords: &Vec, show_mugwumps: bool) { - let draw_top_bottom = |is_top: bool| { - let (mut left, mut right) = ("╔", "╗"); - - if !is_top { - (left, right) = ("╚", "╝"); - } - - for i in 0..11 { - if i == 0 { - print!("{}══", left); - } else if i == 10 { - print!("═══{}", right) - } else { - print!("══"); - } - } - println!(""); - }; - - draw_top_bottom(true); - - let mut y: i8 = 9; - - print!("║ {} ", y); - for (i, c) in coords.iter().enumerate() { - { - use CoordState::*; - - let mut _char = ' '; - - match c.state { - Normal => _char = '-', - HasMugwump => _char = if show_mugwumps { 'M' } else { '-' }, - Checked => _char = '*', - FoundMugwump => _char = '𑗌', - } - - print!("{} ", _char); - } - - if ((i + 1) % 10) == 0 { - y -= 1; - - print!("║"); - println!(""); - - if i != 99 { - print!("║ {} ", y); - } - } - } - - print!("║ ♥︎ "); - for i in 0..10 { - print!("{} ", i); - - if i == 9 { - print!("║"); - } - } - println!(""); - - draw_top_bottom(false); -} diff --git a/62_Mugwump/rust/src/game.rs b/62_Mugwump/rust/src/game.rs deleted file mode 100644 index f556dfac1..000000000 --- a/62_Mugwump/rust/src/game.rs +++ /dev/null @@ -1,162 +0,0 @@ -use rand::Rng; - -use crate::{ - coordinate::{CoordState, Coordinate}, - draw::draw_board, - util, -}; - -pub struct Game { - pub coords: Vec, - tries: u8, - show_board: bool, -} - -impl Game { - pub fn new(show_board: bool) -> Self { - let mut coords = Vec::new(); - let mut random_indexes = Vec::new(); - let get_random_index = || -> i32 { rand::thread_rng().gen_range(0..100) }; - - for _ in 0..4 { - let mut i = get_random_index(); - while random_indexes.contains(&i) { - i = get_random_index(); - } - random_indexes.push(i); - } - - let mut x = 0; - let mut y: i8 = 9; - - let mut mugwump_number = 0; - - for i in 0..100 { - let mut has_mugwump = false; - - if random_indexes.contains(&i) { - has_mugwump = true; - mugwump_number += 1; - } - - coords.push(Coordinate::new((x, y as u8), has_mugwump, mugwump_number)); - - x += 1; - - if ((i + 1) % 10) == 0 { - x = 0; - y -= 1; - } - } - - Game { - coords, - tries: 0, - show_board, - } - } - - pub fn tick(&mut self) -> Option { - let mut game_over = false; - - if self.tries >= 10 { - println!("SORRY THAT'S 10 TRIES. HERE IS WHERE THEY ARE HIDING"); - - for m in self.get_mugwumps() { - println!("MUGWUMP {} IS AT {:?}", m.mugwump_number, m.get_pos()); - } - - if self.show_board { - draw_board(&self.coords, true); - } - - game_over = true; - } - - if self.get_mugwumps().len() == 0 { - println!("YOU HAVE FOUND ALL MUGWUMPS!"); - - game_over = true; - } - - if game_over { - return util::prompt_bool("THAT WAS FUN! PLAY AGAIN (Y/n)?"); - } - - self.tries += 1; - - if self.show_board { - draw_board(&self.coords, true); - } - - let entered_position = self.input_coordinate(); - self.check_position(entered_position); - - None - } - - fn check_position(&mut self, pos: (u8, u8)) { - if let Some(coord) = self.coords.iter_mut().find(|c| c.get_pos() == pos) { - use CoordState::*; - - match coord.state { - Normal => { - coord.state = Checked; - self.print_distances(pos); - } - HasMugwump => { - coord.state = FoundMugwump; - println!("YOU FOUND MUGWUMP {}", coord.mugwump_number); - self.print_distances(pos); - } - Checked | FoundMugwump => println!("YOU ALREADY LOOKED HERE!"), - } - } - } - - fn print_distances(&self, (x, y): (u8, u8)) { - let print = |m: &Coordinate| { - let (mx, my) = m.get_pos(); - let (x, y, mx, my) = (x as i32, y as i32, mx as i32, my as i32); - let distance = (((x - mx).pow(2) + (y - my).pow(2)) as f32).sqrt(); - - println!( - "YOU ARE {} UNITS FROM MUGWUMP {}", - distance, m.mugwump_number - ); - }; - - for m in self.get_mugwumps() { - print(m); - } - } - - fn input_coordinate(&self) -> (u8, u8) { - let msg = format!("TURN NO. {} WHAT IS YOUR GUESS?", self.tries); - let input = util::prompt(msg.as_str()); - - if !input.contains(",") { - println!("YOU MUST ENTER A COORDINATE: #,#"); - return (0, 0); - } - - let axes: Vec<&str> = input.split(",").collect(); - let mut pos = [0; 2]; - - for (i, a) in axes.iter().enumerate() { - match a.parse::() { - Ok(p) => pos[i] = p as u8, - Err(_) => println!("YOU MUST ENTER A COORDINATE: #,#"), - } - } - - (pos[0], pos[1]) - } - - fn get_mugwumps(&self) -> Vec<&Coordinate> { - self.coords - .iter() - .filter(|c| c.state == CoordState::HasMugwump) - .collect() - } -} diff --git a/62_Mugwump/rust/src/main.rs b/62_Mugwump/rust/src/main.rs deleted file mode 100644 index fbd4479de..000000000 --- a/62_Mugwump/rust/src/main.rs +++ /dev/null @@ -1,44 +0,0 @@ -mod coordinate; -mod draw; -mod game; -pub mod util; - -use crate::game::Game; - -fn main() { - println!("\n\nMUGWUMP"); - println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); - - println!("THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS"); - println!("HIDDEN ON A 10 BY 10 GRID. HOMEBASE IS POSITION 0,0."); - println!("ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH"); - println!("NUMBER BETWEEN 0 AND 9, INCLUSIVE. FIRST NUMBER"); - println!("IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER"); - println!("IS DISTANCE ABOVE HOMEBASE!\n"); - - println!("YOU GET 10 TRIES. AFTER EACH TRY, I WILL TELL"); - println!("YOU HOW FAR YOU ARE FROM EACH MUGWUMP.\n"); - - let mut _quit = false; - - while !_quit { - let mut show_board = true; - - if let Some(r) = util::prompt_bool("WOULD YOU LIKE TO SEE THE BOARD?") { - show_board = r; - } - - let mut game = Game::new(show_board); - - loop { - if let Some(again) = game.tick() { - if !again { - _quit = true; - } else { - println!("FOUR MORE MUGWUMPS ARE NOW IN HIDING") - } - break; - } - } - } -} diff --git a/62_Mugwump/rust/src/util.rs b/62_Mugwump/rust/src/util.rs deleted file mode 100644 index ff4e9ecb8..000000000 --- a/62_Mugwump/rust/src/util.rs +++ /dev/null @@ -1,25 +0,0 @@ -use std::io; - -pub fn prompt(msg: &str) -> String { - println!("\n{}", msg); - - let mut input = String::new(); - - io::stdin() - .read_line(&mut input) - .expect("Failed to read line."); - - input.trim().to_string() -} - -pub fn prompt_bool(msg: &str) -> Option { - loop { - let response = prompt(msg); - - match response.to_uppercase().as_str() { - "Y" | "YES" => return Some(true), - "N" | "NO" => return Some(false), - _ => println!("PLEASE ENTER (Y)ES or (N)O."), - } - } -} diff --git a/63_Name/lua/name.lua b/63_Name/lua/name.lua deleted file mode 100644 index 32d51c93e..000000000 --- a/63_Name/lua/name.lua +++ /dev/null @@ -1,85 +0,0 @@ --- HELLO --- --- Converted from BASIC to Lua by Recanman - -local function tab(space) - local str = "" - - for _ = space, 1, -1 do - str = str .. " " - end - - return str -end - --- reused from Bagels.lua -function getInput(prompt) - io.write(prompt) - io.flush() - local input = io.read("l") - if not input then --- test for EOF - print("GOODBYE") - os.exit(0) - end - return input -end - -print(tab(33) .. "HELLO\n") -print(tab(15) .. "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n") -print("\n") -print("\n") -print("\n") - -print("HELLO. MY NAME IS CREATIVE COMPUTER.\n") -print("\n") -print("\n") - -print("WHAT'S YOUR NAME (FIRST AND LAST)") - -local ns = getInput("? ") -local l = string.len(ns) -print("\n") - -local function main() - print("THANK YOU, " .. string.reverse(ns) .. ".\n") - - print("OOPS! I GUESS I GOT IT BACKWARDS. A SMART") - print("COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\n") - print("BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\n") - print("LET'S PUT THEM IN ORDER LIKE THIS: ") - - local b = {} - - for i = 1, l, 1 do - local letter = string.sub(ns, i, i) - b[i] = string.byte(letter) - end - - table.sort(b, function(v1, v2) - return v1 < v2 - end) - - local str = "" - for _, letter in ipairs(b) do - str = str .. string.char(letter) - end - - str = string.reverse(str) - print(str) - - print("\n\n") - print("DON'T YOU LIKE THAT BETTER") - - local ds = getInput("? ") - - if ds == "YES" then - print("I KNEW YOU'D AGREE!!\n") - else - print("I'M SORRY YOU DON'T LIKE IT THAT WAY.\n") - end - - print("I REALLY ENJOYED MEETING YOU " .. ns .. ".\n") - print("HAVE A NICE DAY!\n") -end - -main() diff --git a/63_Name/python/name.py b/63_Name/python/name.py index 94b8170d6..b3067f7ea 100644 --- a/63_Name/python/name.py +++ b/63_Name/python/name.py @@ -7,27 +7,45 @@ """ -def is_yes_ish(answer: str) -> bool: +def print_with_tab(space_count: int, msg: str) -> None: + if space_count > 0: + spaces = " " * space_count + else: + spaces = "" + print(spaces + msg) + + +def is_yes_ish(answer): cleaned = answer.strip().upper() - return cleaned in {"Y", "YES"} + if cleaned == "Y" or cleaned == "YES": + return True + return False def main() -> None: - print(" " * 34 + "NAME") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_with_tab(34, "NAME") + print_with_tab(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)?") print() name_as_list = list(name) reversed_name = "".join(name_as_list[::-1]) - print(f"THANK YOU, {reversed_name}.\n") + print(f"THANK YOU, {reversed_name}.") + print() print("OOPS! I GUESS I GOT IT BACKWARDS. A SMART") - print("COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\n\n") + print("COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!") + print() + print() print("BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.") sorted_name = "".join(sorted(name_as_list)) - print(f"LET'S PUT THEM IN ORDER LIKE THIS: {sorted_name}\n\n") + print(f"LET'S PUT THEM IN ORDER LIKE THIS: {sorted_name}") + print() + print() print("DON'T YOU LIKE THAT BETTER?") like_answer = input() diff --git a/63_Name/ruby/name.rb b/63_Name/ruby/name.rb deleted file mode 100644 index 522c7af01..000000000 --- a/63_Name/ruby/name.rb +++ /dev/null @@ -1,42 +0,0 @@ -def is_yes_ish answer - cleaned = answer.upcase - return true if ["Y", "YES"].include? cleaned - return false -end - -def main - puts " " * 34 + "NAME" - - puts "HELLO." - puts "MY NAME iS COMPUTER." - print "WHAT'S YOUR NAME (FIRST AND LAST)? " - name = gets.chomp! - puts "" - name_as_list = name.split("") - reversed_name = name_as_list.reverse.join("") - - puts "THANK YOU, #{reversed_name}.\n" - puts "OOPS! I GUESS I GOT IT BACKWARDS. A SMART" - puts "COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\n\n" - puts "BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER." - - sorted_name = name_as_list.sort.join("") - puts "LET'S PUT THEM IN ORDER LIKE THIS: #{sorted_name}\n\n" - print "DON'T YOU LIKE THAT BETTER? " - like_answer = gets.chomp! - puts - if is_yes_ish(like_answer) - puts "I KNEW YOU'D AGREE!!" - else - puts "I'M SORRY YOU DON'T LIKE IT THAT WAY." - end - - puts "" - puts "I REALLY ENJOYED MEETING YOU, #{name}." - puts "HAVE A NICE DAY!" -end - - -if __FILE__ == $0 - main -end \ No newline at end of file diff --git a/63_Name/rust/Cargo.toml b/63_Name/rust/Cargo.toml deleted file mode 100644 index 7d75412a6..000000000 --- a/63_Name/rust/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[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 deleted file mode 100644 index 1a1f631a7..000000000 --- a/63_Name/rust/src/main.rs +++ /dev/null @@ -1,116 +0,0 @@ -/** 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. - * 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 -} diff --git a/64_Nicomachus/csharp/program.cs b/64_Nicomachus/csharp/program.cs deleted file mode 100644 index c8ba4184d..000000000 --- a/64_Nicomachus/csharp/program.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System.Text; -using System.Threading; - -namespace Nicomachus -{ - class Nicomachus - { - private void DisplayIntro() - { - Console.WriteLine(); - Console.WriteLine("NICOMA".PadLeft(23)); - Console.WriteLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine("Boomerang puzzle from Arithmetica of Nicomachus -- A.D. 90!"); - } - - private bool PromptYesNo(string Prompt) - { - bool Success = false; - - while (!Success) - { - Console.Write(Prompt); - string LineInput = Console.ReadLine().Trim().ToLower(); - - if (LineInput.Equals("yes")) - return true; - else if (LineInput.Equals("no")) - return false; - else - Console.WriteLine("Eh? I don't understand '{0}' Try 'Yes' or 'No'.", LineInput); - } - - return false; - } - - private int PromptForNumber(string Prompt) - { - bool InputSuccess = false; - int ReturnResult = 0; - - while (!InputSuccess) - { - Console.Write(Prompt); - string Input = Console.ReadLine().Trim(); - InputSuccess = int.TryParse(Input, out ReturnResult); - if (!InputSuccess) - Console.WriteLine("*** Please enter a valid number ***"); - } - - return ReturnResult; - } - - private void PlayOneRound() - { - Random rand = new Random(); - int A_Number = 0; - int B_Number = 0; - int C_Number = 0; - int D_Number = 0; - - Console.WriteLine(); - Console.WriteLine("Please think of a number between 1 and 100."); - - A_Number = PromptForNumber("Your number divided by 3 has a remainder of? "); - B_Number = PromptForNumber("Your number divided by 5 has a remainder of? "); - C_Number = PromptForNumber("Your number divided by 7 has a remainder of? "); - - Console.WriteLine(); - Console.WriteLine("Let me think a moment..."); - - Thread.Sleep(2000); - - D_Number = 70 * A_Number + 21 * B_Number + 15 * C_Number; - - while (D_Number > 105) - { - D_Number -= 105; - } - - if (PromptYesNo("Your number was " + D_Number.ToString() + ", right? ")) - { - Console.WriteLine(); - Console.WriteLine("How about that!!"); - } - else - { - Console.WriteLine(); - Console.WriteLine("I feel your arithmetic is in error."); - } - - Console.WriteLine(); - - } - - public void Play() - { - bool ContinuePlay = true; - - DisplayIntro(); - - do - { - PlayOneRound(); - - ContinuePlay = PromptYesNo("Let's try another? "); - } - while (ContinuePlay); - } - } - class Program - { - static void Main(string[] args) - { - - new Nicomachus().Play(); - - } - } -} \ No newline at end of file diff --git a/64_Nicomachus/python/nicomachus.py b/64_Nicomachus/python/nicomachus.py index e5d1c8253..abc482934 100644 --- a/64_Nicomachus/python/nicomachus.py +++ b/64_Nicomachus/python/nicomachus.py @@ -15,7 +15,15 @@ import time -def get_yes_or_no() -> bool: +def print_with_tab(spaces_count: int, msg: str) -> None: + if spaces_count > 0: + spaces = " " * spaces_count + else: + spaces = "" + print(spaces + msg) + + +def get_yes_or_no(): while True: response = input().upper() if response == "YES": @@ -25,7 +33,7 @@ def get_yes_or_no() -> bool: print(f"EH? I DON'T UNDERSTAND '{response}' TRY 'YES' OR 'NO'.") -def play_game() -> None: +def play_game(): print("PLEASE THINK OF A NUMBER BETWEEN 1 AND 100.") print("YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF") a = int(input()) @@ -43,7 +51,9 @@ def play_game() -> None: print(f"YOUR NUMBER WAS {d}, RIGHT?") - if response := get_yes_or_no(): + response = get_yes_or_no() + + if response: print("HOW ABOUT THAT!!") else: print("I FEEL YOUR ARITHMETIC IS IN ERROR.") @@ -52,8 +62,11 @@ def play_game() -> None: def main() -> None: - print(" " * 33 + "NICOMA") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_with_tab(33, "NICOMA") + print_with_tab(15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() print("BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!") print() diff --git a/64_Nicomachus/rust/Cargo.lock b/64_Nicomachus/rust/Cargo.lock deleted file mode 100644 index b21cc6a2d..000000000 --- a/64_Nicomachus/rust/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# 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/64_Nicomachus/rust/Cargo.toml b/64_Nicomachus/rust/Cargo.toml deleted file mode 100644 index 1ec696335..000000000 --- a/64_Nicomachus/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/64_Nicomachus/rust/src/main.rs b/64_Nicomachus/rust/src/main.rs deleted file mode 100644 index 40a8aa51b..000000000 --- a/64_Nicomachus/rust/src/main.rs +++ /dev/null @@ -1,71 +0,0 @@ -use std::io; - -fn main() { - println!("\n\n~~Nicomachus~~"); - println!("Creative Computing Morristown, New Jersey\n"); - - println!("Boomerang Puzzle from Arithmetica of Nicomachus -- A.D. 90!\n"); - - loop { - println!("Please think of a number between 1 and 100.\n"); - - let a = question("3"); - let b = question("5"); - let c = question("7"); - - println!("\nLet me think a moment..."); - std::thread::sleep(std::time::Duration::from_secs(2)); - - let d: i32 = (70 * a + 21 * b + 15 * c) % 105; - - if prompt(format!("Your number was {}, right?", d)) { - println!("\nHow about that!!"); - } else { - println!("\nI feel your arithmetic is in error."); - } - - if !prompt("\nTry another?".to_string()) { - break; - } - } -} - -fn question(n: &str) -> i32 { - loop { - println!("Your number divided by {} has a remainder of?", n); - - let input = read_line().trim().parse::(); - - match input { - Ok(r) => return r, - Err(_) => println!("Input must be a number."), - } - } -} - -fn prompt(msg: String) -> bool { - println!("{}", msg); - - loop { - let input = read_line().trim().to_uppercase(); - let input = input.as_str(); - - if input == "Y" || input == "YES" { - return true; - } else if input == "N" || input == "NO" { - return false; - } else { - println!("Please input either (Y)es or (N)o.") - } - } -} - -fn read_line() -> String { - let mut input = String::new(); - - io::stdin() - .read_line(&mut input) - .expect("Failed to read line."); - - input -} diff --git a/65_Nim/README.md b/65_Nim/README.md index fae886395..11243f0fc 100644 --- a/65_Nim/README.md +++ b/65_Nim/README.md @@ -28,7 +28,3 @@ 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. diff --git a/65_Nim/python/Traditional_NIM.py b/65_Nim/python/Traditional_NIM.py index ead90b2d0..6c3a2d08b 100644 --- a/65_Nim/python/Traditional_NIM.py +++ b/65_Nim/python/Traditional_NIM.py @@ -1,12 +1,12 @@ import random -from typing import Tuple +# Class of the Game class NIM: - def __init__(self) -> None: + def __init__(self): self.piles = {1: 7, 2: 5, 3: 3, 4: 1} - def remove_pegs(self, command) -> None: + def remove_pegs(self, command): try: pile, num = command.split(",") @@ -29,22 +29,26 @@ def remove_pegs(self, command) -> None: else: print("\nInvalid value of either Peg or Pile\n") - def get_ai_move(self) -> Tuple[int, int]: - possible_pile = [k for k, v in self.piles.items() if v != 0] + def get_ai_move(self): + possible_pile = [] + for k, v in self.piles.items(): + if v != 0: + possible_pile.append(k) + pile = random.choice(possible_pile) num = random.randint(1, self.piles[pile]) return pile, num - def _command_integrity(self, num, pile) -> bool: + def _command_integrity(self, num, pile): return pile <= 4 and pile >= 1 and num <= self.piles[pile] def print_pegs(self) -> None: for pile, peg in self.piles.items(): - print(f'Pile {pile} : {"O " * peg}') + print("Pile {} : {}".format(pile, "O " * peg)) - def help(self) -> None: + def help(self): print("-" * 10) print('\nThe Game is player with a number of Piles of Objects("O" == one peg)') print("\nThe Piles are arranged as given below(Tradional NIM)\n") @@ -58,7 +62,7 @@ def help(self) -> None: print("\nThe winner is defined as the one that picks the last remaning object") print("-" * 10) - def check_for_win(self) -> bool: + def check_for_win(self): sum = 0 for v in self.piles.values(): sum += v @@ -85,18 +89,22 @@ def main() -> None: # Players Move command = input("\nYOUR MOVE - Number of PILE, Number of Object? ") game.remove_pegs(command) - if end := game.check_for_win(): + end = game.check_for_win() + if end: print("\nPlayer Wins the Game, Congratulations!!") input("\nPress any key to exit") break # Computers Move - ai_command = game.get_ai_move() + command = game.get_ai_move() print( - f"\nA.I MOVE - A.I Removed {ai_command[1]} pegs from Pile {ai_command[0]}" + "\nA.I MOVE - A.I Removed {} pegs from Pile {}".format( + command[1], command[0] + ) ) - game.remove_pegs(f"{str(ai_command[0])},{str(ai_command[1])}") - if end := game.check_for_win(): + game.remove_pegs(str(command[0]) + "," + str(command[1])) + end = game.check_for_win() + if end: print("\nComputer Wins the Game, Better Luck Next Time\n") input("Press any key to exit") break diff --git a/65_Nim/rust/Cargo.lock b/65_Nim/rust/Cargo.lock deleted file mode 100644 index fc74a49e2..000000000 --- a/65_Nim/rust/Cargo.lock +++ /dev/null @@ -1,23 +0,0 @@ -# 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/README.md b/66_Number/README.md index 2df37b6b7..43d97db3b 100644 --- a/66_Number/README.md +++ b/66_Number/README.md @@ -15,4 +15,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -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. +(please note any difficulties or challenges in porting here) diff --git a/66_Number/python/number.py b/66_Number/python/number.py index e6840d92a..e58dd20b1 100644 --- a/66_Number/python/number.py +++ b/66_Number/python/number.py @@ -9,6 +9,15 @@ import random +def print_with_tab(num_spaces: int, msg: str) -> None: + if num_spaces > 0: + spaces = " " * num_spaces + else: + spaces = "" + + print(spaces + msg) + + def print_instructions() -> None: print("YOU HAVE 100 POINTS. BY GUESSING NUMBERS FROM 1 TO 5, YOU") print("CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO") @@ -19,13 +28,16 @@ def print_instructions() -> None: print() -def fnr() -> int: +def fnr(): return random.randint(1, 5) def main() -> None: - print(" " * 33 + "NUMBER") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print_with_tab(33, "NUMBER") + print_with_tab(15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() print_instructions() diff --git a/66_Number/rust/Cargo.lock b/66_Number/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/66_Number/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/67_One_Check/csharp/Board.cs b/67_One_Check/csharp/Board.cs deleted file mode 100644 index 2e68072dc..000000000 --- a/67_One_Check/csharp/Board.cs +++ /dev/null @@ -1,64 +0,0 @@ -namespace OneCheck; - -internal class Board -{ - private readonly bool[][] _checkers; - private int _pieceCount; - private int _moveCount; - - public Board() - { - _checkers = - Enumerable.Range(0, 8) - .Select(r => Enumerable.Range(0, 8) - .Select(c => r <= 1 || r >= 6 || c <= 1 || c >= 6).ToArray()) - .ToArray(); - _pieceCount = 48; - } - - private bool this[int index] - { - get => _checkers[index / 8][index % 8]; - set => _checkers[index / 8][index % 8] = value; - } - - public bool PlayMove(IReadWrite io) - { - while (true) - { - var from = (int)io.ReadNumber(Prompts.From); - if (from == 0) { return false; } - - var move = new Move { From = from - 1, To = (int)io.ReadNumber(Prompts.To) - 1 }; - - if (TryMove(move)) - { - _moveCount++; - return true; - } - - io.Write(Streams.IllegalMove); - } - } - - public bool TryMove(Move move) - { - if (move.IsInRange && move.IsTwoSpacesDiagonally && IsPieceJumpingPieceToEmptySpace(move)) - { - this[move.From] = false; - this[move.Jumped] = false; - this[move.To] = true; - _pieceCount--; - return true; - } - - return false; - } - - private bool IsPieceJumpingPieceToEmptySpace(Move move) => this[move.From] && this[move.Jumped] && !this[move.To]; - - public string GetReport() => string.Format(Formats.Results, _moveCount, _pieceCount); - - public override string ToString() => - string.Join(Environment.NewLine, _checkers.Select(r => string.Join(" ", r.Select(c => c ? " 1" : " 0")))); -} diff --git a/67_One_Check/csharp/Game.cs b/67_One_Check/csharp/Game.cs deleted file mode 100644 index d9e64e265..000000000 --- a/67_One_Check/csharp/Game.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace OneCheck; - -internal class Game -{ - private readonly IReadWrite _io; - - public Game(IReadWrite io) - { - _io = io; - } - - public void Play() - { - _io.Write(Streams.Introduction); - - do - { - var board = new Board(); - do - { - _io.WriteLine(board); - _io.WriteLine(); - } while (board.PlayMove(_io)); - - _io.WriteLine(board.GetReport()); - } while (_io.ReadYesNo(Prompts.TryAgain) == "yes"); - - _io.Write(Streams.Bye); - } -} - -internal static class IOExtensions -{ - internal static string ReadYesNo(this IReadWrite io, string prompt) - { - while (true) - { - var response = io.ReadString(prompt).ToLower(); - - if (response == "yes" || response == "no") { return response; } - - io.Write(Streams.YesOrNo); - } - } -} diff --git a/67_One_Check/csharp/Move.cs b/67_One_Check/csharp/Move.cs deleted file mode 100644 index 0b48659e4..000000000 --- a/67_One_Check/csharp/Move.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace OneCheck; - -internal class Move -{ - public int From { get; init; } - public int To { get; init; } - public int Jumped => (From + To) / 2; - - public bool IsInRange => From >= 0 && From <= 63 && To >= 0 && To <= 63; - public bool IsTwoSpacesDiagonally => RowDelta == 2 && ColumnDelta == 2; - private int RowDelta => Math.Abs(From / 8 - To / 8); - private int ColumnDelta => Math.Abs(From % 8 - To % 8); -} \ No newline at end of file diff --git a/67_One_Check/csharp/OneCheck.csproj b/67_One_Check/csharp/OneCheck.csproj index 3870320c9..d3fe4757c 100644 --- a/67_One_Check/csharp/OneCheck.csproj +++ b/67_One_Check/csharp/OneCheck.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/67_One_Check/csharp/Program.cs b/67_One_Check/csharp/Program.cs deleted file mode 100644 index 4a3ab83b6..000000000 --- a/67_One_Check/csharp/Program.cs +++ /dev/null @@ -1,5 +0,0 @@ -global using Games.Common.IO; -global using static OneCheck.Resources.Resource; -using OneCheck; - -new Game(new ConsoleIO()).Play(); diff --git a/67_One_Check/csharp/Resources/Bye.txt b/67_One_Check/csharp/Resources/Bye.txt deleted file mode 100644 index ee4ddab11..000000000 --- a/67_One_Check/csharp/Resources/Bye.txt +++ /dev/null @@ -1,2 +0,0 @@ - -O.K. Hope you had fun!! \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/From.txt b/67_One_Check/csharp/Resources/From.txt deleted file mode 100644 index bb4c7a2d3..000000000 --- a/67_One_Check/csharp/Resources/From.txt +++ /dev/null @@ -1 +0,0 @@ -Jump from \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/IllegalMove.txt b/67_One_Check/csharp/Resources/IllegalMove.txt deleted file mode 100644 index a96b6e81e..000000000 --- a/67_One_Check/csharp/Resources/IllegalMove.txt +++ /dev/null @@ -1 +0,0 @@ -Illegal move. Try again... \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/Introduction.txt b/67_One_Check/csharp/Resources/Introduction.txt deleted file mode 100644 index 409f6b37f..000000000 --- a/67_One_Check/csharp/Resources/Introduction.txt +++ /dev/null @@ -1,30 +0,0 @@ - One Check - Creative Computing Morristown, New Jersey - - - -Solitaire checker puzzle by David Ahl - -48 checkers and placed on the 2 outside spaces of a -standard 64-square checkerboard. The object is to -remove as many checkers as possible by diagonal jumps -(as in standard checkers). Use the numbered board to -indicate the square you wish to jump from and to. On -the board printed out on each turn '1' indicates a -checker and '0' an empty square. When you have no -possible jumps remaining, input a '0' in response to -question 'Jump from ?' - -Here is the numerical board: - - 1 2 3 4 5 6 7 8 - 9 10 11 12 13 14 15 16 - 17 18 19 20 21 22 23 24 - 25 26 27 28 29 30 31 32 - 33 34 35 36 37 38 39 40 - 41 42 43 44 45 46 47 48 - 49 50 51 52 53 54 55 56 - 57 58 59 60 61 62 63 64 - -And here is the opening position of the checkers. - diff --git a/67_One_Check/csharp/Resources/Resource.cs b/67_One_Check/csharp/Resources/Resource.cs deleted file mode 100644 index 7095d7ec0..000000000 --- a/67_One_Check/csharp/Resources/Resource.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace OneCheck.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Introduction => GetStream(); - public static Stream IllegalMove => GetStream(); - public static Stream YesOrNo => GetStream(); - public static Stream Bye => GetStream(); - } - - internal static class Formats - { - public static string Results => GetString(); - } - - internal static class Prompts - { - public static string From => GetString(); - public static string To => GetString(); - public static string TryAgain => GetString(); - } - - internal static class Strings - { - public static string TooManyColumns => GetString(); - public static string TooManyRows => GetString(); - } - - 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/67_One_Check/csharp/Resources/Results.txt b/67_One_Check/csharp/Resources/Results.txt deleted file mode 100644 index a8771b6b0..000000000 --- a/67_One_Check/csharp/Resources/Results.txt +++ /dev/null @@ -1,3 +0,0 @@ - -You made {0} jumps and had {1} pieces -remaining on the board. diff --git a/67_One_Check/csharp/Resources/To.txt b/67_One_Check/csharp/Resources/To.txt deleted file mode 100644 index 788636ffb..000000000 --- a/67_One_Check/csharp/Resources/To.txt +++ /dev/null @@ -1 +0,0 @@ -to \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/TryAgain.txt b/67_One_Check/csharp/Resources/TryAgain.txt deleted file mode 100644 index c65e51fc8..000000000 --- a/67_One_Check/csharp/Resources/TryAgain.txt +++ /dev/null @@ -1 +0,0 @@ -Try again \ No newline at end of file diff --git a/67_One_Check/csharp/Resources/YesOrNo.txt b/67_One_Check/csharp/Resources/YesOrNo.txt deleted file mode 100644 index 703d4ad6c..000000000 --- a/67_One_Check/csharp/Resources/YesOrNo.txt +++ /dev/null @@ -1 +0,0 @@ -Please answer 'Yes' or 'No'. \ No newline at end of file diff --git a/67_One_Check/python/onecheck.py b/67_One_Check/python/onecheck.py index 21ffbd6e1..b866ebd9f 100644 --- a/67_One_Check/python/onecheck.py +++ b/67_One_Check/python/onecheck.py @@ -1,17 +1,22 @@ -""" -ONE CHECK +# ONE CHECK -Port to Python by imiro -""" +# Port to python by imiro -from typing import Tuple + +def tab(x): + return " " * x def main() -> None: + # Initial instructions - print(" " * 30 + "ONE CHECK") - print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") - print("SOLITAIRE CHECKER PUZZLE BY DAVID AHL\n") + print(tab(30) + "ONE CHECK") + print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() + 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") @@ -20,29 +25,35 @@ def main() -> None: 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 ?'\n") - print("HERE IS THE NUMERICAL BOARD:\n") + print("QUESTION 'JUMP FROM ?'") + print() + print("HERE IS THE NUMERICAL BOARD:") + print() while True: for j in range(1, 64, 8): for i in range(j, j + 7): print(i, end=(" " * (3 if i < 10 else 2))) print(j + 7) - print("\nAND HERE IS THE OPENING POSITION OF THE CHECKERS.\n") + print() + print("AND HERE IS THE OPENING POSITION OF THE CHECKERS.") + print() (jumps, left) = play_game() print() - print(f"YOU MADE {jumps} JUMPS AND HAD {left} PIECES") - print("REMAINING ON THE BOARD.\n") + print("YOU MADE " + jumps + " JUMPS AND HAD " + left + " PIECES") + print("REMAINING ON THE BOARD.") + print() if not (try_again()): break - print("\nO.K. HOPE YOU HAD FUN!!") + print() + print("O.K. HOPE YOU HAD FUN!!") -def play_game() -> Tuple[str, str]: +def play_game(): # Initialize board # Give more than 64 elements to accomodate 1-based indexing board = [1] * 70 @@ -60,13 +71,13 @@ def play_game() -> Tuple[str, str]: while True: print("JUMP FROM", end=" ") - f_str = input() - f = int(f_str) + f = input() + f = int(f) if f == 0: break print("TO", end=" ") - t_str = input() - t = int(t_str) + t = input() + t = int(t) print() # Check legality of move @@ -102,15 +113,15 @@ def play_game() -> Tuple[str, str]: return (str(jumps), str(left)) -def try_again() -> bool: +def try_again(): print("TRY AGAIN", end=" ") - answer = input().upper() - if answer == "YES": + answer = input() + if answer.upper() == "YES": return True - elif answer == "NO": + elif answer.upper() == "NO": return False print("PLEASE ANSWER 'YES' OR 'NO'.") - return try_again() + try_again() if __name__ == "__main__": diff --git a/68_Orbit/README.md b/68_Orbit/README.md index be765b557..01fb758c4 100644 --- a/68_Orbit/README.md +++ b/68_Orbit/README.md @@ -20,10 +20,10 @@ of orbit < ^ ship ``` -The distance of the bomb from the ship is computed using the law of cosines. The law of cosines states: +The distance of the bomb from the ship is computed using the law of consines. The law of cosines states: ``` -D = SQUAREROOT( R**2 + D1**2 - 2*R*D1*COS(A-A1) ) +D = SQUAREROOT( R**2+D1**2+R*D1*COS(A-A1) ) ``` Where D is the distance between the ship and the bomb, R is the altitude of the ship, D1 is the altitude of the bomb, and A-A1 is the angle between the ship and the bomb. diff --git a/68_Orbit/python/orbit.py b/68_Orbit/python/orbit.py index cfca3c93b..ce22a9b48 100644 --- a/68_Orbit/python/orbit.py +++ b/68_Orbit/python/orbit.py @@ -81,7 +81,7 @@ def print_instructions() -> None: ) -def get_yes_or_no() -> bool: +def get_yes_or_no(): while True: response = input().upper() if response == "YES": @@ -92,7 +92,7 @@ def get_yes_or_no() -> bool: print("PLEASE TYPE 'YES' OR 'NO'") -def game_over(is_success: bool) -> bool: +def game_over(is_success): if is_success: print("YOU HAVE SUCCESSFULLY COMPLETED YOUR MISSION.") else: @@ -103,11 +103,13 @@ def game_over(is_success: bool) -> bool: return get_yes_or_no() -def play_game() -> bool: +def play_game(): rom_angle = random.randint(0, 359) rom_distance = random.randint(100, 300) rom_angular_velocity = random.randint(10, 30) - for hour in range(1, 8): + hour = 0 + while hour < 7: + hour += 1 print() print() print(f"THIS IS HOUR {hour}, AT WHAT ANGLE DO YOU WISH TO SEND") @@ -143,7 +145,10 @@ def play_game() -> bool: def main() -> None: print_centered("ORBIT") - print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() print_instructions() diff --git a/68_Orbit/ruby/orbit.rb b/68_Orbit/ruby/orbit.rb deleted file mode 100644 index cbf86b4d1..000000000 --- a/68_Orbit/ruby/orbit.rb +++ /dev/null @@ -1,132 +0,0 @@ -PAGE_WIDTH = 64 - -def print_centered(msg) - spaces = " " * ((PAGE_WIDTH / msg.length).fdiv(2)) - puts "#{spaces}#{msg}" -end - -def print_instructions - puts "SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP. -THE SHIP IS IN A CONSTANT POLAR ORBIT. ITS -DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM -10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN -CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS. -UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO -YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL -INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR -PHOTON BOMB EXPLODED. YOU HAVE SEVEN HOURS UNTIL THEY -HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE -YOUR PLANET'S GRAVITY. -YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR. -AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN -ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF -100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S -DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN. -AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP -WILL DESTROY IT. -BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT. - 90 - 0000000000000 - 0000000000000000000 - 000000 000000 - 00000 00000 - 00000 XXXXXXXXXXX 00000 - 00000 XXXXXXXXXXXXX 00000 - 0000 XXXXXXXXXXXXXXX 0000 - 0000 XXXXXXXXXXXXXXXXX 0000 - 0000 XXXXXXXXXXXXXXXXXXX 0000 -180<== 00000 XXXXXXXXXXXXXXXXXXX 00000 ==>0 - 0000 XXXXXXXXXXXXXXXXXXX 0000 - 0000 XXXXXXXXXXXXXXXXX 0000 - 0000 XXXXXXXXXXXXXXX 0000 - 00000 XXXXXXXXXXXXX 00000 - 00000 XXXXXXXXXXX 00000 - 00000 00000 - 000000 000000 - 0000000000000000000 - 0000000000000 - 270 -X - YOUR PLANET -O - THE ORBIT OF THE ROMULAN SHIP -ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING -COUNTERCLOCKWISE AROUND YOUR PLANET. DON'T FORGET THAT -WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE -AND ORBITAL RATE WILL REMAIN CONSTANT. -GOOD LUCK. THE FEDERATION IS COUNTING ON YOU. -" -end - - -def get_yes_or_no() - while true - response = gets.chomp!.upcase - if response == "YES" - return true - elsif response == "NO" - return false - else - print("PLEASE TYPE 'YES' OR 'NO'") - end - end -end - -def game_over(is_success) - if is_success - puts "YOU HAVE SUCCESSFULLY COMPLETED YOUR MISSION." - else - puts "YOU HAVE ALLOWED THE ROMULANS TO ESCAPE." - puts "ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT." - puts "DO YOU WISH TO TRY TO DESTROY IT?" - return get_yes_or_no() - end -end - -def play_game - rom_angle = rand(1...360) - rom_distance = rand(100...301) - rom_angular_velocity = rand(10...31) - hour = 0 - while hour < 7 - hour += 1 - puts "\n\n" - puts "THIS IS HOUR #{hour}, AT WHAT ANGLE DO YOU WISH TO SEND" - puts "YOUR PHOTON BOMB?" - - bomb_angle = gets.chomp!.to_f - puts "HOW FAR OUT DO YOU WISH TO DETONATE IT?" - bomb_distance = gets.chomp!.to_f - puts "\n\n" - - rom_angle = (rom_angle + rom_angular_velocity) % 360 - angular_difference = rom_angle - bomb_angle - c = Math.sqrt(rom_distance**2 + bomb_distance**2 - 2 * rom_distance * bomb_distance * Math.cos(angular_difference * Math::PI / 180)) - - puts "YOUR PHOTON BOMB EXPLODED #{sprintf('%.4f', 5)}*10^2 MILES FROM THE" - puts "ROMULAN SHIP." - - if c <= 50 - # Destroyed the Romulan - return true - end - end - return false -end - -def main - print_centered "ORBIT" - - print_instructions() - - while true - success = play_game() - again = game_over(success) - if !again - return - end - end -end - -if __FILE__ == $0 - main -end - \ No newline at end of file diff --git a/68_Orbit/rust/Cargo.lock b/68_Orbit/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/68_Orbit/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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.toml b/68_Orbit/rust/Cargo.toml deleted file mode 100644 index 1c2935d47..000000000 --- a/68_Orbit/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" \ No newline at end of file diff --git a/68_Orbit/rust/README.md b/68_Orbit/rust/README.md deleted file mode 100644 index 7e85f9a15..000000000 --- a/68_Orbit/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) - -Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) diff --git a/68_Orbit/rust/src/lib.rs b/68_Orbit/rust/src/lib.rs deleted file mode 100644 index 2075d7843..000000000 --- a/68_Orbit/rust/src/lib.rs +++ /dev/null @@ -1,215 +0,0 @@ -/* - lib.rs contains all the logic of the program -*/ - -use std::{error::Error, fmt::Display, str::FromStr, io::{self, Write}, f64::consts::PI}; - -use rand::{thread_rng, Rng}; - -/// handles setup for the game -pub struct Config { -} -impl Config { - /// creates and returns a new Config from user input - pub fn new() -> Result> { - //DATA - let config: Config = Config {}; - - //this game doesn't actually need a config - - //return new config - return Ok(config); - } -} - -/// run the program -pub fn run(_config: &Config) -> Result<(), Box> { - - //play game as long as user wants to play it - while play_game() {} - - //return to main - Ok(()) -} - -/// handles playing the game one time -/// after playing, asks the user if they want to play again and ... -/// returns true if user wants to play again, false otherwise -fn play_game() -> bool { - //DATA - let mut rng = thread_rng(); - let mut ship_destroyed:bool = false; - //generate position of the ship - let mut ship:Polar = Polar::new(rng.gen_range(0.0..2.0*PI), rng.gen_range(100.0_f64..300.0_f64).floor()); - let ship_speed:f64 = rng.gen_range((PI/36.0)..(PI/12.0)); //10deg - 30deg, but radians - - //game - // round loop - for hour in 0..7 { - //DATA - let photon_bomb:Polar; - let two_pi = 2.0*PI; - let distance; - - //tell user the hour - println!("THIS IS HOUR {},", hour); - - //get input for angle and distance to send the bomb - photon_bomb = get_bomb_from_user_input(); - - //move ship - ship.angle += ship_speed; - if ship.angle > two_pi { ship.angle -= two_pi} - - //calculate distance of bomb from ship - distance = photon_bomb.distance_from(&ship); - //tell user how far away they were from the target - println!("YOUR PHOTON BOMB EXPLODED {}*10^2 MILES FROM THE ROMULAN SHIP\n\n", distance); - - //did the bomb destroy the ship? - ship_destroyed = distance <= 50.0; - if ship_destroyed {break;} - //otherwise user didn't destroy the ship, run loop again - } - - //print results message depending on whether or not the user destroyed the ship in time - if ship_destroyed { - println!("YOU HAVE SUCCESFULLY COMPLETED YOUR MISSION."); - } else { - println!("YOU HAVE ALLOWED THE ROMULANS TO ESCAPE.") - } - - //prompt user to play again - //do they want to play yes? if they do return true, otherwise false - return match get_string_from_user_input("ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT.\nDO YOU WISH TO TRY TO DESTROY IT?\n(y/n) ") { - Ok(string) => string.chars().any(|c| c.eq_ignore_ascii_case(&'y')), - Err(_e) => false, - }; -} - -/// structure to handle polar coordinates -struct Polar { - angle: f64, - radius: f64, -} -impl Polar { - /// create new polar cordinate with the given angle (in degrees) and radiurd from the origin - fn new(angle:f64, radius:f64) -> Polar { - //if radius is negative, correct it - if radius < 0.0 { - return Polar{ angle: angle + PI/2.0, radius: -radius }; - } - Polar { angle, radius} - } - ///create new polar cordinate with the given angle (in degrees, converted to radians) and radius from the origin - fn new_from_degrees(angle:usize, radius:f64) -> Polar { - let angle_to_rads: f64 = f64::from( (angle % 360) as u16) * PI/180.0; - - Polar::new(angle_to_rads, radius) - } - ///calculates the distance between 2 coordinates using the law of cosines - fn distance_from(&self,other:&Polar) -> f64 { - (other.radius*other.radius + self.radius*self.radius - 2.0*other.radius*self.radius*((other.angle-self.angle).abs().cos())).sqrt().floor() - } -} - -/// gets a Polar with bomb angle and detonation range from user -fn get_bomb_from_user_input() -> Polar { - return loop {//input loop - //DATA - let bomb_angle:usize; - let bomb_altitude:f64; - //get angle - match get_number_from_input("AT WHAT ANGLE DO YOU WISH TO SEND YOUR PHOTON BOMB (0-360): ", 0_usize, 360_usize) { - Ok(angle) => bomb_angle = angle, - Err(err) => { - println!("{}",err); - continue; - }, - } - //get radius - match get_number_from_input("HOW FAR OUT DO YOU WISH TO DETONATE IT (100.0-300.0): ", 100.0, 300.0) { - Ok(radius) => bomb_altitude = radius, - Err(err) => { - println!("{}",err); - continue; - }, - } - println!(""); - //create coordinates from input - break Polar::new_from_degrees( bomb_angle, bomb_altitude); - }; -} - -/// gets a string from user input -fn get_string_from_user_input(prompt: &str) -> Result> { - //DATA - let mut raw_input = String::new(); - - //print prompt - print!("{}", prompt); - //make sure it's printed before getting input - io::stdout().flush().unwrap(); - - //read user input from standard input, and store it to raw_input, then return it or an error as needed - raw_input.clear(); //clear input - match io::stdin().read_line(&mut raw_input) { - Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())), - Err(err) => return Err(format!("ERROR: CANNOT READ INPUT!: {}", err).into()), - } -} - -/// generic function to get a number from the passed string (user input) -/// pass a min lower than the max to have minimun and maximun bounds -/// pass a min higher than the max to only have a minumum bound -/// pass a min equal to the max to only have a maximun bound -/// -/// Errors: -/// no number on user input -fn get_number_from_input(prompt: &str, min:T, max:T) -> Result> { - //DATA - let raw_input: String; - let processed_input: String; - - - //input looop - raw_input = loop { - match get_string_from_user_input(prompt) { - Ok(input) => break input, - Err(e) => { - eprintln!("{}",e); - continue; - }, - } - }; - - //filter out num-numeric characters from user input - processed_input = raw_input.chars().filter(|c| c.is_numeric() || c.eq_ignore_ascii_case(&'.')).collect(); - - //from input, try to read a number - match processed_input.trim().parse() { - Ok(i) => { - //what bounds must the input fall into - if min < max { //have a min and max bound: [min,max] - if i >= min && i <= max {//is input valid, within bounds - return Ok(i); //exit the loop with the value i, returning it - } else { //print error message specific to this case - return Err(format!("ONLY BETWEEN {} AND {}, PLEASE!", min, max).into()); - } - } else if min > max { //only a min bound: [min, infinity) - if i >= min { - return Ok(i); - } else { - return Err(format!("NO LESS THAN {}, PLEASE!", min).into()); - } - } else { //only a max bound: (-infinity, max] - if i <= max { - return Ok(i); - } else { - return Err(format!("NO MORE THAN {}, PLEASE!", max).into()); - } - } - }, - Err(_e) => return Err(format!("Error: couldn't find a valid number in {}",raw_input).into()), - } -} \ No newline at end of file diff --git a/68_Orbit/rust/src/main.rs b/68_Orbit/rust/src/main.rs deleted file mode 100644 index 18d61a762..000000000 --- a/68_Orbit/rust/src/main.rs +++ /dev/null @@ -1,103 +0,0 @@ -/* - The responsibilities that remain in the main function after separating concerns - should be limited to the following: - - Setting up any configuration - - Calling a run function in lib.rs - - Handling the error if run returns an error -*/ - -use std::process; //allows for some better error handling - -mod lib; -use lib::Config; - -/// main function -fn main() { - //greet user - welcome(); - - // set up other configuration - let mut config = Config::new().unwrap_or_else(|err| { - eprintln!("Problem configuring program: {}", err); - process::exit(1); - }); - - // run the program - if let Err(e) = lib::run(&mut config) { - eprintln!("Application Error: {}", e); //use the eprintln! macro to output to standard error - process::exit(1); //exit the program with an error code - } - - //end of program - println!("THANKS FOR PLAYING!"); -} - -/// prints the welcome/start message -fn welcome() { - println!(" - Orbit - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - - - - SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP. - - THE SHIP IS IN A CONSTANT POLAR ORBIT. ITS - DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM - 10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN - CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS. - - UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO - YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL - INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR - PHOTON BOMB EXPLODED. YOU HAVE SEVEN HOURS UNTIL THEY - HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE - YOUR PLANET'S GRAVITY. - - YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR. - - AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN - ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF - 100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S - DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN. - - AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP - WILL DESTROY IT. - - BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT. - - - 90 - 0000000000000 - 0000000000000000000 - 000000 000000 - 00000 00000 - 00000 XXXXXXXXXXX 00000 - 00000 XXXXXXXXXXXXX 00000 - 0000 XXXXXXXXXXXXXXX 0000 - 0000 XXXXXXXXXXXXXXXXX 0000 - 0000 XXXXXXXXXXXXXXXXXXX 0000 - 180<== 00000 XXXXXXXXXXXXXXXXXXX 00000 ==>0 - 0000 XXXXXXXXXXXXXXXXXXX 0000 - 0000 XXXXXXXXXXXXXXXXX 0000 - 0000 XXXXXXXXXXXXXXX 0000 - 00000 XXXXXXXXXXXXX 00000 - 00000 XXXXXXXXXXX 00000 - 00000 00000 - 000000 000000 - 0000000000000000000 - 0000000000000 - 270 - - X - YOUR PLANET - O - THE ORBIT OF THE ROMULAN SHIP - - ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING - COUNTERCLOCKWISE AROUND YOUR PLANET. DON'T FORGET THAT - WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE - AND ORBITAL RATE WILL REMAIN CONSTANT. - - GOOD LUCK. THE FEDERATION IS COUNTING ON YOU. - "); -} - diff --git a/69_Pizza/README.md b/69_Pizza/README.md index 7f9e3fcf2..56548b645 100644 --- a/69_Pizza/README.md +++ b/69_Pizza/README.md @@ -15,10 +15,6 @@ 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) diff --git a/69_Pizza/python/pizza.py b/69_Pizza/python/pizza.py index aa4a01e93..bb8ed3ed9 100644 --- a/69_Pizza/python/pizza.py +++ b/69_Pizza/python/pizza.py @@ -89,7 +89,7 @@ def print_instructions() -> str: return player_name -def yes_no_prompt(msg: str) -> bool: +def yes_no_prompt(msg): while True: print(msg) response = input().upper() @@ -113,11 +113,11 @@ def print_more_directions(player_name: str) -> None: print() -def calculate_customer_index(x: int, y: int) -> int: +def calculate_customer_index(x, y): return 4 * (y - 1) + x - 1 -def deliver_to(customer_index, customer_name, player_name) -> bool: +def deliver_to(customer_index, customer_name, player_name): print(f" DRIVER TO {player_name}: WHERE DOES {customer_name} LIVE?") coords = input() @@ -133,7 +133,7 @@ def deliver_to(customer_index, customer_name, player_name) -> bool: return False -def play_game(num_turns, player_name) -> None: +def play_game(num_turns, player_name): for _turn in range(num_turns): x = random.randint(1, 4) y = random.randint(1, 4) @@ -155,7 +155,9 @@ def main() -> None: player_name = print_instructions() - if more_directions := yes_no_prompt("DO YOU NEED MORE DIRECTIONS?"): + more_directions = yes_no_prompt("DO YOU NEED MORE DIRECTIONS?") + + if more_directions: print_more_directions(player_name) understand = yes_no_prompt("UNDERSTAND?") @@ -169,8 +171,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/69_Pizza/rust/Cargo.lock b/69_Pizza/rust/Cargo.lock deleted file mode 100644 index b4abe0dca..000000000 --- a/69_Pizza/rust/Cargo.lock +++ /dev/null @@ -1,23 +0,0 @@ -# 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 deleted file mode 100644 index 5224dbab6..000000000 --- a/69_Pizza/rust/Cargo.toml +++ /dev/null @@ -1,10 +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] -anyhow = "1.0.75" -fastrand = "2.0.1" diff --git a/69_Pizza/rust/README.md b/69_Pizza/rust/README.md deleted file mode 100644 index ce0d38dc2..000000000 --- a/69_Pizza/rust/README.md +++ /dev/null @@ -1,3 +0,0 @@ -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 deleted file mode 100644 index 4bfe4f226..000000000 --- a/69_Pizza/rust/src/main.rs +++ /dev/null @@ -1,178 +0,0 @@ -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(()); - } - } -} diff --git a/70_Poetry/README.md b/70_Poetry/README.md index be21f8bee..7684ebecc 100644 --- a/70_Poetry/README.md +++ b/70_Poetry/README.md @@ -30,6 +30,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -- 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. +(please note any difficulties or challenges in porting here) diff --git a/70_Poetry/csharp/Context.cs b/70_Poetry/csharp/Context.cs deleted file mode 100644 index a9297915e..000000000 --- a/70_Poetry/csharp/Context.cs +++ /dev/null @@ -1,109 +0,0 @@ -namespace Poetry; - -internal class Context -{ - private readonly IReadWrite _io; - private readonly IRandom _random; - private int _phraseNumber; - private int _groupNumber; - private bool _skipComma; - private int _lineCount; - private bool _useGroup2; - private bool _atStartOfLine = true; - - public Context(IReadWrite io, IRandom random) - { - _io = io; - _random = random; - } - - public int PhraseNumber => Math.Max(_phraseNumber - 1, 0); - - public int GroupNumber - { - get - { - var value = _useGroup2 ? 2 : _groupNumber; - _useGroup2 = false; - return Math.Max(value - 1, 0); - } - } - - public int PhraseCount { get; set; } - public bool GroupNumberIsValid => _groupNumber < 5; - - public void WritePhrase() - { - Phrase.GetPhrase(this).Write(_io, this); - _atStartOfLine = false; - } - - public void MaybeWriteComma() - { - if (!_skipComma && _random.NextFloat() <= 0.19F && PhraseCount != 0) - { - _io.Write(","); - PhraseCount = 2; - } - _skipComma = false; - } - - public void WriteSpaceOrNewLine() - { - if (_random.NextFloat() <= 0.65F) - { - _io.Write(" "); - PhraseCount += 1; - } - else - { - EndLine(); - PhraseCount = 0; - } - } - - public void Update(IRandom random) - { - _phraseNumber = random.Next(1, 6); - _groupNumber += 1; - _lineCount += 1; - } - - public void MaybeIndent() - { - if (PhraseCount == 0 && _groupNumber % 2 == 0) - { - _io.Write(" "); - } - } - - public void ResetGroup() - { - _groupNumber = 0; - EndLine(); - } - - public bool MaybeCompleteStanza() - { - if (_lineCount > 20) - { - _io.WriteLine(); - PhraseCount = _lineCount = 0; - _useGroup2 = true; - return true; - } - - return false; - } - - internal string MaybeCapitalise(string text) => - _atStartOfLine ? (char.ToUpper(text[0]) + text[1..]) : text; - - public void SkipNextComma() => _skipComma = true; - - public void EndLine() - { - _io.WriteLine(); - _atStartOfLine = true; - } -} diff --git a/70_Poetry/csharp/Phrase.cs b/70_Poetry/csharp/Phrase.cs deleted file mode 100644 index f70de30bd..000000000 --- a/70_Poetry/csharp/Phrase.cs +++ /dev/null @@ -1,78 +0,0 @@ -namespace Poetry; - -internal class Phrase -{ - private readonly static Phrase[][] _phrases = new Phrase[][] - { - new Phrase[] - { - new("midnight dreary"), - new("fiery eyes"), - new("bird or fiend"), - new("thing of evil"), - new("prophet") - }, - new Phrase[] - { - new("beguiling me", ctx => ctx.PhraseCount = 2), - new("thrilled me"), - new("still sitting....", ctx => ctx.SkipNextComma()), - new("never flitting", ctx => ctx.PhraseCount = 2), - new("burned") - }, - new Phrase[] - { - new("and my soul"), - new("darkness there"), - new("shall be lifted"), - new("quoth the raven"), - new(ctx => ctx.PhraseCount != 0, "sign of parting") - }, - new Phrase[] - { - new("nothing more"), - new("yet again"), - new("slowly creeping"), - new("...evermore"), - new("nevermore") - } - }; - - private readonly Predicate _condition; - private readonly string _text; - private readonly Action _update; - - private Phrase(Predicate condition, string text) - : this(condition, text, _ => { }) - { - } - - private Phrase(string text, Action update) - : this(_ => true, text, update) - { - } - - private Phrase(string text) - : this(_ => true, text, _ => { }) - { - } - - private Phrase(Predicate condition, string text, Action update) - { - _condition = condition; - _text = text; - _update = update; - } - - public static Phrase GetPhrase(Context context) => _phrases[context.GroupNumber][context.PhraseNumber]; - - public void Write(IReadWrite io, Context context) - { - if (_condition.Invoke(context)) - { - io.Write(context.MaybeCapitalise(_text)); - } - - _update.Invoke(context); - } -} \ No newline at end of file diff --git a/70_Poetry/csharp/Poem.cs b/70_Poetry/csharp/Poem.cs deleted file mode 100644 index fa3d50459..000000000 --- a/70_Poetry/csharp/Poem.cs +++ /dev/null @@ -1,32 +0,0 @@ -using static Poetry.Resources.Resource; - -namespace Poetry; - -internal class Poem -{ - internal static void Compose(IReadWrite io, IRandom random) - { - io.Write(Streams.Title); - - var context = new Context(io, random); - - while (true) - { - context.WritePhrase(); - context.MaybeWriteComma(); - context.WriteSpaceOrNewLine(); - - while (true) - { - context.Update(random); - context.MaybeIndent(); - - if (context.GroupNumberIsValid) { break; } - - context.ResetGroup(); - - if (context.MaybeCompleteStanza()) { break; } - } - } - } -} \ No newline at end of file diff --git a/70_Poetry/csharp/Poetry.csproj b/70_Poetry/csharp/Poetry.csproj index 3870320c9..d3fe4757c 100644 --- a/70_Poetry/csharp/Poetry.csproj +++ b/70_Poetry/csharp/Poetry.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/70_Poetry/csharp/Program.cs b/70_Poetry/csharp/Program.cs deleted file mode 100644 index 3a17d72c2..000000000 --- a/70_Poetry/csharp/Program.cs +++ /dev/null @@ -1,5 +0,0 @@ -global using Games.Common.IO; -global using Games.Common.Randomness; -global using Poetry; - -Poem.Compose(new ConsoleIO(), new RandomNumberGenerator()); diff --git a/70_Poetry/csharp/Resources/Resource.cs b/70_Poetry/csharp/Resources/Resource.cs deleted file mode 100644 index b789f0357..000000000 --- a/70_Poetry/csharp/Resources/Resource.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Poetry.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Title => GetStream(); - } - - 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/70_Poetry/csharp/Resources/Title.txt b/70_Poetry/csharp/Resources/Title.txt deleted file mode 100644 index 861613403..000000000 --- a/70_Poetry/csharp/Resources/Title.txt +++ /dev/null @@ -1,5 +0,0 @@ - Poetry - Creative Computing Morristown, New Jersey - - - diff --git a/70_Poetry/poetry.bas b/70_Poetry/poetry.bas index 7fa3a1c40..3661287de 100644 --- a/70_Poetry/poetry.bas +++ b/70_Poetry/poetry.bas @@ -1,8 +1,3 @@ -5 Y=RND(-1) -6 REM FOR X = 1 TO 100 -7 REM PRINT RND(1);"," -8 REM NEXT X -9 REM GOTO 999 10 PRINT TAB(30);"POETRY" 20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" 30 PRINT:PRINT:PRINT @@ -31,21 +26,17 @@ 133 PRINT "SLOWLY CREEPING";:GOTO 210 134 PRINT "...EVERMORE";:GOTO 210 135 PRINT "NEVERMORE"; -210 GOSUB 500 : IF U=0 OR X>.19 THEN 212 +210 IF U=0 OR RND(1)>.19 THEN 212 211 PRINT ",";:U=2 -212 GOSUB 500 : IF X>.65 THEN 214 +212 IF RND(1)>.65 THEN 214 213 PRINT " ";:U=U+1:GOTO 215 214 PRINT : U=0 -215 GOSUB 500 : I=INT(INT(10*X)/2)+1 +215 I=INT(INT(10*RND(1))/2)+1 220 J=J+1 : K=K+1 -225 REM PRINT "I=";I;"; J=";J;"; K=";K;"; U=";U 230 IF U>0 OR INT(J/2)<>J/2 THEN 240 235 PRINT " "; 240 ON J GOTO 90,110,120,130,250 250 J=0 : PRINT : IF K>20 THEN 270 260 GOTO 215 270 PRINT : U=0 : K=0 : GOTO 110 -500 X = RND(1) -505 REM PRINT "#";X;"#" -510 RETURN 999 END diff --git a/70_Poetry/python/poetry.py b/70_Poetry/python/poetry.py index f261db375..84b0b2aea 100644 --- a/70_Poetry/python/poetry.py +++ b/70_Poetry/python/poetry.py @@ -6,20 +6,24 @@ Ported by Dave LeCompte """ +# PORTING EDITORIAL NOTE: +# +# The original code is a pretty convoluted mesh of GOTOs and global +# state. This adaptation pulls things apart into phrases, but I have +# left the variables as globals, which makes goes against decades of +# wisdom that global state is bad. import random -from dataclasses import dataclass PAGE_WIDTH = 64 -@dataclass -class State: - u: int = 0 - i: int = 0 - j: int = 0 - k: int = 0 - phrase: int = 1 - line: str = "" +# globals +u = 0 +i = 0 +j = 0 +k = 0 +phrase = 1 +line = "" def print_centered(msg: str) -> None: @@ -27,7 +31,9 @@ def print_centered(msg: str) -> None: print(spaces + msg) -def process_phrase_1(state: State) -> str: +def process_phrase_1() -> str: + global line + line_1_options = [ "MIDNIGHT DREARY", "FIERY EYES", @@ -35,11 +41,15 @@ def process_phrase_1(state: State) -> str: "THING OF EVIL", "PROPHET", ] - state.line = state.line + line_1_options[state.i] - return state.line + + line = line + line_1_options[i] + return line -def process_phrase_2(state: State) -> None: +def process_phrase_2() -> None: + global line + global u + line_2_options = [ ("BEGUILING ME", 2), ("THRILLED ME", None), @@ -47,13 +57,15 @@ def process_phrase_2(state: State) -> None: ("NEVER FLITTING", 2), ("BURNED", None), ] - words, u_modifier = line_2_options[state.i] - state.line += words - if u_modifier is not None: - state.u = u_modifier + words, u_modifier = line_2_options[i] + line += words + if not (u_modifier is None): + u = u_modifier + +def process_phrase_3() -> None: + global line -def process_phrase_3(state: State) -> None: phrases = [ (False, "AND MY SOUL"), (False, "DARKNESS THERE"), @@ -62,12 +74,14 @@ def process_phrase_3(state: State) -> None: (True, "SIGN OF PARTING"), ] - only_if_u, words = phrases[state.i] - if (not only_if_u) or (state.u > 0): - state.line = state.line + words + only_if_u, words = phrases[i] + if (not only_if_u) or (u > 0): + line = line + words -def process_phrase_4(state: State) -> None: +def process_phrase_4() -> None: + global line + phrases = [ ("NOTHING MORE"), ("YET AGAIN"), @@ -76,42 +90,55 @@ def process_phrase_4(state: State) -> None: ("NEVERMORE"), ] - state.line += phrases[state.i] + line += phrases[i] + +def maybe_comma(): + # line 210 + global u + global line -def maybe_comma(state: State) -> None: - if len(state.line) > 0 and state.line[-1] == ".": + if len(line) > 0 and line[-1] == ".": # don't follow a period with a comma, ever return - if state.u != 0 and random.random() <= 0.19: - state.line += ", " - state.u = 2 + if u != 0 and random.random() <= 0.19: + line += ", " + u = 2 + # line 212 if random.random() <= 0.65: - state.line += " " - state.u += 1 + line += " " + u += 1 else: - print(state.line) - state.line = "" - state.u = 0 + # line 214 + print(line) + line = "" + u = 0 + +def pick_phrase(): + global phrase + global line + global i, j, k -def pick_phrase(state: State) -> None: - state.i = random.randint(0, 4) - state.j += 1 - state.k += 1 + i = random.randint(0, 4) + j += 1 + k += 1 - if state.u <= 0 and (state.j % 2) != 0: + if u <= 0 and (j % 2) != 0: # random indentation is fun! - state.line += " " * 5 - state.phrase = state.j + 1 + line += " " * 5 + phrase = j + 1 def main() -> None: print_centered("POETRY") - print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n") + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() - state = State() + global line, phrase, j, k, u phrase_processors = { 1: process_phrase_1, @@ -121,21 +148,21 @@ def main() -> None: } while True: - if state.phrase >= 1 and state.phrase <= 4: - phrase_processors[state.phrase](state) - maybe_comma(state) - elif state.phrase == 5: - state.j = 0 - print(state.line) - state.line = "" - if state.k > 20: + if phrase >= 1 and phrase <= 4: + phrase_processors[phrase]() + maybe_comma() + elif phrase == 5: + j = 0 + print(line) + line = "" + if k > 20: print() - state.u = 0 - state.k = 0 + u = 0 + k = 0 else: - state.phrase = 2 + phrase = 2 continue - pick_phrase(state) + pick_phrase() if __name__ == "__main__": diff --git a/70_Poetry/ruby/poetry.rb b/70_Poetry/ruby/poetry.rb deleted file mode 100644 index 4fe6afd33..000000000 --- a/70_Poetry/ruby/poetry.rb +++ /dev/null @@ -1,141 +0,0 @@ -PAGE_WIDTH = 64 - -class State - attr_accessor :u, :i, :j, :k, :phrase, :line - - def initialize - self.u = 0 - self.i = 0 - self.j = 0 - self.k = 0 - self.phrase = 1 - self.line = "" - end -end - - -def print_centered msg - spaces = " " * ((PAGE_WIDTH - msg.length).fdiv(2)) - print(spaces + msg) -end - -def process_phrase_1 state - line_1_options = [ - "MIDNIGHT DREARY", - "FIERY EYES", - "BIRD OR FIEND", - "THING OF EVIL", - "PROPHET" - ] - - state.line = state.line + line_1_options[state.i] - return state.line -end - -def process_phrase_2 state - line_2_options = [ - ["BEGUILING ME", 2], - ["THRILLED ME", nil], - ["STILL SITTING....", nil], - ["NEVER FLITTING", 2], - ["BURNED", nil] - ] - words, u_modifier = line_2_options[state.i] - state.line += words - if !u_modifier.nil? - state.u = u_modifier - end -end - -def process_phrase_3 state - phrases = [ - [false, "AND MY SOUL"], - [false, "DARKNESS THERE"], - [false, "SHALL BE LIFTED"], - [false, "QUOTH THE RAVEN"], - [true, "SIGN OF PARTING"] - ] - - only_if_u, words = phrases[state.i] - if !only_if_u || state.u > 0 - state.line = state.line + words - end -end - -def process_phrase_4 state - phrases = [ - "NOTHING MORE", - "YET AGAIN", - "SLOWLY CREEPING", - "...EVERMORE", - "NEVERMORE" - ] - - state.line += phrases[state.i] -end - -def maybe_comma state - if state.line.length > 0 && state.line[-1] == "." - return - end - - if state.u != 0 && Random.rand <= 0.19 - state.line += ", " - state.u = 2 - end - - if Random.rand <= 0.65 - state.line += " " - state.u += 1 - else - puts state.line - state.line = "" - state.u = 0 - end -end - -def pick_phrase state - state.i = Random.rand(0..4) - state.j += 1 - state.k += 1 - - if state.u <= 0 && (state.j % 2) != 0 - state.line += (" " * 5) - end - state.phrase = state.j + 1 -end - -def main - print_centered("POETRY") - state = State.new - phrase_processors = { - '1' => 'process_phrase_1', - '2' => 'process_phrase_2', - '3' => 'process_phrase_3', - '4' => 'process_phrase_4' - } - - while true - if state.phrase >= 1 && state.phrase <= 4 - method(phrase_processors[state.phrase.to_s]).call(state) - maybe_comma state - elsif state.phrase == 5 - state.j = 0 - puts state.line - state.line = "" - if state.k > 20 - puts "" - state.u = 0 - state.k = 0 - else - state.phrase = 2 - next - end - end - pick_phrase state - end -end - -if __FILE__ == $0 - main -end \ No newline at end of file diff --git a/71_Poker/README.md b/71_Poker/README.md index 08bc04c63..a80820598 100644 --- a/71_Poker/README.md +++ b/71_Poker/README.md @@ -15,17 +15,6 @@ 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) diff --git a/71_Poker/csharp/Cards/Card.cs b/71_Poker/csharp/Cards/Card.cs deleted file mode 100644 index d31762130..000000000 --- a/71_Poker/csharp/Cards/Card.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Poker.Cards; - -internal record struct Card (Rank Rank, Suit Suit) -{ - public override string ToString() => $"{Rank} of {Suit}"; - - public static bool operator <(Card x, Card y) => x.Rank < y.Rank; - public static bool operator >(Card x, Card y) => x.Rank > y.Rank; - - public static int operator -(Card x, Card y) => x.Rank - y.Rank; -} diff --git a/71_Poker/csharp/Cards/Deck.cs b/71_Poker/csharp/Cards/Deck.cs deleted file mode 100644 index d3a101b49..000000000 --- a/71_Poker/csharp/Cards/Deck.cs +++ /dev/null @@ -1,28 +0,0 @@ -using static Poker.Cards.Rank; - -namespace Poker.Cards; - -internal class Deck -{ - private readonly Card[] _cards; - private int _nextCard; - - public Deck() - { - _cards = Ranks.SelectMany(r => Enum.GetValues().Select(s => new Card(r, s))).ToArray(); - } - - public void Shuffle(IRandom _random) - { - for (int i = 0; i < _cards.Length; i++) - { - var j = _random.Next(_cards.Length); - (_cards[i], _cards[j]) = (_cards[j], _cards[i]); - } - _nextCard = 0; - } - - public Card DealCard() => _cards[_nextCard++]; - - public Hand DealHand() => new Hand(Enumerable.Range(0, 5).Select(_ => DealCard())); -} diff --git a/71_Poker/csharp/Cards/Hand.cs b/71_Poker/csharp/Cards/Hand.cs deleted file mode 100644 index 34c14ac45..000000000 --- a/71_Poker/csharp/Cards/Hand.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System.Text; -using static Poker.Cards.HandRank; -namespace Poker.Cards; - -internal class Hand -{ - public static readonly Hand Empty = new Hand(); - - private readonly Card[] _cards; - - private Hand() - { - _cards = Array.Empty(); - Rank = None; - } - - public Hand(IEnumerable cards) - : this(cards, isAfterDraw: false) - { - } - - private Hand(IEnumerable cards, bool isAfterDraw) - { - _cards = cards.ToArray(); - (Rank, HighCard, KeepMask) = Analyze(); - - IsWeak = Rank < PartialStraight - || Rank == PartialStraight && isAfterDraw - || Rank <= TwoPair && HighCard.Rank <= 6; - } - - public string Name => Rank.ToString(HighCard); - public HandRank Rank { get; } - public Card HighCard { get; } - public int KeepMask { get; set; } - public bool IsWeak { get; } - - public Hand Replace(int cardNumber, Card newCard) - { - if (cardNumber < 1 || cardNumber > _cards.Length) { return this; } - - _cards[cardNumber - 1] = newCard; - return new Hand(_cards, isAfterDraw: true); - } - - private (HandRank, Card, int) Analyze() - { - var suitMatchCount = 0; - for (var i = 0; i < _cards.Length; i++) - { - if (i < _cards.Length-1 && _cards[i].Suit == _cards[i+1].Suit) - { - suitMatchCount++; - } - } - if (suitMatchCount == 4) - { - return (Flush, _cards[0], 0b11111); - } - var sortedCards = _cards.OrderBy(c => c.Rank).ToArray(); - - var handRank = Schmaltz; - var keepMask = 0; - Card highCard = default; - for (var i = 0; i < sortedCards.Length - 1; i++) - { - var matchesNextCard = sortedCards[i].Rank == sortedCards[i+1].Rank; - var matchesPreviousCard = i > 0 && sortedCards[i].Rank == sortedCards[i - 1].Rank; - - if (matchesNextCard) - { - keepMask |= 0b11 << i; - highCard = sortedCards[i]; - handRank = matchesPreviousCard switch - { - _ when handRank < Pair => Pair, - true when handRank == Pair => Three, - _ when handRank == Pair => TwoPair, - _ when handRank == TwoPair => FullHouse, - true => Four, - _ => FullHouse - }; - } - } - if (keepMask == 0) - { - if (sortedCards[3] - sortedCards[0] == 3) - { - keepMask=0b1111; - handRank=PartialStraight; - } - if (sortedCards[4] - sortedCards[1] == 3) - { - if (handRank == PartialStraight) - { - return (Straight, sortedCards[4], 0b11111); - } - handRank=PartialStraight; - keepMask=0b11110; - } - } - return handRank < PartialStraight - ? (Schmaltz, sortedCards[4], 0b11000) - : (handRank, highCard, keepMask); - } - - public override string ToString() - { - var sb = new StringBuilder(); - for (var i = 0; i < _cards.Length; i++) - { - var cardDisplay = $" {i+1} -- {_cards[i]}"; - // Emulates the effect of the BASIC PRINT statement using the ',' to align text to 14-char print zones - sb.Append(cardDisplay.PadRight(cardDisplay.Length + 14 - cardDisplay.Length % 14)); - if (i % 2 == 1) - { - sb.AppendLine(); - } - } - sb.AppendLine(); - return sb.ToString(); - } - - public static bool operator >(Hand x, Hand y) => - x.Rank > y.Rank || - x.Rank == y.Rank && x.HighCard > y.HighCard; - - public static bool operator <(Hand x, Hand y) => - x.Rank < y.Rank || - x.Rank == y.Rank && x.HighCard < y.HighCard; -} diff --git a/71_Poker/csharp/Cards/HandRank.cs b/71_Poker/csharp/Cards/HandRank.cs deleted file mode 100644 index 878746ee5..000000000 --- a/71_Poker/csharp/Cards/HandRank.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace Poker.Cards; - -internal class HandRank -{ - public static HandRank None = new(0, ""); - public static HandRank Schmaltz = new(1, "schmaltz, ", c => $"{c.Rank} high"); - public static HandRank PartialStraight = new(2, ""); // The original code does not assign a display string here - public static HandRank Pair = new(3, "a pair of ", c => $"{c.Rank}'s"); - public static HandRank TwoPair = new(4, "two pair, ", c => $"{c.Rank}'s"); - public static HandRank Three = new(5, "three ", c => $"{c.Rank}'s"); - public static HandRank Straight = new(6, "straight", c => $"{c.Rank} high"); - public static HandRank Flush = new(7, "a flush in ", c => c.Suit.ToString()); - public static HandRank FullHouse = new(8, "full house, ", c => $"{c.Rank}'s"); - public static HandRank Four = new(9, "four ", c => $"{c.Rank}'s"); - // The original code does not detect a straight flush or royal flush - - private readonly int _value; - private readonly string _displayName; - private readonly Func _suffixSelector; - - private HandRank(int value, string displayName, Func? suffixSelector = null) - { - _value = value; - _displayName = displayName; - _suffixSelector = suffixSelector ?? (_ => ""); - } - - public string ToString(Card highCard) => $"{_displayName}{_suffixSelector.Invoke(highCard)}"; - - public static bool operator >(HandRank x, HandRank y) => x._value > y._value; - public static bool operator <(HandRank x, HandRank y) => x._value < y._value; - public static bool operator >=(HandRank x, HandRank y) => x._value >= y._value; - public static bool operator <=(HandRank x, HandRank y) => x._value <= y._value; -} diff --git a/71_Poker/csharp/Cards/Rank.cs b/71_Poker/csharp/Cards/Rank.cs deleted file mode 100644 index cd44922a6..000000000 --- a/71_Poker/csharp/Cards/Rank.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace Poker.Cards; - -internal struct Rank : IComparable -{ - public static IEnumerable Ranks => new[] - { - Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace - }; - - public static Rank Two = new(2); - public static Rank Three = new(3); - public static Rank Four = new(4); - public static Rank Five = new(5); - public static Rank Six = new(6); - public static Rank Seven = new(7); - public static Rank Eight = new(8); - public static Rank Nine = new(9); - public static Rank Ten = new(10); - public static Rank Jack = new(11, "Jack"); - public static Rank Queen = new(12, "Queen"); - public static Rank King = new(13, "King"); - public static Rank Ace = new(14, "Ace"); - - private readonly int _value; - private readonly string _name; - - private Rank(int value, string? name = null) - { - _value = value; - _name = name ?? $" {value} "; - } - - public override string ToString() => _name; - - public int CompareTo(Rank other) => this - other; - - public static bool operator <(Rank x, Rank y) => x._value < y._value; - public static bool operator >(Rank x, Rank y) => x._value > y._value; - public static bool operator ==(Rank x, Rank y) => x._value == y._value; - public static bool operator !=(Rank x, Rank y) => x._value != y._value; - - public static int operator -(Rank x, Rank y) => x._value - y._value; - - public static bool operator <=(Rank rank, int value) => rank._value <= value; - public static bool operator >=(Rank rank, int value) => rank._value >= value; - - public override bool Equals(object? obj) => obj is Rank other && this == other; - - public override int GetHashCode() => _value.GetHashCode(); -} diff --git a/71_Poker/csharp/Cards/Suit.cs b/71_Poker/csharp/Cards/Suit.cs deleted file mode 100644 index 0a246999f..000000000 --- a/71_Poker/csharp/Cards/Suit.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Poker.Cards; - -internal enum Suit -{ - Clubs, - Diamonds, - Hearts, - Spades -} diff --git a/71_Poker/csharp/Game.cs b/71_Poker/csharp/Game.cs deleted file mode 100644 index c7621a36c..000000000 --- a/71_Poker/csharp/Game.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Poker.Cards; -using Poker.Players; -using Poker.Resources; - -namespace Poker; - -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(Resource.Streams.Title); - _io.Write(Resource.Streams.Instructions); - - var deck = new Deck(); - var human = new Human(200, _io); - var computer = new Computer(200, _io, _random); - var table = new Table(_io, _random, deck, human, computer); - - do - { - table.PlayHand(); - } while (table.ShouldPlayAnotherHand()); - } -} diff --git a/71_Poker/csharp/IReadWriteExtensions.cs b/71_Poker/csharp/IReadWriteExtensions.cs deleted file mode 100644 index 7559a3289..000000000 --- a/71_Poker/csharp/IReadWriteExtensions.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Poker.Strategies; -using static System.StringComparison; - -namespace Poker; - -internal static class IReadWriteExtensions -{ - internal static bool ReadYesNo(this IReadWrite io, string prompt) - { - while (true) - { - var response = io.ReadString(prompt); - if (response.Equals("YES", InvariantCultureIgnoreCase)) { return true; } - if (response.Equals("NO", InvariantCultureIgnoreCase)) { return false; } - io.WriteLine("Answer Yes or No, please."); - } - } - - internal static float ReadNumber(this IReadWrite io) => io.ReadNumber(""); - - internal static int ReadNumber(this IReadWrite io, string prompt, int max, string maxPrompt) - { - io.Write(prompt); - while (true) - { - var response = io.ReadNumber(); - if (response <= max) { return (int)response; } - io.WriteLine(maxPrompt); - } - } - - internal static Strategy ReadHumanStrategy(this IReadWrite io, bool noCurrentBets) - { - while(true) - { - io.WriteLine(); - var bet = io.ReadNumber("What is your bet"); - if (bet != (int)bet) - { - if (noCurrentBets && bet == .5) { return Strategy.Check; } - io.WriteLine("No small change, please."); - continue; - } - if (bet == 0) { return Strategy.Fold; } - return Strategy.Bet(bet); - } - } -} \ No newline at end of file diff --git a/71_Poker/csharp/Players/Computer.cs b/71_Poker/csharp/Players/Computer.cs deleted file mode 100644 index 5ab2e77d8..000000000 --- a/71_Poker/csharp/Players/Computer.cs +++ /dev/null @@ -1,130 +0,0 @@ -using Poker.Cards; -using Poker.Strategies; -using static System.StringComparison; - -namespace Poker.Players; - -internal class Computer : Player -{ - private readonly IReadWrite _io; - private readonly IRandom _random; - - public Computer(int bank, IReadWrite io, IRandom random) - : base(bank) - { - _io = io; - _random = random; - Strategy = Strategy.None; - } - - public Strategy Strategy { get; set; } - - public override void NewHand() - { - base.NewHand(); - - Strategy = (Hand.IsWeak, Hand.Rank < HandRank.Three, Hand.Rank < HandRank.FullHouse) switch - { - (true, _, _) when _random.Next(10) < 2 => Strategy.Bluff(23, 0b11100), - (true, _, _) when _random.Next(10) < 2 => Strategy.Bluff(23, 0b11110), - (true, _, _) when _random.Next(10) < 1 => Strategy.Bluff(23, 0b11111), - (true, _, _) => Strategy.Fold, - (false, true, _) => _random.Next(10) < 2 ? Strategy.Bluff(23) : Strategy.Check, - (false, false, true) => Strategy.Bet(35), - (false, false, false) => _random.Next(10) < 1 ? Strategy.Bet(35) : Strategy.Raise - }; - } - - protected override void DrawCards(Deck deck) - { - var keepMask = Strategy.KeepMask ?? Hand.KeepMask; - var count = 0; - for (var i = 1; i <= 5; i++) - { - if ((keepMask & (1 << (i - 1))) == 0) - { - Hand = Hand.Replace(i, deck.DealCard()); - count++; - } - } - - _io.WriteLine(); - _io.Write($"I am taking {count} card"); - if (count != 1) - { - _io.WriteLine("s"); - } - - Strategy = (Hand.IsWeak, Hand.Rank < HandRank.Three, Hand.Rank < HandRank.FullHouse) switch - { - _ when Strategy is Bluff => Strategy.Bluff(28), - (true, _, _) => Strategy.Fold, - (false, true, _) => _random.Next(10) == 0 ? Strategy.Bet(19) : Strategy.Raise, - (false, false, true) => _random.Next(10) == 0 ? Strategy.Bet(11) : Strategy.Bet(19), - (false, false, false) => Strategy.Raise - }; - } - - public int GetWager(int wager) - { - wager += _random.Next(10); - if (Balance < Table.Human.Bet + wager) - { - if (Table.Human.Bet == 0) { return Balance; } - - if (Balance >= Table.Human.Bet) - { - _io.WriteLine("I'll see you."); - Bet = Table.Human.Bet; - Table.CollectBets(); - } - else - { - RaiseFunds(); - } - } - - return wager; - } - - public bool TryBuyWatch() - { - if (!Table.Human.HasWatch) { return false; } - - var response = _io.ReadString("Would you like to sell your watch"); - if (response.StartsWith("N", InvariantCultureIgnoreCase)) { return false; } - - var (value, message) = (_random.Next(10) < 7) switch - { - true => (75, "I'll give you $75 for it."), - false => (25, "That's a pretty crummy watch - I'll give you $25.") - }; - - _io.WriteLine(message); - Table.Human.SellWatch(value); - // The original code does not have the computer part with any money - - return true; - } - - public void RaiseFunds() - { - if (Table.Human.HasWatch) { return; } - - var response = _io.ReadString("Would you like to buy back your watch for $50"); - if (response.StartsWith("N", InvariantCultureIgnoreCase)) { return; } - - // The original code does not deduct $50 from the player - Balance += 50; - Table.Human.ReceiveWatch(); - IsBroke = true; - } - - public void CheckFunds() { IsBroke = Balance <= Table.Ante; } - - public override void TakeWinnings() - { - _io.WriteLine("I win."); - base.TakeWinnings(); - } -} diff --git a/71_Poker/csharp/Players/Human.cs b/71_Poker/csharp/Players/Human.cs deleted file mode 100644 index ec3e7d3cd..000000000 --- a/71_Poker/csharp/Players/Human.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Poker.Cards; -using Poker.Strategies; - -namespace Poker.Players; - -internal class Human : Player -{ - private readonly IReadWrite _io; - - public Human(int bank, IReadWrite io) - : base(bank) - { - HasWatch = true; - _io = io; - } - - public bool HasWatch { get; set; } - - protected override void DrawCards(Deck deck) - { - var count = _io.ReadNumber("How many cards do you want", 3, "You can't draw more than three cards."); - if (count == 0) { return; } - - _io.WriteLine("What are their numbers:"); - for (var i = 1; i <= count; i++) - { - Hand = Hand.Replace((int)_io.ReadNumber(), deck.DealCard()); - } - - _io.WriteLine("Your new hand:"); - _io.Write(Hand); - } - - internal bool SetWager() - { - var strategy = _io.ReadHumanStrategy(Table.Computer.Bet == 0 && Bet == 0); - if (strategy is Strategies.Bet or Check) - { - if (Bet + strategy.Value < Table.Computer.Bet) - { - _io.WriteLine("If you can't see my bet, then fold."); - return false; - } - if (Balance - Bet - strategy.Value >= 0) - { - HasBet = true; - Bet += strategy.Value; - return true; - } - RaiseFunds(); - } - else - { - Fold(); - Table.CollectBets(); - } - return false; - } - - public void RaiseFunds() - { - _io.WriteLine(); - _io.WriteLine("You can't bet with what you haven't got."); - - if (Table.Computer.TryBuyWatch()) { return; } - - // The original program had some code about selling a tie tack, but due to a fault - // in the logic the code was unreachable. I've omitted it in this port. - - IsBroke = true; - } - - public void ReceiveWatch() - { - // In the original code the player does not pay any money to receive the watch back. - HasWatch = true; - } - - public void SellWatch(int amount) - { - HasWatch = false; - Balance += amount; - } - - public override void TakeWinnings() - { - _io.WriteLine("You win."); - base.TakeWinnings(); - } -} diff --git a/71_Poker/csharp/Players/Player.cs b/71_Poker/csharp/Players/Player.cs deleted file mode 100644 index 65e7e6855..000000000 --- a/71_Poker/csharp/Players/Player.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Poker.Cards; - -namespace Poker.Players; - -internal abstract class Player -{ - private Table? _table; - private bool _hasFolded; - - protected Player(int bank) - { - Hand = Hand.Empty; - Balance = bank; - } - - public Hand Hand { get; set; } - public int Balance { get; set; } - public bool HasBet { get; set; } - public int Bet { get; set; } - public bool HasFolded => _hasFolded; - public bool IsBroke { get; protected set; } - - protected Table Table => - _table ?? throw new InvalidOperationException("The player must be sitting at the table."); - - public void Sit(Table table) => _table = table; - - public virtual void NewHand() - { - Bet = 0; - Hand = Table.Deck.DealHand(); - _hasFolded = false; - } - - public int AnteUp() - { - Balance -= Table.Ante; - return Table.Ante; - } - - public void DrawCards() - { - Bet = 0; - DrawCards(Table.Deck); - } - - protected abstract void DrawCards(Deck deck); - - public virtual void TakeWinnings() - { - Balance += Table.Pot; - Table.Pot = 0; - } - - public void Fold() - { - _hasFolded = true; - } -} diff --git a/71_Poker/csharp/Poker.csproj b/71_Poker/csharp/Poker.csproj index 3870320c9..d3fe4757c 100644 --- a/71_Poker/csharp/Poker.csproj +++ b/71_Poker/csharp/Poker.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/71_Poker/csharp/Program.cs b/71_Poker/csharp/Program.cs deleted file mode 100644 index c3200a960..000000000 --- a/71_Poker/csharp/Program.cs +++ /dev/null @@ -1,5 +0,0 @@ -global using Games.Common.IO; -global using Games.Common.Randomness; -global using Poker; - -new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); \ No newline at end of file diff --git a/71_Poker/csharp/Resources/Instructions.txt b/71_Poker/csharp/Resources/Instructions.txt deleted file mode 100644 index 7f82c07e5..000000000 --- a/71_Poker/csharp/Resources/Instructions.txt +++ /dev/null @@ -1,5 +0,0 @@ -Welcome to the casino. We each have $200. -I will open the betting before the draw; you open after. -To fold bet 0; to check bet .5. -Enough talk -- Let's get down to business. - diff --git a/71_Poker/csharp/Resources/Resource.cs b/71_Poker/csharp/Resources/Resource.cs deleted file mode 100644 index 0ceddb0dd..000000000 --- a/71_Poker/csharp/Resources/Resource.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Poker.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Instructions => GetStream(); - public static Stream Title => GetStream(); - } - - private static Stream GetStream([CallerMemberName] string? name = null) - => Assembly.GetExecutingAssembly().GetManifestResourceStream($"Poker.Resources.{name}.txt") - ?? throw new ArgumentException($"Resource stream {name} does not exist", nameof(name)); -} \ No newline at end of file diff --git a/71_Poker/csharp/Resources/Title.txt b/71_Poker/csharp/Resources/Title.txt deleted file mode 100644 index 2f5c6aa23..000000000 --- a/71_Poker/csharp/Resources/Title.txt +++ /dev/null @@ -1,5 +0,0 @@ - Poker - Creative Computing Morristown, New Jersey - - - diff --git a/71_Poker/csharp/Strategies/Bet.cs b/71_Poker/csharp/Strategies/Bet.cs deleted file mode 100644 index 7299898d5..000000000 --- a/71_Poker/csharp/Strategies/Bet.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Poker.Strategies; - -internal class Bet : Strategy -{ - public Bet(int amount) => Value = amount; - - public override int Value { get; } -} diff --git a/71_Poker/csharp/Strategies/Bluff.cs b/71_Poker/csharp/Strategies/Bluff.cs deleted file mode 100644 index ed51e33ed..000000000 --- a/71_Poker/csharp/Strategies/Bluff.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Poker.Strategies; - -internal class Bluff : Bet -{ - public Bluff(int amount, int? keepMask) - : base(amount) - { - KeepMask = keepMask; - } - - public override int? KeepMask { get; } -} \ No newline at end of file diff --git a/71_Poker/csharp/Strategies/Check.cs b/71_Poker/csharp/Strategies/Check.cs deleted file mode 100644 index 4bbab9735..000000000 --- a/71_Poker/csharp/Strategies/Check.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Poker.Strategies; - -internal class Check : Strategy -{ - public override int Value => 0; -} diff --git a/71_Poker/csharp/Strategies/Fold.cs b/71_Poker/csharp/Strategies/Fold.cs deleted file mode 100644 index 2ba31c33a..000000000 --- a/71_Poker/csharp/Strategies/Fold.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Poker.Strategies; - -internal class Fold : Strategy -{ - public override int Value => -1; -} diff --git a/71_Poker/csharp/Strategies/None.cs b/71_Poker/csharp/Strategies/None.cs deleted file mode 100644 index 4be351a8a..000000000 --- a/71_Poker/csharp/Strategies/None.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Poker.Strategies; - -internal class None : Strategy -{ - public override int Value => -1; -} diff --git a/71_Poker/csharp/Strategies/Raise.cs b/71_Poker/csharp/Strategies/Raise.cs deleted file mode 100644 index 7be9e5227..000000000 --- a/71_Poker/csharp/Strategies/Raise.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Poker.Strategies; - -internal class Raise : Bet -{ - public Raise() : base(2) { } -} diff --git a/71_Poker/csharp/Strategies/Strategy.cs b/71_Poker/csharp/Strategies/Strategy.cs deleted file mode 100644 index ae6c93d22..000000000 --- a/71_Poker/csharp/Strategies/Strategy.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Poker.Strategies; - -internal abstract class Strategy -{ - public static Strategy None = new None(); - public static Strategy Fold = new Fold(); - public static Strategy Check = new Check(); - public static Strategy Raise = new Raise(); - public static Strategy Bet(float amount) => new Bet((int)amount); - public static Strategy Bet(int amount) => new Bet(amount); - public static Strategy Bluff(int amount, int? keepMask = null) => new Bluff(amount, keepMask); - - public abstract int Value { get; } - public virtual int? KeepMask { get; } -} diff --git a/71_Poker/csharp/Table.cs b/71_Poker/csharp/Table.cs deleted file mode 100644 index da8198010..000000000 --- a/71_Poker/csharp/Table.cs +++ /dev/null @@ -1,214 +0,0 @@ -using Poker.Cards; -using Poker.Players; -using Poker.Strategies; - -namespace Poker; - -internal class Table -{ - private readonly IReadWrite _io; - private readonly IRandom _random; - public int Pot; - - public Table(IReadWrite io, IRandom random, Deck deck, Human human, Computer computer) - { - _io = io; - _random = random; - Deck = deck; - Human = human; - Computer = computer; - - human.Sit(this); - computer.Sit(this); - } - - public int Ante { get; } = 5; - public Deck Deck { get; } - public Human Human { get; } - public Computer Computer { get; } - - internal void PlayHand() - { - while (true) - { - _io.WriteLine(); - Computer.CheckFunds(); - if (Computer.IsBroke) { return; } - - _io.WriteLine($"The ante is ${Ante}. I will deal:"); - _io.WriteLine(); - if (Human.Balance <= Ante) - { - Human.RaiseFunds(); - if (Human.IsBroke) { return; } - } - - Deal(_random); - - _io.WriteLine(); - GetWagers("I'll open with ${0}", "I check.", allowRaiseAfterCheck: true); - if (SomeoneIsBroke() || SomeoneHasFolded()) { return; } - - Draw(); - - GetWagers(); - if (SomeoneIsBroke()) { return; } - if (!Human.HasBet) - { - GetWagers("I'll bet ${0}", "I'll check"); - } - if (SomeoneIsBroke() || SomeoneHasFolded()) { return; } - if (GetWinner() is { } winner) - { - winner.TakeWinnings(); - return; - } - } - } - - private void Deal(IRandom random) - { - Deck.Shuffle(random); - - Pot = Human.AnteUp() + Computer.AnteUp(); - - Human.NewHand(); - Computer.NewHand(); - - _io.WriteLine("Your hand:"); - _io.Write(Human.Hand); - } - - private void Draw() - { - _io.WriteLine(); - _io.Write("Now we draw -- "); - Human.DrawCards(); - Computer.DrawCards(); - _io.WriteLine(); - } - - private void GetWagers(string betFormat, string checkMessage, bool allowRaiseAfterCheck = false) - { - if (Computer.Strategy is Bet) - { - Computer.Bet = Computer.GetWager(Computer.Strategy.Value); - if (Computer.IsBroke) { return; } - - _io.WriteLine(betFormat, Computer.Bet); - } - else - { - _io.WriteLine(checkMessage); - if (!allowRaiseAfterCheck) { return; } - } - - GetWagers(); - } - - private void GetWagers() - { - while (true) - { - Human.HasBet = false; - while (true) - { - if (Human.SetWager()) { break; } - if (Human.IsBroke || Human.HasFolded) { return; } - } - if (Human.Bet == Computer.Bet) - { - CollectBets(); - return; - } - if (Computer.Strategy is Fold) - { - if (Human.Bet > 5) - { - Computer.Fold(); - _io.WriteLine("I fold."); - return; - } - } - if (Human.Bet > 3 * Computer.Strategy.Value) - { - if (Computer.Strategy is not Raise) - { - _io.WriteLine("I'll see you."); - Computer.Bet = Human.Bet; - CollectBets(); - return; - } - } - - var raise = Computer.GetWager(Human.Bet - Computer.Bet); - if (Computer.IsBroke) { return; } - _io.WriteLine($"I'll see you, and raise you {raise}"); - Computer.Bet = Human.Bet + raise; - } - } - - internal void CollectBets() - { - Human.Balance -= Human.Bet; - Computer.Balance -= Computer.Bet; - Pot += Human.Bet + Computer.Bet; - } - - private bool SomeoneHasFolded() - { - if (Human.HasFolded) - { - _io.WriteLine(); - Computer.TakeWinnings(); - } - else if (Computer.HasFolded) - { - _io.WriteLine(); - Human.TakeWinnings(); - } - else - { - return false; - } - - Pot = 0; - return true; - } - - private bool SomeoneIsBroke() => Human.IsBroke || Computer.IsBroke; - - private Player? GetWinner() - { - _io.WriteLine(); - _io.WriteLine("Now we compare hands:"); - _io.WriteLine("My hand:"); - _io.Write(Computer.Hand); - _io.WriteLine(); - _io.WriteLine($"You have {Human.Hand.Name}"); - _io.WriteLine($"and I have {Computer.Hand.Name}"); - if (Computer.Hand > Human.Hand) { return Computer; } - if (Human.Hand > Computer.Hand) { return Human; } - _io.WriteLine("The hand is drawn."); - _io.WriteLine($"All $ {Pot} remains in the pot."); - return null; - } - - internal bool ShouldPlayAnotherHand() - { - if (Computer.IsBroke) - { - _io.WriteLine("I'm busted. Congratulations!"); - return true; - } - - if (Human.IsBroke) - { - _io.WriteLine("Your wad is shot. So long, sucker!"); - return true; - } - - _io.WriteLine($"Now I have $ {Computer.Balance} and you have $ {Human.Balance}"); - return _io.ReadYesNo("Do you wish to continue"); - } -} \ No newline at end of file diff --git a/72_Queen/csharp/Computer.cs b/72_Queen/csharp/Computer.cs deleted file mode 100644 index 459c73377..000000000 --- a/72_Queen/csharp/Computer.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace Queen; - -internal class Computer -{ - private static readonly HashSet _randomiseFrom = new() { 41, 44, 73, 75, 126, 127 }; - private static readonly HashSet _desirable = new() { 73, 75, 126, 127, 158 }; - private readonly IRandom _random; - - public Computer(IRandom random) - { - _random = random; - } - - public Position GetMove(Position from) - => from + (_randomiseFrom.Contains(from) ? _random.NextMove() : FindMove(from)); - - private Move FindMove(Position from) - { - for (int i = 7; i > 0; i--) - { - if (IsOptimal(Move.Left, out var move)) { return move; } - if (IsOptimal(Move.Down, out move)) { return move; } - if (IsOptimal(Move.DownLeft, out move)) { return move; } - - bool IsOptimal(Move direction, out Move move) - { - move = direction * i; - return _desirable.Contains(from + move); - } - } - - return _random.NextMove(); - } -} diff --git a/72_Queen/csharp/Game.cs b/72_Queen/csharp/Game.cs deleted file mode 100644 index 35b1dc9a0..000000000 --- a/72_Queen/csharp/Game.cs +++ /dev/null @@ -1,57 +0,0 @@ -namespace Queen; - -internal class Game -{ - private readonly IReadWrite _io; - private readonly IRandom _random; - private readonly Computer _computer; - - public Game(IReadWrite io, IRandom random) - { - _io = io; - _random = random; - _computer = new Computer(random); - } - - internal void PlaySeries() - { - _io.Write(Streams.Title); - if (_io.ReadYesNo(Prompts.Instructions)) { _io.Write(Streams.Instructions); } - - while (true) - { - var result = PlayGame(); - _io.Write(result switch - { - Result.HumanForfeits => Streams.Forfeit, - Result.HumanWins => Streams.Congratulations, - Result.ComputerWins => Streams.IWin, - _ => throw new InvalidOperationException($"Unexpected result {result}") - }); - - if (!_io.ReadYesNo(Prompts.Anyone)) { break; } - } - - _io.Write(Streams.Thanks); - } - - private Result PlayGame() - { - _io.Write(Streams.Board); - var humanPosition = _io.ReadPosition(Prompts.Start, p => p.IsStart, Streams.IllegalStart, repeatPrompt: true); - if (humanPosition.IsZero) { return Result.HumanForfeits; } - - while (true) - { - var computerPosition = _computer.GetMove(humanPosition); - _io.Write(Strings.ComputerMove(computerPosition)); - if (computerPosition.IsEnd) { return Result.ComputerWins; } - - humanPosition = _io.ReadPosition(Prompts.Move, p => (p - computerPosition).IsValid, Streams.IllegalMove); - if (humanPosition.IsZero) { return Result.HumanForfeits; } - if (humanPosition.IsEnd) { return Result.HumanWins; } - } - } - - private enum Result { ComputerWins, HumanWins, HumanForfeits }; -} diff --git a/72_Queen/csharp/IOExtensions.cs b/72_Queen/csharp/IOExtensions.cs deleted file mode 100644 index 519599674..000000000 --- a/72_Queen/csharp/IOExtensions.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Queen; - -internal static class IOExtensions -{ - internal static bool ReadYesNo(this IReadWrite io, string prompt) - { - while (true) - { - var answer = io.ReadString(prompt).ToLower(); - if (answer == "yes") { return true; } - if (answer == "no") { return false; } - - io.Write(Streams.YesOrNo); - } - } - - internal static Position ReadPosition( - this IReadWrite io, - string prompt, - Predicate isValid, - Stream error, - bool repeatPrompt = false) - { - while (true) - { - var response = io.ReadNumber(prompt); - var number = (int)response; - var position = new Position(number); - if (number == response && (position.IsZero || isValid(position))) - { - return position; - } - - io.Write(error); - if (!repeatPrompt) { prompt = ""; } - } - } -} diff --git a/72_Queen/csharp/Move.cs b/72_Queen/csharp/Move.cs deleted file mode 100644 index 4e18647b6..000000000 --- a/72_Queen/csharp/Move.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Queen; - -internal record struct Move(int Diagonal, int Row) -{ - public static readonly Move Left = new(1, 0); - public static readonly Move DownLeft = new(2, 1); - public static readonly Move Down = new(1, 1); - - public bool IsValid => Diagonal > 0 && (IsLeft || IsDown || IsDownLeft); - private bool IsLeft => Row == 0; - private bool IsDown => Row == Diagonal; - private bool IsDownLeft => Row * 2 == Diagonal; - - public static Move operator *(Move move, int scale) => new(move.Diagonal * scale, move.Row * scale); -} \ No newline at end of file diff --git a/72_Queen/csharp/Position.cs b/72_Queen/csharp/Position.cs deleted file mode 100644 index 69971163a..000000000 --- a/72_Queen/csharp/Position.cs +++ /dev/null @@ -1,24 +0,0 @@ -namespace Queen; - -internal record struct Position(int Diagonal, int Row) -{ - public static readonly Position Zero = new(0); - - public Position(int number) - : this(Diagonal: number / 10, Row: number % 10) - { - } - - public bool IsZero => Row == 0 && Diagonal == 0; - public bool IsStart => Row == 1 || Row == Diagonal; - public bool IsEnd => Row == 8 && Diagonal == 15; - - public override string ToString() => $"{Diagonal}{Row}"; - - public static implicit operator Position(int value) => new(value); - - public static Position operator +(Position position, Move move) - => new(Diagonal: position.Diagonal + move.Diagonal, Row: position.Row + move.Row); - public static Move operator -(Position to, Position from) - => new(Diagonal: to.Diagonal - from.Diagonal, Row: to.Row - from.Row); -} diff --git a/72_Queen/csharp/Program.cs b/72_Queen/csharp/Program.cs deleted file mode 100644 index 5e017df63..000000000 --- a/72_Queen/csharp/Program.cs +++ /dev/null @@ -1,7 +0,0 @@ -global using Games.Common.IO; -global using Games.Common.Randomness; -global using static Queen.Resources.Resource; - -using Queen; - -new Game(new ConsoleIO(), new RandomNumberGenerator()).PlaySeries(); \ No newline at end of file diff --git a/72_Queen/csharp/Queen.csproj b/72_Queen/csharp/Queen.csproj index 3870320c9..d3fe4757c 100644 --- a/72_Queen/csharp/Queen.csproj +++ b/72_Queen/csharp/Queen.csproj @@ -6,12 +6,4 @@ enable enable - - - - - - - - diff --git a/72_Queen/csharp/RandomExtensions.cs b/72_Queen/csharp/RandomExtensions.cs deleted file mode 100644 index b4e375fdf..000000000 --- a/72_Queen/csharp/RandomExtensions.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Queen; - -internal static class RandomExtensions -{ - internal static Move NextMove(this IRandom random) - => random.NextFloat() switch - { - > 0.6F => Move.Down, - > 0.3F => Move.DownLeft, - _ => Move.Left - }; -} diff --git a/72_Queen/csharp/Resources/AnyonePrompt.txt b/72_Queen/csharp/Resources/AnyonePrompt.txt deleted file mode 100644 index a0289fd62..000000000 --- a/72_Queen/csharp/Resources/AnyonePrompt.txt +++ /dev/null @@ -1 +0,0 @@ -Anyone else care to try \ No newline at end of file diff --git a/72_Queen/csharp/Resources/Board.txt b/72_Queen/csharp/Resources/Board.txt deleted file mode 100644 index 854be1bbc..000000000 --- a/72_Queen/csharp/Resources/Board.txt +++ /dev/null @@ -1,27 +0,0 @@ - - - 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 - - - diff --git a/72_Queen/csharp/Resources/ComputerMove.txt b/72_Queen/csharp/Resources/ComputerMove.txt deleted file mode 100644 index f31b8e32d..000000000 --- a/72_Queen/csharp/Resources/ComputerMove.txt +++ /dev/null @@ -1 +0,0 @@ -Computer moves to square {0} diff --git a/72_Queen/csharp/Resources/Congratulations.txt b/72_Queen/csharp/Resources/Congratulations.txt deleted file mode 100644 index 9f1db2322..000000000 --- a/72_Queen/csharp/Resources/Congratulations.txt +++ /dev/null @@ -1,7 +0,0 @@ - -C O N G R A T U L A T I O N S . . . - -You have won--very well played. -It looks like I have met my match. -Thanks for playing--I can't win all the time. - diff --git a/72_Queen/csharp/Resources/Forfeit.txt b/72_Queen/csharp/Resources/Forfeit.txt deleted file mode 100644 index 09858bc15..000000000 --- a/72_Queen/csharp/Resources/Forfeit.txt +++ /dev/null @@ -1,3 +0,0 @@ - -It looks like I have won by forfeit. - diff --git a/72_Queen/csharp/Resources/IWin.txt b/72_Queen/csharp/Resources/IWin.txt deleted file mode 100644 index ced5d7163..000000000 --- a/72_Queen/csharp/Resources/IWin.txt +++ /dev/null @@ -1,4 +0,0 @@ - -Nice try, but it looks like I have won. -Thanks for playing. - diff --git a/72_Queen/csharp/Resources/IllegalMove.txt b/72_Queen/csharp/Resources/IllegalMove.txt deleted file mode 100644 index ae4a3bbcc..000000000 --- a/72_Queen/csharp/Resources/IllegalMove.txt +++ /dev/null @@ -1,2 +0,0 @@ - -Y O U C H E A T . . . Try again \ No newline at end of file diff --git a/72_Queen/csharp/Resources/IllegalStart.txt b/72_Queen/csharp/Resources/IllegalStart.txt deleted file mode 100644 index 25402bb64..000000000 --- a/72_Queen/csharp/Resources/IllegalStart.txt +++ /dev/null @@ -1,3 +0,0 @@ -Please read the instructions again. -You have begun illegally. - diff --git a/72_Queen/csharp/Resources/Instructions.txt b/72_Queen/csharp/Resources/Instructions.txt deleted file mode 100644 index fc2e85b08..000000000 --- a/72_Queen/csharp/Resources/Instructions.txt +++ /dev/null @@ -1,15 +0,0 @@ -We are going to play a game based on one of the chess -moves. Our queen will be able to move only to the left, -down, or diagonally down and to the left. - -The object of the game is to place the queen in the lower -left hand square by alternating moves between you and the -computer. The first one to place the queen there wins. - -You go first and place the queen in any one of the squares -on the top row or right hand column. -That will be your first move. -We alternate moves. -You may forfeit by typing '0' as your move. -Be sure to press the return key after each response. - diff --git a/72_Queen/csharp/Resources/InstructionsPrompt.txt b/72_Queen/csharp/Resources/InstructionsPrompt.txt deleted file mode 100644 index 0d311b605..000000000 --- a/72_Queen/csharp/Resources/InstructionsPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -Do you want instructions \ No newline at end of file diff --git a/72_Queen/csharp/Resources/MovePrompt.txt b/72_Queen/csharp/Resources/MovePrompt.txt deleted file mode 100644 index 8cb189992..000000000 --- a/72_Queen/csharp/Resources/MovePrompt.txt +++ /dev/null @@ -1 +0,0 @@ -What is your move \ No newline at end of file diff --git a/72_Queen/csharp/Resources/Resource.cs b/72_Queen/csharp/Resources/Resource.cs deleted file mode 100644 index e8297ecad..000000000 --- a/72_Queen/csharp/Resources/Resource.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Queen.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Title => GetStream(); - public static Stream Instructions => GetStream(); - public static Stream YesOrNo => GetStream(); - public static Stream Board => GetStream(); - public static Stream IllegalStart => GetStream(); - public static Stream IllegalMove => GetStream(); - public static Stream Forfeit => GetStream(); - public static Stream IWin => GetStream(); - public static Stream Congratulations => GetStream(); - public static Stream Thanks => GetStream(); - } - - internal static class Prompts - { - public static string Instructions => GetPrompt(); - public static string Start => GetPrompt(); - public static string Move => GetPrompt(); - public static string Anyone => GetPrompt(); - } - - internal static class Strings - { - public static string ComputerMove(Position position) => string.Format(GetString(), position); - } - - 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/72_Queen/csharp/Resources/StartPrompt.txt b/72_Queen/csharp/Resources/StartPrompt.txt deleted file mode 100644 index 0b6f395b0..000000000 --- a/72_Queen/csharp/Resources/StartPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -Where would you like to start \ No newline at end of file diff --git a/72_Queen/csharp/Resources/Thanks.txt b/72_Queen/csharp/Resources/Thanks.txt deleted file mode 100644 index 2e2e7b635..000000000 --- a/72_Queen/csharp/Resources/Thanks.txt +++ /dev/null @@ -1,3 +0,0 @@ - - -Ok --- thanks again. \ No newline at end of file diff --git a/72_Queen/csharp/Resources/Title.txt b/72_Queen/csharp/Resources/Title.txt deleted file mode 100644 index 63549d09c..000000000 --- a/72_Queen/csharp/Resources/Title.txt +++ /dev/null @@ -1,5 +0,0 @@ - Queen - Creative Computing Morristown, New Jersey - - - diff --git a/72_Queen/csharp/Resources/YesOrNo.txt b/72_Queen/csharp/Resources/YesOrNo.txt deleted file mode 100644 index 657bf8aab..000000000 --- a/72_Queen/csharp/Resources/YesOrNo.txt +++ /dev/null @@ -1 +0,0 @@ -Please answer 'Yes' or 'No'. diff --git a/72_Queen/java/Queen.java b/72_Queen/java/Queen.java deleted file mode 100644 index 7dfb6353c..000000000 --- a/72_Queen/java/Queen.java +++ /dev/null @@ -1,370 +0,0 @@ -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; - } - - } -} diff --git a/72_Queen/python/queen.py b/72_Queen/python/queen.py index 285174c49..201ea5d0e 100755 --- a/72_Queen/python/queen.py +++ b/72_Queen/python/queen.py @@ -82,7 +82,10 @@ 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}" - return out_str if not fix_align or len(out_str) == 3 else f"{out_str} " + if not fix_align or len(out_str) == 3: + return out_str + else: + return out_str + " " GAME_BOARD: Final[str] = ( @@ -131,10 +134,17 @@ def num_to_loc(num: int) -> Tuple[int, int]: ) +def str_with_tab(indent: int, text: str, uppercase: bool = True) -> str: + """Create a string with ``indent`` spaces followed by ``text``.""" + if uppercase: + text = text.upper() + return " " * indent + text + + def intro() -> None: """Print the intro and print instructions if desired.""" - print(" " * 33 + "Queen") - print(" " * 15 + "Creative Computing Morristown, New Jersey") + print(str_with_tab(33, "Queen")) + print(str_with_tab(15, "Creative Computing Morristown, New Jersey")) print("\n" * 2) if ask("DO YOU WANT INSTRUCTIONS"): print(INSTR_TXT) @@ -170,14 +180,15 @@ def get_move(current_loc: Optional[Tuple[int, int]]) -> Tuple[int, int]: "YOU HAVE BEGUN ILLEGALLY.\n\n" "WHERE WOULD YOU LIKE TO START? " ) - elif ( + else: + if ( (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? " @@ -252,12 +263,12 @@ def ask(prompt: str) -> bool: inpt: str while True: # Normalize input to uppercase, no whitespace, then get first character - inpt = input(f"{prompt}? ").upper().strip()[0] + inpt = input(prompt + "? ").upper().strip()[0] print() - if inpt == "N": - return False - elif inpt == "Y": + if inpt == "Y": return True + elif inpt == "N": + return False print("PLEASE ANSWER 'YES' OR 'NO'.") return False diff --git a/72_Queen/rust/Cargo.lock b/72_Queen/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/72_Queen/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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.toml b/72_Queen/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/72_Queen/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/72_Queen/rust/src/ai.rs b/72_Queen/rust/src/ai.rs deleted file mode 100644 index cf4d03103..000000000 --- a/72_Queen/rust/src/ai.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::util; - -const PREFERRED_MOVES: [u8; 5] = [158, 72, 75, 126, 127]; -const SAFE_MOVES: [u8; 2] = [44, 41]; - -pub fn get_computer_move(loc: u8) -> u8 { - if SAFE_MOVES.contains(&loc) { - return random_move(loc); - } - - for m in PREFERRED_MOVES { - if util::is_move_legal(loc, m) && m != loc { - return m; - } - } - - random_move(loc) -} - -fn random_move(l: u8) -> u8 { - let r: f32 = rand::random(); - - if r > 0.6 { - l + 11 - } else if r > 0.3 { - l + 21 - } else { - l + 10 - } -} diff --git a/72_Queen/rust/src/game.rs b/72_Queen/rust/src/game.rs deleted file mode 100644 index 2445980b6..000000000 --- a/72_Queen/rust/src/game.rs +++ /dev/null @@ -1,180 +0,0 @@ -use crate::{ - ai, - util::{self, prompt, PromptResult::*}, -}; - -pub struct Game { - blocks: [u8; 64], - location: Option, - player_move: bool, - show_board: bool, - forfeit: bool, -} - -impl Game { - pub fn new() -> Self { - let mut blocks = [0 as u8; 64]; - - let mut block = 91; - let mut i = 0; - - for _ in 0..8 { - for _ in 0..8 { - block -= 10; - blocks[i] = block; - i += 1; - } - block += 91; - } - - Game { - blocks, - location: None, - player_move: true, - show_board: false, - forfeit: false, - } - } - - pub fn update(&mut self) -> bool { - let mut still_going = true; - - if let Some(l) = self.location { - if self.show_board { - self.draw(l); - } - - match self.player_move { - true => self.player_move(l), - false => { - std::thread::sleep(std::time::Duration::from_secs(1)); - let loc = ai::get_computer_move(l); - println!("COMPUTER MOVES TO SQUARE {}", loc); - self.location = Some(loc); - } - } - - still_going = self.check_location(); - } else { - self.set_start_location(); - } - self.player_move = !self.player_move; - still_going - } - - fn set_start_location(&mut self) { - self.draw(0); - - if let YesNo(yes) = prompt(Some(false), "UPDATE BOARD?") { - self.show_board = yes; - } - - loop { - if let Numeric(n) = prompt(Some(true), "WHERE WOULD YOU LIKE TO START?") { - let n = n as u8; - - if util::is_legal_start(n) { - self.location = Some(n); - break; - } else { - println!("PLEASE READ THE DIRECTIONS AGAIN.\nYOU HAVE BEGUN ILLEGALLY.\n") - } - } - } - } - - fn player_move(&mut self, loc: u8) { - loop { - if let Numeric(n) = prompt(Some(true), "WHAT IS YOUR MOVE?") { - if n == 0 { - self.forfeit = true; - break; - } - - let n = n as u8; - - if util::is_move_legal(loc, n) { - self.location = Some(n); - break; - } else { - println!("Y O U C H E A T . . . TRY AGAIN? "); - } - } - } - } - - fn check_location(&self) -> bool { - if self.location == Some(158) { - util::print_gameover(self.player_move, self.forfeit); - return false; - } - - true - } - - fn draw(&self, loc: u8) { - let draw_h_border = |top: Option| { - let corners; - - if let Some(top) = top { - if top { - corners = ("┌", "┐", "┬"); - } else { - corners = ("└", "┘", "┴"); - } - } else { - corners = ("├", "┤", "┼"); - } - - print!("{}", corners.0); - - for i in 0..8 { - let corner = if i == 7 { corners.1 } else { corners.2 }; - - print!("───{}", corner); - } - println!(); - }; - - draw_h_border(Some(true)); - - let mut column = 0; - let mut row = 0; - - for block in self.blocks.iter() { - let block = *block as u8; - - let n = if block == loc { - format!("│{}", "*Q*".to_string()) - } else { - let b = block.to_string(); - - if block > 99 { - format!("│{}", b) - } else { - format!("│{} ", b) - } - }; - - print!("{}", n); - - column += 1; - - if column != 1 && (column % 8) == 0 { - column = 0; - row += 1; - - print!("│"); - println!(); - - if row == 8 { - draw_h_border(Some(false)); - } else { - draw_h_border(None); - } - } - } - - println!(); - } -} diff --git a/72_Queen/rust/src/main.rs b/72_Queen/rust/src/main.rs deleted file mode 100644 index 57d65e0f4..000000000 --- a/72_Queen/rust/src/main.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::{ - game::Game, - util::{prompt, PromptResult::*}, -}; - -mod game; -mod util; -mod ai; - -fn main() { - util::intro(); - - loop { - let mut game = Game::new(); - - loop { - if !game.update() { - break; - } - } - - if let YesNo(y) = prompt(Some(false), "\nANYONE ELSE CARE TO TRY?") { - if !y { - println!("OK --- THANKS AGAIN."); - break; - } - } - } -} diff --git a/72_Queen/rust/src/util.rs b/72_Queen/rust/src/util.rs deleted file mode 100644 index 3439aabb0..000000000 --- a/72_Queen/rust/src/util.rs +++ /dev/null @@ -1,114 +0,0 @@ -use std::io; - -pub enum PromptResult { - Normal(String), - YesNo(bool), - Numeric(i32), -} - -pub fn prompt(is_numeric: Option, msg: &str) -> PromptResult { - use PromptResult::*; - - println!("{msg}"); - - loop { - let mut input = String::new(); - - io::stdin() - .read_line(&mut input) - .expect("**Failed to read input**"); - - if let Some(is_numeric) = is_numeric { - let input = input.trim(); - - if is_numeric { - if let Ok(n) = input.parse::() { - return Numeric(n); - } - println!("PLEASE ENTER A VALID NUMBER!"); - } else { - match input.to_uppercase().as_str() { - "YES" | "Y" => return YesNo(true), - "NO" | "N" => return YesNo(false), - _ => println!("PLEASE ENTER (Y)ES OR (N)O."), - } - } - } else { - return Normal(input); - } - } -} - -pub fn is_move_legal(loc: u8, mov: u8) -> bool { - let dt: i32 = mov as i32 - loc as i32; - - if dt.is_negative() { - return false; - } - - if (dt % 21) == 0 || (dt % 10) == 0 || (dt % 11) == 0 { - return true; - } - - false -} - -pub fn is_legal_start(loc: u8) -> bool { - let mut legal_spots = Vec::new(); - let start: u8 = 11; - - legal_spots.push(start); - - for i in 1..=7 { - legal_spots.push(start + (10 * i)); - } - - for i in 1..=7 { - legal_spots.push(start + (11 * i)); - } - - if legal_spots.contains(&loc) { - true - } else { - false - } -} - -pub fn print_gameover(win: bool, forfeit: bool) { - if win { - println!("C O N G R A T U L A T I O N S . . .\nYOU HAVE WON--VERY WELL PLAYED."); - println!( - "IT LOOKS LIKE I HAVE MET MY MATCH.\nTHANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.\n", - ); - } else { - if forfeit { - println!("IT LOOKS LIKE I HAVE WON BY FORFEIT.\n"); - } else { - println!("NICE TRY, BUT IT LOOKS LIKE I HAVE WON.\nTHANKS FOR PLAYING."); - } - } -} - -pub fn intro() { - println!("\n\n\t\tQUEEN"); - println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); - - if let PromptResult::YesNo(yes) = prompt(Some(false), "DO YOU WANT INSTRUCTIONS?") { - if yes { - println!( - r#"WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS -MOVES. OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT, -DOWN, OR DIAGONALLY DOWN AND TO THE LEFT. -THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER -LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE -COMPUTER. THE FIRST ONE TO PLACE THE QUEEN THERE WINS. -YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES -ON THE TOP ROW OR RIGHT HAND COLUMN. -THAT WILL BE YOUR FIRST MOVE. -WE ALTERNATE MOVES. -YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE. -BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE."# - ) - } - } -} diff --git a/73_Reverse/python/reverse.py b/73_Reverse/python/reverse.py index e34378406..b72aa320a 100755 --- a/73_Reverse/python/reverse.py +++ b/73_Reverse/python/reverse.py @@ -5,7 +5,7 @@ NUMCNT = 9 # How many numbers are we playing with? -def main() -> None: +def play(): print("REVERSE".center(72)) print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".center(72)) print() @@ -14,7 +14,7 @@ def main() -> None: print() if not input("DO YOU WANT THE RULES? (yes/no) ").lower().startswith("n"): - print_rules() + rules() while True: game_loop() @@ -23,7 +23,7 @@ def main() -> None: return -def game_loop() -> None: +def game_loop(): """Play the main game.""" # Make a random list from 1 to NUMCNT numbers = list(range(1, NUMCNT + 1)) @@ -52,7 +52,7 @@ def game_loop() -> None: turns += 1 # Reverse as many items as requested. - newnums = numbers[:howmany] + newnums = numbers[0:howmany] newnums.reverse() newnums.extend(numbers[howmany:]) numbers = newnums @@ -67,10 +67,12 @@ def game_loop() -> None: def print_list(numbers) -> None: + """Print out the list""" print(" ".join(map(str, numbers))) -def print_rules() -> None: +def rules(): + """Print out the rules""" help = textwrap.dedent( """ THIS IS THE GAME OF "REVERSE". TO WIN, ALL YOU HAVE @@ -101,6 +103,6 @@ def print_rules() -> None: if __name__ == "__main__": try: - main() + play() except KeyboardInterrupt: pass diff --git a/73_Reverse/rust/Cargo.lock b/73_Reverse/rust/Cargo.lock deleted file mode 100644 index 0da17814e..000000000 --- a/73_Reverse/rust/Cargo.lock +++ /dev/null @@ -1,243 +0,0 @@ -# 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 deleted file mode 100644 index 3a87396aa..000000000 --- a/73_Reverse/rust/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[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 deleted file mode 100644 index 8fd06505e..000000000 --- a/73_Reverse/rust/src/main.rs +++ /dev/null @@ -1,209 +0,0 @@ -/** 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![0; 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" || opt == "Y" { - // 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) - // 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 - 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 - if a[k-1] == a[j-1] { - continue 'a; - } - // 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:\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 - let r = input("HOW MANY SHALL I REVERSE: ").parse::().unwrap(); - - // 350 IF R=0 THEN 520 - if r == 0 { - if replay() { continue 'c; } - else { 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"); - - 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}"); - } - } - } - // 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", - ) -} - -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 diff --git a/74_Rock_Scissors_Paper/lua/rockscissors.lua b/74_Rock_Scissors_Paper/lua/rockscissors.lua deleted file mode 100644 index 8a19d5da0..000000000 --- a/74_Rock_Scissors_Paper/lua/rockscissors.lua +++ /dev/null @@ -1,99 +0,0 @@ --- rockscissors.lua --- Ported by Brian Wilkins (BrianWilkinsFL) --- Utilized has_key again and choice. A lot of these basic programs --- follow a similar choice structure so I think I'll use these functions alot. - -function getInput(prompt) - io.write(prompt) - io.flush() - local input = io.read("l") - if not input then --- test for EOF - print("GOODBYE") - os.exit(0) - end - return input -end - -function has_key(table, key) - return table[key]~=nil -end - -function choice(prompt, table) - resp = getInput(prompt) - while not has_key(table, resp) do - print("INVALID.") - resp = getInput(prompt) - end - return resp -end - -function playGame(n) - local computerWins = 0 - local humanWins = 0 - itemChoices = { - ["1"] = "PAPER", - ["2"] = "SCISSORS", - ["3"] = "ROCK", - } - print("GAME NUMBER " .. n) - - math.randomseed(os.time()) - computerChoice = math.random(1,3) - - humanChoice = choice("3=ROCK...2=SCISSORS...1=PAPER\n1...2...3...WHAT'S YOUR CHOICE? ", itemChoices) - humanChoice = tonumber(humanChoice) - print("THIS IS MY CHOICE...") - - print("... " .. itemChoices[tostring(computerChoice)]) - - -- Working around a Lua thing where I can't seem to interact - -- with function values outside of the function itself - -- So the total wins are calculated outside of this function - -- and summarized. - if computerChoice == humanChoice then - print("TIE GAME. NO WINNER.") - elseif computerChoice > humanChoice then - if humanChoice ~=1 or computerChoice ~= 3 then - computerWins = 1 - print("WOW! I WIN!!!") - else - humanWins = 1 - print("YOU WIN!!!") - end - elseif computerChoice == 1 then - if humanChoice ~= 3 then - humanWins = 1 - print("YOU WIN!!!") - else - computerWins = 1 - print("WOW! I WIN!!!") - end - end - return computerWins, humanWins -end - -local games = 0 -while games == 0 or games >= 11 do - resp = getInput("HOW MANY GAMES? ") - - assert(tonumber(resp)) - games = tonumber(resp) - if games < 11 then break end - - print("SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.") -end - -totalComputerWins = 0 -totalHumanWins = 0 - -for n=1, games, 1 do - computerWins, humanWins = playGame(n) - totalComputerWins = totalComputerWins + computerWins - totalHumanWins = totalHumanWins + humanWins -end - -print("HERE IS THE FINAL GAME SCORE:") -print("I HAVE WON " .. totalComputerWins .. " GAME(S).") -print("YOU HAVE WON " .. totalHumanWins .." GAME(S).") -print("AND " .. games-(totalComputerWins+totalHumanWins) .. " GAME(S) ENDED IN A TIE.") -print("THANKS FOR PLAYING!!") \ No newline at end of file diff --git a/74_Rock_Scissors_Paper/python/rockscissors.py b/74_Rock_Scissors_Paper/python/rockscissors.py index 3d150bd4f..09d63d2d8 100644 --- a/74_Rock_Scissors_Paper/python/rockscissors.py +++ b/74_Rock_Scissors_Paper/python/rockscissors.py @@ -6,7 +6,7 @@ import random -def play_game() -> None: +def play_game(): """Play one round of the game""" while True: @@ -44,27 +44,22 @@ def play_game() -> None: print("...Scissors") elif guess_computer == 3: print("...Rock") - 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: + if 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/74_Rock_Scissors_Paper/rust/Cargo.lock b/74_Rock_Scissors_Paper/rust/Cargo.lock deleted file mode 100644 index 81a95200e..000000000 --- a/74_Rock_Scissors_Paper/rust/Cargo.lock +++ /dev/null @@ -1,91 +0,0 @@ -# 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/README.md b/75_Roulette/README.md index b68a2ad1b..4902aa9ba 100644 --- a/75_Roulette/README.md +++ b/75_Roulette/README.md @@ -17,4 +17,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -- The program keeps a count of how often each number comes up in array `X`, but never makes use of this information. +(please note any difficulties or challenges in porting here) diff --git a/75_Roulette/csharp/Bet.cs b/75_Roulette/csharp/Bet.cs deleted file mode 100644 index da0e31b71..000000000 --- a/75_Roulette/csharp/Bet.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Roulette; - -internal record struct Bet(BetType Type, int Number, int Wager) -{ - public int Payout => Wager * Type.Payout; -} diff --git a/75_Roulette/csharp/BetType.cs b/75_Roulette/csharp/BetType.cs deleted file mode 100644 index 79b3b67c4..000000000 --- a/75_Roulette/csharp/BetType.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Roulette; - -internal record struct BetType(int Value) -{ - public static implicit operator BetType(int value) => new(value); - - public int Payout => Value switch - { - <= 36 or >= 49 => 35, - <= 42 => 2, - <= 48 => 1 - }; -} diff --git a/75_Roulette/csharp/Croupier.cs b/75_Roulette/csharp/Croupier.cs deleted file mode 100644 index 32f76c33b..000000000 --- a/75_Roulette/csharp/Croupier.cs +++ /dev/null @@ -1,41 +0,0 @@ -namespace Roulette; - -internal class Croupier -{ - private const int _initialHouse = 100_000; - private const int _initialPlayer = 1_000; - - private int _house = _initialHouse; - private int _player = _initialPlayer; - - public string Totals => Strings.Totals(_house, _player); - public bool PlayerIsBroke => _player <= 0; - public bool HouseIsBroke => _house <= 0; - - internal string Pay(Bet bet) - { - _house -= bet.Payout; - _player += bet.Payout; - - if (_house <= 0) - { - _player = _initialHouse + _initialPlayer; - } - - return Strings.Win(bet); - } - - internal string Take(Bet bet) - { - _house += bet.Wager; - _player -= bet.Wager; - - return Strings.Lose(bet); - } - - public void CutCheck(IReadWrite io, IRandom random) - { - var name = io.ReadString(Prompts.Check); - io.Write(Strings.Check(random, name, _player)); - } -} diff --git a/75_Roulette/csharp/Game.cs b/75_Roulette/csharp/Game.cs deleted file mode 100644 index 75a6d7e54..000000000 --- a/75_Roulette/csharp/Game.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace Roulette; - -internal class Game -{ - private readonly IReadWrite _io; - private readonly IRandom _random; - private readonly Table _table; - private readonly Croupier _croupier; - - public Game(IReadWrite io, IRandom random) - { - _io = io; - _random = random; - _croupier = new(); - _table = new(_croupier, io, random); - } - - public void Play() - { - _io.Write(Streams.Title); - if (!_io.ReadString(Prompts.Instructions).ToLowerInvariant().StartsWith('n')) - { - _io.Write(Streams.Instructions); - } - - while (_table.Play()); - - if (_croupier.PlayerIsBroke) - { - _io.Write(Streams.LastDollar); - _io.Write(Streams.Thanks); - return; - } - - if (_croupier.HouseIsBroke) - { - _io.Write(Streams.BrokeHouse); - } - - _croupier.CutCheck(_io, _random); - } -} diff --git a/75_Roulette/csharp/IOExtensions.cs b/75_Roulette/csharp/IOExtensions.cs deleted file mode 100644 index 49326bef7..000000000 --- a/75_Roulette/csharp/IOExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace Roulette; - -internal static class IOExtensions -{ - internal static int ReadBetCount(this IReadWrite io) - { - while (true) - { - var betCount = io.ReadNumber(Prompts.HowManyBets); - if (betCount.IsValidInt(1)) { return (int)betCount; } - } - } - - internal static Bet ReadBet(this IReadWrite io, int number) - { - while (true) - { - var (type, amount) = io.Read2Numbers(Prompts.Bet(number)); - - if (type.IsValidInt(1, 50) && amount.IsValidInt(5, 500)) - { - return new() - { - Type = (int)type, - Number = number, - Wager = (int)amount - }; - } - } - } - - internal static bool IsValidInt(this float value, int minValue, int maxValue = int.MaxValue) - => value == (int)value && value >= minValue && value <= maxValue; -} \ No newline at end of file diff --git a/75_Roulette/csharp/Program.cs b/75_Roulette/csharp/Program.cs deleted file mode 100644 index 4be74962b..000000000 --- a/75_Roulette/csharp/Program.cs +++ /dev/null @@ -1,6 +0,0 @@ -global using Games.Common.IO; -global using Games.Common.Randomness; -global using static Roulette.Resources.Resource; -using Roulette; - -new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); diff --git a/75_Roulette/csharp/Resources/AgainPrompt.txt b/75_Roulette/csharp/Resources/AgainPrompt.txt deleted file mode 100644 index bd1d18b62..000000000 --- a/75_Roulette/csharp/Resources/AgainPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -Again \ No newline at end of file diff --git a/75_Roulette/csharp/Resources/BetAlready.txt b/75_Roulette/csharp/Resources/BetAlready.txt deleted file mode 100644 index be86cbeaf..000000000 --- a/75_Roulette/csharp/Resources/BetAlready.txt +++ /dev/null @@ -1 +0,0 @@ -You made that bet once already,dum-dum \ No newline at end of file diff --git a/75_Roulette/csharp/Resources/BetPrompt.txt b/75_Roulette/csharp/Resources/BetPrompt.txt deleted file mode 100644 index 500398400..000000000 --- a/75_Roulette/csharp/Resources/BetPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -Number {0} \ No newline at end of file diff --git a/75_Roulette/csharp/Resources/BrokeHouse.txt b/75_Roulette/csharp/Resources/BrokeHouse.txt deleted file mode 100644 index 638dafb4e..000000000 --- a/75_Roulette/csharp/Resources/BrokeHouse.txt +++ /dev/null @@ -1 +0,0 @@ -You broke the house! diff --git a/75_Roulette/csharp/Resources/Check.txt b/75_Roulette/csharp/Resources/Check.txt deleted file mode 100644 index ffdd640ab..000000000 --- a/75_Roulette/csharp/Resources/Check.txt +++ /dev/null @@ -1,16 +0,0 @@ - -------------------------------------------------------------------------Check No. {0} - - {1:MMMM d',' yyyy} - - -Pay to the order of-----{2}-----$ {3} - - - The Memory Bank of New YORK - - The Computer - ----------X----- - ---------------------------------------------------------------Come back soon! - diff --git a/75_Roulette/csharp/Resources/CheckPrompt.txt b/75_Roulette/csharp/Resources/CheckPrompt.txt deleted file mode 100644 index 16321fe95..000000000 --- a/75_Roulette/csharp/Resources/CheckPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -To whom shall I make the check \ No newline at end of file diff --git a/75_Roulette/csharp/Resources/HowManyBetsPrompt.txt b/75_Roulette/csharp/Resources/HowManyBetsPrompt.txt deleted file mode 100644 index 0b6abdfa3..000000000 --- a/75_Roulette/csharp/Resources/HowManyBetsPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -How many bets \ No newline at end of file diff --git a/75_Roulette/csharp/Resources/Instructions.txt b/75_Roulette/csharp/Resources/Instructions.txt deleted file mode 100644 index 8ced724b5..000000000 --- a/75_Roulette/csharp/Resources/Instructions.txt +++ /dev/null @@ -1,48 +0,0 @@ - -This is the betting layout - (*=RED) - - 1* 2 3* - 4 5* 6 - 7* 8 9* -10 11 12* ---------------- -13 14* 15 -16* 17 18* -19* 20 21* -22 23* 24 ---------------- -25* 26 27* -28 29 30* -31 32* 33 -34* 35 36* ---------------- - 00 0 - -Types of bets - -The numbers 1 to 36 signify a straight bet -on that number. -These pay off 35:1 - -The 2:1 bets are: - 37) 1-12 40) First column - 38) 13-24 41) Second column - 39) 25-36 42) Third column - -The even money bets are: - 43) 1-18 46) Odd - 44) 19-36 47) Red - 45) Even 48) Black - -49)0 and 50)00 pay off 35:1 -Note: 0 and 00 do not count under any - bets except their own. - -When I ask for each bet, type the number -and the amount, separated by a comma. -For example: to bet $500 on Black, type 48,500 -when I ask for a bet. - -The minimum bet is $5, the maximum is $500. - diff --git a/75_Roulette/csharp/Resources/InstructionsPrompt.txt b/75_Roulette/csharp/Resources/InstructionsPrompt.txt deleted file mode 100644 index 0d311b605..000000000 --- a/75_Roulette/csharp/Resources/InstructionsPrompt.txt +++ /dev/null @@ -1 +0,0 @@ -Do you want instructions \ No newline at end of file diff --git a/75_Roulette/csharp/Resources/LastDollar.txt b/75_Roulette/csharp/Resources/LastDollar.txt deleted file mode 100644 index 632516de0..000000000 --- a/75_Roulette/csharp/Resources/LastDollar.txt +++ /dev/null @@ -1 +0,0 @@ -Oops! you just spent your last dollar! diff --git a/75_Roulette/csharp/Resources/Outcome.txt b/75_Roulette/csharp/Resources/Outcome.txt deleted file mode 100644 index 30e227f7c..000000000 --- a/75_Roulette/csharp/Resources/Outcome.txt +++ /dev/null @@ -1 +0,0 @@ -You {0} {1} dollars on bet {2} diff --git a/75_Roulette/csharp/Resources/Resource.cs b/75_Roulette/csharp/Resources/Resource.cs deleted file mode 100644 index dd9c86723..000000000 --- a/75_Roulette/csharp/Resources/Resource.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using Games.Common.Randomness; - -namespace Roulette.Resources; - -internal static class Resource -{ - internal static class Streams - { - public static Stream Title => GetStream(); - public static Stream Instructions => GetStream(); - public static Stream BetAlready => GetStream(); - public static Stream Spinning => GetStream(); - public static Stream LastDollar => GetStream(); - public static Stream BrokeHouse => GetStream(); - public static Stream Thanks => GetStream(); - } - - internal static class Strings - { - public static string Black(int number) => Slot(number); - public static string Red(int number) => Slot(number); - private static string Slot(int number, [CallerMemberName] string? colour = null) - => string.Format(GetString(), number, colour); - - public static string Lose(Bet bet) => Outcome(bet.Wager, bet.Number); - public static string Win(Bet bet) => Outcome(bet.Payout, bet.Number); - private static string Outcome(int amount, int number, [CallerMemberName] string? winlose = null) - => string.Format(GetString(), winlose, amount, number); - - public static string Totals(int me, int you) => string.Format(GetString(), me, you); - - public static string Check(IRandom random, string payee, int amount) - => string.Format(GetString(), random.Next(100), DateTime.Now, payee, amount); - } - - internal static class Prompts - { - public static string Instructions => GetPrompt(); - public static string HowManyBets => GetPrompt(); - public static string Bet(int number) => string.Format(GetPrompt(), number); - public static string Again => GetPrompt(); - public static string Check => GetPrompt(); - } - - 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/75_Roulette/csharp/Resources/Slot.txt b/75_Roulette/csharp/Resources/Slot.txt deleted file mode 100644 index de02695df..000000000 --- a/75_Roulette/csharp/Resources/Slot.txt +++ /dev/null @@ -1,2 +0,0 @@ - {0} {1} - diff --git a/75_Roulette/csharp/Resources/Spinning.txt b/75_Roulette/csharp/Resources/Spinning.txt deleted file mode 100644 index 0d87fe392..000000000 --- a/75_Roulette/csharp/Resources/Spinning.txt +++ /dev/null @@ -1,3 +0,0 @@ -Spinning - - diff --git a/75_Roulette/csharp/Resources/Thanks.txt b/75_Roulette/csharp/Resources/Thanks.txt deleted file mode 100644 index 0b8352376..000000000 --- a/75_Roulette/csharp/Resources/Thanks.txt +++ /dev/null @@ -1,3 +0,0 @@ -Thanks for you money. -I'll use it to buy a solid gold roulette WHEEL - diff --git a/75_Roulette/csharp/Resources/Title.txt b/75_Roulette/csharp/Resources/Title.txt deleted file mode 100644 index 0d53f1a80..000000000 --- a/75_Roulette/csharp/Resources/Title.txt +++ /dev/null @@ -1,7 +0,0 @@ - Roulette - Creative Computing Morristown, New Jersey - - - -Welcome to the roulette table - diff --git a/75_Roulette/csharp/Resources/Totals.txt b/75_Roulette/csharp/Resources/Totals.txt deleted file mode 100644 index 4cecae3f1..000000000 --- a/75_Roulette/csharp/Resources/Totals.txt +++ /dev/null @@ -1,3 +0,0 @@ - -Totals Me You - {0,-14}{1} diff --git a/75_Roulette/csharp/Roulette.csproj b/75_Roulette/csharp/Roulette.csproj index 23d27b76d..d3fe4757c 100644 --- a/75_Roulette/csharp/Roulette.csproj +++ b/75_Roulette/csharp/Roulette.csproj @@ -1,17 +1,9 @@ Exe - net7.0 + net6.0 10 enable enable - - - - - - - - diff --git a/75_Roulette/csharp/Slot.cs b/75_Roulette/csharp/Slot.cs deleted file mode 100644 index df30cea1f..000000000 --- a/75_Roulette/csharp/Slot.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Immutable; - -namespace Roulette; - -internal class Slot -{ - private readonly ImmutableHashSet _coveringBets; - - public Slot (string name, params BetType[] coveringBets) - { - Name = name; - _coveringBets = coveringBets.ToImmutableHashSet(); - } - - public string Name { get; } - - public bool IsCoveredBy(Bet bet) => _coveringBets.Contains(bet.Type); -} diff --git a/75_Roulette/csharp/Table.cs b/75_Roulette/csharp/Table.cs deleted file mode 100644 index 026152d1c..000000000 --- a/75_Roulette/csharp/Table.cs +++ /dev/null @@ -1,71 +0,0 @@ -namespace Roulette; - -internal class Table -{ - private readonly IReadWrite _io; - private readonly Wheel _wheel; - private readonly Croupier _croupier; - - public Table(Croupier croupier, IReadWrite io, IRandom random) - { - _croupier = croupier; - _io = io; - _wheel = new(random); - } - - public bool Play() - { - var bets = AcceptBets(); - var slot = SpinWheel(); - SettleBets(bets, slot); - - _io.Write(_croupier.Totals); - - if (_croupier.PlayerIsBroke || _croupier.HouseIsBroke) { return false; } - - return _io.ReadString(Prompts.Again).ToLowerInvariant().StartsWith('y'); - } - - private Slot SpinWheel() - { - _io.Write(Streams.Spinning); - var slot = _wheel.Spin(); - _io.Write(slot.Name); - return slot; - } - - private IReadOnlyList AcceptBets() - { - var betCount = _io.ReadBetCount(); - var betTypes = new HashSet(); - var bets = new List(); - for (int i = 1; i <= betCount; i++) - { - while (!TryAdd(_io.ReadBet(i))) - { - _io.Write(Streams.BetAlready); - } - } - - return bets.AsReadOnly(); - - bool TryAdd(Bet bet) - { - if (betTypes.Add(bet.Type)) - { - bets.Add(bet); - return true; - } - - return false; - } - } - - private void SettleBets(IReadOnlyList bets, Slot slot) - { - foreach (var bet in bets) - { - _io.Write(slot.IsCoveredBy(bet) ? _croupier.Pay(bet) : _croupier.Take(bet)); - } - } -} diff --git a/75_Roulette/csharp/Wheel.cs b/75_Roulette/csharp/Wheel.cs deleted file mode 100644 index dfcecd293..000000000 --- a/75_Roulette/csharp/Wheel.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Collections.Immutable; - -namespace Roulette; - -internal class Wheel -{ - private static readonly ImmutableArray _slots = ImmutableArray.Create( - new Slot(Strings.Red(1), 1, 37, 40, 43, 46, 47), - new Slot(Strings.Black(2), 2, 37, 41, 43, 45, 48), - new Slot(Strings.Red(3), 3, 37, 42, 43, 46, 47), - new Slot(Strings.Black(4), 4, 37, 40, 43, 45, 48), - new Slot(Strings.Red(5), 5, 37, 41, 43, 46, 47), - new Slot(Strings.Black(6), 6, 37, 42, 43, 45, 48), - new Slot(Strings.Red(7), 7, 37, 40, 43, 46, 47), - new Slot(Strings.Black(8), 8, 37, 41, 43, 45, 48), - new Slot(Strings.Red(9), 9, 37, 42, 43, 46, 47), - new Slot(Strings.Black(10), 10, 37, 40, 43, 45, 48), - new Slot(Strings.Black(11), 11, 37, 41, 43, 46, 48), - new Slot(Strings.Red(12), 12, 37, 42, 43, 45, 47), - new Slot(Strings.Black(13), 13, 38, 40, 43, 46, 48), - new Slot(Strings.Red(14), 14, 38, 41, 43, 45, 47), - new Slot(Strings.Black(15), 15, 38, 42, 43, 46, 48), - new Slot(Strings.Red(16), 16, 38, 40, 43, 45, 47), - new Slot(Strings.Black(17), 17, 38, 41, 43, 46, 48), - new Slot(Strings.Red(18), 18, 38, 42, 43, 45, 47), - new Slot(Strings.Red(19), 19, 38, 40, 44, 46, 47), - new Slot(Strings.Black(20), 20, 38, 41, 44, 45, 48), - new Slot(Strings.Red(21), 21, 38, 42, 44, 46, 47), - new Slot(Strings.Black(22), 22, 38, 40, 44, 45, 48), - new Slot(Strings.Red(23), 23, 38, 41, 44, 46, 47), - new Slot(Strings.Black(24), 24, 38, 42, 44, 45, 48), - new Slot(Strings.Red(25), 25, 39, 40, 44, 46, 47), - new Slot(Strings.Black(26), 26, 39, 41, 44, 45, 48), - new Slot(Strings.Red(27), 27, 39, 42, 44, 46, 47), - new Slot(Strings.Black(28), 28, 39, 40, 44, 45, 48), - new Slot(Strings.Black(29), 29, 39, 41, 44, 46, 48), - new Slot(Strings.Red(30), 30, 39, 42, 44, 45, 47), - new Slot(Strings.Black(31), 31, 39, 40, 44, 46, 48), - new Slot(Strings.Red(32), 32, 39, 41, 44, 45, 47), - new Slot(Strings.Black(33), 33, 39, 42, 44, 46, 48), - new Slot(Strings.Red(34), 34, 39, 40, 44, 45, 47), - new Slot(Strings.Black(35), 35, 39, 41, 44, 46, 48), - new Slot(Strings.Red(36), 36, 39, 42, 44, 45, 47), - new Slot("0", 49), - new Slot("00", 50)); - - private readonly IRandom _random; - - public Wheel(IRandom random) => _random = random; - - public Slot Spin() => _slots[_random.Next(_slots.Length)]; -} diff --git a/75_Roulette/python/roulette.py b/75_Roulette/python/roulette.py index eec68bed7..b20b00e67 100644 --- a/75_Roulette/python/roulette.py +++ b/75_Roulette/python/roulette.py @@ -75,8 +75,8 @@ def query_bets() -> Tuple[List[int], List[int]]: for i in range(bet_count): while bet_ids[i] == -1: try: - in_string = input(f"NUMBER {str(i + 1)}? ").split(",") - id_, val = int(in_string[0]), int(in_string[1]) + inString = input("NUMBER " + str(i + 1) + "? ").split(",") + id_, val = int(inString[0]), int(inString[1]) # check other bet_IDs for j in range(i): @@ -93,7 +93,7 @@ def query_bets() -> Tuple[List[int], List[int]]: return bet_ids, bet_values -def bet_results(bet_ids: List[int], bet_values: List[int], result) -> int: +def bet_results(bet_ids: List[int], bet_values: List[int], result): """Computes the results, prints them, and returns the total net winnings""" total_winnings = 0 @@ -126,15 +126,15 @@ def get_modifier(id_: int, num: int) -> int: total_winnings += winnings if winnings >= 0: - print(f"YOU WIN {str(winnings)} DOLLARS ON BET {str(i + 1)}") + print("YOU WIN " + str(winnings) + " DOLLARS ON BET " + str(i + 1)) else: - print(f"YOU LOSE {str(winnings * -1)} DOLLARS ON BET {str(i + 1)}") + print("YOU LOSE " + str(winnings * -1) + " DOLLARS ON BET " + str(i + 1)) return winnings def print_check(amount: int) -> None: - """Print a check of a given amount""" + """Prints a check of a given amount""" name = input("TO WHOM SHALL I MAKE THE CHECK? ") print("-" * 72) @@ -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(f"PAY TO THE ORDER OF -----{name}----- ${amount}") + print("PAY TO THE ORDER OF -----" + name + "----- $" + str(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(f"{val} RED") + print(str(val) + " RED") else: - print(f"{val} BLACK") + print(str(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 {"y", "true", "t", "yes"} + return string.lower() in ("yes", "y", "true", "t", "yes") if __name__ == "__main__": diff --git a/75_Roulette/rust/Cargo.lock b/75_Roulette/rust/Cargo.lock deleted file mode 100644 index 81365033b..000000000 --- a/75_Roulette/rust/Cargo.lock +++ /dev/null @@ -1,82 +0,0 @@ -# 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/75_Roulette/rust/Cargo.toml b/75_Roulette/rust/Cargo.toml deleted file mode 100644 index 37f4add75..000000000 --- a/75_Roulette/rust/Cargo.toml +++ /dev/null @@ -1,10 +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] -morristown = "0.1.4" -rand = "0.8.5" diff --git a/75_Roulette/rust/src/main.rs b/75_Roulette/rust/src/main.rs deleted file mode 100644 index b0fd8765b..000000000 --- a/75_Roulette/rust/src/main.rs +++ /dev/null @@ -1,106 +0,0 @@ -mod util; - -use morristown::{Instructions, PromptMultiOption}; -use rand::Rng; -use util::INSTRUCTIONS; - -fn main() { - morristown::print_intro("ROULETTE"); - - let date = morristown::prompt_multi_string( - "ENTER CURRENT DATE (AS IN 'JANUARY 23, 1978)", - ",", - Some(PromptMultiOption::UnitAmount(2)), - ); - - Instructions::new_multiline( - true, - false, - "DO YOU WANT INSTRUCTIONS?", - INSTRUCTIONS.to_vec(), - ) - .print(); - - let mut house: usize = 100000; - let mut player: usize = 1000; - - loop { - let bet_count = morristown::prompt_number_range::("HOW MANY BETS?", 1..=10); - let mut bets: Vec> = Vec::new(); - - for i in 1..=bet_count { - loop { - let msg = format!("NUMBER {}?", i); - let bet_input = morristown::prompt_multi_number::( - msg.as_str(), - ",", - Some(PromptMultiOption::UnitAmount(2)), - None, - ); - let (bet_num, wager) = (bet_input[0], bet_input[1]); - - if let Some(_) = bets.iter().find(|bet| bet[0] == bet_num) { - println!("YOU MADE THAT BET ONCE ALREADY, DUM-DUM"); - } else if bet_num > 0 && bet_num <= 50 && wager >= 5 && wager <= 500 { - bets.push(bet_input); - player -= wager; - house += wager; - break; - } else if wager > player { - println!("NOT ENOUGH MONEY") - } else { - println!("INVALID BET. TRY AGAIN"); - } - } - } - - println!("\nSPINNING"); - std::thread::sleep(std::time::Duration::from_secs(1)); - let spin: u8 = rand::thread_rng().gen_range(1..=38); - - let color = if util::REDS.contains(&spin) { - "RED" - } else { - "BLACK" - }; - - println!("\n{} {}\n", spin, color); - - for (i, bet) in bets.iter().enumerate() { - let (bet_num, wager) = (bet[0] as u8, bet[1]); - let (win, payoff) = util::process_bet(bet_num, spin); - - let msg = if win { - let pay = wager * payoff as usize; - player += wager + pay; - house -= pay; - "WIN" - } else { - "LOSE" - }; - - println!("YOU {msg} {wager} DOLLARS ON BET {}", i + 1); - } - - println!("\nTOTALS:\t\tME\t\tYOU"); - println!("\t\t{house}\t\t{player}"); - - if player <= 0 { - println!("OOPS! YOU JUST SPENT YOUR LAST DOLLAR"); - println!("THANKS FOR YOUR MONEY"); - println!("I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL"); - break; - } - - if house <= 0 { - println!("YOU BROKE THE HOUSE!"); - util::print_check(player, date); - break; - } - - if !morristown::prompt_bool("AGAIN?", false) { - util::print_check(player, date); - break; - } - } -} diff --git a/75_Roulette/rust/src/util.rs b/75_Roulette/rust/src/util.rs deleted file mode 100644 index 321a14167..000000000 --- a/75_Roulette/rust/src/util.rs +++ /dev/null @@ -1,91 +0,0 @@ -use std::ops::RangeInclusive; - -use rand::{thread_rng, Rng}; - -pub const INSTRUCTIONS: [&str; 38] = [ - "\nTHIS IS THE BETTING LAYOUT", - "\n(*=RED)\n", - "1*\t2\t3*", - "4\t5*\t6", - "7*\t8\t9*", - "10\t11\t12*", - "--------------------", - "13\t14*\t15", - "16*\t17\t18*", - "19*\t20\t21*", - "22\t23*\t24", - "--------------------", - "25*\t26\t27*", - "28\t29\t30*", - "31\t32*\t33", - "34*\t35\t36*", - "--------------------", - " 00 0\n", - "TYPES OF BETS\n", - "THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET", - "ON THAT NUMBER", - "THESE PAY OFF 35:1\n", - "THE 2:1 BETS ARE:", - "37) 1-12\t40) FIRST COLUMN", - "38) 13-24\t41) SECOND COLUMN", - "39) 25-36\t42) THIRD COLUMN\n", - "THE EVEN MONEY BETS ARE:", - "43) 1-18\t46) ODD", - "44) 19-36\t47) RED", - "45) EVEN\t48) BLACK\n", - "\n49)0 AND 50)00 PAY OFF 35:1", - "NOTE: 0 AND 00 DO NOT COUNT UNDER ANY", - "\tBETS EXCEPT THEIR OWN\n", - "WHEN I ASK FOR EACH BET,TYPE THE NUMBER", - "AND THE AMOUNT,SEPARATED BY A COMMA", - "FOR EXAMPLE:TO BET $500 ON BLACK,TYPE 48,500", - "WHEN I ASK FOR A BET\n", - "MINIMUM BET IS $5,MAXIMUM IS $500\n", -]; - -pub const REDS: [u8; 18] = [ - 1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36, -]; - -pub fn process_bet(bet_num: u8, spin: u8) -> (bool, u8) { - match bet_num { - 1..=36 => (bet_num == spin, 35), - 37 => (is_within_range(1..=12, spin), 2), - 38 => (is_within_range(13..=24, spin), 2), - 39 => (is_within_range(25..=36, spin), 2), - 40 => (spin % 3 == 1, 2), - 41 => (spin % 3 == 2, 2), - 42 => (spin % 3 == 0, 2), - 43 => (is_within_range(1..=18, spin), 1), - 44 => (is_within_range(19..=36, spin), 1), - 45 => (spin % 2 == 0, 1), - 46 => (spin % 2 == 1, 1), - 47 => (REDS.contains(&spin), 1), - 48 => (!REDS.contains(&spin), 1), - _ => { - println!("##INVALID BET##"); - return (false, 0); - } - } -} - -fn is_within_range(r: RangeInclusive, n: u8) -> bool { - r.contains(&n) -} - -pub fn print_check(money: usize, date: Vec) { - let name = morristown::prompt_string("TO WHOM SHALL I MAKE THE CHECK?"); - let check_no = thread_rng().gen_range(1..=100); - - let dashes = 60; - - println!("\n{}", "-".repeat(dashes)); - println!("CHECK NO. {}\n", check_no); - println!("{}{}, {}\n\n", "\t".repeat(4), date[0], date[1]); - println!("PAY TO THE ORDER OF-----{name}-----$ {money}\n\n"); - println!("\t\tTHE MEMORY BANK OF VIRGINIA\n"); - println!("\t\t\t\tTHE COMPUTER"); - println!("\t\t\t ----------X-----\t"); - println!("{}", "-".repeat(dashes)); - println!("COME BACK SOON!\n") -} diff --git a/76_Russian_Roulette/lua/russianroulette.lua b/76_Russian_Roulette/lua/russianroulette.lua deleted file mode 100644 index 546ec6c4e..000000000 --- a/76_Russian_Roulette/lua/russianroulette.lua +++ /dev/null @@ -1,58 +0,0 @@ -print [[ - RUSSIAN ROULETTE - CREATIVE COMPUTING MORRISTOWN, NEW JERSY -This is a game of >>>>>>>>>>Russian Roulette -Here is a Revolver - -]] - -local function parse_input() - local incorrect_input = true - local input = nil - while incorrect_input do - input = io.read(1) - if input == "1" or input == "2" then incorrect_input = false end - end - return input -end - -local function russian_roulette() - local NUMBER_OF_ROUNDS = 9 - - while true do - local dead = false - local n = 0 - print("Type '1' to Spin chamber and pull trigger") - print("Type '2' to Give up") - print("Go") - - while not dead do - local choice = parse_input() - if choice == "2" then break end - - if math.random() > 0.833333333333334 then - dead = true - else - print("CLICK") - n = n + 1 - end - - if n > NUMBER_OF_ROUNDS then break end - end - - if dead then - print("BANG!!!!! You're Dead!") - print("Condolences will be sent to your relatives.\n\n\n") - print("...Next victim...") - elseif n > NUMBER_OF_ROUNDS then - print("You win!!!!!") - print("Let someone else blow his brain out.\n") - else - print(" Chicken!!!!!\n\n\n") - print("...Next victim....") - end - end -end - -russian_roulette() - diff --git a/76_Russian_Roulette/python/russianroulette.py b/76_Russian_Roulette/python/russianroulette.py index 71e0ee129..3af235152 100644 --- a/76_Russian_Roulette/python/russianroulette.py +++ b/76_Russian_Roulette/python/russianroulette.py @@ -1,17 +1,19 @@ -""" -Russian Roulette - -From Basic Computer Games (1978) - - In this game, you are given by the computer a - revolver loaded with one bullet and five empty - chambers. You spin the chamber and pull the trigger - by inputting a "1", or, if you want to quit, input - a "2". You win if you play ten times and are still - alive. - Tom Adametx wrote this program while a student at - Curtis Jr. High School in Sudbury, Massachusetts. -""" +######################################################## +# +# Russian Roulette +# +# From Basic Computer Games (1978) +# +# In this game, you are given by the computer a +# revolver loaded with one bullet and five empty +# chambers. You spin the chamber and pull the trigger +# by inputting a "1", or, if you want to quit, input +# a "2". You win if you play ten times and are still +# alive. +# Tom Adametx wrote this program while a student at +# Curtis Jr. High School in Sudbury, Massachusetts. +# +######################################################## from random import random @@ -29,7 +31,8 @@ def initial_message() -> None: def parse_input() -> int: while True: try: - return int(input("? ")) + i = int(input("? ")) + return i except ValueError: print("Number expected...") @@ -60,12 +63,13 @@ 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: - print(" Chicken!!!!!\n\n\n") - print("...Next victim....") + 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....") if __name__ == "__main__": diff --git a/76_Russian_Roulette/rust/Cargo.lock b/76_Russian_Roulette/rust/Cargo.lock deleted file mode 100644 index 4fe2abbea..000000000 --- a/76_Russian_Roulette/rust/Cargo.lock +++ /dev/null @@ -1,75 +0,0 @@ -# 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/76_Russian_Roulette/rust/Cargo.toml b/76_Russian_Roulette/rust/Cargo.toml deleted file mode 100644 index 3b1d02f52..000000000 --- a/76_Russian_Roulette/rust/Cargo.toml +++ /dev/null @@ -1,9 +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] -rand = "0.8.5" diff --git a/76_Russian_Roulette/rust/src/main.rs b/76_Russian_Roulette/rust/src/main.rs deleted file mode 100644 index 7475ad5cf..000000000 --- a/76_Russian_Roulette/rust/src/main.rs +++ /dev/null @@ -1,67 +0,0 @@ -use std::time::Duration; - -use rand::Rng; - -fn main() { - println!("\n\t\tRUSSIAN ROULETTE"); - println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); - println!("\nTHIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\n"); - println!("HERE IS A REVOLVER."); - - loop { - println!("TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER"); - println!("TYPE '2' TO GIVE UP."); - println!("GO"); - - let mut tries = 0; - - loop { - let mut pull_trigger = true; - - loop { - println!("?"); - let mut input = String::new(); - - std::io::stdin() - .read_line(&mut input) - .expect("Error reading line!"); - - match input.trim() { - "1" => break, - "2" => { - pull_trigger = false; - break; - } - _ => println!("Invalid input."), - } - } - - if pull_trigger { - std::thread::sleep(Duration::from_secs(1)); - - match rand::thread_rng().gen_range(0..6) { - 0 => { - println!("\tBANG!!!!! YOU'RE DEAD!"); - println!("CONDOLENCES WILL BE SENT TO YOUR RELATIVES."); - println!("\n\n...NEXT VICTIM..."); - break; - } - _ => { - println!("- CLICK -"); - tries += 1; - } - } - - if tries >= 10 { - println!("YOU WIN!!!!!"); - println!("LET SOMEONE ELSE BLOW HIS BRAINS OUT.\n"); - break; - } - } else { - println!("\tCHICKEN!!!!!"); - println!("\n\n...NEXT VICTIM..."); - break; - } - } - } -} diff --git a/77_Salvo/README.md b/77_Salvo/README.md index 3ef9f21c9..d5e029a92 100644 --- a/77_Salvo/README.md +++ b/77_Salvo/README.md @@ -26,21 +26,4 @@ http://www.vintage-basic.net/games.html #### Porting Notes -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 - -see also the earlier post - -https://forums.raspberrypi.com/viewtopic.php?p=1994961#p1994961 - -in the same thread, there is a typo in later published versions of the SALVO Basic source code compared to the original edition of 101 Basic Computer Games. - -This typo is interesting because it causes the program to play by a much weaker strategy while exhibiting no other obvious side effects. I would recommend changing the line 3970 in the Basic program back to the original - -`3970 K(R,S)=K(R,S)+E(U)-2*INT(H(U)+.5)` - -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.) - +(please note any difficulties or challenges in porting here) diff --git a/77_Salvo/csharp/Coordinate.cs b/77_Salvo/csharp/Coordinate.cs deleted file mode 100644 index 4cd2c4334..000000000 --- a/77_Salvo/csharp/Coordinate.cs +++ /dev/null @@ -1,45 +0,0 @@ -namespace Salvo; - -internal record struct Coordinate(int Value) -{ - public const int MinValue = 1; - public const int MaxValue = 10; - - 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); - - 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) => 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} "; -} diff --git a/77_Salvo/csharp/Extensions/IOExtensions.cs b/77_Salvo/csharp/Extensions/IOExtensions.cs deleted file mode 100644 index 6d021deb3..000000000 --- a/77_Salvo/csharp/Extensions/IOExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -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.Write(Streams.Illegal); - } - } - - 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 deleted file mode 100644 index e83ab2657..000000000 --- a/77_Salvo/csharp/Extensions/RandomExtensions.cs +++ /dev/null @@ -1,32 +0,0 @@ -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/Fleet.cs b/77_Salvo/csharp/Fleet.cs deleted file mode 100644 index 5f267225f..000000000 --- a/77_Salvo/csharp/Fleet.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; - -namespace Salvo; - -internal class Fleet -{ - private readonly List _ships; - - internal Fleet(IReadWrite io) - { - io.WriteLine(Prompts.Coordinates); - _ships = new() - { - new Battleship(io), - new Cruiser(io), - new Destroyer("A", io), - new Destroyer("B", io) - }; - } - - internal Fleet(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; - } - } - } - } - - internal IEnumerable Ships => _ships.AsEnumerable(); - - internal void ReceiveShots(IEnumerable shots, Action reportHit) - { - 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 deleted file mode 100644 index a0223d8ba..000000000 --- a/77_Salvo/csharp/Game.cs +++ /dev/null @@ -1,29 +0,0 @@ -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); - - var turnHandler = new TurnHandler(_io, _random); - _io.WriteLine(); - - Winner? winner; - do - { - winner = turnHandler.PlayTurn(); - } while (winner == null); - - _io.Write(winner == Winner.Computer ? Streams.IWon : Streams.YouWon); - } -} diff --git a/77_Salvo/csharp/Offset.cs b/77_Salvo/csharp/Offset.cs deleted file mode 100644 index 3c873f101..000000000 --- a/77_Salvo/csharp/Offset.cs +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index 3bafe2179..000000000 --- a/77_Salvo/csharp/Position.cs +++ /dev/null @@ -1,52 +0,0 @@ -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 deleted file mode 100644 index 5dde4d052..000000000 --- a/77_Salvo/csharp/Program.cs +++ /dev/null @@ -1,9 +0,0 @@ -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; - -//new Game(new ConsoleIO(), new RandomNumberGenerator()).Play(); -new Game(new ConsoleIO(), new DataRandom()).Play(); diff --git a/77_Salvo/csharp/Resources/Coordinates.txt b/77_Salvo/csharp/Resources/Coordinates.txt deleted file mode 100644 index 387d7a6b4..000000000 --- a/77_Salvo/csharp/Resources/Coordinates.txt +++ /dev/null @@ -1 +0,0 @@ -Enter coordinates for... diff --git a/77_Salvo/csharp/Resources/IHaveMoreShotsThanSquares.txt b/77_Salvo/csharp/Resources/IHaveMoreShotsThanSquares.txt deleted file mode 100644 index a6f371107..000000000 --- a/77_Salvo/csharp/Resources/IHaveMoreShotsThanSquares.txt +++ /dev/null @@ -1 +0,0 @@ -I have more shots than blank squares. diff --git a/77_Salvo/csharp/Resources/IHaveShots.txt b/77_Salvo/csharp/Resources/IHaveShots.txt deleted file mode 100644 index 9157e1a7b..000000000 --- a/77_Salvo/csharp/Resources/IHaveShots.txt +++ /dev/null @@ -1 +0,0 @@ -I have {0} shots. diff --git a/77_Salvo/csharp/Resources/IHit.txt b/77_Salvo/csharp/Resources/IHit.txt deleted file mode 100644 index 3b43216cd..000000000 --- a/77_Salvo/csharp/Resources/IHit.txt +++ /dev/null @@ -1 +0,0 @@ -I hit your {0} diff --git a/77_Salvo/csharp/Resources/IWon.txt b/77_Salvo/csharp/Resources/IWon.txt deleted file mode 100644 index b3f506348..000000000 --- a/77_Salvo/csharp/Resources/IWon.txt +++ /dev/null @@ -1 +0,0 @@ -I have won. diff --git a/77_Salvo/csharp/Resources/Illegal.txt b/77_Salvo/csharp/Resources/Illegal.txt deleted file mode 100644 index 6a71787a7..000000000 --- a/77_Salvo/csharp/Resources/Illegal.txt +++ /dev/null @@ -1 +0,0 @@ -Illegal, enter again. diff --git a/77_Salvo/csharp/Resources/Resource.cs b/77_Salvo/csharp/Resources/Resource.cs deleted file mode 100644 index 8be52fdb0..000000000 --- a/77_Salvo/csharp/Resources/Resource.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -namespace Salvo.Resources; - -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 IHit(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 Format(T value, [CallerMemberName] string? name = null) - => string.Format(GetString(name), value); - - 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/SeeShots.txt b/77_Salvo/csharp/Resources/SeeShots.txt deleted file mode 100644 index 7f608b0ba..000000000 --- a/77_Salvo/csharp/Resources/SeeShots.txt +++ /dev/null @@ -1 +0,0 @@ -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 deleted file mode 100644 index 18e90fcbd..000000000 --- a/77_Salvo/csharp/Resources/ShotBefore.txt +++ /dev/null @@ -1 +0,0 @@ -You shot there before on turn {0} diff --git a/77_Salvo/csharp/Resources/Start.txt b/77_Salvo/csharp/Resources/Start.txt deleted file mode 100644 index 283a0fbb0..000000000 --- a/77_Salvo/csharp/Resources/Start.txt +++ /dev/null @@ -1 +0,0 @@ -Do you want to start \ No newline at end of file diff --git a/77_Salvo/csharp/Resources/Title.txt b/77_Salvo/csharp/Resources/Title.txt deleted file mode 100644 index 6b2ba9b31..000000000 --- a/77_Salvo/csharp/Resources/Title.txt +++ /dev/null @@ -1,5 +0,0 @@ - Salvo - Creative Computing Morristown, New Jersey - - - diff --git a/77_Salvo/csharp/Resources/Turn.txt b/77_Salvo/csharp/Resources/Turn.txt deleted file mode 100644 index 14bf316ea..000000000 --- a/77_Salvo/csharp/Resources/Turn.txt +++ /dev/null @@ -1,2 +0,0 @@ - -Turn {0} diff --git a/77_Salvo/csharp/Resources/WhereAreYourShips.txt b/77_Salvo/csharp/Resources/WhereAreYourShips.txt deleted file mode 100644 index e8391a465..000000000 --- a/77_Salvo/csharp/Resources/WhereAreYourShips.txt +++ /dev/null @@ -1 +0,0 @@ -Where are your ships? \ No newline at end of file diff --git a/77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt b/77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt deleted file mode 100644 index 04d58f92e..000000000 --- a/77_Salvo/csharp/Resources/YouHaveMoreShotsThanSquares.txt +++ /dev/null @@ -1 +0,0 @@ -You have more shots than there are blank squares. diff --git a/77_Salvo/csharp/Resources/YouHaveShots.txt b/77_Salvo/csharp/Resources/YouHaveShots.txt deleted file mode 100644 index 43abeda83..000000000 --- a/77_Salvo/csharp/Resources/YouHaveShots.txt +++ /dev/null @@ -1 +0,0 @@ -You have {0} shots. diff --git a/77_Salvo/csharp/Resources/YouHit.txt b/77_Salvo/csharp/Resources/YouHit.txt deleted file mode 100644 index b5b5d7614..000000000 --- a/77_Salvo/csharp/Resources/YouHit.txt +++ /dev/null @@ -1 +0,0 @@ -You hit my {0}. diff --git a/77_Salvo/csharp/Resources/YouWon.txt b/77_Salvo/csharp/Resources/YouWon.txt deleted file mode 100644 index 1f71343bc..000000000 --- a/77_Salvo/csharp/Resources/YouWon.txt +++ /dev/null @@ -1 +0,0 @@ -You have won. diff --git a/77_Salvo/csharp/Salvo.csproj b/77_Salvo/csharp/Salvo.csproj index 51470ec9f..d3fe4757c 100644 --- a/77_Salvo/csharp/Salvo.csproj +++ b/77_Salvo/csharp/Salvo.csproj @@ -2,16 +2,8 @@ Exe net6.0 - 11 + 10 enable enable - - - - - - - - diff --git a/77_Salvo/csharp/Ships/Battleship.cs b/77_Salvo/csharp/Ships/Battleship.cs deleted file mode 100644 index 4f864eb6f..000000000 --- a/77_Salvo/csharp/Ships/Battleship.cs +++ /dev/null @@ -1,17 +0,0 @@ -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; -} diff --git a/77_Salvo/csharp/Ships/Cruiser.cs b/77_Salvo/csharp/Ships/Cruiser.cs deleted file mode 100644 index d004f24cf..000000000 --- a/77_Salvo/csharp/Ships/Cruiser.cs +++ /dev/null @@ -1,17 +0,0 @@ -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; -} diff --git a/77_Salvo/csharp/Ships/Destroyer.cs b/77_Salvo/csharp/Ships/Destroyer.cs deleted file mode 100644 index 6523395d3..000000000 --- a/77_Salvo/csharp/Ships/Destroyer.cs +++ /dev/null @@ -1,17 +0,0 @@ -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; -} diff --git a/77_Salvo/csharp/Ships/Ship.cs b/77_Salvo/csharp/Ships/Ship.cs deleted file mode 100644 index ee204d3f3..000000000 --- a/77_Salvo/csharp/Ships/Ship.cs +++ /dev/null @@ -1,37 +0,0 @@ -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 bool IsDamaged => _positions.Count > 0 && _positions.Count < Size; - 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 deleted file mode 100644 index 721f50c50..000000000 --- a/77_Salvo/csharp/Targetting/ComputerShotSelector.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace Salvo.Targetting; - -internal class ComputerShotSelector : ShotSelector -{ - private readonly KnownHitsShotSelectionStrategy _knownHitsStrategy; - private readonly SearchPatternShotSelectionStrategy _searchPatternStrategy; - private readonly IReadWrite _io; - private readonly bool _showShots; - - 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() - { - 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); - - private ShotSelectionStrategy GetSelectionStrategy() - => _knownHitsStrategy.KnowsOfDamagedShips ? _knownHitsStrategy : _searchPatternStrategy; -} diff --git a/77_Salvo/csharp/Targetting/HumanShotSelector.cs b/77_Salvo/csharp/Targetting/HumanShotSelector.cs deleted file mode 100644 index ea49bf124..000000000 --- a/77_Salvo/csharp/Targetting/HumanShotSelector.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace Salvo.Targetting; - -internal class HumanShotSelector : ShotSelector -{ - private readonly IReadWrite _io; - - internal HumanShotSelector(Fleet source, IReadWrite io) - : base(source) - { - _io = io; - } - - protected override IEnumerable GetShots() - { - var shots = new Position[NumberOfShots]; - - for (var i = 0; i < shots.Length; i++) - { - while (true) - { - var position = _io.ReadValidPosition(); - if (WasSelectedPreviously(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/KnownHitsShotSelectionStrategy.cs b/77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs deleted file mode 100644 index 5e0b9d2ca..000000000 --- a/77_Salvo/csharp/Targetting/KnownHitsShotSelectionStrategy.cs +++ /dev/null @@ -1,71 +0,0 @@ -namespace Salvo.Targetting; - -internal class KnownHitsShotSelectionStrategy : ShotSelectionStrategy -{ - private readonly List<(int Turn, Ship Ship)> _damagedShips = new(); - - internal KnownHitsShotSelectionStrategy(ShotSelector shotSelector) - : base(shotSelector) - { - } - - 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(); - - 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/SearchPattern.cs b/77_Salvo/csharp/Targetting/SearchPattern.cs deleted file mode 100644 index ac2071c8f..000000000 --- a/77_Salvo/csharp/Targetting/SearchPattern.cs +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 1eae88f81..000000000 --- a/77_Salvo/csharp/Targetting/SearchPatternShotSelector.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace Salvo.Targetting; - -internal class SearchPatternShotSelectionStrategy : ShotSelectionStrategy -{ - private const int MaxSearchPatternAttempts = 100; - private readonly IRandom _random; - private readonly SearchPattern _searchPattern = new(); - private readonly List _shots = new(); - - internal SearchPatternShotSelectionStrategy(ShotSelector shotSelector, IRandom random) - : base(shotSelector) - { - _random = random; - } - - internal override IEnumerable GetShots(int numberOfShots) - { - _shots.Clear(); - while(_shots.Count < numberOfShots) - { - var (seed, _) = _random.NextShipPosition(); - SearchFrom(numberOfShots, seed); - } - return _shots; - } - - private void SearchFrom(int numberOfShots, Position candidateShot) - { - var attemptsLeft = MaxSearchPatternAttempts; - while (true) - { - _searchPattern.Reset(); - if (attemptsLeft-- == 0) { return; } - candidateShot = candidateShot.BringIntoRange(_random); - if (FindValidShots(numberOfShots, ref candidateShot)) { return; } - } - } - - private bool FindValidShots(int numberOfShots, ref 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 && !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 deleted file mode 100644 index b4cf14b16..000000000 --- a/77_Salvo/csharp/Targetting/ShotSelectionStrategy.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Salvo.Targetting; - -internal abstract class ShotSelectionStrategy -{ - private readonly ShotSelector _shotSelector; - protected ShotSelectionStrategy(ShotSelector shotSelector) - { - _shotSelector = shotSelector; - } - - internal abstract IEnumerable GetShots(int numberOfShots); - - protected bool WasSelectedPreviously(Position position) => _shotSelector.WasSelectedPreviously(position); - - protected bool WasSelectedPreviously(Position position, out int turn) - => _shotSelector.WasSelectedPreviously(position, out turn); -} diff --git a/77_Salvo/csharp/Targetting/ShotSelector.cs b/77_Salvo/csharp/Targetting/ShotSelector.cs deleted file mode 100644 index 695dbc42d..000000000 --- a/77_Salvo/csharp/Targetting/ShotSelector.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Salvo.Targetting; - -internal abstract class ShotSelector -{ - private readonly Fleet _source; - private readonly Dictionary _previousShots = new(); - - internal ShotSelector(Fleet source) - { - _source = source; - } - - 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 IEnumerable GetShots(int turnNumber) - { - foreach (var shot in GetShots()) - { - _previousShots.Add(shot, turnNumber); - yield return shot; - } - } - - protected abstract IEnumerable GetShots(); -} diff --git a/77_Salvo/csharp/TurnHandler.cs b/77_Salvo/csharp/TurnHandler.cs deleted file mode 100644 index afde96133..000000000 --- a/77_Salvo/csharp/TurnHandler.cs +++ /dev/null @@ -1,92 +0,0 @@ -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 deleted file mode 100644 index a5a73eb47..000000000 --- a/77_Salvo/csharp/Winner.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Salvo; - -internal enum Winner -{ - Human, - Computer -} diff --git a/77_Salvo/python/salvo.ipynb b/77_Salvo/python/salvo.ipynb new file mode 100644 index 000000000..1cc71208a --- /dev/null +++ b/77_Salvo/python/salvo.ipynb @@ -0,0 +1,328 @@ +{ + "metadata": { + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3-final" + }, + "orig_nbformat": 2, + "kernelspec": { + "name": "python3", + "display_name": "Python 3", + "language": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2, + "cells": [ + { + "cell_type": "code", + "execution_count": 727, + "metadata": {}, + "outputs": [], + "source": [ + "import random" + ] + }, + { + "cell_type": "code", + "execution_count": 728, + "metadata": {}, + "outputs": [], + "source": [ + "BOARD_WIDTH = 10\n", + "BOARD_HEIGHT = 10\n", + "\n", + "SHIPS = [(\"BATTLESHIP\", 5), (\"CRUISER\", 3), (\"DESTROYER\", 2), (\"DESTROYER\", 2)]\n", + "\n", + "VALID_MOVES = [[-1, 0], [-1, 1], [0, 1], [1, 1], [1, 0], [1, -1], [0, -1], [-1, -1]]" + ] + }, + { + "cell_type": "code", + "execution_count": 729, + "metadata": {}, + "outputs": [], + "source": [ + "# random number functions\n", + "#\n", + "# seed the random number generator\n", + "random.seed()\n", + "\n", + "# random_x_y\n", + "#\n", + "# generate a valid x,y coordinate on the board\n", + "# returns: x,y\n", + "# x: integer between 1 and BOARD_HEIGHT\n", + "# y: integer between 1 and BOARD WIDTH\n", + "def random_x_y():\n", + " x = random.randrange(1, BOARD_WIDTH + 1)\n", + " y = random.randrange(1, BOARD_HEIGHT + 1)\n", + " return (x, y)" + ] + }, + { + "cell_type": "code", + "execution_count": 730, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "5 3\n" + ] + } + ], + "source": [ + "x, y = random_x_y()\n", + "print(x, y)" + ] + }, + { + "cell_type": "code", + "execution_count": 731, + "metadata": {}, + "outputs": [], + "source": [ + "# TODO: add an optional starting coordinate for testing\n", + "# purposes\n", + "def generate_ship_coordinates(ship):\n", + "\n", + " # randomly generate starting x,y coordinates\n", + " start_x, start_y = random_x_y()\n", + "\n", + " # using starting coordinates and the ship type,\n", + " # generate a vector of possible directions the ship\n", + " # could be placed. directions are numbered 0-7 along\n", + " # points of the compass (N, NE, E, SE, S, SW, W, NW)\n", + " # clockwise. a vector of valid directions where the\n", + " # ship does not go off the board is determined\n", + " ship_len = SHIPS[ship][1] - 1\n", + " dirs = [False for x in range(8)]\n", + " dirs[0] = (start_x - ship_len) >= 1\n", + " dirs[2] = (start_y + ship_len) <= BOARD_WIDTH\n", + " dirs[1] = dirs[0] and dirs[2]\n", + " dirs[4] = (start_x + ship_len) <= BOARD_HEIGHT\n", + " dirs[3] = dirs[2] and dirs[4]\n", + " dirs[6] = (start_y - ship_len) >= 1\n", + " dirs[5] = dirs[4] and dirs[6]\n", + " dirs[7] = dirs[6] and dirs[0]\n", + " directions = [p for p in range(len(dirs)) if dirs[p]]\n", + "\n", + " # using the vector of valid directions, pick a\n", + " # random direction to place the ship\n", + " dir_idx = random.randrange(len(directions))\n", + " direction = directions[dir_idx]\n", + "\n", + " # using the starting x,y, direction and ship\n", + " # type, return the coordinates of each point\n", + " # of the ship. VALID_MOVES is a staic array\n", + " # of coordinate offsets to walk from starting\n", + " # coordinate to the end coordinate in the\n", + " # chosen direction\n", + " ship_len = SHIPS[ship][1] - 1\n", + " d_x = VALID_MOVES[direction][0]\n", + " d_y = VALID_MOVES[direction][1]\n", + "\n", + " coords = [(start_x, start_y)]\n", + " x_coord = start_x\n", + " y_coord = start_y\n", + " for i in range(ship_len):\n", + " x_coord = x_coord + d_x\n", + " y_coord = y_coord + d_y\n", + " coords.append((x_coord, y_coord))\n", + " return coords" + ] + }, + { + "cell_type": "code", + "execution_count": 732, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "BATTLESHIP 5 [(10, 2), (10, 3), (10, 4), (10, 5), (10, 6)]\nCRUISER 3 [(9, 4), (8, 4), (7, 4)]\nDESTROYER 2 [(2, 5), (1, 5)]\nDESTROYER 2 [(7, 8), (7, 9)]\n" + ] + } + ], + "source": [ + "for ship in range(len(SHIPS)):\n", + " coords = generate_ship_coordinates(ship)\n", + " print(f\"{SHIPS[ship][0]:15}\", f\"{SHIPS[ship][1]:2}\", coords)" + ] + }, + { + "cell_type": "code", + "execution_count": 733, + "metadata": {}, + "outputs": [], + "source": [ + "def create_blank_board():\n", + " return [[None for y in range(BOARD_WIDTH)] for x in range(BOARD_HEIGHT)]" + ] + }, + { + "cell_type": "code", + "execution_count": 734, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " 1 2 3 4 5 6 7 8 9 10\n 1 \n 2 \n 3 \n 4 \n 5 \n 6 \n 7 \n 8 \n 9 \n10 \n" + ] + } + ], + "source": [ + "def print_board(board):\n", + "\n", + " # print board header (column numbers)\n", + " print(\" \", end=\"\")\n", + " for z in range(BOARD_WIDTH):\n", + " print(f\"{z+1:3}\", end=\"\")\n", + " print(\"\")\n", + "\n", + " for x in range(len(board)):\n", + " print(f\"{x+1:2}\", end=\"\")\n", + " for y in range(len(board[x])):\n", + " if board[x][y] is None:\n", + " print(f\"{' ':3}\", end=\"\")\n", + " else:\n", + " print(f\"{board[x][y]:3}\", end=\"\")\n", + " print(\"\")\n", + "\n", + "\n", + "computer_board = create_blank_board()\n", + "print_board(computer_board)" + ] + }, + { + "cell_type": "code", + "execution_count": 735, + "metadata": {}, + "outputs": [], + "source": [ + "def place_ship(board, coords, ship):\n", + " for coord in coords:\n", + " board[coord[0] - 1][coord[1] - 1] = ship" + ] + }, + { + "cell_type": "code", + "execution_count": 736, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "DESTROYER 2 [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]\n 1 2 3 4 5 6 7 8 9 10\n 1 0 \n 2 0 \n 3 0 \n 4 0 \n 5 0 \n 6 \n 7 \n 8 \n 9 \n10 \n" + ] + } + ], + "source": [ + "# test place_ship\n", + "board = create_blank_board()\n", + "coords = generate_ship_coordinates(0)\n", + "print(f\"{SHIPS[ship][0]:15}\", f\"{SHIPS[ship][1]:2}\", coords)\n", + "place_ship(board, coords, 0)\n", + "print_board(board)" + ] + }, + { + "cell_type": "code", + "execution_count": 737, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + " 1 2 3 4 5 6 7 8 9 10\n", + " 1 \n", + " 2 1 \n", + " 3 1 2 \n", + " 4 1 2 \n", + " 5 0 \n", + " 6 0 \n", + " 7 0 \n", + " 8 0 \n", + " 9 0 3 \n", + "10 3 \n" + ] + } + ], + "source": [ + "# NOTE: A little quirk that exists here and in the orginal\n", + "# game: Ships are allowed to cross each other!\n", + "# For example: 2 destroyers, length 2, one at\n", + "# [(1,1),(2,2)] and other at [(2,1),(1,2)]\n", + "\n", + "\n", + "def generate_board():\n", + " board = create_blank_board()\n", + "\n", + " for ship in range(len(SHIPS)):\n", + " placed = False\n", + " coords = []\n", + " while not placed:\n", + " coords = generate_ship_coordinates(ship)\n", + " clear = True\n", + " for coord in coords:\n", + " if board[coord[0] - 1][coord[1] - 1] is not None:\n", + " clear = False\n", + " break\n", + " if clear:\n", + " placed = True\n", + " place_ship(board, coords, ship)\n", + " return board\n", + "\n", + "\n", + "print_board(generate_board())" + ] + }, + { + "cell_type": "code", + "execution_count": 738, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[(4, 1), (3, 6), (6, 10), (10, 6), (4, 5)]\n" + ] + } + ], + "source": [ + "def generate_shots(number):\n", + " shots = []\n", + " for i in range(number):\n", + " shots.append(random_x_y())\n", + " return shots\n", + "\n", + "\n", + "shots = generate_shots(5)\n", + "print(shots)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ] +} diff --git a/77_Salvo/python/salvo.py b/77_Salvo/python/salvo.py index 417bebc14..456ad7551 100644 --- a/77_Salvo/python/salvo.py +++ b/77_Salvo/python/salvo.py @@ -1,14 +1,17 @@ import random import re -from typing import List, Optional, Tuple -BoardType = List[List[Optional[int]]] -CoordinateType = Tuple[int, int] +################### +# +# static variables +# +################### BOARD_WIDTH = 10 BOARD_HEIGHT = 10 - +# game ships +# # data structure keeping track of information # about the ships in the game. for each ship, # the following information is provided: @@ -32,21 +35,26 @@ [1, 0], # South [1, -1], # South West [0, -1], # West - [-1, -1], # North West -] + [-1, -1], +] # North West COORD_REGEX = "[ \t]{0,}(-?[0-9]{1,3})[ \t]{0,},[ \t]{0,}(-?[0-9]{1,2})" +#################### +# +# global variables +# +#################### # array of BOARD_HEIGHT arrays, BOARD_WIDTH in length, # representing the human player and computer -player_board: BoardType = [] -computer_board: BoardType = [] +player_board = [] +computer_board = [] # array representing the coordinates # for each ship for player and computer # array is in the same order as SHIPS -computer_ship_coords: List[List[CoordinateType]] = [] +computer_ship_coords = [] #################################### @@ -80,9 +88,10 @@ # #################################### -# flag indicating whose turn it currently is -COMPUTER = False -PLAYER = True +# flag indicating whose turn +# it currently is +COMPUTER = 0 +PLAYER = 1 active_turn = COMPUTER #################### @@ -99,27 +108,26 @@ # random_x_y # - - -def random_x_y() -> CoordinateType: - """Generate a valid x,y coordinate on the board""" - +# generate a valid x,y coordinate on the board +# returns: x,y +# x: integer between 1 and BOARD_HEIGHT +# y: integer between 1 and BOARD WIDTH +def random_x_y(): x = random.randrange(1, BOARD_WIDTH + 1) y = random.randrange(1, BOARD_HEIGHT + 1) return (x, y) -def input_coord() -> CoordinateType: - """ - Ask user for single (x,y) coordinate - - validate the coordinates are within the bounds - of the board width and height. mimic the behavior - of the original program which exited with error - messages if coordinates where outside of array bounds. - if input is not numeric, print error out to user and - let them try again. - """ +# input_coord +# +# ask user for single (x,y) coordinate +# validate the coordinates are within the bounds +# of the board width and height. mimic the behavior +# of the original program which exited with error +# messages if coordinates where outside of array bounds. +# if input is not numeric, print error out to user and +# let them try again. +def input_coord(): match = None while not match: coords = input("? ") @@ -140,25 +148,25 @@ def input_coord() -> CoordinateType: return x, y -def generate_ship_coordinates(ship: int) -> List[CoordinateType]: - """ - given a ship from the SHIPS array, generate - the coordinates of the ship. the starting point - of the ship's first coordinate is generated randomly. - once the starting coordinates are determined, the - possible directions of the ship, accounting for the - edges of the board, are determined. once possible - directions are found, a direction is randomly - determined and the remaining coordinates are - generated by adding or substraction from the starting - coordinates as determined by direction. - - arguments: - ship - index into the SHIPS array - - returns: - array of sets of coordinates (x,y) - """ +# generate_ship_coordinates +# +# given a ship from the SHIPS array, generate +# the coordinates of the ship. the starting point +# of the ship's first coordinate is generated randomly. +# once the starting coordinates are determined, the +# possible directions of the ship, accounting for the +# edges of the board, are determined. once possible +# directions are found, a direction is randomly +# determined and the remaining coordinates are +# generated by adding or substraction from the starting +# coordinates as determined by direction. +# +# arguments: +# ship - index into the SHIPS array +# +# returns: +# array of sets of coordinates (x,y) +def generate_ship_coordinates(ship): # randomly generate starting x,y coordinates start_x, start_y = random_x_y() @@ -169,7 +177,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 _ in range(8)] + dirs = [False for x 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] @@ -205,18 +213,25 @@ def generate_ship_coordinates(ship: int) -> List[CoordinateType]: return coords -def create_blank_board() -> BoardType: - """Create a blank game board""" - return [[None for _y in range(BOARD_WIDTH)] for _x in range(BOARD_HEIGHT)] +# create_blank_board +# +# helper function to create a game board +# that is blank +def create_blank_board(): + return [[None for y in range(BOARD_WIDTH)] for x in range(BOARD_HEIGHT)] + +# print_board +# +# print out the game board for testing +# purposes +def print_board(board) -> None: -def print_board(board: BoardType) -> None: - """Print out the game board for testing purposes""" # print board header (column numbers) print(" ", end="") for z in range(BOARD_WIDTH): print(f"{z+1:3}", end="") - print() + print("") for x in range(len(board)): print(f"{x+1:2}", end="") @@ -225,34 +240,30 @@ def print_board(board: BoardType) -> None: print(f"{' ':3}", end="") else: print(f"{board[x][y]:3}", end="") - print() + print("") -def place_ship(board: BoardType, coords: List[CoordinateType], ship: int) -> None: - """ - Place a ship on a given board. - - updates - the board's row,column value at the given - coordinates to indicate where a ship is - on the board. - - inputs: board - array of BOARD_HEIGHT by BOARD_WIDTH - coords - array of sets of (x,y) coordinates of each - part of the given ship - ship - integer representing the type of ship (given in SHIPS) - """ +# place_ship +# +# place a ship on a given board. updates +# the board's row,column value at the given +# coordinates to indicate where a ship is +# on the board. +# +# inputs: board - array of BOARD_HEIGHT by BOARD_WIDTH +# coords - array of sets of (x,y) coordinates of each +# part of the given ship +# ship - integer repreesnting the type of ship (given in SHIPS) +def place_ship(board, coords, ship): for coord in coords: board[coord[0] - 1][coord[1] - 1] = ship -def generate_board() -> Tuple[BoardType, List[List[CoordinateType]]]: - """ - NOTE: A little quirk that exists here and in the orginal - game: Ships are allowed to cross each other! - For example: 2 destroyers, length 2, one at - [(1,1),(2,2)] and other at [(2,1),(1,2)] - """ +# NOTE: A little quirk that exists here and in the orginal +# game: Ships are allowed to cross each other! +# For example: 2 destroyers, length 2, one at +# [(1,1),(2,2)] and other at [(2,1),(1,2)] +def generate_board(): board = create_blank_board() ship_coords = [] @@ -261,7 +272,11 @@ def generate_board() -> Tuple[BoardType, List[List[CoordinateType]]]: coords = [] while not placed: coords = generate_ship_coordinates(ship) - clear = all(board[coord[0] - 1][coord[1] - 1] is None for coord in coords) + clear = True + for coord in coords: + if board[coord[0] - 1][coord[1] - 1] is not None: + clear = False + break if clear: placed = True place_ship(board, coords, ship) @@ -269,9 +284,7 @@ def generate_board() -> Tuple[BoardType, List[List[CoordinateType]]]: return board, ship_coords -def execute_shot( - turn: bool, board: BoardType, x: int, y: int, current_turn: int -) -> int: +def execute_shot(turn, board, x, y, current_turn): """ given a board and x, y coordinates, execute a shot. returns True if the shot @@ -285,27 +298,39 @@ def execute_shot( return ship_hit -def calculate_shots(board: BoardType) -> int: - """Examine each board and determine how many shots remaining""" - ships_found = [0 for _ in range(len(SHIPS))] +# calculate_shots +# +# function to examine each board +# and determine how many shots remaining +def calculate_shots(board): + + ships_found = [0 for x 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 - return sum( - SHIPS[ship][2] - for ship in range(len(ships_found)) - if ships_found[ship] == 1 - ) + shots = 0 + for ship in range(len(ships_found)): + if ships_found[ship] == 1: + shots += SHIPS[ship][2] + return shots + + +# initialize +# +# function to initialize global variables used +# during game play. +def initialize_game(): -def initialize_game() -> None: - # initialize the global player and computer boards + # initialize the global player and computer + # boards global player_board player_board = create_blank_board() - # generate the ships for the computer's board + # generate the ships for the computer's + # board global computer_board global computer_ship_coords computer_board, computer_ship_coords = generate_board() @@ -313,7 +338,7 @@ def initialize_game() -> None: # print out the title 'screen' print("{:>38}".format("SALVO")) print("{:>57s}".format("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")) - print() + print("") print("{:>52s}".format("ORIGINAL BY LAWRENCE SIEGEL, 1973")) print("{:>56s}".format("PYTHON 3 PORT BY TODD KAISER, MARCH 2021")) print("\n") @@ -330,8 +355,8 @@ def initialize_game() -> None: ship_coords.append(list) # add ships to the user's board - for ship_index in range(len(SHIPS)): - place_ship(player_board, ship_coords[ship_index], ship_index) + for ship in range(len(SHIPS)): + place_ship(player_board, ship_coords[ship], ship) # see if the player wants the computer's ship # locations printed out and if the player wants to @@ -341,9 +366,9 @@ def initialize_game() -> None: while input_loop: player_start = input("DO YOU WANT TO START? ") if player_start == "WHERE ARE YOUR SHIPS?": - for ship_index in range(len(SHIPS)): - print(SHIPS[ship_index][0]) - coords = computer_ship_coords[ship_index] + for ship in range(len(SHIPS)): + print(SHIPS[ship][0]) + coords = computer_ship_coords[ship] for coord in coords: x = coord[0] y = coord[1] @@ -359,11 +384,14 @@ def initialize_game() -> None: print_computer_shots = True global first_turn + global second_turn if player_start.lower() != "yes": first_turn = COMPUTER + second_turn = PLAYER # calculate the initial number of shots for each - global num_computer_shots, num_player_shots + global num_computer_shots + global num_player_shots num_player_shots = calculate_shots(player_board) num_computer_shots = calculate_shots(computer_board) @@ -379,22 +407,31 @@ def initialize_game() -> None: # forth, replicating the gotos in the original game -# initialize the first_turn function to the player's turn +# initialize the first_turn function to the +# player's turn first_turn = PLAYER -def execute_turn(turn: bool, current_turn: int) -> int: - global num_computer_shots, num_player_shots +# initialize the second_turn to the computer's +# turn +second_turn = COMPUTER + + +def execute_turn(turn, current_turn): - # print out the number of shots the current player has + global num_computer_shots + global num_player_shots + + # print out the number of shots the current + # player has board = None num_shots = 0 if turn == COMPUTER: - print(f"I HAVE {num_computer_shots} SHOTS.") + print("I HAVE", num_computer_shots, "SHOTS.") board = player_board num_shots = num_computer_shots else: - print(f"YOU HAVE {num_player_shots} SHOTS.") + print("YOU HAVE", num_player_shots, "SHOTS.") board = computer_board num_shots = num_player_shots @@ -408,7 +445,10 @@ 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: - x, y = random_x_y() if turn == COMPUTER else input_coord() + if turn == COMPUTER: + x, y = random_x_y() + else: + x, y = input_coord() square = board[x - 1][y - 1] if square is not None and square > 10: if turn == PLAYER: @@ -446,22 +486,34 @@ def execute_turn(turn: bool, current_turn: int) -> int: def main() -> None: + # keep track of the turn current_turn = 0 + + # initialize the player and computer + # boards initialize_game() # execute turns until someone wins or we run # out of squares to shoot + game_over = False while not game_over: - current_turn += 1 + + # increment the turn + current_turn = current_turn + 1 print("\n") print("TURN", current_turn) - if ( - execute_turn(first_turn, current_turn) == 0 - or execute_turn(not first_turn, current_turn) == 0 - ): + # print("computer") + # print_board(computer_board) + # print("player") + # print_board(player_board) + + if execute_turn(first_turn, current_turn) == 0: + game_over = True + continue + if execute_turn(second_turn, current_turn) == 0: game_over = True continue diff --git a/78_Sine_Wave/README.md b/78_Sine_Wave/README.md index c5c340f3c..32789d048 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 of 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 on different versions. At least those CRTs don’t look so lifeless anymore. --- diff --git a/78_Sine_Wave/javascript/sinewave.html b/78_Sine_Wave/javascript/sinewave.html new file mode 100644 index 000000000..c9ff7d9b6 --- /dev/null +++ b/78_Sine_Wave/javascript/sinewave.html @@ -0,0 +1,16 @@ + + +SINE WAVE + + + +

    
    +
    +
    +
    +
    diff --git a/78_Sine_Wave/lua/sinewave.lua b/78_Sine_Wave/lua/sinewave.lua
    deleted file mode 100644
    index 0ea2630b1..000000000
    --- a/78_Sine_Wave/lua/sinewave.lua
    +++ /dev/null
    @@ -1,21 +0,0 @@
    -require("math")
    -require("string")
    -
    -print("\n                         Sine Wave")
    -print("           Creative Computing Morriston, New Jersy")
    -print("\n\n\n\n")
    -
    --- Original BASIC version by David Ahl
    --- Ported to lua by BeeverFeever(github), 2022
    -
    -local toggleWord = true
    -
    -for t = 0, 40, 0.25 do
    -    local gap = math.floor(26 + 25 * math.sin(t))
    -    if toggleWord == true then
    -        -- string.rep used to add the gat at the front of the printed out words
    -        print(string.rep(" ", math.floor(gap)) .. "Creative")
    -    elseif toggleWord == false then
    -        print(string.rep(" ", math.floor(gap)) .. "Computing")
    -    end
    -end
    diff --git a/78_Sine_Wave/rust/Cargo.lock b/78_Sine_Wave/rust/Cargo.lock
    deleted file mode 100644
    index b21cc6a2d..000000000
    --- a/78_Sine_Wave/rust/Cargo.lock
    +++ /dev/null
    @@ -1,7 +0,0 @@
    -# 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/79_Slalom/README.md b/79_Slalom/README.md
    index c95309ceb..8c45820c0 100644
    --- a/79_Slalom/README.md
    +++ b/79_Slalom/README.md
    @@ -15,10 +15,8 @@ As published in Basic Computer Games (1978):
     Downloaded from Vintage Basic at
     http://www.vintage-basic.net/games.html
     
    -#### 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'.
    +#### Porting Notes
     
    -- 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.
    +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,
     
    -#### Porting Notes
    +    540    READ Q
    diff --git a/79_Slalom/python/slalom.py b/79_Slalom/python/slalom.py
    index e3387e6f6..1db5d5d80 100644
    --- a/79_Slalom/python/slalom.py
    +++ b/79_Slalom/python/slalom.py
    @@ -7,17 +7,17 @@
     }
     
     
    -def ask(question: str) -> str:
    +def ask(question):
         print(question, end="? ")
         return input().upper()
     
     
    -def ask_int(question: str) -> int:
    +def ask_int(question):
         reply = ask(question)
         return int(reply) if reply.isnumeric() else -1
     
     
    -def pre_run(gates, max_speeds) -> None:
    +def pre_run(gates, max_speeds):
         print('\nType "INS" for instructions')
         print('Type "MAX" for approximate maximum speeds')
         print('Type "RUN" for the beginning of the race')
    @@ -50,10 +50,10 @@ def pre_run(gates, max_speeds) -> None:
                 cmd = ask(f'"{cmd}" is an illegal command--Retry')
     
     
    -def run(gates, lvl, max_speeds) -> None:
    +def run(gates, lvl, max_speeds):
         global medals
         print("The starter counts down...5...4...3...2...1...Go!")
    -    time: float = 0
    +    time = 0
         speed = int(random() * (18 - 9) + 9)
         print("You're off")
         for i in range(0, gates):
    @@ -97,7 +97,7 @@ def run(gates, lvl, max_speeds) -> None:
     
                         case 7:
                             speed -= int(random() * (10 - 5) + 5)
    -                print(f" {speed} M.P.H.")
    +                print(f" {int(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 in ["YES", "NO"]:
    +            if answer == "YES" or answer == "NO":
                     break
                 else:
                     print('Please type "YES" or "NO"')
    diff --git a/79_Slalom/slalom.bas b/79_Slalom/slalom.bas
    index 47c6d8010..b46cc39be 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 IF YOU WANT TO SEE HOW LONG YOU'VE TAKEN."
    +845 PRINT "     0 -- TYPE THIS IS 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/80_Slots/README.md b/80_Slots/README.md
    index 522c7c811..dcc3aabe2 100644
    --- a/80_Slots/README.md
    +++ b/80_Slots/README.md
    @@ -17,10 +17,6 @@ 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)
    diff --git a/80_Slots/python/slots.py b/80_Slots/python/slots.py
    index 6464458b6..e54f3b4e3 100644
    --- a/80_Slots/python/slots.py
    +++ b/80_Slots/python/slots.py
    @@ -34,10 +34,9 @@
     import sys
     from collections import Counter
     from random import choices
    -from typing import List
     
     
    -def initial_message() -> None:
    +def initial_message():
         print(" " * 30 + "Slots")
         print(" " * 15 + "Creative Computing Morrison, New Jersey")
         print("\n" * 3)
    @@ -46,7 +45,7 @@ def initial_message() -> None:
         print("To pull the arm, punch the return key after making your bet.")
     
     
    -def input_betting() -> int:
    +def input_betting():
         print("\n")
         b = -1
         while b < 1 or b > 100:
    @@ -59,10 +58,10 @@ def input_betting() -> int:
             elif b < 1:
                 print("Minium bet is $1")
         beeping()
    -    return b
    +    return int(b)
     
     
    -def beeping() -> None:
    +def beeping():
         # Function to produce a beep sound.
         # In the original program is the subroutine at line 1270
         for _ in range(5):
    @@ -70,7 +69,7 @@ def beeping() -> None:
             sys.stdout.flush()
     
     
    -def spin_wheels() -> List[str]:
    +def spin_wheels():
         possible_fruits = ["Bar", "Bell", "Orange", "Lemon", "Plum", "Cherry"]
         wheel = choices(possible_fruits, k=3)
     
    @@ -80,7 +79,7 @@ def spin_wheels() -> List[str]:
         return wheel
     
     
    -def adjust_profits(wheel: List[str], m: int, profits: int) -> int:
    +def adjust_profits(wheel, m, profits):
         # we remove the duplicates
         s = set(wheel)
     
    @@ -113,12 +112,12 @@ def adjust_profits(wheel: List[str], m: int, profits: int) -> int:
         else:
             # three different fruits
             print("\nYou Lost.")
    -        profits -= m
    +        profits = profits - m
     
         return profits
     
     
    -def final_message(profits: int) -> None:
    +def final_message(profits) -> None:
         if profits < 0:
             print("Pay up!  Please leave your money on the terminal")
         elif profits == 0:
    @@ -141,7 +140,7 @@ def main() -> None:
             answer = input("Again?")
     
             try:
    -            if answer[0].lower() != "y":
    +            if not answer[0].lower() == "y":
                     keep_betting = False
             except IndexError:
                 keep_betting = False
    diff --git a/81_Splat/python/splat.py b/81_Splat/python/splat.py
    index f521f3a23..665494b33 100644
    --- a/81_Splat/python/splat.py
    +++ b/81_Splat/python/splat.py
    @@ -24,22 +24,22 @@
     """
     from math import sqrt
     from random import choice, random, uniform
    -from typing import List, Tuple
    +from typing import List
     
     PAGE_WIDTH = 72
     
     
    -def numeric_input(question, default=0) -> float:
    +def numeric_input(question, default=0):
         """Ask user for a numeric value."""
         while True:
    -        answer_str = input(f"{question} [{default}]: ").strip() or default
    +        answer = input(f"{question} [{default}]: ").strip() or default
             try:
    -            return float(answer_str)
    +            return float(answer)
             except ValueError:
                 pass
     
     
    -def yes_no_input(question: str, default="YES") -> bool:
    +def yes_no_input(question, default="YES"):
         """Ask user a yes/no question and returns True if yes, otherwise False."""
         answer = input(f"{question} (YES OR NO) [{default}]: ").strip() or default
         while answer.lower() not in ["n", "no", "y", "yes"]:
    @@ -47,7 +47,7 @@ def yes_no_input(question: str, default="YES") -> bool:
         return answer.lower() in ["y", "yes"]
     
     
    -def get_terminal_velocity() -> float:
    +def get_terminal_velocity():
         """Terminal velocity by user or picked by computer."""
         if yes_no_input("SELECT YOUR OWN TERMINAL VELOCITY", default="NO"):
             v1 = numeric_input("WHAT TERMINAL VELOCITY (MI/HR)", default=100)
    @@ -60,7 +60,7 @@ def get_terminal_velocity() -> float:
         return v1 * (5280 / 3600)
     
     
    -def get_acceleration() -> float:
    +def get_acceleration():
         """Acceleration due to gravity by user or picked by computer."""
         if yes_no_input("WANT TO SELECT ACCELERATION DUE TO GRAVITY", default="NO"):
             a2 = numeric_input("WHAT ACCELERATION (FT/SEC/SEC)", default=32.16)
    @@ -70,14 +70,14 @@ def get_acceleration() -> float:
         return a2
     
     
    -def get_freefall_time() -> float:
    +def get_freefall_time():
         """User-guessed freefall time.
     
         The idea of the game is to pick a freefall time, given initial
         altitude, terminal velocity and acceleration, so the parachute
         as close to the ground as possible without going splat.
         """
    -    t_freefall: float = 0
    +    t_freefall = 0
         # A zero or negative freefall time is not handled by the motion
         # equations during the jump.
         while t_freefall <= 0:
    @@ -85,13 +85,13 @@ def get_freefall_time() -> float:
         return t_freefall
     
     
    -def jump() -> float:
    +def jump():
         """Simulate a jump and returns the altitude where the chute opened.
     
         The idea is to open the chute as late as possible -- but not too late.
         """
    -    v: float = 0  # Terminal velocity.
    -    a: float = 0  # Acceleration.
    +    v = 0  # Terminal velocity.
    +    a = 0  # Acceleration.
         initial_altitude = int(9001 * random() + 1000)
     
         v1 = get_terminal_velocity()
    @@ -181,9 +181,9 @@ def jump() -> float:
         return altitude
     
     
    -def pick_random_celestial_body() -> Tuple[str, float]:
    +def pick_random_celestial_body():
         """Pick a random planet, the moon, or the sun with associated gravity."""
    -    return choice(
    +    body, gravity = choice(
             [
                 ("MERCURY", 12.2),
                 ("VENUS", 28.3),
    @@ -197,9 +197,10 @@ def pick_random_celestial_body() -> Tuple[str, float]:
                 ("THE SUN", 896.0),
             ]
         )
    +    return body, gravity
     
     
    -def jump_stats(previous_jumps, chute_altitude) -> Tuple[int, int]:
    +def jump_stats(previous_jumps, chute_altitude):
         """Compare altitude when chute opened with previous successful jumps.
     
         Return the number of previous jumps and the number of times
    @@ -311,9 +312,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/81_Splat/rust/Cargo.lock b/81_Splat/rust/Cargo.lock
    deleted file mode 100644
    index 4fe2abbea..000000000
    --- a/81_Splat/rust/Cargo.lock
    +++ /dev/null
    @@ -1,75 +0,0 @@
    -# 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/81_Splat/rust/Cargo.toml b/81_Splat/rust/Cargo.toml
    deleted file mode 100644
    index 3b1d02f52..000000000
    --- a/81_Splat/rust/Cargo.toml
    +++ /dev/null
    @@ -1,9 +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]
    -rand = "0.8.5"
    diff --git a/81_Splat/rust/src/celestial_body.rs b/81_Splat/rust/src/celestial_body.rs
    deleted file mode 100644
    index 594a3bcbe..000000000
    --- a/81_Splat/rust/src/celestial_body.rs
    +++ /dev/null
    @@ -1,64 +0,0 @@
    -use rand::{prelude::SliceRandom, Rng};
    -
    -#[derive(Debug)]
    -pub enum CelestialBody {
    -    MERCURY,
    -    VENUS,
    -    EARTH,
    -    MOON,
    -    MARS,
    -    JUPITER,
    -    SATURN,
    -    URANUS,
    -    NEPTUNE,
    -    SUN,
    -}
    -
    -impl CelestialBody {
    -    pub fn get_acceleration(&self) -> f32 {
    -        use CelestialBody::*;
    -
    -        match self {
    -            MERCURY => 12.2,
    -            VENUS => 28.3,
    -            EARTH => 32.16,
    -            MOON => 5.12,
    -            MARS => 12.5,
    -            JUPITER => 85.2,
    -            SATURN => 37.6,
    -            URANUS => 33.8,
    -            NEPTUNE => 39.6,
    -            SUN => 896.,
    -        }
    -    }
    -
    -    pub fn print_acceleration_message(&self) {
    -        let messages: [&str; 3] = ["Fine,", "All right,", "Then"];
    -        let m = messages.choose(&mut rand::thread_rng()).unwrap();
    -
    -        println!(
    -            "{} YOU'RE ON {:?}. ACCELERATION = {} FT/SEC/SEC.",
    -            m.to_uppercase(),
    -            self,
    -            self.get_acceleration()
    -        );
    -    }
    -}
    -
    -pub fn random_celestial_body() -> Option {
    -    use CelestialBody::*;
    -
    -    match rand::thread_rng().gen_range(0..10) {
    -        0 => Some(MERCURY),
    -        1 => Some(VENUS),
    -        2 => Some(EARTH),
    -        3 => Some(MOON),
    -        4 => Some(MARS),
    -        5 => Some(JUPITER),
    -        6 => Some(SATURN),
    -        7 => Some(URANUS),
    -        8 => Some(NEPTUNE),
    -        9 => Some(SUN),
    -        _ => None,
    -    }
    -}
    diff --git a/81_Splat/rust/src/game.rs b/81_Splat/rust/src/game.rs
    deleted file mode 100644
    index 8b3bba184..000000000
    --- a/81_Splat/rust/src/game.rs
    +++ /dev/null
    @@ -1,105 +0,0 @@
    -use crate::utility;
    -
    -pub struct Game {
    -    altitude: f32,
    -    terminal_velocity: f32,
    -    acceleration: f32,
    -    interval: f32,
    -}
    -
    -impl Game {
    -    pub fn new() -> Game {
    -        let altitude = utility::get_altitude();
    -
    -        let terminal_velocity = utility::get_terminal_velocity(
    -            "SELECT YOUR OWN TERMINAL VELOCITY",
    -            "WHAT TERMINAL VELOCITY (MI/HR)?",
    -        );
    -
    -        let acceleration = utility::get_acceleration(
    -            "WANT TO SELECT ACCELERATION DUE TO GRAVITY",
    -            "WHAT ACCELERATION (FT/SEC/SEC)?",
    -        );
    -
    -        println!("");
    -        println!("      ALTITUDE        = {} FT", altitude);
    -        println!("      TERM. VELOCITY  = {} FT/SEC +-5%", terminal_velocity);
    -        println!("      ACCELERATION    = {} FT/SEC/SEC +-5%", acceleration);
    -
    -        let seconds =
    -            utility::prompt_numeric("\nSET THE TIMER FOR YOUR FREEFALL.\nHOW MANY SECONDS?");
    -
    -        println!("\nHERE WE GO.\n");
    -
    -        println!("TIME (SEC)\tDIST TO FALL (FT)");
    -        println!("==========\t=================");
    -
    -        Game {
    -            altitude,
    -            terminal_velocity,
    -            acceleration,
    -            interval: seconds / 8.,
    -        }
    -    }
    -
    -    pub fn tick(&mut self) -> f32 {
    -        let mut splat = false;
    -        let mut terminal_velocity_reached = false;
    -
    -        let (v, a) = (self.terminal_velocity, self.acceleration);
    -        let terminal_velocity_time = v / a;
    -
    -        let initial_altitude = self.altitude;
    -
    -        for i in 0..=8 {
    -            let dt = i as f32 * self.interval;
    -
    -            if dt >= terminal_velocity_time {
    -                if !terminal_velocity_reached {
    -                    println!(
    -                        "TERMINAL VELOCITY REACHED AT T PLUS {} SECONDS.",
    -                        terminal_velocity_time
    -                    );
    -                    terminal_velocity_reached = true;
    -                }
    -
    -                let d1 = v.powi(2) / (2. * a);
    -                let d2 = v * (dt - (terminal_velocity_time));
    -                self.altitude = initial_altitude - (d1 + d2);
    -
    -                if self.altitude <= 0. {
    -                    let t = (initial_altitude - d1) / v;
    -                    utility::print_splat(t + terminal_velocity_time);
    -
    -                    splat = true;
    -                    break;
    -                }
    -            } else {
    -                let d1 = (a * 0.5) * (dt.powi(2));
    -                self.altitude = initial_altitude - d1;
    -
    -                if self.altitude <= 0. {
    -                    let t = (2. * initial_altitude / a).sqrt();
    -                    utility::print_splat(t);
    -
    -                    splat = true;
    -                    break;
    -                }
    -            }
    -
    -            println!("{}\t\t{}", dt, self.altitude);
    -
    -            std::thread::sleep(std::time::Duration::from_secs(1));
    -        }
    -
    -        let mut a = -1.;
    -
    -        if !splat {
    -            println!("\nCHUTE OPEN\n");
    -
    -            a = self.altitude;
    -        }
    -
    -        a
    -    }
    -}
    diff --git a/81_Splat/rust/src/main.rs b/81_Splat/rust/src/main.rs
    deleted file mode 100644
    index eec8bfe6b..000000000
    --- a/81_Splat/rust/src/main.rs
    +++ /dev/null
    @@ -1,39 +0,0 @@
    -use crate::{game::Game, stats::Stats};
    -
    -mod celestial_body;
    -mod game;
    -mod stats;
    -mod utility;
    -
    -fn main() {
    -    println!("\n\n\n                       SPLAT");
    -    println!("      CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n");
    -
    -    println!("WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES");
    -    println!("A PARACHUTE JUMP. TRY OPEN YOUR CHUTE AT THE");
    -    println!("LAST POSSIBLE MOMENT WITHOUT GOING SPLAT.\n");
    -
    -    let mut stats = Stats::new();
    -
    -    loop {
    -        let mut game = Game::new();
    -
    -        let latest_altitude = game.tick();
    -
    -        if latest_altitude > 0. {
    -            if let Some(s) = &mut stats {
    -                s.add_altitude(latest_altitude);
    -            }
    -        }
    -
    -        use utility::prompt_bool;
    -        if !prompt_bool("DO YOU WANT TO PLAY AGAIN?", true) {
    -            if !prompt_bool("PLEASE?", false) {
    -                if !prompt_bool("YES OR NO PLEASE?", false) {
    -                    println!("SSSSSSSSSS.");
    -                    break;
    -                }
    -            }
    -        }
    -    }
    -}
    diff --git a/81_Splat/rust/src/stats.rs b/81_Splat/rust/src/stats.rs
    deleted file mode 100644
    index c86b83ae8..000000000
    --- a/81_Splat/rust/src/stats.rs
    +++ /dev/null
    @@ -1,88 +0,0 @@
    -use std::{
    -    fs::{self, File},
    -    io::Write,
    -};
    -
    -use crate::utility;
    -
    -pub struct Stats {
    -    altitudes: Vec,
    -}
    -
    -impl Stats {
    -    pub fn new() -> Option {
    -        if utility::prompt_bool("WOULD YOU LIKE TO LOAD PREVIOUS GAME DATA?", false) {
    -            let path = "src/stats.txt";
    -            let mut altitudes = Vec::new();
    -
    -            if let Ok(stats) = fs::read_to_string(path) {
    -                if stats.is_empty() {
    -                    return Some(Stats {
    -                        altitudes: Vec::new(),
    -                    });
    -                }
    -
    -                let stats: Vec<&str> = stats.trim().split(",").collect();
    -
    -                for s in stats {
    -                    if s.is_empty() {
    -                        continue;
    -                    }
    -
    -                    let s = s.parse::().expect("Corrupt stats file!");
    -                    altitudes.push(s);
    -                }
    -
    -                return Some(Stats { altitudes });
    -            } else {
    -                println!("PREVIOUS GAME DATA NOT FOUND!");
    -
    -                if !utility::prompt_bool("WOULD YOU LIKE TO CREATE ONE?", false) {
    -                    return None;
    -                } else {
    -                    let mut file = File::create(path).expect("Invalid file path!");
    -                    file.write_all("".as_bytes())
    -                        .expect("Could not create file!");
    -
    -                    return Some(Stats {
    -                        altitudes: Vec::new(),
    -                    });
    -                }
    -            }
    -        }
    -
    -        println!("\nRESULTS OF THIS SESSION WILL NOT BE SAVED.");
    -        None
    -    }
    -
    -    pub fn add_altitude(&mut self, a: f32) {
    -        let all_jumps = self.altitudes.len() + 1;
    -        let mut placement = all_jumps;
    -
    -        for (i, altitude) in self.altitudes.iter().enumerate() {
    -            if a <= *altitude {
    -                placement = i + 1;
    -                break;
    -            }
    -        }
    -
    -        utility::print_win(all_jumps, placement);
    -
    -        self.altitudes.push(a);
    -        self.altitudes.sort_by(|a, b| a.partial_cmp(b).unwrap());
    -
    -        self.write();
    -    }
    -
    -    fn write(&self) {
    -        let mut file = File::create("src/stats.txt").expect("Error loading stats data!");
    -
    -        let mut altitudes = String::new();
    -
    -        for a in &self.altitudes {
    -            altitudes.push_str(format!("{},", a).as_str());
    -        }
    -
    -        write!(&mut file, "{}", altitudes.trim()).expect("ERROR WRITING Stats FILE!");
    -    }
    -}
    diff --git a/81_Splat/rust/src/utility.rs b/81_Splat/rust/src/utility.rs
    deleted file mode 100644
    index c37a2af31..000000000
    --- a/81_Splat/rust/src/utility.rs
    +++ /dev/null
    @@ -1,168 +0,0 @@
    -use crate::celestial_body;
    -use rand::Rng;
    -use std::io;
    -
    -const DEATH_MESSAGES: [&str; 10] = [
    -    "REQUIESCAT IN PACE.",
    -    "MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.",
    -    "REST IN PEACE.",
    -    "SON-OF-A-GUN.",
    -    "#$%&&%!$",
    -    "A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.",
    -    "HMMM. SHOULD HAVE PICKED A SHORTER TIME.",
    -    "MUTTER. MUTTER. MUTTER.",
    -    "PUSHING UP DAISIES.",
    -    "EASY COME, EASY GO.",
    -];
    -
    -pub fn read_line() -> String {
    -    let mut input = String::new();
    -    io::stdin()
    -        .read_line(&mut input)
    -        .expect("Failed to read line.");
    -    input.trim().to_uppercase()
    -}
    -
    -pub fn prompt_bool(msg: &str, template: bool) -> bool {
    -    if template {
    -        println!("{} (YES OR NO)?", msg);
    -    } else {
    -        println!("{}", msg);
    -    }
    -
    -    loop {
    -        let response = read_line();
    -
    -        match response.as_str() {
    -            "YES" => return true,
    -            "NO" => return false,
    -            _ => println!("PLEASE ENTER YES OR NO."),
    -        }
    -    }
    -}
    -
    -pub fn prompt_numeric(msg: &str) -> f32 {
    -    println!("{}", msg);
    -
    -    loop {
    -        let response = read_line();
    -
    -        if let Some(_) = response.chars().find(|c| !c.is_numeric()) {
    -            println!("PLEASE ENTER A NUMBER.");
    -        } else {
    -            return response.parse::().unwrap();
    -        }
    -    }
    -}
    -
    -pub fn get_altitude() -> f32 {
    -    9001. * rand::random::() + 1000.
    -}
    -
    -pub fn get_terminal_velocity(bool_msg: &str, num_msg: &str) -> f32 {
    -    let mut _num = 0.0;
    -
    -    if prompt_bool(bool_msg, true) {
    -        _num = prompt_numeric(num_msg);
    -    } else {
    -        _num = get_random_float(0., 1000.);
    -        println!("OK. TERMINAL VELOCTY = {} MI/HR", _num);
    -    }
    -
    -    (_num * ((5280 / 3600) as f32)) * get_random_float(0.95, 1.05)
    -}
    -
    -pub fn get_acceleration(bool_msg: &str, num_msg: &str) -> f32 {
    -    let mut _num = 0.0;
    -
    -    if prompt_bool(bool_msg, true) {
    -        _num = prompt_numeric(num_msg);
    -    } else {
    -        let b =
    -            celestial_body::random_celestial_body().expect("Fatal Error: Invalid Celestial Body!");
    -
    -        _num = b.get_acceleration();
    -        b.print_acceleration_message();
    -    }
    -
    -    _num * get_random_float(0.95, 1.05)
    -}
    -
    -fn get_random_float(min: f32, max: f32) -> f32 {
    -    rand::thread_rng().gen_range(min..=max)
    -}
    -
    -pub fn print_splat(t: f32) {
    -    print_random(format!("{}\t\tSPLAT!", t).as_str(), &DEATH_MESSAGES);
    -    print!("I'LL GIVE YOU ANOTHER CHANCE.\n");
    -}
    -
    -fn print_random(msg: &str, choices: &[&str]) {
    -    use rand::seq::SliceRandom;
    -    use rand::thread_rng;
    -
    -    let mut rng = thread_rng();
    -
    -    println!("{}", msg);
    -    println!("\n{}\n", choices.choose(&mut rng).unwrap());
    -}
    -
    -pub fn print_win(total: usize, placement: usize) {
    -    if total <= 3 {
    -        let order;
    -
    -        match total {
    -            1 => order = "1ST",
    -            2 => order = "2ND",
    -            3 => order = "3RD",
    -            _ => order = "#INVALID#",
    -        }
    -
    -        println!("AMAZING!!! NOT BAD FOR YOUR {} SUCCESSFUL JUMP!!!", order);
    -        return;
    -    }
    -
    -    let (total, placement) = (total as f32, placement as f32);
    -
    -    let betters = placement - 1.;
    -    let p: f32 = (total - betters) / total;
    -
    -    println!("{}", p);
    -
    -    println!(
    -        "placement: {}, total jumps: {}, percent is: {}",
    -        placement, total, p
    -    );
    -
    -    if p < 0.1 {
    -        println!(
    -            "HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. {} SUCCESSFUL\nJUMPS BEFORE YOURS AND YOU CAME IN NUMBER {}! GET WITH IT!",
    -            total, placement
    -        );
    -    } else if p < 0.25 {
    -        println!(
    -            "HUMPH!  DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE\n{} SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN {} JUMPS\nBETTER THAN THE WORST. SHAPE UP!!!",
    -            total, placement
    -        );
    -    } else if p < 0.5 {
    -        println!(
    -            "CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY {} IN THE\n{} SUCCESSFUL JUMPS BEFORE YOURS.",
    -            placement, total
    -        );
    -    } else if p < 0.75 {
    -        println!(
    -            "NOT BAD.  THERE HAVE BEEN {} SUCCESSFUL JUMPS BEFORE YOURS.\nYOU WERE BEATEN OUT BY {} OF THEM.",
    -            total, betters
    -        );
    -    } else if p < 0.9 {
    -        println!(
    -            "PRETTY GOOD! {} SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\n{} OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\nOPENED.",
    -            total, betters
    -        )
    -    } else {
    -        println!(
    -            "WOW!  THAT'S SOME JUMPING. OF THE {} SUCCESSFUL JUMPS\nBEFORE YOURS, ONLY {} OPENED THEIR CHUTES LOWER THAN\nYOU DID.",
    -            total, betters
    -        )
    -    }
    -}
    diff --git a/82_Stars/python/stars.py b/82_Stars/python/stars.py
    index 5a5f9fed0..00e17bb57 100644
    --- a/82_Stars/python/stars.py
    +++ b/82_Stars/python/stars.py
    @@ -40,15 +40,21 @@ def print_instructions() -> None:
     
     def print_stars(secret_number, guess) -> None:
         diff = abs(guess - secret_number)
    -    stars = "".join("*" for i in range(8) if diff < 2**i)
    +    stars = ""
    +    for i in range(8):
    +        if diff < 2**i:
    +            stars += "*"
         print(stars)
     
     
    -def get_guess(prompt: str) -> int:
    -    while True:
    -        guess_str = input(prompt)
    -        if guess_str.isdigit():
    -            return int(guess_str)
    +def get_guess():
    +    valid_response = False
    +    while not valid_response:
    +        guess = input("Your guess? ")
    +        if guess.isdigit():
    +            valid_response = True
    +            guess = int(guess)
    +    return guess
     
     
     def main() -> None:
    @@ -74,8 +80,8 @@ def main() -> None:
             player_has_won = False
             while (guess_number < MAX_GUESSES) and not player_has_won:
     
    -            print()
    -            guess = get_guess("Your guess? ")
    +            print("")
    +            guess = get_guess()
                 guess_number += 1
     
                 if guess == secret_number:
    diff --git a/82_Stars/ruby/stars.rb b/82_Stars/ruby/stars.rb
    deleted file mode 100644
    index d6b31e8ac..000000000
    --- a/82_Stars/ruby/stars.rb
    +++ /dev/null
    @@ -1,90 +0,0 @@
    -class Stars
    -  MAX_NUM = 100
    -  MAX_GUESSES = 7
    -
    -  def start
    -    print "Do you want instructions? (Y/N) "
    -    response = gets.chomp!
    -
    -    if response.upcase[0] == "Y"
    -      print_instructions()
    -    end
    -
    -    still_playing = true
    -    while still_playing
    -      secret_number = rand(1..MAX_NUM)
    -      puts "\n\nOK, I am thinking of a number, start guessing."
    -
    -      guess_number = 0
    -      player_has_won = false
    -
    -      while (guess_number < MAX_GUESSES) and not player_has_won
    -        puts "\n"
    -        guess = get_guess()
    -        guess_number += 1
    -
    -        if guess == secret_number
    -          player_has_won = true
    -            puts "**************************************************!!!"
    -            puts "You got it in #{guess_number} guesses!!!\n\n"
    -        else
    -          print_stars(secret_number, guess)
    -        end
    -      end
    -
    -      if not player_has_won
    -        puts "\nSorry, that's #{guess_number} guesses, number was #{secret_number}\n"
    -      end
    -
    -      print "Play again? (Y/N) "
    -      response = gets.chomp!
    -
    -      if response.upcase[0] != "Y"
    -        still_playing = false
    -      end
    -      
    -    end
    -  end
    -
    -  private
    -    def print_instructions
    -      puts "I am thinking of a whole number from 1 to #{MAX_NUM}"
    -      puts "Try to guess my number.  After you guess, I"
    -      puts "will type one or more stars (*).  The more"
    -      puts "stars I type, the closer you are to my number."
    -      puts "one star (*) means far away, seven stars (*******)"
    -      puts "means really close!  You get #{MAX_GUESSES} guesses."
    -    end
    -
    -    def get_guess
    -      valid_response = false
    -      while not valid_response
    -        print "Your guess? "
    -        guess = gets.chomp!
    -
    -        if guess.match?(/[[:digit:]]/)
    -          valid_response = true
    -          guess = guess.to_i
    -        end
    -      end
    -
    -      return guess
    -    end
    -
    -    def print_stars secret_number, guess
    -      diff = (guess - secret_number).abs
    -      stars = ""
    -      for i in 0..7
    -        if diff < 2**i
    -          stars += "*"
    -        end
    -      end
    -      print(stars)
    -    end
    -end
    -
    -
    -if __FILE__ == $0
    -  stars = Stars.new
    -  stars.start()
    -end
    \ No newline at end of file
    diff --git a/82_Stars/rust/Cargo.lock b/82_Stars/rust/Cargo.lock
    deleted file mode 100644
    index b13b873bb..000000000
    --- a/82_Stars/rust/Cargo.lock
    +++ /dev/null
    @@ -1,75 +0,0 @@
    -# 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/82_Stars/rust/Cargo.toml b/82_Stars/rust/Cargo.toml
    deleted file mode 100644
    index 8d4e044ff..000000000
    --- a/82_Stars/rust/Cargo.toml
    +++ /dev/null
    @@ -1,9 +0,0 @@
    -[package]
    -name = "stars"
    -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/82_Stars/rust/README.md b/82_Stars/rust/README.md
    deleted file mode 100644
    index fc6468b9f..000000000
    --- a/82_Stars/rust/README.md
    +++ /dev/null
    @@ -1,3 +0,0 @@
    -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
    -
    -Conversion to [Rust](https://www.rust-lang.org/)
    diff --git a/82_Stars/rust/src/main.rs b/82_Stars/rust/src/main.rs
    deleted file mode 100644
    index 429646b39..000000000
    --- a/82_Stars/rust/src/main.rs
    +++ /dev/null
    @@ -1,85 +0,0 @@
    -use rand::Rng;
    -use std::io;
    -
    -fn main() {
    -    println!(
    -        "{: >39}\n{: >57}\n\n\n",
    -        "STARS", "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
    -    );
    -    // STARS - PEOPLE'S COMPUTER CENTER, MENLO PARK, CA
    -    // A IS LIMIT ON NUMBER, M IS NUMBER OF GUESSES
    -    let a: u32 = 101;
    -    let m: u32 = 7;
    -    let mut need_instrut = String::new();
    -
    -    println!("DO YOU WANT INSTRUCTIONS?");
    -    io::stdin()
    -        .read_line(&mut need_instrut)
    -        .expect("Failed to get input");
    -
    -    if need_instrut[..1].to_ascii_lowercase().eq("y") {
    -        println!("I AM THINKING OF A WHOLE NUMBER FROM 1 TO {}", a - 1);
    -        println!("TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I");
    -        println!("WILL TYPE ONE OR MORE STARS (*).  THE MORE");
    -        println!("STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER.");
    -        println!("ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)");
    -        println!("MEANS REALLY CLOSE!  YOU GET {} GUESSES.\n\n", m);
    -    }
    -
    -    loop {
    -        println!("\nOK, I AM THINKING OF A NUMBER, START GUESSING.\n");
    -        let rand_number: i32 = rand::thread_rng().gen_range(1..a) as i32; // generates a random number between 1 and 100
    -
    -        // GUESSING BEGINS, HUMAN GETS M GUESSES
    -        for i in 0..m {
    -            let mut guess = String::new();
    -            println!("YOUR GUESS?");
    -            io::stdin()
    -                .read_line(&mut guess)
    -                .expect("Failed to get input");
    -            let guess: i32 = match guess.trim().parse() {
    -                Ok(num) => num,
    -                Err(_) => {
    -                    println!("PLEASE ENTER A NUMBER VALUE.\n");
    -                    continue;
    -                }
    -            };
    -            if guess == rand_number {
    -                print!("");
    -                for _i in 0..50 {
    -                    print!("*");
    -                }
    -                println!("!!!");
    -                println!("YOU GOT IT IN {} GUESSES!!!  LET'S PLAY AGAIN...\n", i + 1);
    -                break;
    -            } else {
    -                match_guess(rand_number - guess);
    -            }
    -
    -            if i == 6 {
    -                println!(
    -                    "SORRY, THAT'S {} GUESSES. THE NUMBER WAS {}",
    -                    m, rand_number
    -                );
    -            }
    -        }
    -    }
    -}
    -
    -fn match_guess(diff: i32) {
    -    if diff.abs() >= 64 {
    -        println!("*\n");
    -    } else if diff.abs() >= 32 {
    -        println!("**\n");
    -    } else if diff.abs() >= 16 {
    -        println!("***\n");
    -    } else if diff.abs() >= 8 {
    -        println!("****\n");
    -    } else if diff.abs() >= 4 {
    -        println!("*****\n");
    -    } else if diff.abs() >= 2 {
    -        println!("******\n");
    -    } else {
    -        println!("*******\n");
    -    }
    -}
    diff --git a/82_Stars/rust_JWB/Cargo.toml b/82_Stars/rust_JWB/Cargo.toml
    deleted file mode 100644
    index b35f5d945..000000000
    --- a/82_Stars/rust_JWB/Cargo.toml
    +++ /dev/null
    @@ -1,17 +0,0 @@
    -[package]
    -<<<<<<< HEAD
    -name = "rust"
    -=======
    -name = "stars"
    ->>>>>>> 3e27c70ca800f5efbe6bc1a7d180211decf55b7d
    -version = "0.1.0"
    -edition = "2021"
    -
    -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
    -
    -[dependencies]
    -<<<<<<< HEAD
    -rand = "0.8.5"
    -=======
    -rand = "0.8.3"
    ->>>>>>> 3e27c70ca800f5efbe6bc1a7d180211decf55b7d
    diff --git a/82_Stars/rust_JWB/README.md b/82_Stars/rust_JWB/README.md
    deleted file mode 100644
    index 06139f036..000000000
    --- a/82_Stars/rust_JWB/README.md
    +++ /dev/null
    @@ -1,29 +0,0 @@
    -<<<<<<< HEAD
    -#STARS
    -
    -From: BASIC Computer Games (1978), edited by David H. Ahl
    -
    -In this game, the computer selects a random number from 1 to 100
    -(or any value you set [for MAX_NUM]).  You try to guess the number
    -and the computer gives you clues to tell you how close you're
    -getting.  One star (*) means you're far away from the number; seven
    -stars (*******) means you're really close.  You get 7  guesses.
    -
    -On the surface this game is very similar to GUESS; however, the
    -guessing strategy is quite different.  See if you can come up with
    -one or more approaches to finding the mystery number.
    -
    -Bob Albrecht of People's Computer Company created this game.
    -
    -## NOTES
    -
    -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
    -
    -Conversion to [Rust](https://www.rust-lang.org/) by JW Bruce
    -
    -thanks to Jeff Jetton for his Python port which provide inspiration
    -=======
    -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
    -
    -Conversion to [Rust](https://www.rust-lang.org/)
    ->>>>>>> 3e27c70ca800f5efbe6bc1a7d180211decf55b7d
    diff --git a/82_Stars/rust_JWB/src/main.rs b/82_Stars/rust_JWB/src/main.rs
    deleted file mode 100644
    index 162b8b4f6..000000000
    --- a/82_Stars/rust_JWB/src/main.rs
    +++ /dev/null
    @@ -1,236 +0,0 @@
    -<<<<<<< HEAD
    -//
    -// Stars
    -//
    -// From: BASIC Computer Games (1978), edited by David H. Ahl
    -//
    -// In this game, the computer selects a random number from 1 to 100
    -// (or any value you set [for MAX_NUM]).  You try to guess the number
    -// and the computer gives you clues to tell you how close you're
    -// getting.  One star (*) means you're far away from the number; seven
    -// stars (*******) means you're really close.  You get 7  guesses.
    -//
    -// On the surface this game is very similar to GUESS; however, the
    -// guessing strategy is quite different.  See if you can come up with
    -// one or more approaches to finding the mystery number.
    -//
    -// Bob Albrecht of People's Computer Company created this game.
    -//
    -// rust port by JW BRUCE 2022
    -//
    -// ********************************************************************
    -//
    -// Porting Notes (taken for Jeff Jetton's Python version)
    -//
    -//   The original program never exited--it just kept playing rounds
    -//   over and over.  This version asks to continue each time.
    -//
    -// Ideas for Modifications
    -//
    -//   Let the player know how many guesses they have remaining after
    -//   each incorrect guess.
    -//
    -//   Ask the player to select a skill level at the start of the game,
    -//   which will affect the values of MAX_NUM and MAX_GUESSES.
    -//   For example:
    -//
    -//       Easy   = 8 guesses, 1 to 50
    -//       Medium = 7 guesses, 1 to 100
    -//       Hard   = 6 guesses, 1 to 200
    -//
    -// *********************************************************************
    -
    -// I M P O R T S
    -use std::io;
    -use std::io::stdin;
    -//use std::io::{stdin, stdout, Write};
    -use rand::Rng;
    -
    -const   MAX_NUM: u8 = 100;
    -const   MAX_GUESSES: u8 = 7;
    -
    -fn main() -> io::Result<()> {
    -    print_header();
    -    if !read_lowercase_input()?.starts_with('n') {
    -        print_rules();
    -    }
    -    loop {
    -        let secret_number : u8 = rand::thread_rng().gen_range(1..101);
    -        let mut guess_count = 0;
    -        let mut player_won: bool = false;
    -        
    -        println!("\n\nOK, I am thinking of a number, start guessing.");
    -        while guess_count < MAX_GUESSES && !player_won {
    -            
    -            guess_count += 1;        
    -
    -            println!("Your guess? ");
    -            let mut guess = String::new();
    -            io::stdin()
    -                .read_line(&mut guess)
    -                .expect("Failed to read line");
    -
    -            let guess: u8 = match guess.trim().parse() {
    -                Ok(num) => num,
    -                Err(_) => continue,
    -            };
    -            
    -            // USE THIS STATEMENT FOR DEBUG PURPOSES
    -            // println!("Guess #{} is {}. secret number is {}",guess_count, guess, secret_number);
    -            
    -            if guess == secret_number {
    -                // winner winner chicken dinner
    -                player_won = true;
    -                println!("**************************************************!!!");
    -                println!("You got it in {guess_count} guesses!!!");
    -            } else {
    -                print_stars( guess, secret_number) ;
    -            }      
    -        }
    -        
    -        // player exhausted their number of guesses and did not win.
    -        if !player_won {
    -            println!("Sorry, that's {guess_count} guesses, number was {secret_number}");
    -        }
    -
    -        println!("\nPlay again (yes or no)?");
    -        if !read_lowercase_input()?.starts_with('y') {
    -            return Ok(());
    -=======
    -use rand::Rng;
    -use std::io;
    -
    -fn main() {
    -    println!(
    -        "{: >39}\n{: >57}\n\n\n",
    -        "STARS", "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
    -    );
    -    // STARS - PEOPLE'S COMPUTER CENTER, MENLO PARK, CA
    -    // A IS LIMIT ON NUMBER, M IS NUMBER OF GUESSES
    -    let a: u32 = 101;
    -    let m: u32 = 7;
    -    let mut need_instrut = String::new();
    -
    -    println!("DO YOU WANT INSTRUCTIONS?");
    -    io::stdin()
    -        .read_line(&mut need_instrut)
    -        .expect("Failed to get input");
    -
    -    if need_instrut[..1].to_ascii_lowercase().eq("y") {
    -        println!("I AM THINKING OF A WHOLE NUMBER FROM 1 TO {}", a - 1);
    -        println!("TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I");
    -        println!("WILL TYPE ONE OR MORE STARS (*).  THE MORE");
    -        println!("STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER.");
    -        println!("ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)");
    -        println!("MEANS REALLY CLOSE!  YOU GET {} GUESSES.\n\n", m);
    -    }
    -
    -    loop {
    -        println!("\nOK, I AM THINKING OF A NUMBER, START GUESSING.\n");
    -        let rand_number: i32 = rand::thread_rng().gen_range(1..a) as i32; // generates a random number between 1 and 100
    -
    -        // GUESSING BEGINS, HUMAN GETS M GUESSES
    -        for i in 0..m {
    -            let mut guess = String::new();
    -            println!("YOUR GUESS?");
    -            io::stdin()
    -                .read_line(&mut guess)
    -                .expect("Failed to get input");
    -            let guess: i32 = match guess.trim().parse() {
    -                Ok(num) => num,
    -                Err(_) => {
    -                    println!("PLEASE ENTER A NUMBER VALUE.\n");
    -                    continue;
    -                }
    -            };
    -            if guess == rand_number {
    -                print!("");
    -                for _i in 0..50 {
    -                    print!("*");
    -                }
    -                println!("!!!");
    -                println!("YOU GOT IT IN {} GUESSES!!!  LET'S PLAY AGAIN...\n", i + 1);
    -                break;
    -            } else {
    -                match_guess(rand_number - guess);
    -            }
    -
    -            if i == 6 {
    -                println!(
    -                    "SORRY, THAT'S {} GUESSES. THE NUMBER WAS {}",
    -                    m, rand_number
    -                );
    -            }
    ->>>>>>> 3e27c70ca800f5efbe6bc1a7d180211decf55b7d
    -        }
    -    }
    -}
    -
    -<<<<<<< HEAD
    -// guess is wrong, so print stars to show how far away they are
    -fn print_stars( guess: u8, target: u8) {
    -    // choose to use u8 in main, but currently (1.59.0) does not
    -    //   have abs() defined for u8.  abs() is defined for i16, so
    -    //   this provide an opportunity to demonstrate casting in rust
    -    let diff : i16 = ((guess as i16)-(target as i16)).abs();
    -    
    -    // Since we only print 1-7 stars, this finite set of choices is
    -    //   small enough that we can use rust's match keyword.
    -    // The match "arms" here use the inclusive range notation.
    -    //   The exlusive range notation is not an approved feature of
    -    //   rust, yet.
    -    match diff {
    -        1..=2 => println!("*******"),
    -        3..=4 => println!("******"),
    -        5..=8 => println!("*****"),
    -        9..=16 => println!("****"),
    -        17..=32 => println!("***"),
    -        33..=64 => println!("**"),
    -        _ => println!("*"),
    -    }
    -}
    -
    -//
    -fn read_lowercase_input() -> io::Result {
    -    let mut input = String::new();
    -    stdin().read_line(&mut input)?;
    -    Ok(input.trim().to_lowercase())
    -}
    -
    -// Text to print at the start of the game
    -fn print_header() {
    -    println!("\n                   Stars");
    -    println!("Creative-Computing  Morristown, New Jersey");
    -    println!("\n\n");
    -    println!("Do you want instructions? ");
    -}
    -
    -// Instructions on how to play
    -fn print_rules() {
    -    println!();
    -    println!("I am thinking of a whole number from 1 to {}", MAX_NUM);
    -    println!("Try to guess my number.  After you guess, I");
    -    println!("will type one or more stars (*).  The more");
    -    println!("stars I type, the closer you are to my number.");
    -    println!("one star (*) means far away, seven stars (*******)");
    -    println!("means really close!  You get {} guesses.", MAX_GUESSES);
    -}
    -=======
    -fn match_guess(diff: i32) {
    -    if diff.abs() >= 64 {
    -        println!("*\n");
    -    } else if diff.abs() >= 32 {
    -        println!("**\n");
    -    } else if diff.abs() >= 16 {
    -        println!("***\n");
    -    } else if diff.abs() >= 8 {
    -        println!("****\n");
    -    } else if diff.abs() >= 4 {
    -        println!("*****\n");
    -    } else if diff.abs() >= 2 {
    -        println!("******\n");
    -    } else {
    -        println!("*******\n");
    -    }
    -}
    ->>>>>>> 3e27c70ca800f5efbe6bc1a7d180211decf55b7d
    diff --git a/83_Stock_Market/python/Stock_Market.py b/83_Stock_Market/python/Stock_Market.py
    index 6ad3f8d1a..dbc9d9491 100644
    --- a/83_Stock_Market/python/Stock_Market.py
    +++ b/83_Stock_Market/python/Stock_Market.py
    @@ -1,9 +1,10 @@
     import random
    -from typing import Any, Dict, List
     
     
    +# Stock_Market
     class Stock_Market:
    -    def __init__(self) -> None:
    +    def __init__(self):
    +
             # Hard Coded Names
             short_names = ["IBM", "RCA", "LBJ", "ABC", "CBS"]
             full_names = [
    @@ -15,7 +16,7 @@ def __init__(self) -> None:
             ]
     
             # Initializing Dictionary to hold all the information systematically
    -        self.data: Dict[str, Any] = {}
    +        self.data = {}
             for sn, fn in zip(short_names, full_names):
                 # A dictionary for each stock
                 temp = {"Name": fn, "Price": None, "Holdings": 0}
    @@ -30,16 +31,20 @@ def __init__(self) -> None:
             self.cash_assets = 10000
             self.stock_assets = 0
     
    -    def total_assets(self) -> float:
    +    def total_assets(self):
    +
             return self.cash_assets + self.stock_assets
     
    -    def _generate_day_change(self) -> None:
    -        self.changes: List[float] = []
    -        self.changes.extend(
    -            round(random.uniform(-5, 5), 2) for _ in range(len(self.data))
    -        )
    +    def _generate_day_change(self):
    +
    +        self.changes = []
    +        for _ in range(len(self.data)):
    +            self.changes.append(
    +                round(random.uniform(-5, 5), 2)
    +            )  # Random % Change b/w -5 and 5
    +
    +    def update_prices(self):
     
    -    def update_prices(self) -> None:
             self._generate_day_change()
             for stock, change in zip(self.data.values(), self.changes):
                 stock["Price"] = round(stock["Price"] + (change / 100) * stock["Price"], 2)
    @@ -52,8 +57,9 @@ def print_exchange_average(self) -> None:
     
             print(f"\nNEW YORK STOCK EXCHANGE AVERAGE: ${sum / 5:.2f}")
     
    -    def get_average_change(self) -> float:
    -        sum: float = 0
    +    def get_average_change(self):
    +
    +        sum = 0
             for change in self.changes:
                 sum += change
     
    @@ -64,14 +70,15 @@ 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(f'{data["Name"]}\t\t\t{stock}\t\t{data["Price"]}')
    +                print("{}\t\t\t{}\t\t{}".format(data["Name"], stock, data["Price"]))
                 else:
    -                print(f'{data["Name"]}\t\t{stock}\t\t{data["Price"]}')
    +                print("{}\t\t{}\t\t{}".format(data["Name"], stock, data["Price"]))
     
             self.print_exchange_average()
             self.print_assets()
     
    -    def take_inputs(self) -> List[str]:
    +    def take_inputs(self):
    +
             print("\nWHAT IS YOUR TRANSACTION IN")
             flag = False
             while not flag:
    @@ -85,7 +92,7 @@ def take_inputs(self) -> List[str]:
                 if len(new_holdings) == 5:
                     flag = self._check_transaction(new_holdings)
     
    -        return new_holdings  # type: ignore
    +        return new_holdings
     
         def print_trading_day(self) -> None:
     
    @@ -100,7 +107,8 @@ def print_trading_day(self) -> None:
                     )
                 )
     
    -    def update_cash_assets(self, new_holdings) -> None:
    +    def update_cash_assets(self, new_holdings):
    +
             sell = 0
             buy = 0
             for stock, holding in zip(self.data.values(), new_holdings):
    @@ -112,7 +120,8 @@ def update_cash_assets(self, new_holdings) -> None:
     
             self.cash_assets = self.cash_assets + sell - buy
     
    -    def update_stock_assets(self) -> None:
    +    def update_stock_assets(self):
    +
             sum = 0
             for data in self.data.values():
                 sum += data["Price"] * data["Holdings"]
    @@ -120,11 +129,13 @@ def update_stock_assets(self) -> None:
             self.stock_assets = round(sum, 2)
     
         def print_assets(self) -> None:
    +
             print(f"\nTOTAL STOCK ASSETS ARE: ${self.stock_assets:.2f}")
             print(f"TOTAL CASH ASSETS ARE: ${self.cash_assets:.2f}")
             print(f"TOTAL ASSETS ARE: ${self.total_assets():.2f}")
     
    -    def _check_transaction(self, new_holdings) -> bool:
    +    def _check_transaction(self, new_holdings):
    +
             sum = 0
             for stock, holding in zip(self.data.values(), new_holdings):
                 if holding > 0:
    @@ -145,7 +156,8 @@ def _check_transaction(self, new_holdings) -> bool:
     
             return True
     
    -    def update_holdings(self, new_holdings) -> None:
    +    def update_holdings(self, new_holdings):
    +
             for stock, new_holding in zip(self.data.values(), new_holdings):
                 stock["Holdings"] += new_holding
     
    @@ -174,12 +186,13 @@ def print_instruction() -> None:
         )
     
     
    -def main() -> None:
    +if __name__ == "__main__":
    +
         print("\t\t      STOCK MARKET")
         help = input("\nDO YOU WANT INSTRUCTIONS(YES OR NO)? ")
     
         # Printing Instruction
    -    if help.lower() == "yes":
    +    if help == "YES" or help == "yes" or help == "Yes":
             print_instruction()
     
         # Initialize Game
    @@ -212,8 +225,4 @@ def main() -> None:
             print("\n------------END OF TRADING DAY--------------\n")
     
         print("\nHOPE YOU HAD FUN!!!!")
    -    input()
    -
    -
    -if __name__ == "__main__":
    -    main()
    +    input("")
    diff --git a/84_Super_Star_Trek/README.md b/84_Super_Star_Trek/README.md
    index 32f827c67..1edeb8694 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 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.
    +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.
     
     #### 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 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).
    +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).
     
     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          | II | III | IV |
    +|   | I            | II | III | IV | I          |    | III | IV |
     | 2 |     RIGEL    |    |     |    |    DENEB   |    |     |    |
     |   | I            | II | III | IV | I          | II | III | IV |
     | 3 |    PROCYON   |    |     |    |   CAPELLA  |    |     |    |
    @@ -72,7 +72,7 @@ The relation between the Historical and Standard nomenclatures is shown in the s
         - If you don’t zap a Klingon hard enough (relative to his shield strength) you won’t damage him at all. Your sensors will tell the story.
         - Damage control will let you know when out-of-commission devices have been completely repaired.
     
    -9. Your engines will automatically shut down if you should attempt to leave the galaxy, or if you should try to maneuver through a star, or Starbase, or—heaven help you—a Klingon warship.
    +9. Your engines will automatically shit down if you should attempt to leave the galaxy, or if you should try to maneuver through a star, or Starbase, or—heaven help you—a Klingon warship.
     
     10. In a pinch, or if you should miscalculate slightly, some shield control energy will be automatically diverted to warp engine control (if your shield are operational!).
     
    @@ -88,13 +88,11 @@ 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=172)
    +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=166)
     
     Downloaded from Vintage Basic at
     http://www.vintage-basic.net/games.html
    @@ -112,5 +110,6 @@ 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
    diff --git a/84_Super_Star_Trek/javascript/README.md b/84_Super_Star_Trek/javascript/README.md
    index 06f53f122..49b7ece64 100644
    --- a/84_Super_Star_Trek/javascript/README.md
    +++ b/84_Super_Star_Trek/javascript/README.md
    @@ -1,6 +1,3 @@
    -Original source downloaded [from Vintage Basic][def]
    +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
     
    -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
    +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
    diff --git a/84_Super_Star_Trek/javascript/cli.mjs b/84_Super_Star_Trek/javascript/cli.mjs
    index 4277c2323..bacceff85 100644
    --- a/84_Super_Star_Trek/javascript/cli.mjs
    +++ b/84_Super_Star_Trek/javascript/cli.mjs
    @@ -2,9 +2,12 @@ import {
       onExit,
       onPrint,
       onInput,
    +  setGameOptions,
    +  getGameState,
       gameMain,
     } from "./superstartrek.mjs";
     
    +import util from "util";
     import readline from "readline";
     
     onExit(function exit() {
    diff --git a/84_Super_Star_Trek/python/superstartrek.py b/84_Super_Star_Trek/python/superstartrek.py
    index 892988c76..5f4f030d6 100644
    --- a/84_Super_Star_Trek/python/superstartrek.py
    +++ b/84_Super_Star_Trek/python/superstartrek.py
    @@ -1,1117 +1,771 @@
    -"""
    -****        **** STAR TREK ****        ****
    -**** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,
    -**** AS SEEN ON THE STAR TREK TV SHOW.
    -**** ORIGINAL 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 . . .
    -
    -  Output is identical to BASIC version except for a few
    -  fixes (as noted, search `bug`) and minor cleanup.
    -"""
    +# ****        **** STAR TREK ****        ****
    +# **** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,
    +# **** AS SEEN ON THE STAR TREK TV SHOW.
    +# **** ORIGINAL 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 . . .
    +#
    +# 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.
     
     
     import random
    -import sys
    -from dataclasses import dataclass
    -from enum import Enum
     from math import sqrt
    -from typing import Callable, Dict, Final, List, Optional, Tuple
    +from typing import Any, Callable, Dict, List, Tuple
    +
    +# Global variables
    +restart = False
    +s = 0
    +e = 0
    +d: List[int] = []
    +k: List[List[float]] = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]  # Klingons in current quadrant
    +devices = [
    +    "WARP ENGINES",
    +    "SHORT RANGE SENSORS",
    +    "LONG RANGE SENSORS",
    +    "PHASER CONTROL",
    +    "PHOTON TUBES",
    +    "DAMAGE CONTROL",
    +    "SHIELD CONTROL",
    +    "LIBRARY-COMPUTER",
    +]
    +c = [
    +    [0, 1],
    +    [-1, 1],
    +    [-1, 0],
    +    [-1, -1],
    +    [0, -1],
    +    [1, -1],
    +    [1, 0],
    +    [1, 1],
    +    [0, 1],
    +]  # vectors in cardinal directions
    +q1 = s1 = 0
    +q2 = s2 = 0
    +k3 = b3 = s3 = 0  # Klingons, bases, stars in quad.
    +
    +b4 = b5 = 0
    +qs = " " * 192  # quadrant string
    +# set up global game variables
    +g = [[0] * 8 for _ in range(8)]  # galaxy map
    +z = [[0] * 8 for _ in range(8)]  # charted galaxy map
    +d = [0] * 8  # damage stats for devices
    +t = t0 = 100 * random.randint(20, 39)  # stardate (current, initial)
    +t9 = random.randint(25, 34)  # mission duration (stardates)
    +docked = False  # true when docked at starbase
    +e = e0 = 3000  # energy (current, initial)
    +p = p0 = 10  # torpedoes (current, initial)
    +s = 0  # shields
    +k9, b9 = 0, 0  # total Klingons, bases in galaxy
    +# ^ bug in original, was b9 = 2
    +s9 = 200  # avg. Klingon shield strength
    +
    +k7 = k9  # Klingons at start of game
    +d4 = 0.5 * random.random()  # extra delay in repairs at base
    +
    +# -------------------------------------------------------------------------
    +#  Utility functions
    +# -------------------------------------------------------------------------
    +
    +
    +def fnr():
    +    # Generate a random integer from 0 to 7 inclusive.
    +    return random.randint(0, 7)
     
     
    -def get_user_float(prompt: str) -> float:
    -    """Get input from user and return it."""
    +def quadrant_name(row, col, region_only=False):
    +    # Return quadrant name visible on scans, etc.
    +    region1 = [
    +        "ANTARES",
    +        "RIGEL",
    +        "PROCYON",
    +        "VEGA",
    +        "CANOPUS",
    +        "ALTAIR",
    +        "SAGITTARIUS",
    +        "POLLUX",
    +    ]
    +    region2 = [
    +        "SIRIUS",
    +        "DENEB",
    +        "CAPELLA",
    +        "BETELGEUSE",
    +        "ALDEBARAN",
    +        "REGULUS",
    +        "ARCTURUS",
    +        "SPICA",
    +    ]
    +    modifier = ["I", "II", "III", "IV"]
    +
    +    quadrant = region1[row] if col < 4 else region2[row]
    +
    +    if not region_only:
    +        quadrant += " " + modifier[col % 4]
    +
    +    return quadrant
    +
    +
    +def insert_marker(row, col, marker):
    +    # Insert a marker into a given position in the quadrant string `qs`. The
    +    # contents of a quadrant (Enterprise, stars, etc.) are stored in `qs`.
    +    global qs
    +
    +    if len(marker) != 3:
    +        print("ERROR")
    +        exit()
    +
    +    pos = round(col) * 3 + round(row) * 24
    +    qs = qs[0:pos] + marker + qs[(pos + 3) : 192]
    +
    +
    +def compare_marker(row, col, test_marker):
    +    # Check whether the position in the current quadrant is occupied with a
    +    # given marker.
    +    pos = round(col) * 3 + round(row) * 24
    +    return qs[pos : (pos + 3)] == test_marker
    +
    +
    +def find_empty_place() -> Tuple[int, int]:
    +    # Find an empty location in the current quadrant.
         while True:
    -        answer = input(prompt)
    -        try:
    -            return float(answer)
    -        except ValueError:
    -            pass
    -
    -
    -class Entity(Enum):
    -    klingon = "+K+"
    -    ship = "<*>"
    -    empty = "***"
    -    starbase = ">!<"
    -    star = " * "
    -    void = "   "
    -
    -
    -@dataclass
    -class Point:
    -    x: int
    -    y: int
    -
    -    def __str__(self) -> str:
    -        return f"{self.x + 1} , {self.y + 1}"
    +        row, col = fnr(), fnr()
    +        if compare_marker(row, col, "   "):
    +            return row, col
     
     
    -@dataclass
    -class Position:
    -    """
    -    Every quadrant has 8 sectors
    +# -------------------------------------------------------------------------
    +#  Functions for individual player commands
    +# -------------------------------------------------------------------------
     
    -    Hence the position could also be represented as:
    -    x = quadrant.x * 8 + sector.x
    -    y = quadrant.y * 8 + sector.y
    -    """
     
    -    quadrant: Point
    -    sector: Point
    -
    -
    -@dataclass
    -class QuadrantData:
    -    klingons: int
    -    bases: int
    -    stars: int
    -
    -    def num(self) -> int:
    -        return 100 * self.klingons + 10 * self.bases + self.stars
    -
    -
    -@dataclass
    -class KlingonShip:
    -    sector: Point
    -    shield: float
    +def navigation() -> None:
    +    # Take navigation input and move the Enterprise.
    +    global d, s, e, k, qs, t, q1, q2, s1, s2
     
    +    while True:
    +        c1s = input("COURSE (1-9)? ")
    +        if len(c1s) > 0:
    +            c1 = float(c1s)
    +            break
    +    if c1 == 9:
    +        c1 = 1
    +    if c1 < 1 or c1 >= 9:
    +        print("   LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'")
    +        return
     
    -class Ship:
    -    energy_capacity: int = 3000
    -    torpedo_capacity: int = 10
    +    while True:
    +        warps = input(f"WARP FACTOR (0-{'0.2' if d[0] < 0 else '8'})? ")
    +        if len(warps) > 0:
    +            warp = float(warps)
    +            break
    +    if d[0] < 0 and warp > 0.2:
    +        print("WARP ENGINES ARE DAMAGED. MAXIMUM SPEED = WARP 0.2")
    +        return
    +    if warp == 0:
    +        return
    +    if warp < 0 or warp > 8:
    +        print(f"   CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE WARP {warp}!'")
    +        return
    +
    +    n = round(warp * 8)
    +    if e < n:
    +        print("ENGINEERING REPORTS   'INSUFFICIENT ENERGY AVAILABLE")
    +        print(f"                       FOR MANEUVERING AT WARP {warp}!'")
    +        if s >= n - e and d[6] >= 0:
    +            print(f"DEFLECTOR CONTROL ROOM ACKNOWLEDGES {s} UNITS OF ENERGY")
    +            print("                         PRESENTLY DEPLOYED TO SHIELDS.")
    +        return
    +
    +    # klingons move and fire
    +    for i in range(3):
    +        if k[i][2] != 0:
    +            insert_marker(k[i][0], k[i][1], "   ")
    +            k[i][0], k[i][1] = find_empty_place()
    +            insert_marker(k[i][0], k[i][1], "+K+")
    +
    +    klingons_fire()
    +
    +    # repair damaged devices and print damage report
    +    line = ""
    +    for i in range(8):
    +        if d[i] < 0:
    +            d[i] += min(warp, 1)  # type: ignore
    +            if -0.1 < d[i] < 0:
    +                d[i] = -0.1  # type: ignore
    +            elif d[i] >= 0:
    +                if len(line) == 0:
    +                    line = "DAMAGE CONTROL REPORT:"
    +                line += "   " + devices[i] + " REPAIR COMPLETED\n"
    +    if len(line) > 0:
    +        print(line)
    +    if random.random() <= 0.2:
    +        r1 = fnr()
    +        if random.random() < 0.6:
    +            d[r1] -= random.random() * 5 + 1
    +            print(f"DAMAGE CONTROL REPORT:   {devices[r1]} DAMAGED\n")
    +        else:
    +            d[r1] += random.random() * 3 + 1
    +            print(f"DAMAGE CONTROL REPORT:   {devices[r1]} STATE OF REPAIR IMPROVED\n")
    +
    +    # begin moving starship
    +    insert_marker(int(s1), int(s2), "   ")
    +    ic1 = int(c1)
    +    x1 = c[ic1 - 1][0] + (c[ic1][0] - c[ic1 - 1][0]) * (c1 - ic1)
    +    x2 = c[ic1 - 1][1] + (c[ic1][1] - c[ic1 - 1][1]) * (c1 - ic1)
    +    q1_start, q2_start = q1, q2
    +    x, y = s1, s2
    +
    +    for _ in range(n):
    +        s1 += x1  # type: ignore
    +        s2 += x2  # type: ignore
    +
    +        if s1 < 0 or s1 > 7 or s2 < 0 or s2 > 7:
    +            # exceeded quadrant limits; calculate final position
    +            x += 8 * q1 + n * x1  # type: ignore
    +            y += 8 * q2 + n * x2  # type: ignore
    +            q1, q2 = int(x / 8), int(y / 8)
    +            s1, s2 = int(x - q1 * 8), int(y - q2 * 8)
    +            if s1 < 0:
    +                q1 -= 1
    +                s1 = 7
    +            if s2 < 0:
    +                q2 -= 1
    +                s2 = 7
    +
    +            hit_edge = False
    +            if q1 < 0:
    +                hit_edge = True
    +                q1 = s1 = 0
    +            if q1 > 7:
    +                hit_edge = True
    +                q1 = s1 = 7
    +            if q2 < 0:
    +                hit_edge = True
    +                q2 = s2 = 0
    +            if q2 > 7:
    +                hit_edge = True
    +                q2 = s2 = 7
    +            if hit_edge:
    +                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(
    +                    f"  AT SECTOR {s1 + 1} , {s2 + 1} OF QUADRANT "
    +                    f"{q1 + 1} , {q2 + 1}.'"
    +                )
    +                if t > t0 + t9:
    +                    end_game(won=False, quit=False)
    +                    return
     
    -    def __init__(self) -> None:
    -        self.position = Position(Point(fnr(), fnr()), Point(fnr(), fnr()))
    -        self.energy: int = Ship.energy_capacity
    -        self.devices: Tuple[str, ...] = (
    -            "WARP ENGINES",
    -            "SHORT RANGE SENSORS",
    -            "LONG RANGE SENSORS",
    -            "PHASER CONTROL",
    -            "PHOTON TUBES",
    -            "DAMAGE CONTROL",
    -            "SHIELD CONTROL",
    -            "LIBRARY-COMPUTER",
    -        )
    -        self.damage_stats: List[float] = [0] * len(self.devices)
    -        self.shields = 0
    -        self.torpedoes = Ship.torpedo_capacity
    -        self.docked: bool = False  # true when docked at starbase
    -
    -    def refill(self) -> None:
    -        self.energy = Ship.energy_capacity
    -        self.torpedoes = Ship.torpedo_capacity
    -
    -    def maneuver_energy(self, n: int) -> None:
    -        """Deduct the energy for navigation from energy/shields."""
    -        self.energy -= n + 10
    -
    -        if self.energy <= 0:
    -            print("SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER.")
    -            self.shields += self.energy
    -            self.energy = 0
    -            self.shields = max(0, self.shields)
    -
    -    def shield_control(self) -> None:
    -        """Raise or lower the shields."""
    -        if self.damage_stats[6] < 0:
    -            print("SHIELD CONTROL INOPERABLE")
    +            if q1 == q1_start and q2 == q2_start:
    +                break
    +            t += 1
    +            maneuver_energy(n)
    +            new_quadrant()
                 return
    -
    -        while True:
    -            energy_to_shield = input(
    -                f"ENERGY AVAILABLE = {self.energy + self.shields} NUMBER OF UNITS TO SHIELDS? "
    -            )
    -            if len(energy_to_shield) > 0:
    -                x = int(energy_to_shield)
    +        else:
    +            pos = int(s1) * 24 + int(s2) * 3
    +            if qs[pos : (pos + 2)] != "  ":
    +                s1, s2 = int(s1 - x1), int(s2 - x2)
    +                print(
    +                    "WARP ENGINES SHUT DOWN AT SECTOR "
    +                    f"{s1 + 1} , {s2 + 1} DUE TO BAD NAVAGATION"
    +                )
                     break
    +    else:
    +        s1, s2 = int(s1), int(s2)
     
    -        if x < 0 or self.shields == x:
    -            print("")
    -            return
    +    insert_marker(int(s1), int(s2), "<*>")
    +    maneuver_energy(n)
     
    -        if x > self.energy + self.shields:
    -            print(
    -                "SHIELD CONTROL REPORTS  'THIS IS NOT THE FEDERATION "
    -                "TREASURY.'\n"
    -                ""
    -            )
    -            return
    +    t += 0.1 * int(10 * warp) if warp < 1 else 1  # type: ignore
    +    if t > t0 + t9:
    +        end_game(won=False, quit=False)
    +        return
     
    -        self.energy += self.shields - x
    -        self.shields = x
    -        print("DEFLECTOR CONTROL ROOM REPORT:")
    -        print(f"  'SHIELDS NOW AT {self.shields} UNITS PER YOUR COMMAND.'")
    -
    -
    -class Quadrant:
    -    def __init__(
    -        self,
    -        point: Point,  # position of the quadrant
    -        population: QuadrantData,
    -        ship_position: Position,
    -    ) -> None:
    -        """Populate quadrant map"""
    -        assert 0 <= point.x <= 7 and 0 <= point.y <= 7
    -        self.name = Quadrant.quadrant_name(point.x, point.y, False)
    -
    -        self.nb_klingons = population.klingons
    -        self.nb_bases = population.bases
    -        self.nb_stars = population.stars
    -
    -        # extra delay in repairs at base
    -        self.delay_in_repairs_at_base: float = 0.5 * random.random()
    -
    -        # Klingons in current quadrant
    -        self.klingon_ships: List[KlingonShip] = []
    -
    -        # Initialize empty: save what is at which position
    -        self.data = [[Entity.void for _ in range(8)] for _ in range(8)]
    -
    -        self.populate_quadrant(ship_position)
    -
    -    @classmethod
    -    def quadrant_name(cls, row: int, col: int, region_only: bool = False) -> str:
    -        """Return quadrant name visible on scans, etc."""
    -        region1 = [
    -            "ANTARES",
    -            "RIGEL",
    -            "PROCYON",
    -            "VEGA",
    -            "CANOPUS",
    -            "ALTAIR",
    -            "SAGITTARIUS",
    -            "POLLUX",
    -        ]
    -        region2 = [
    -            "SIRIUS",
    -            "DENEB",
    -            "CAPELLA",
    -            "BETELGEUSE",
    -            "ALDEBARAN",
    -            "REGULUS",
    -            "ARCTURUS",
    -            "SPICA",
    -        ]
    -        modifier = ["I", "II", "III", "IV"]
    -
    -        quadrant = region1[row] if col < 4 else region2[row]
    -
    -        if not region_only:
    -            quadrant += f" {modifier[col % 4]}"
    -
    -        return quadrant
    -
    -    def set_value(self, x: float, y: float, entity: Entity) -> None:
    -        self.data[round(x)][round(y)] = entity
    -
    -    def get_value(self, x: float, y: float) -> Entity:
    -        return self.data[round(x)][round(y)]
    -
    -    def find_empty_place(self) -> Tuple[int, int]:
    -        """Find an empty location in the current quadrant."""
    -        while True:
    -            row, col = fnr(), fnr()
    -            if self.get_value(row, col) == Entity.void:
    -                return row, col
    -
    -    def populate_quadrant(self, ship_position: Position) -> None:
    -        self.set_value(ship_position.sector.x, ship_position.sector.y, Entity.ship)
    -        for _ in range(self.nb_klingons):
    -            x, y = self.find_empty_place()
    -            self.set_value(x, y, Entity.klingon)
    -            self.klingon_ships.append(
    -                KlingonShip(
    -                    Point(x, y), klingon_shield_strength * (0.5 + random.random())
    -                )
    -            )
    -        if self.nb_bases > 0:
    -            # Position of starbase in current sector
    -            starbase_x, starbase_y = self.find_empty_place()
    -            self.starbase = Point(starbase_x, starbase_y)
    -            self.set_value(starbase_x, starbase_y, Entity.starbase)
    -        for _ in range(self.nb_stars):
    -            x, y = self.find_empty_place()
    -            self.set_value(x, y, Entity.star)
    -
    -    def __str__(self) -> str:
    -        quadrant_string = ""
    -        for row in self.data:
    -            for entity in row:
    -                quadrant_string += entity.value
    -        return quadrant_string
    -
    -
    -class World:
    -    def __init__(
    -        self,
    -        total_klingons: int = 0,  # Klingons at start of game
    -        bases_in_galaxy: int = 0,
    -    ) -> None:
    -        self.ship = Ship()
    -        self.initial_stardate = 100 * random.randint(20, 39)
    -        self.stardate: float = self.initial_stardate
    -        self.mission_duration = random.randint(25, 34)
    -
    -        # Enemy
    -        self.remaining_klingons = total_klingons
    -
    -        # Player starbases
    -        self.bases_in_galaxy = bases_in_galaxy
    -
    -        self.galaxy_map: List[List[QuadrantData]] = [
    -            [QuadrantData(0, 0, 0) for _ in range(8)] for _ in range(8)
    -        ]
    -        self.charted_galaxy_map: List[List[QuadrantData]] = [
    -            [QuadrantData(0, 0, 0) for _ in range(8)] for _ in range(8)
    -        ]
    -
    -        # initialize contents of galaxy
    -        for x in range(8):
    -            for y in range(8):
    -                r1 = random.random()
    -
    -                if r1 > 0.98:
    -                    quadrant_klingons = 3
    -                elif r1 > 0.95:
    -                    quadrant_klingons = 2
    -                elif r1 > 0.80:
    -                    quadrant_klingons = 1
    -                else:
    -                    quadrant_klingons = 0
    -                self.remaining_klingons += quadrant_klingons
    -
    -                quadrant_bases = 0
    -                if random.random() > 0.96:
    -                    quadrant_bases = 1
    -                    self.bases_in_galaxy += 1
    -                self.galaxy_map[x][y] = QuadrantData(
    -                    quadrant_klingons, quadrant_bases, 1 + fnr()
    -                )
    +    short_range_scan()
     
    -        if self.remaining_klingons > self.mission_duration:
    -            self.mission_duration = self.remaining_klingons + 1
     
    -        if self.bases_in_galaxy == 0:  # original has buggy extra code here
    -            self.bases_in_galaxy = 1
    -            self.galaxy_map[self.ship.position.quadrant.x][
    -                self.ship.position.quadrant.y
    -            ].bases += 1
    +def maneuver_energy(n):
    +    # Deduct the energy for navigation from energy/shields.
    +    global e, s
     
    -        curr = self.ship.position.quadrant
    -        self.quadrant = Quadrant(
    -            self.ship.position.quadrant,
    -            self.galaxy_map[curr.x][curr.y],
    -            self.ship.position,
    -        )
    +    e -= n + 10
     
    -    def remaining_time(self) -> float:
    -        return self.initial_stardate + self.mission_duration - self.stardate
    +    if e <= 0:
    +        print("SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER.")
    +        s += e
    +        e = 0
    +        s = max(0, s)
     
    -    def has_mission_ended(self) -> bool:
    -        return self.remaining_time() < 0
     
    +def short_range_scan() -> None:
    +    # Print a short range scan.
    +    global docked, e, p, s
     
    -class Game:
    -    """Handle user actions"""
    +    docked = False
    +    for i in (s1 - 1, s1, s1 + 1):
    +        for j in (s2 - 1, s2, s2 + 1):
    +            if 0 <= i <= 7 and 0 <= j <= 7 and compare_marker(i, j, ">!<"):
    +                docked = True
    +                cs = "DOCKED"
    +                e, p = e0, p0
    +                print("SHIELDS DROPPED FOR DOCKING PURPOSES")
    +                s = 0
    +                break
    +        else:
    +            continue
    +        break
    +    else:
    +        if k3 > 0:
    +            cs = "*RED*"
    +        elif e < e0 * 0.1:
    +            cs = "YELLOW"
    +        else:
    +            cs = "GREEN"
     
    -    def __init__(self) -> None:
    -        self.restart = False
    -        self.world = World()
    +    if d[1] < 0:
    +        print("\n*** SHORT RANGE SENSORS ARE OUT ***\n")
    +        return
     
    -    def startup(self) -> None:
    -        """Initialize the game variables and map, and print startup messages."""
    -        print(
    -            "\n\n\n\n\n\n\n\n\n\n\n"
    -            "                                    ,------*------,\n"
    -            "                    ,-------------   '---  ------'\n"
    -            "                     '-------- --'      / /\n"
    -            "                         ,---' '-------/ /--,\n"
    -            "                          '----------------'\n\n"
    -            "                    THE USS ENTERPRISE --- NCC-1701\n"
    -            "\n\n\n\n"
    -        )
    -        world = self.world
    -        print(
    -            "YOUR ORDERS ARE AS FOLLOWS:\n"
    -            f"     DESTROY THE {world.remaining_klingons} KLINGON WARSHIPS WHICH HAVE INVADED\n"
    -            "   THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS\n"
    -            f"   ON STARDATE {world.initial_stardate+world.mission_duration}. "
    -            f" THIS GIVES YOU {world.mission_duration} DAYS. THERE "
    -            f"{'IS' if world.bases_in_galaxy == 1 else 'ARE'}\n"
    -            f"   {world.bases_in_galaxy} "
    -            f"STARBASE{'' if world.bases_in_galaxy == 1 else 'S'} IN THE GALAXY FOR "
    -            "RESUPPLYING YOUR SHIP.\n"
    -        )
    +    sep = "---------------------------------"
    +    print(sep)
    +    for i in range(8):
    +        line = ""
    +        for j in range(8):
    +            pos = i * 24 + j * 3
    +            line = line + " " + qs[pos : (pos + 3)]
    +
    +        if i == 0:
    +            line += f"        STARDATE           {round(int(t * 10) * 0.1, 1)}"
    +        elif i == 1:
    +            line += f"        CONDITION          {cs}"
    +        elif i == 2:
    +            line += f"        QUADRANT           {q1 + 1} , {q2 + 1}"
    +        elif i == 3:
    +            line += f"        SECTOR             {s1 + 1} , {s2 + 1}"
    +        elif i == 4:
    +            line += f"        PHOTON TORPEDOES   {int(p)}"
    +        elif i == 5:
    +            line += f"        TOTAL ENERGY       {int(e + s)}"
    +        elif i == 6:
    +            line += f"        SHIELDS            {int(s)}"
    +        else:
    +            line += f"        KLINGONS REMAINING {k9}"
     
    -    def new_quadrant(self) -> None:
    -        """Enter a new quadrant: populate map and print a short range scan."""
    -        world = self.world
    -        ship = world.ship
    -        q = ship.position.quadrant
    +        print(line)
    +    print(sep)
     
    -        world.quadrant = Quadrant(
    -            q,
    -            world.galaxy_map[q.x][q.y],
    -            ship.position,
    -        )
     
    -        world.charted_galaxy_map[q.x][q.y] = world.galaxy_map[q.x][q.y]
    +def long_range_scan() -> None:
    +    # Print a long range scan.
    +    global z, g
     
    -        if world.stardate == world.initial_stardate:
    -            print("\nYOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED")
    -            print(f"IN THE GALACTIC QUADRANT, '{world.quadrant.name}'.\n")
    -        else:
    -            print(f"\nNOW ENTERING {world.quadrant.name} QUADRANT . . .\n")
    +    if d[2] < 0:
    +        print("LONG RANGE SENSORS ARE INOPERABLE")
    +        return
     
    -        if world.quadrant.nb_klingons != 0:
    -            print("COMBAT AREA      CONDITION RED")
    -            if ship.shields <= 200:
    -                print("   SHIELDS DANGEROUSLY LOW")
    -        self.short_range_scan()
    +    print(f"LONG RANGE SCAN FOR QUADRANT {q1 + 1} , {q2 + 1}")
    +    print_scan_results(q1, q2, g, z)
     
    -    def fnd(self, i: int) -> float:
    -        """Find distance between Enterprise and i'th Klingon warship."""
    -        ship = self.world.ship.position.sector
    -        klingons = self.world.quadrant.klingon_ships[i].sector
    -        return sqrt((klingons.x - ship.x) ** 2 + (klingons.y - ship.y) ** 2)
     
    -    def klingons_fire(self) -> None:
    -        """Process nearby Klingons firing on Enterprise."""
    -        ship = self.world.ship
    +def print_scan_results(
    +    q1: int, q2: int, g: List[List[Any]], z: List[List[Any]]
    +) -> None:
    +    sep = "-------------------"
    +    print(sep)
    +    for i in (q1 - 1, q1, q1 + 1):
    +        n = [-1, -2, -3]
     
    -        if self.world.quadrant.nb_klingons <= 0:
    -            return
    -        if ship.docked:
    -            print("STARBASE SHIELDS PROTECT THE ENTERPRISE")
    -            return
    +        for j in (q2 - 1, q2, q2 + 1):
    +            if 0 <= i <= 7 and 0 <= j <= 7:
    +                n[j - q2 + 1] = g[i][j]
    +                z[i][j] = g[i][j]
     
    -        for i, klingon_ship in enumerate(self.world.quadrant.klingon_ships):
    -            if klingon_ship.shield <= 0:
    -                continue
    +        line = ": "
    +        for line_index in range(3):
    +            if n[line_index] < 0:
    +                line += "*** : "
    +            else:
    +                line += str(n[line_index] + 1000).rjust(4, " ")[-3:] + " : "
    +        print(line)
    +        print(sep)
     
    -            h = int((klingon_ship.shield / self.fnd(i)) * (random.random() + 2))
    -            ship.shields -= h
    -            klingon_ship.shield /= random.random() + 3
    -            print(f" {h} UNIT HIT ON ENTERPRISE FROM SECTOR {klingon_ship.sector} ")
    -            if ship.shields <= 0:
    -                self.end_game(won=False, quit=False, enterprise_killed=True)
    -                return
    -            print(f"      ")
    -            if h >= 20 and random.random() < 0.60 and h / ship.shields > 0.02:
    -                device = fnr()
    -                ship.damage_stats[device] -= h / ship.shields + 0.5 * random.random()
    -                print(
    -                    f"DAMAGE CONTROL REPORTS  '{ship.devices[device]} DAMAGED BY THE HIT'"
    -                )
     
    -    def phaser_control(self) -> None:
    -        """Take phaser control input and fire phasers."""
    -        world = self.world
    -        klingon_ships = world.quadrant.klingon_ships
    -        ship = world.ship
    +def phaser_control() -> None:
    +    # Take phaser control input and fire phasers.
    +    global e, k, g, z, k3, k9
     
    -        if ship.damage_stats[3] < 0:
    -            print("PHASERS INOPERATIVE")
    -            return
    +    if d[3] < 0:
    +        print("PHASERS INOPERATIVE")
    +        return
     
    -        if self.world.quadrant.nb_klingons <= 0:
    -            print("SCIENCE OFFICER SPOCK REPORTS  'SENSORS SHOW NO ENEMY SHIPS")
    -            print("                                IN THIS QUADRANT'")
    -            return
    +    if k3 <= 0:
    +        print("SCIENCE OFFICER SPOCK REPORTS  'SENSORS SHOW NO ENEMY SHIPS")
    +        print("                                IN THIS QUADRANT'")
    +        return
     
    -        if ship.damage_stats[7] < 0:
    -            print("COMPUTER FAILURE HAMPERS ACCURACY")
    +    if d[7] < 0:
    +        print("COMPUTER FAILURE HAMPERS ACCURACY")
     
    -        print(f"PHASERS LOCKED ON TARGET;  ENERGY AVAILABLE = {ship.energy} UNITS")
    -        phaser_firepower: float = 0
    +    print(f"PHASERS LOCKED ON TARGET;  ENERGY AVAILABLE = {e} UNITS")
    +    x = 0
    +    while True:
             while True:
    -            while True:
    -                units_to_fire = input("NUMBER OF UNITS TO FIRE? ")
    -                if len(units_to_fire) > 0:
    -                    phaser_firepower = int(units_to_fire)
    -                    break
    -            if phaser_firepower <= 0:
    -                return
    -            if ship.energy >= phaser_firepower:
    +            units_to_fire = input("NUMBER OF UNITS TO FIRE? ")
    +            if len(units_to_fire) > 0:
    +                x = int(units_to_fire)
                     break
    -            print(f"ENERGY AVAILABLE = {ship.energy} UNITS")
    +        if x <= 0:
    +            return
    +        if e >= x:
    +            break
    +        print(f"ENERGY AVAILABLE = {e} UNITS")
     
    -        ship.energy -= phaser_firepower
    -        if ship.damage_stats[7] < 0:  # bug in original, was d[6]
    -            phaser_firepower *= random.random()
    +    e -= x
    +    if d[7] < 0:  # bug in original, was d[6]
    +        x *= random.random()  # type: ignore
     
    -        phaser_per_klingon = int(phaser_firepower / self.world.quadrant.nb_klingons)
    -        for i, klingon_ship in enumerate(klingon_ships):
    -            if klingon_ship.shield <= 0:
    -                continue
    +    h1 = int(x / k3)
    +    for i in range(3):
    +        if k[i][2] <= 0:
    +            continue
     
    -            h = int((phaser_per_klingon / self.fnd(i)) * (random.random() + 2))
    -            if h <= 0.15 * klingon_ship.shield:
    -                print(f"SENSORS SHOW NO DAMAGE TO ENEMY AT {klingon_ship.sector}")
    +        h = int((h1 / fnd(i)) * (random.random() + 2))
    +        if h <= 0.15 * k[i][2]:
    +            print(f"SENSORS SHOW NO DAMAGE TO ENEMY AT {k[i][0] + 1} , {k[i][1] + 1}")
    +        else:
    +            k[i][2] -= h
    +            print(f" {h} UNIT HIT ON KLINGON AT SECTOR {k[i][0] + 1} , {k[i][1] + 1}")
    +            if k[i][2] <= 0:
    +                print("*** KLINGON DESTROYED ***")
    +                k3 -= 1
    +                k9 -= 1
    +                insert_marker(k[i][0], k[i][1], "   ")
    +                k[i][2] = 0
    +                g[q1][q2] -= 100
    +                z[q1][q2] = g[q1][q2]
    +                if k9 <= 0:
    +                    end_game(won=True, quit=False)
    +                    return
                 else:
    -                klingon_ship.shield -= h
    -                print(f" {h} UNIT HIT ON KLINGON AT SECTOR {klingon_ship.sector}")
    -                if klingon_ship.shield <= 0:
    -                    print("*** KLINGON DESTROYED ***")
    -                    self.world.quadrant.nb_klingons -= 1
    -                    world.remaining_klingons -= 1
    -                    world.quadrant.set_value(
    -                        klingon_ship.sector.x, klingon_ship.sector.y, Entity.void
    -                    )
    -                    klingon_ship.shield = 0
    -                    world.galaxy_map[ship.position.quadrant.x][
    -                        ship.position.quadrant.y
    -                    ].klingons -= 1
    -                    world.charted_galaxy_map[ship.position.quadrant.x][
    -                        ship.position.quadrant.y
    -                    ] = world.galaxy_map[ship.position.quadrant.x][
    -                        ship.position.quadrant.y
    -                    ]
    -                    if world.remaining_klingons <= 0:
    -                        self.end_game(won=True, quit=False)
    -                        return
    -                else:
    -                    print(
    -                        f"   (SENSORS SHOW {round(klingon_ship.shield,6)} UNITS REMAINING)"
    -                    )
    +                print(f"   (SENSORS SHOW {round(k[i][2],6)} UNITS REMAINING)")
     
    -        self.klingons_fire()
    +    klingons_fire()
     
    -    def photon_torpedoes(self) -> None:
    -        """Take photon torpedo input and process firing of torpedoes."""
    -        world = self.world
    -        klingon_ships = world.quadrant.klingon_ships
    -        ship = world.ship
    -
    -        if ship.torpedoes <= 0:
    -            print("ALL PHOTON TORPEDOES EXPENDED")
    -            return
    -        if ship.damage_stats[4] < 0:
    -            print("PHOTON TUBES ARE NOT OPERATIONAL")
    -            return
    -
    -        cd = get_user_float("PHOTON TORPEDO COURSE (1-9)? ")
    -        if cd == 9:
    -            cd = 1
    -        if cd < 1 or cd >= 9:
    -            print("ENSIGN CHEKOV REPORTS, 'INCORRECT COURSE DATA, SIR!'")
    -            return
     
    -        cdi = int(cd)
    +def photon_torpedoes() -> None:
    +    # Take photon torpedo input and process firing of torpedoes.
    +    global e, p, k3, k9, k, b3, b9, docked, g, z
     
    -        # Interpolate direction:
    -        dx = dirs[cdi - 1][0] + (dirs[cdi][0] - dirs[cdi - 1][0]) * (cd - cdi)
    -        dy = dirs[cdi - 1][1] + (dirs[cdi][1] - dirs[cdi - 1][1]) * (cd - cdi)
    +    if p <= 0:
    +        print("ALL PHOTON TORPEDOES EXPENDED")
    +        return
    +    if d[4] < 0:
    +        print("PHOTON TUBES ARE NOT OPERATIONAL")
    +        return
     
    -        ship.energy -= 2
    -        ship.torpedoes -= 1
    -
    -        # Exact position
    -        x: float = ship.position.sector.x
    -        y: float = ship.position.sector.y
    -
    -        # Rounded position (to coordinates)
    -        torpedo_x, torpedo_y = x, y
    -        print("TORPEDO TRACK:")
    -        while True:
    -            x += dx
    -            y += dy
    -            torpedo_x, torpedo_y = round(x), round(y)
    -            if torpedo_x < 0 or torpedo_x > 7 or torpedo_y < 0 or torpedo_y > 7:
    -                print("TORPEDO MISSED")
    -                self.klingons_fire()
    -                return
    -            print(f"                {torpedo_x + 1} , {torpedo_y + 1}")
    -            if world.quadrant.get_value(torpedo_x, torpedo_y) != Entity.void:
    -                break
    +    while True:
    +        torpedo_course = input("PHOTON TORPEDO COURSE (1-9)? ")
    +        if len(torpedo_course) > 0:
    +            c1 = float(torpedo_course)
    +            break
    +    if c1 == 9:
    +        c1 = 1
    +    if c1 < 1 or c1 >= 9:
    +        print("ENSIGN CHEKOV REPORTS, 'INCORRECT COURSE DATA, SIR!'")
    +        return
    +
    +    ic1 = int(c1)
    +    x1 = c[ic1 - 1][0] + (c[ic1][0] - c[ic1 - 1][0]) * (c1 - ic1)
    +    e -= 2
    +    p -= 1
    +    x2 = c[ic1 - 1][1] + (c[ic1][1] - c[ic1 - 1][1]) * (c1 - ic1)
    +    x, y = s1, s2
    +    x3, y3 = x, y
    +    print("TORPEDO TRACK:")
    +    while True:
    +        x += x1  # type: ignore
    +        y += x2  # type: ignore
    +        x3, y3 = round(x), round(y)
    +        if x3 < 0 or x3 > 7 or y3 < 0 or y3 > 7:
    +            print("TORPEDO MISSED")
    +            klingons_fire()
    +            return
    +        print(f"                {x3 + 1} , {y3 + 1}")
    +        if not compare_marker(x3, y3, "   "):
    +            break
     
    -        if world.quadrant.get_value(torpedo_x, torpedo_y) == Entity.klingon:
    -            print("*** KLINGON DESTROYED ***")
    -            self.world.quadrant.nb_klingons -= 1
    -            world.remaining_klingons -= 1
    -            if world.remaining_klingons <= 0:
    -                self.end_game(won=True, quit=False)
    -                return
    -            for klingon_ship in klingon_ships:
    -                if (
    -                    torpedo_x == klingon_ship.sector.x
    -                    and torpedo_y == klingon_ship.sector.y
    -                ):
    -                    klingon_ship.shield = 0
    -        elif world.quadrant.get_value(torpedo_x, torpedo_y) == Entity.star:
    -            print(f"STAR AT {torpedo_x + 1} , {torpedo_y + 1} ABSORBED TORPEDO ENERGY.")
    -            self.klingons_fire()
    +    if compare_marker(x3, y3, "+K+"):
    +        print("*** KLINGON DESTROYED ***")
    +        k3 -= 1
    +        k9 -= 1
    +        if k9 <= 0:
    +            end_game(won=True, quit=False)
                 return
    -        elif world.quadrant.get_value(torpedo_x, torpedo_y) == Entity.starbase:
    -            print("*** STARBASE DESTROYED ***")
    -            self.world.quadrant.nb_bases -= 1
    -            world.bases_in_galaxy -= 1
    -            if (
    -                world.bases_in_galaxy == 0
    -                and world.remaining_klingons
    -                <= world.stardate - world.initial_stardate - world.mission_duration
    -            ):
    -                print("THAT DOES IT, CAPTAIN!! YOU ARE HEREBY RELIEVED OF COMMAND")
    -                print("AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!")
    -                self.end_game(won=False)
    -                return
    +        for i in range(3):
    +            if x3 == k[i][0] and y3 == k[i][1]:
    +                k[i][2] = 0
    +    elif compare_marker(x3, y3, " * "):
    +        print(f"STAR AT {x3 + 1} , {y3 + 1} ABSORBED TORPEDO ENERGY.")
    +        klingons_fire()
    +        return
    +    elif compare_marker(x3, y3, ">!<"):
    +        print("*** STARBASE DESTROYED ***")
    +        b3 -= 1
    +        b9 -= 1
    +        if b9 == 0 and k9 <= t - t0 - t9:
    +            print("THAT DOES IT, CAPTAIN!! YOU ARE HEREBY RELIEVED OF COMMAND")
    +            print("AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!")
    +            end_game(won=False)
    +            return
    +        else:
                 print("STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER")
                 print("COURT MARTIAL!")
    -            ship.docked = False
    -
    -        world.quadrant.set_value(torpedo_x, torpedo_y, Entity.void)
    -        world.galaxy_map[ship.position.quadrant.x][
    -            ship.position.quadrant.y
    -        ] = QuadrantData(
    -            self.world.quadrant.nb_klingons,
    -            self.world.quadrant.nb_bases,
    -            self.world.quadrant.nb_stars,
    -        )
    -        world.charted_galaxy_map[ship.position.quadrant.x][
    -            ship.position.quadrant.y
    -        ] = world.galaxy_map[ship.position.quadrant.x][ship.position.quadrant.y]
    -        self.klingons_fire()
    -
    -    def short_range_scan(self) -> None:
    -        """Print a short range scan."""
    -        self.world.ship.docked = False
    -        ship = self.world.ship
    -        for x in (
    -            ship.position.sector.x - 1,
    -            ship.position.sector.x,
    -            ship.position.sector.x + 1,
    -        ):
    -            for y in (
    -                ship.position.sector.y - 1,
    -                ship.position.sector.y,
    -                ship.position.sector.y + 1,
    -            ):
    -                if (
    -                    0 <= x <= 7
    -                    and 0 <= y <= 7
    -                    and self.world.quadrant.get_value(x, y) == Entity.starbase
    -                ):
    -                    ship.docked = True
    -                    cs = "DOCKED"
    -                    ship.refill()
    -                    print("SHIELDS DROPPED FOR DOCKING PURPOSES")
    -                    ship.shields = 0
    -                    break
    -            else:
    -                continue
    -            break
    -        else:
    -            if self.world.quadrant.nb_klingons > 0:
    -                cs = "*RED*"
    -            elif ship.energy < Ship.energy_capacity * 0.1:
    -                cs = "YELLOW"
    -            else:
    -                cs = "GREEN"
    +            docked = False
     
    -        if ship.damage_stats[1] < 0:
    -            print("\n*** SHORT RANGE SENSORS ARE OUT ***\n")
    -            return
    +    insert_marker(x3, y3, "   ")
    +    g[q1][q2] = k3 * 100 + b3 * 10 + s3
    +    z[q1][q2] = g[q1][q2]
    +    klingons_fire()
     
    -        sep = "---------------------------------"
    -        print(sep)
    -        for x in range(8):
    -            line = ""
    -            for y in range(8):
    -                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)}"
    -            elif x == 1:
    -                line += f"        CONDITION          {cs}"
    -            elif x == 2:
    -                line += f"        QUADRANT           {ship.position.quadrant}"
    -            elif x == 3:
    -                line += f"        SECTOR             {ship.position.sector}"
    -            elif x == 4:
    -                line += f"        PHOTON TORPEDOES   {int(ship.torpedoes)}"
    -            elif x == 5:
    -                line += f"        TOTAL ENERGY       {int(ship.energy + ship.shields)}"
    -            elif x == 6:
    -                line += f"        SHIELDS            {int(ship.shields)}"
    -            else:
    -                line += f"        KLINGONS REMAINING {self.world.remaining_klingons}"
     
    -            print(line)
    -        print(sep)
    +def fnd(i):
    +    # Find distance between Enterprise and i'th Klingon warship.
    +    return sqrt((k[i][0] - s1) ** 2 + (k[i][1] - s2) ** 2)
     
    -    def long_range_scan(self) -> None:
    -        """Print a long range scan."""
    -        if self.world.ship.damage_stats[2] < 0:
    -            print("LONG RANGE SENSORS ARE INOPERABLE")
    -            return
     
    -        print(f"LONG RANGE SCAN FOR QUADRANT {self.world.ship.position.quadrant}")
    -        print_scan_results(
    -            self.world.ship.position.quadrant,
    -            self.world.galaxy_map,
    -            self.world.charted_galaxy_map,
    -        )
    +def klingons_fire():
    +    # Process nearby Klingons firing on Enterprise.
    +    global s, k, d
     
    -    def navigation(self) -> None:
    -        """
    -        Take navigation input and move the Enterprise.
    +    if k3 <= 0:
    +        return
    +    if docked:
    +        print("STARBASE SHIELDS PROTECT THE ENTERPRISE")
    +        return
     
    -        1/8 warp goes 1 sector in the direction dirs[course]
    -        """
    -        world = self.world
    -        ship = world.ship
    +    for i in range(3):
    +        if k[i][2] <= 0:
    +            continue
     
    -        cd = get_user_float("COURSE (1-9)? ") - 1  # Convert to 0-8
    -        if cd == len(dirs) - 1:
    -            cd = 0
    -        if cd < 0 or cd >= len(dirs):
    -            print("   LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'")
    +        h = int((k[i][2] / fnd(i)) * (random.random() + 2))
    +        s -= h
    +        k[i][2] /= random.random() + 3
    +        print(f" {h} UNIT HIT ON ENTERPRISE FROM SECTOR {k[i][0] + 1} , {k[i][1] + 1}")
    +        if s <= 0:
    +            end_game(won=False, quit=False, enterprise_killed=True)
                 return
    +        print(f"      ")
    +        if h >= 20 and random.random() < 0.60 and h / s > 0.02:
    +            r1 = fnr()
    +            d[r1] -= h / s + 0.5 * random.random()
    +            print(f"DAMAGE CONTROL REPORTS  '{devices[r1]} DAMAGED BY THE HIT'")
     
    -        warp = get_user_float(
    -            f"WARP FACTOR (0-{'0.2' if ship.damage_stats[0] < 0 else '8'})? "
    -        )
    -        if ship.damage_stats[0] < 0 and warp > 0.2:
    -            print("WARP ENGINES ARE DAMAGED. MAXIMUM SPEED = WARP 0.2")
    -            return
    -        if warp == 0:
    -            return
    -        if warp < 0 or warp > 8:
    -            print(
    -                f"   CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE WARP {warp}!'"
    -            )
    -            return
     
    -        warp_rounds = round(warp * 8)
    -        if ship.energy < warp_rounds:
    -            print("ENGINEERING REPORTS   'INSUFFICIENT ENERGY AVAILABLE")
    -            print(f"                       FOR MANEUVERING AT WARP {warp}!'")
    -            if ship.shields >= warp_rounds - ship.energy and ship.damage_stats[6] >= 0:
    -                print(
    -                    f"DEFLECTOR CONTROL ROOM ACKNOWLEDGES {ship.shields} UNITS OF ENERGY"
    -                )
    -                print("                         PRESENTLY DEPLOYED TO SHIELDS.")
    -            return
    +def shield_control() -> None:
    +    # Raise or lower the shields.
    +    global e, s
     
    -        # klingons move and fire
    -        for klingon_ship in self.world.quadrant.klingon_ships:
    -            if klingon_ship.shield != 0:
    -                world.quadrant.set_value(
    -                    klingon_ship.sector.x, klingon_ship.sector.y, Entity.void
    -                )
    -                (
    -                    klingon_ship.sector.x,
    -                    klingon_ship.sector.y,
    -                ) = world.quadrant.find_empty_place()
    -                world.quadrant.set_value(
    -                    klingon_ship.sector.x, klingon_ship.sector.y, Entity.klingon
    -                )
    +    if d[6] < 0:
    +        print("SHIELD CONTROL INOPERABLE")
    +        return
     
    -        self.klingons_fire()
    +    while True:
    +        energy_to_shield = input(
    +            f"ENERGY AVAILABLE = {e + s} NUMBER OF UNITS TO SHIELDS? "
    +        )
    +        if len(energy_to_shield) > 0:
    +            x = int(energy_to_shield)
    +            break
     
    -        # repair damaged devices and print damage report
    -        line = ""
    -        for i in range(8):
    -            if ship.damage_stats[i] < 0:
    -                ship.damage_stats[i] += min(warp, 1)
    -                if -0.1 < ship.damage_stats[i] < 0:
    -                    ship.damage_stats[i] = -0.1
    -                elif ship.damage_stats[i] >= 0:
    -                    if len(line) == 0:
    -                        line = "DAMAGE CONTROL REPORT:"
    -                    line += f"   {ship.devices[i]} REPAIR COMPLETED\n"
    -        if len(line) > 0:
    -            print(line)
    -        if random.random() <= 0.2:
    -            device = fnr()
    -            if random.random() < 0.6:
    -                ship.damage_stats[device] -= random.random() * 5 + 1
    -                print(f"DAMAGE CONTROL REPORT:   {ship.devices[device]} DAMAGED\n")
    -            else:
    -                ship.damage_stats[device] += random.random() * 3 + 1
    -                print(
    -                    f"DAMAGE CONTROL REPORT:   {ship.devices[device]} STATE OF REPAIR IMPROVED\n"
    -                )
    +    if x < 0 or s == x:
    +        print("")
    +        return
     
    -        self.move_ship(warp_rounds, cd)
    -        world.stardate += 0.1 * int(10 * warp) if warp < 1 else 1
    -        if world.has_mission_ended():
    -            self.end_game(won=False, quit=False)
    -            return
    +    if x > e + s:
    +        print(
    +            "SHIELD CONTROL REPORTS  'THIS IS NOT THE FEDERATION "
    +            "TREASURY.'\n"
    +            ""
    +        )
    +        return
     
    -        self.short_range_scan()
    +    e += s - x
    +    s = x
    +    print("DEFLECTOR CONTROL ROOM REPORT:")
    +    print(f"  'SHIELDS NOW AT {s} UNITS PER YOUR COMMAND.'")
     
    -    def move_ship(self, warp_rounds: int, cd: float) -> None:
    -        assert cd >= 0
    -        assert cd < len(dirs) - 1
    -        # cd is the course data which points to 'dirs'
    -        world = self.world
    -        ship = self.world.ship
    -        world.quadrant.set_value(
    -            int(ship.position.sector.x), int(ship.position.sector.y), Entity.void
    -        )
    -        cdi = int(cd)
    -
    -        # Interpolate direction:
    -        dx = dirs[cdi][0] + (dirs[cdi + 1][0] - dirs[cdi][0]) * (cd - cdi)
    -        dy = dirs[cdi][1] + (dirs[cdi + 1][1] - dirs[cdi][1]) * (cd - cdi)
    -
    -        start_quadrant = Point(ship.position.quadrant.x, ship.position.quadrant.y)
    -        sector_start_x: float = ship.position.sector.x
    -        sector_start_y: float = ship.position.sector.y
    -
    -        for _ in range(warp_rounds):
    -            ship.position.sector.x += dx  # type: ignore
    -            ship.position.sector.y += dy  # type: ignore
    -
    -            if (
    -                ship.position.sector.x < 0
    -                or ship.position.sector.x > 7
    -                or ship.position.sector.y < 0
    -                or ship.position.sector.y > 7
    -            ):
    -                # exceeded quadrant limits; calculate final position
    -                sector_start_x += ship.position.quadrant.x * 8 + warp_rounds * dx
    -                sector_start_y += ship.position.quadrant.y * 8 + warp_rounds * dy
    -                ship.position.quadrant.x = int(sector_start_x / 8)
    -                ship.position.quadrant.y = int(sector_start_y / 8)
    -                ship.position.sector.x = int(
    -                    sector_start_x - ship.position.quadrant.x * 8
    -                )
    -                ship.position.sector.y = int(
    -                    sector_start_y - ship.position.quadrant.y * 8
    -                )
    -                if ship.position.sector.x < 0:
    -                    ship.position.quadrant.x -= 1
    -                    ship.position.sector.x = 7
    -                if ship.position.sector.y < 0:
    -                    ship.position.quadrant.y -= 1
    -                    ship.position.sector.y = 7
    -
    -                hit_edge = False
    -                if ship.position.quadrant.x < 0:
    -                    hit_edge = True
    -                    ship.position.quadrant.x = ship.position.sector.x = 0
    -                if ship.position.quadrant.x > 7:
    -                    hit_edge = True
    -                    ship.position.quadrant.x = ship.position.sector.x = 7
    -                if ship.position.quadrant.y < 0:
    -                    hit_edge = True
    -                    ship.position.quadrant.y = ship.position.sector.y = 0
    -                if ship.position.quadrant.y > 7:
    -                    hit_edge = True
    -                    ship.position.quadrant.y = ship.position.sector.y = 7
    -                if hit_edge:
    -                    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(
    -                        f"  AT SECTOR {ship.position.sector} OF "
    -                        f"QUADRANT {ship.position.quadrant}.'"
    -                    )
    -                    if world.has_mission_ended():
    -                        self.end_game(won=False, quit=False)
    -                        return
    -
    -                stayed_in_quadrant = (
    -                    ship.position.quadrant.x == start_quadrant.x
    -                    and ship.position.quadrant.y == start_quadrant.y
    -                )
    -                if stayed_in_quadrant:
    -                    break
    -                world.stardate += 1
    -                ship.maneuver_energy(warp_rounds)
    -                self.new_quadrant()
    -                return
    -            ship_sector = self.world.ship.position.sector
    -            ship_x = int(ship_sector.x)
    -            ship_y = int(ship_sector.y)
    -            if self.world.quadrant.data[ship_x][ship_y] != Entity.void:
    -                ship_sector.x = int(ship_sector.x - dx)
    -                ship_sector.y = int(ship_sector.y - dy)
    -                print(
    -                    "WARP ENGINES SHUT DOWN AT SECTOR "
    -                    f"{ship_sector} DUE TO BAD NAVIGATION"
    -                )
    -                break
    -        else:
    -            ship.position.sector.x, ship.position.sector.y = int(
    -                ship.position.sector.x
    -            ), int(ship.position.sector.y)
     
    -        world.quadrant.set_value(
    -            int(ship.position.sector.x), int(ship.position.sector.y), Entity.ship
    -        )
    -        ship.maneuver_energy(warp_rounds)
    +def damage_control():
    +    # Print a damage control report.
    +    global d, t
     
    -    def damage_control(self) -> None:
    -        """Print a damage control report."""
    -        ship = self.world.ship
    +    if d[5] < 0:
    +        print("DAMAGE CONTROL REPORT NOT AVAILABLE")
    +    else:
    +        print("\nDEVICE             STATE OF REPAIR")
    +        for r1 in range(8):
    +            print(f"{devices[r1].ljust(26, ' ')}{int(d[r1] * 100) * 0.01:g}")
    +        print()
     
    -        if ship.damage_stats[5] < 0:
    -            print("DAMAGE CONTROL REPORT NOT AVAILABLE")
    -        else:
    -            print("\nDEVICE             STATE OF REPAIR")
    -            for r1 in range(8):
    -                print(
    -                    f"{ship.devices[r1].ljust(26, ' ')}{int(ship.damage_stats[r1] * 100) * 0.01:g}"
    -                )
    -            print()
    +    if not docked:
    +        return
     
    -        if not ship.docked:
    -            return
    +    d3 = sum(0.1 for i in range(8) if d[i] < 0)
    +    if d3 == 0:
    +        return
     
    -        damage_sum = sum(0.1 for i in range(8) if ship.damage_stats[i] < 0)
    -        if damage_sum == 0:
    -            return
    +    d3 += d4
    +    if d3 >= 1:
    +        d3 = 0.9
    +    print("\nTECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;")
    +    print(f"ESTIMATED TIME TO REPAIR: {round(0.01 * int(100 * d3), 2)} STARDATES")
    +    if input("WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)? ").upper().strip() != "Y":
    +        return
     
    -        damage_sum += self.world.quadrant.delay_in_repairs_at_base
    -        if damage_sum >= 1:
    -            damage_sum = 0.9
    -        print("\nTECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;")
    -        print(
    -            f"ESTIMATED TIME TO REPAIR: {round(0.01 * int(100 * damage_sum), 2)} STARDATES"
    -        )
    -        if input("WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)? ").upper().strip() != "Y":
    -            return
    +    for i in range(8):
    +        if d[i] < 0:
    +            d[i] = 0
    +    t += d3 + 0.1
     
    -        for i in range(8):
    -            ship.damage_stats[i] = max(ship.damage_stats[i], 0)
    -        self.world.stardate += damage_sum + 0.1
     
    -    def computer(self) -> None:
    -        """Perform the various functions of the library computer."""
    -        world = self.world
    -        ship = world.ship
    +def computer() -> None:
    +    # Perform the various functions of the library computer.
    +    global d, z, k9, t0, t9, t, b9, s1, s2, b4, b5
     
    -        if ship.damage_stats[7] < 0:
    -            print("COMPUTER DISABLED")
    +    if d[7] < 0:
    +        print("COMPUTER DISABLED")
    +        return
    +
    +    while True:
    +        command = input("COMPUTER ACTIVE AND AWAITING COMMAND? ")
    +        if len(command) == 0:
    +            com = 6
    +        else:
    +            com = int(command)
    +        if com < 0:
                 return
     
    -        while True:
    -            command = input("COMPUTER ACTIVE AND AWAITING COMMAND? ")
    -            if len(command) == 0:
    -                com = 6
    +        print()
    +
    +        if com == 0 or com == 5:
    +            if com == 5:
    +                print("                        THE GALAXY")
                 else:
    -                try:
    -                    com = int(command)
    -                except ValueError:
    -                    com = 6
    -            if com < 0:
    -                return
    +                print(
    +                    "\n        COMPUTER RECORD OF GALAXY FOR "
    +                    f"QUADRANT {q1 + 1} , {q2 + 1}\n"
    +                )
     
    -            print()
    +            print("       1     2     3     4     5     6     7     8")
    +            sep = "     ----- ----- ----- ----- ----- ----- ----- -----"
    +            print(sep)
    +
    +            for i in range(8):
    +                line = " " + str(i + 1) + " "
     
    -            if com in {0, 5}:
                     if com == 5:
    -                    print("                        THE GALAXY")
    +                    g2s = quadrant_name(i, 0, True)
    +                    line += (" " * int(12 - 0.5 * len(g2s))) + g2s
    +                    g2s = quadrant_name(i, 4, True)
    +                    line += (" " * int(39 - 0.5 * len(g2s) - len(line))) + g2s
                     else:
    -                    print(
    -                        "\n        COMPUTER RECORD OF GALAXY FOR "
    -                        f"QUADRANT {ship.position.quadrant}\n"
    -                    )
    -
    -                print("       1     2     3     4     5     6     7     8")
    -                sep = "     ----- ----- ----- ----- ----- ----- ----- -----"
    +                    for j in range(8):
    +                        line += "   "
    +                        if z[i][j] == 0:
    +                            line += "***"
    +                        else:
    +                            line += str(z[i][j] + 1000)[-3:]
    +
    +                print(line)
                     print(sep)
     
    -                for i in range(8):
    -                    line = f" {str(i + 1)} "
    -
    -                    if com == 5:
    -                        g2s = Quadrant.quadrant_name(i, 0, True)
    -                        line += (" " * int(12 - 0.5 * len(g2s))) + g2s
    -                        g2s = Quadrant.quadrant_name(i, 4, True)
    -                        line += (" " * int(39 - 0.5 * len(g2s) - len(line))) + g2s
    -                    else:
    -                        for j in range(8):
    -                            line += "   "
    -                            if world.charted_galaxy_map[i][j].num() == 0:
    -                                line += "***"
    -                            else:
    -                                line += str(
    -                                    world.charted_galaxy_map[i][j].num() + 1000
    -                                )[-3:]
    -
    -                    print(line)
    -                    print(sep)
    -
    -                print()
    -            elif com == 1:
    -                print("   STATUS REPORT:")
    -                print(
    -                    f"KLINGON{'S' if world.remaining_klingons > 1 else ''} LEFT: {world.remaining_klingons}"
    -                )
    +            print()
    +            return
    +        elif com == 1:
    +            print("   STATUS REPORT:")
    +            print(f"KLINGON{'S' if k9 > 1 else ''} LEFT: {k9}")
    +            print(
    +                "MISSION MUST BE COMPLETED IN "
    +                f"{round(0.1 * int((t0+t9-t) * 10), 1)} STARDATES"
    +            )
    +
    +            if b9 == 0:
    +                print("YOUR STUPIDITY HAS LEFT YOU ON YOUR OWN IN")
    +                print("  THE GALAXY -- YOU HAVE NO STARBASES LEFT!")
    +            else:
                     print(
    -                    "MISSION MUST BE COMPLETED IN "
    -                    f"{round(0.1 * int(world.remaining_time() * 10), 1)} STARDATES"
    +                    f"THE FEDERATION IS MAINTAINING {b9} "
    +                    f"STARBASE{'S' if b9 > 1 else ''} IN THE GALAXY"
                     )
     
    -                if world.bases_in_galaxy == 0:
    -                    print("YOUR STUPIDITY HAS LEFT YOU ON YOUR OWN IN")
    -                    print("  THE GALAXY -- YOU HAVE NO STARBASES LEFT!")
    -                else:
    -                    print(
    -                        f"THE FEDERATION IS MAINTAINING {world.bases_in_galaxy} "
    -                        f"STARBASE{'S' if world.bases_in_galaxy > 1 else ''} IN THE GALAXY"
    -                    )
    -
    -                self.damage_control()
    -            elif com == 2:
    -                if self.world.quadrant.nb_klingons <= 0:
    -                    print(
    -                        "SCIENCE OFFICER SPOCK REPORTS  'SENSORS SHOW NO ENEMY "
    -                        "SHIPS\n"
    -                        "                                IN THIS QUADRANT'"
    -                    )
    -                    return
    -
    +            damage_control()
    +            return
    +        elif com == 2:
    +            if k3 <= 0:
                     print(
    -                    f"FROM ENTERPRISE TO KLINGON BATTLE CRUISER{'S' if self.world.quadrant.nb_klingons > 1 else ''}"
    +                    "SCIENCE OFFICER SPOCK REPORTS  'SENSORS SHOW NO ENEMY "
    +                    "SHIPS\n"
    +                    "                                IN THIS QUADRANT'"
                     )
    +                return
     
    -                for klingon_ship in self.world.quadrant.klingon_ships:
    -                    if klingon_ship.shield > 0:
    -                        print_direction(
    -                            Point(ship.position.sector.x, ship.position.sector.y),
    -                            Point(
    -                                int(klingon_ship.sector.x),
    -                                int(klingon_ship.sector.y),
    -                            ),
    -                        )
    -            elif com == 3:
    -                if self.world.quadrant.nb_bases == 0:
    -                    print(
    -                        "MR. SPOCK REPORTS,  'SENSORS SHOW NO STARBASES IN THIS "
    -                        "QUADRANT.'"
    -                    )
    -                    return
    +            print(f"FROM ENTERPRISE TO KLINGON BATTLE CRUISER{'S' if k3 > 1 else ''}")
     
    -                print("FROM ENTERPRISE TO STARBASE:")
    -                print_direction(
    -                    Point(ship.position.sector.x, ship.position.sector.y),
    -                    self.world.quadrant.starbase,
    -                )
    -            elif com == 4:
    -                print("DIRECTION/DISTANCE CALCULATOR:")
    -                print(
    -                    f"YOU ARE AT QUADRANT {ship.position.quadrant} "
    -                    f"SECTOR {ship.position.sector}"
    -                )
    -                print("PLEASE ENTER")
    -                while True:
    -                    coordinates = input("  INITIAL COORDINATES (X,Y)? ").split(",")
    -                    if len(coordinates) == 2:
    -                        from1, from2 = int(coordinates[0]) - 1, int(coordinates[1]) - 1
    -                        if 0 <= from1 <= 7 and 0 <= from2 <= 7:
    -                            break
    -                while True:
    -                    coordinates = input("  FINAL COORDINATES (X,Y)? ").split(",")
    -                    if len(coordinates) == 2:
    -                        to1, to2 = int(coordinates[0]) - 1, int(coordinates[1]) - 1
    -                        if 0 <= to1 <= 7 and 0 <= to2 <= 7:
    -                            break
    -                print_direction(Point(from1, from2), Point(to1, to2))
    -            else:
    +            for i in range(3):
    +                if k[i][2] > 0:
    +                    print_direction(s1, s2, k[i][0], k[i][1])
    +            return
    +        elif com == 3:
    +            if b3 == 0:
                     print(
    -                    "FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:\n"
    -                    "   0 = CUMULATIVE GALACTIC RECORD\n"
    -                    "   1 = STATUS REPORT\n"
    -                    "   2 = PHOTON TORPEDO DATA\n"
    -                    "   3 = STARBASE NAV DATA\n"
    -                    "   4 = DIRECTION/DISTANCE CALCULATOR\n"
    -                    "   5 = GALAXY 'REGION NAME' MAP\n"
    +                    "MR. SPOCK REPORTS,  'SENSORS SHOW NO STARBASES IN THIS "
    +                    "QUADRANT.'"
                     )
    +                return
     
    -    def end_game(
    -        self, won: bool = False, quit: bool = True, enterprise_killed: bool = False
    -    ) -> None:
    -        """Handle end-of-game situations."""
    -        if won:
    -            print("CONGRATULATIONS, CAPTAIN! THE LAST KLINGON BATTLE CRUISER")
    -            print("MENACING THE FEDERATION HAS BEEN DESTROYED.\n")
    -            print(
    -                f"YOUR EFFICIENCY RATING IS {round(1000 * (self.world.remaining_klingons / (self.world.stardate - self.world.initial_stardate))**2, 4)}\n\n"
    -            )
    +            print("FROM ENTERPRISE TO STARBASE:")
    +            print_direction(s1, s2, b4, b5)
    +            return
    +        elif com == 4:
    +            print("DIRECTION/DISTANCE CALCULATOR:")
    +            print(f"YOU ARE AT QUADRANT {q1+1} , {q2+1} SECTOR {s1+1} , {s2+1}")
    +            print("PLEASE ENTER")
    +            while True:
    +                coordinates = input("  INITIAL COORDINATES (X,Y)? ").split(",")
    +                if len(coordinates) == 2:
    +                    from1, from2 = int(coordinates[0]) - 1, int(coordinates[1]) - 1
    +                    if 0 <= from1 <= 7 and 0 <= from2 <= 7:
    +                        break
    +            while True:
    +                coordinates = input("  FINAL COORDINATES (X,Y)? ").split(",")
    +                if len(coordinates) == 2:
    +                    to1, to2 = int(coordinates[0]) - 1, int(coordinates[1]) - 1
    +                    if 0 <= to1 <= 7 and 0 <= to2 <= 7:
    +                        break
    +            print_direction(from1, from2, to1, to2)
    +            return
             else:
    -            if not quit:
    -                if enterprise_killed:
    -                    print(
    -                        "\nTHE ENTERPRISE HAS BEEN DESTROYED. THE FEDERATION "
    -                        "WILL BE CONQUERED."
    -                    )
    -                print(f"IT IS STARDATE {round(self.world.stardate, 1)}")
    -
                 print(
    -                f"THERE WERE {self.world.remaining_klingons} KLINGON BATTLE CRUISERS LEFT AT"
    +                "FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:\n"
    +                "   0 = CUMULATIVE GALACTIC RECORD\n"
    +                "   1 = STATUS REPORT\n"
    +                "   2 = PHOTON TORPEDO DATA\n"
    +                "   3 = STARBASE NAV DATA\n"
    +                "   4 = DIRECTION/DISTANCE CALCULATOR\n"
    +                "   5 = GALAXY 'REGION NAME' MAP\n"
                 )
    -            print("THE END OF YOUR MISSION.\n\n")
    -
    -            if self.world.bases_in_galaxy == 0:
    -                sys.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'? ").upper().strip() != "AYE":
    -            sys.exit()
    -        self.restart = True
    -
    -
    -klingon_shield_strength: Final = 200
    -# 8 sectors = 1 quadrant
    -dirs: Final = [  # (down-up, left,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)
    -]  # vectors in cardinal directions
    -
     
    -def fnr() -> int:
    -    """Generate a random integer from 0 to 7 inclusive."""
    -    return random.randint(0, 7)
     
    -
    -def print_scan_results(
    -    quadrant: Point,
    -    galaxy_map: List[List[QuadrantData]],
    -    charted_galaxy_map: List[List[QuadrantData]],
    -) -> None:
    -    sep = "-------------------"
    -    print(sep)
    -    for x in (quadrant.x - 1, quadrant.x, quadrant.x + 1):
    -        n: List[Optional[int]] = [None, None, None]
    -
    -        # Reveal parts of the current map
    -        for y in (quadrant.y - 1, quadrant.y, quadrant.y + 1):
    -            if 0 <= x <= 7 and 0 <= y <= 7:
    -                n[y - quadrant.y + 1] = galaxy_map[x][y].num()
    -                charted_galaxy_map[x][y] = galaxy_map[x][y]
    -
    -        line = ": "
    -        for line_col in n:
    -            if line_col is None:
    -                line += "*** : "
    -            else:
    -                line += str(line_col + 1000).rjust(4, " ")[-3:] + " : "
    -        print(line)
    -        print(sep)
    -
    -
    -def print_direction(source: Point, to: Point) -> None:
    -    """Print direction and distance between two locations in the grid."""
    -    delta1 = -(to.x - source.x)  # flip so positive is up (heading = 3)
    -    delta2 = to.y - source.y
    +def print_direction(from1, from2, to1, to2) -> None:
    +    # Print direction and distance between two locations in the grid.
    +    delta1 = -(to1 - from1)  # flip so positive is up (heading = 3)
    +    delta2 = to2 - from2
     
         if delta2 > 0:
             if delta1 < 0:
    @@ -1119,11 +773,12 @@ def print_direction(source: Point, to: Point) -> None:
             else:
                 base = 1
                 delta1, delta2 = delta2, delta1
    -    elif delta1 > 0:
    -        base = 3
         else:
    -        base = 5
    -        delta1, delta2 = delta2, delta1
    +        if delta1 > 0:
    +            base = 3
    +        else:
    +            base = 5
    +            delta1, delta2 = delta2, delta1
     
         delta1, delta2 = abs(delta1), abs(delta2)
     
    @@ -1136,32 +791,212 @@ def print_direction(source: Point, to: Point) -> None:
         print(f"DISTANCE = {round(sqrt(delta1 ** 2 + delta2 ** 2), 6)}")
     
     
    +# -------------------------------------------------------------------------
    +#  Game transitions
    +# -------------------------------------------------------------------------
    +
    +
    +def startup() -> None:
    +    # Initialize the game variables and map, and print startup messages.
    +    global g, z, d, t, t0, t9, docked, e, e0, p, p0, s, k9, b9, s9, c
    +    global devices, q1, q2, s1, s2, k7
    +
    +    print(
    +        "\n\n\n\n\n\n\n\n\n\n\n"
    +        "                                    ,------*------,\n"
    +        "                    ,-------------   '---  ------'\n"
    +        "                     '-------- --'      / /\n"
    +        "                         ,---' '-------/ /--,\n"
    +        "                          '----------------'\n\n"
    +        "                    THE USS ENTERPRISE --- NCC-1701\n"
    +        "\n\n\n\n"
    +    )
    +
    +    # set up global game variables
    +    g = [[0] * 8 for _ in range(8)]  # galaxy map
    +    z = [[0] * 8 for _ in range(8)]  # charted galaxy map
    +    d = [0] * 8  # damage stats for devices
    +    t = t0 = 100 * random.randint(20, 39)  # stardate (current, initial)
    +    t9 = random.randint(25, 34)  # mission duration (stardates)
    +    docked = False  # true when docked at starbase
    +    e = e0 = 3000  # energy (current, initial)
    +    p = p0 = 10  # torpedoes (current, initial)
    +    s = 0  # shields
    +    k9, b9 = 0, 0  # total Klingons, bases in galaxy
    +    # ^ bug in original, was b9 = 2
    +    s9 = 200  # avg. Klingon shield strength
    +
    +    c = [
    +        [0, 1],
    +        [-1, 1],
    +        [-1, 0],
    +        [-1, -1],
    +        [0, -1],
    +        [1, -1],
    +        [1, 0],
    +        [1, 1],
    +        [0, 1],
    +    ]  # vectors in cardinal directions
    +
    +    devices = [
    +        "WARP ENGINES",
    +        "SHORT RANGE SENSORS",
    +        "LONG RANGE SENSORS",
    +        "PHASER CONTROL",
    +        "PHOTON TUBES",
    +        "DAMAGE CONTROL",
    +        "SHIELD CONTROL",
    +        "LIBRARY-COMPUTER",
    +    ]
    +
    +    # initialize Enterprise's position
    +    q1, q2 = fnr(), fnr()  # Enterprise's quadrant
    +    s1, s2 = fnr(), fnr()  # ...and sector
    +
    +    # initialize contents of galaxy
    +    for i in range(8):
    +        for j in range(8):
    +            k3 = 0
    +            r1 = random.random()
    +
    +            if r1 > 0.98:
    +                k3 = 3
    +            elif r1 > 0.95:
    +                k3 = 2
    +            elif r1 > 0.80:
    +                k3 = 1
    +            k9 += k3
    +
    +            b3 = 0
    +            if random.random() > 0.96:
    +                b3 = 1
    +                b9 += 1
    +            g[i][j] = k3 * 100 + b3 * 10 + fnr() + 1
    +
    +    if k9 > t9:
    +        t9 = k9 + 1
    +
    +    if b9 == 0:  # original has buggy extra code here
    +        b9 = 1
    +        g[q1][q2] += 10
    +        q1, q2 = fnr(), fnr()
    +
    +    k7 = k9  # Klingons at start of game
    +
    +    print(
    +        "YOUR ORDERS ARE AS FOLLOWS:\n"
    +        f"     DESTROY THE {k9} KLINGON WARSHIPS WHICH HAVE INVADED\n"
    +        "   THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS\n"
    +        f"   ON STARDATE {t0+t9}. THIS GIVES YOU {t9} DAYS. THERE "
    +        f"{'IS' if b9 == 1 else 'ARE'}\n"
    +        f"   {b9} STARBASE{'' if b9 == 1 else 'S'} IN THE GALAXY FOR "
    +        "RESUPPLYING YOUR SHIP.\n"
    +    )
    +
    +
    +def new_quadrant() -> None:
    +    # Enter a new quadrant: populate map and print a short range scan.
    +    global z, k3, b3, s3, d4, k, qs, b4, b5
    +
    +    k3 = b3 = s3 = 0  # Klingons, bases, stars in quad.
    +    d4 = 0.5 * random.random()  # extra delay in repairs at base
    +    z[q1][q2] = g[q1][q2]
    +
    +    if 0 <= q1 <= 7 and 0 <= q2 <= 7:
    +        quad = quadrant_name(q1, q2, False)
    +        if t == t0:
    +            print("\nYOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED")
    +            print(f"IN THE GALACTIC QUADRANT, '{quad}'.\n")
    +        else:
    +            print(f"\nNOW ENTERING {quad} QUADRANT . . .\n")
    +
    +        k3 = g[q1][q2] // 100
    +        b3 = g[q1][q2] // 10 - 10 * k3
    +        s3 = g[q1][q2] - 100 * k3 - 10 * b3
    +
    +        if k3 != 0:
    +            print("COMBAT AREA      CONDITION RED")
    +            if s <= 200:
    +                print("   SHIELDS DANGEROUSLY LOW")
    +
    +    k = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]  # Klingons in current quadrant
    +    qs = " " * 192  # quadrant string
    +
    +    # build quadrant string
    +    insert_marker(s1, s2, "<*>")
    +    for i in range(k3):
    +        r1, r2 = find_empty_place()
    +        insert_marker(r1, r2, "+K+")
    +        k[i] = [r1, r2, s9 * (0.5 + random.random())]
    +    if b3 > 0:
    +        b4, b5 = find_empty_place()  # position of starbase (sector)
    +        insert_marker(b4, b5, ">!<")
    +    for _ in range(s3):
    +        r1, r2 = find_empty_place()
    +        insert_marker(r1, r2, " * ")
    +
    +    short_range_scan()
    +
    +
    +def end_game(
    +    won: bool = False, quit: bool = True, enterprise_killed: bool = False
    +) -> None:
    +    # Handle end-of-game situations.
    +    global restart
    +
    +    if won:
    +        print("CONGRATULATIONS, CAPTAIN! THE LAST KLINGON BATTLE CRUISER")
    +        print("MENACING THE FEDERATION HAS BEEN DESTROYED.\n")
    +        print(f"YOUR EFFICIENCY RATING IS {round(1000 * (k7 / (t - t0))**2, 4)}\n\n")
    +    else:
    +        if not quit:
    +            if enterprise_killed:
    +                print(
    +                    "\nTHE ENTERPRISE HAS BEEN DESTROYED. THE FEDERATION "
    +                    "WILL BE CONQUERED."
    +                )
    +            print(f"IT IS STARDATE {round(t, 1)}")
    +
    +        print(f"THERE WERE {k9} KLINGON BATTLE CRUISERS LEFT AT")
    +        print("THE END OF YOUR MISSION.\n\n")
    +
    +        if b9 == 0:
    +            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'? ").upper().strip() != "AYE":
    +        exit()
    +    restart = True
    +
    +
    +# -------------------------------------------------------------------------
    +#  Entry point and main game loop
    +# -------------------------------------------------------------------------
    +
    +
     def main() -> None:
    -    game = Game()
    -    world = game.world
    -    ship = world.ship
    +    global restart
     
         f: Dict[str, Callable[[], None]] = {
    -        "NAV": game.navigation,
    -        "SRS": game.short_range_scan,
    -        "LRS": game.long_range_scan,
    -        "PHA": game.phaser_control,
    -        "TOR": game.photon_torpedoes,
    -        "SHE": ship.shield_control,
    -        "DAM": game.damage_control,
    -        "COM": game.computer,
    -        "XXX": game.end_game,
    +        "NAV": navigation,
    +        "SRS": short_range_scan,
    +        "LRS": long_range_scan,
    +        "PHA": phaser_control,
    +        "TOR": photon_torpedoes,
    +        "SHE": shield_control,
    +        "DAM": damage_control,
    +        "COM": computer,
    +        "XXX": end_game,
         }
     
         while True:
    -        game.startup()
    -        game.new_quadrant()
    +        startup()
    +        new_quadrant()
             restart = False
     
             while not restart:
    -            if ship.shields + ship.energy <= 10 or (
    -                ship.energy <= 10 and ship.damage_stats[6] != 0
    -            ):
    +            if s + e <= 10 or (e <= 10 and d[6] != 0):
                     print(
                         "\n** FATAL ERROR **   YOU'VE JUST STRANDED YOUR SHIP "
                         "IN SPACE.\nYOU HAVE INSUFFICIENT MANEUVERING ENERGY, "
    diff --git a/84_Super_Star_Trek/python/superstartrekins.py b/84_Super_Star_Trek/python/superstartrekins.py
    index 6060ad9d4..333bb2e41 100644
    --- a/84_Super_Star_Trek/python/superstartrekins.py
    +++ b/84_Super_Star_Trek/python/superstartrekins.py
    @@ -8,7 +8,7 @@
     """
     
     
    -def get_yes_no(prompt: str) -> bool:
    +def get_yes_no(prompt):
         response = input(prompt).upper()
         return response[0] != "N"
     
    @@ -17,13 +17,13 @@ def print_header() -> None:
         for _ in range(12):
             print()
         t10 = " " * 10
    -    print(f"{t10}*************************************")
    -    print(f"{t10}*                                   *")
    -    print(f"{t10}*                                   *")
    -    print(f"{t10}*      * * SUPER STAR TREK * *      *")
    -    print(f"{t10}*                                   *")
    -    print(f"{t10}*                                   *")
    -    print(f"{t10}*************************************")
    +    print(t10 + "*************************************")
    +    print(t10 + "*                                   *")
    +    print(t10 + "*                                   *")
    +    print(t10 + "*      * * SUPER STAR TREK * *      *")
    +    print(t10 + "*                                   *")
    +    print(t10 + "*                                   *")
    +    print(t10 + "*************************************")
         for _ in range(8):
             print()
     
    diff --git a/84_Super_Star_Trek/python/test_superstartrek.py b/84_Super_Star_Trek/python/test_superstartrek.py
    new file mode 100644
    index 000000000..ab553fcb6
    --- /dev/null
    +++ b/84_Super_Star_Trek/python/test_superstartrek.py
    @@ -0,0 +1,11 @@
    +import io
    +
    +import pytest
    +from superstartrek import main
    +
    +
    +def test_main(monkeypatch, capsys):
    +    monkeypatch.setattr("sys.stdin", io.StringIO("NAV\n1\n1\nSRS\nXXX\nXXX\n"))
    +    with pytest.raises(SystemExit):
    +        main()
    +    # captured = capsys.readouterr()
    diff --git a/84_Super_Star_Trek/rust/Cargo.lock b/84_Super_Star_Trek/rust/Cargo.lock
    deleted file mode 100644
    index 71bbf0c8c..000000000
    --- a/84_Super_Star_Trek/rust/Cargo.lock
    +++ /dev/null
    @@ -1,169 +0,0 @@
    -# 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/84_Super_Star_Trek/rust/Cargo.toml b/84_Super_Star_Trek/rust/Cargo.toml
    deleted file mode 100644
    index 01457249b..000000000
    --- a/84_Super_Star_Trek/rust/Cargo.toml
    +++ /dev/null
    @@ -1,10 +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]
    -ctrlc = "3.2.5"
    -rand = "0.8.5"
    diff --git a/84_Super_Star_Trek/rust/readme.md b/84_Super_Star_Trek/rust/readme.md
    deleted file mode 100644
    index ae2f58dc3..000000000
    --- a/84_Super_Star_Trek/rust/readme.md
    +++ /dev/null
    @@ -1,19 +0,0 @@
    -# Super Star Trek - Rust version
    -
    -Explanation of modules:
    -
    -- [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
    diff --git a/84_Super_Star_Trek/rust/src/commands.rs b/84_Super_Star_Trek/rust/src/commands.rs
    deleted file mode 100644
    index c1c4bc8d4..000000000
    --- a/84_Super_Star_Trek/rust/src/commands.rs
    +++ /dev/null
    @@ -1,543 +0,0 @@
    -use rand::Rng;
    -
    -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) {
    -        view::scanners_out();
    -        return;
    -    }
    -
    -    view::short_range_scan(&galaxy)
    -}
    -
    -pub fn get_amount_and_set_shields(galaxy: &mut Galaxy, provided: Vec) {
    -
    -    if galaxy.enterprise.damaged.contains_key(systems::SHIELD_CONTROL) {
    -        view::inoperable(&systems::name_for(systems::SHIELD_CONTROL));
    -        return;
    -    }
    -
    -    view::energy_available(galaxy.enterprise.total_energy);
    -    let value = input::param_or_prompt_value(&provided, 0, view::prompts::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, view::prompts::COURSE, 1.0, 9.0);
    -    if course.is_none() {
    -        view::bad_course_data();
    -        return;
    -    }
    -
    -    let course = course.unwrap();
    -
    -    let mut max_warp = 8.0;
    -    if galaxy.enterprise.damaged.contains_key(systems::WARP_ENGINES) {
    -        max_warp = 0.2;
    -    }
    -
    -    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_course_data();
    -        return;
    -    }
    -    
    -    let speed = speed.unwrap();
    -
    -    if speed > max_warp {
    -        view::damaged_engines(max_warp, speed);
    -        return;
    -    }
    -
    -    klingons_move(galaxy);
    -    klingons_fire(galaxy);
    -
    -    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;
    -    }
    -
    -    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);
    -        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: f32, warp_speed: f32, galaxy: &mut Galaxy) {
    -
    -    let ship = &mut galaxy.enterprise;
    -
    -    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;
    -        }
    -    }
    -
    -    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 {
    -        view::insuffient_warp_energy(warp_speed);
    -        return
    -    }
    -
    -    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 != 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();
    -            if ship.shields <= 200 {
    -                view::danger_shields();
    -            }
    -        }
    -    }
    -
    -    ship.quadrant = end_quadrant;
    -    ship.sector = end_sector;
    -
    -    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 - energy_cost;
    -        if ship.shields > ship.total_energy {
    -            view::divert_energy_from_shields();
    -            ship.shields = ship.total_energy;
    -        }
    -    }
    -
    -    view::short_range_scan(&galaxy)
    -}
    -
    -fn find_nav_path(start_quadrant: Pos, start_sector: Pos, course: f32, warp_speed: f32) -> (Vec, bool) {
    -
    -    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_sector.as_galactic_sector(start_quadrant);
    -    let mut path = Vec::new();
    -    let mut hit_edge;
    -
    -    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);
    -
    -        distance -= 1;
    -        if distance == 0 {
    -            break;
    -        }
    -    }
    -  
    -    (path, hit_edge)
    -}
    -
    -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) {
    -    let quadrant = &mut galaxy.quadrants[galaxy.enterprise.quadrant.as_index()];
    -    for k in 0..quadrant.klingons.len() {
    -        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;
    -    }
    -}
    -
    -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 run_damage_control(galaxy: &Galaxy) {
    -    if galaxy.enterprise.damaged.contains_key(systems::DAMAGE_CONTROL) {
    -        view::inoperable(&systems::name_for(systems::DAMAGE_CONTROL));
    -        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;
    -    }
    -
    -    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(view::prompts::REPAIR) {
    -        return;
    -    }
    -
    -    ship.damaged.clear();
    -    galaxy.stardate += repair_time;
    -    view::damage_control(&ship);
    -}
    -
    -pub fn perform_long_range_scan(galaxy: &mut Galaxy) {
    -    if galaxy.enterprise.damaged.contains_key(systems::LONG_RANGE_SCAN) {
    -        view::inoperable(&systems::name_for(systems::LONG_RANGE_SCAN));
    -        return;
    -    }
    -
    -    let seen = view::long_range_scan(galaxy);
    -    for pos in seen {
    -        galaxy.scanned.insert(pos);
    -    }
    -}
    -
    -pub fn access_computer(galaxy: &Galaxy, provided: Vec) {
    -    if galaxy.enterprise.damaged.contains_key(systems::COMPUTER) {
    -        view::inoperable(&systems::name_for(systems::COMPUTER));
    -        return;
    -    }
    -
    -    let operation : i32;
    -    loop {
    -        let entered = input::param_or_prompt_value(&provided, 0, view::prompts::COMPUTER, 0, 5);
    -        if entered.is_none() {
    -            view::computer_options();
    -        } else {
    -            operation = entered.unwrap();
    -            break;
    -        }
    -    } 
    -    
    -    match operation {
    -        0 => view::galaxy_scanned_map(galaxy),
    -        1 => {
    -            view::status_report(galaxy);
    -            run_damage_control(galaxy);
    -        },
    -        2 => show_klingon_direction_data(galaxy),
    -        3 => show_starbase_direction_data(galaxy),
    -        4 => direction_dist_calculator(galaxy),
    -        5 => view::galaxy_region_map(),
    -        _ => () // unreachable
    -    }
    -}
    -
    -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 => {
    -            view::no_local_starbase();
    -            return;
    -        },
    -        Some(s) => {
    -            view::starbase_report();
    -            let origin = galaxy.enterprise.sector;
    -            let target = s.sector;
    -            view::direction_distance(origin.direction(target), origin.dist(target))
    -        }
    -    }
    -}
    -
    -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));
    -        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, view::prompts::PHASERS, 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;
    -
    -    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);
    -}
    -
    -pub fn gather_dir_and_launch_torpedo(galaxy: &mut Galaxy, provided: Vec) {
    -    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 ship.photon_torpedoes == 0 {
    -        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;
    -    }
    -
    -    ship.photon_torpedoes -= 1;
    -    view::torpedo_track();
    -
    -    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/input.rs b/84_Super_Star_Trek/rust/src/input.rs
    deleted file mode 100644
    index 62d4daee9..000000000
    --- a/84_Super_Star_Trek/rust/src/input.rs
    +++ /dev/null
    @@ -1,73 +0,0 @@
    -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_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 {
    -        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 {
    -    let mut res: Option = None;
    -    if params.len() > param_pos {
    -        match params[param_pos].parse::() {
    -            Ok(n) if (n >= min && n <= max) => res = Some(n),
    -            _ => ()
    -        }
    -    }
    -    if res.is_some() {
    -        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/main.rs b/84_Super_Star_Trek/rust/src/main.rs
    deleted file mode 100644
    index 4c1a277ef..000000000
    --- a/84_Super_Star_Trek/rust/src/main.rs
    +++ /dev/null
    @@ -1,70 +0,0 @@
    -use std::process::exit;
    -
    -use input::{prompt, prompt_yes_no};
    -use model::{Galaxy, systems};
    -
    -mod input;
    -mod model;
    -mod commands;
    -mod view;
    -
    -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;
    -    
    -    view::enterprise();
    -    view::intro(&galaxy);
    -    let _ = input::prompt(view::prompts::WHEN_READY);
    -
    -    view::starting_quadrant(galaxy.enterprise.quadrant);
    -    view::short_range_scan(&galaxy);
    -
    -    loop {
    -        let command = input::prompt(view::prompts::COMMAND);
    -        if command.len() == 0 {
    -            continue;
    -        }
    -        match command[0].to_uppercase().as_str() { // order is weird because i built it in this order :)
    -            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(&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()),
    -            systems::TORPEDOES => commands::gather_dir_and_launch_torpedo(&mut galaxy, command[1..].into()),
    -            systems::RESIGN => galaxy.enterprise.destroyed = true,
    -            _ => view::print_command_help()
    -        }
    -
    -        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();
    -                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;
    -        }
    -    }
    -}
    diff --git a/84_Super_Star_Trek/rust/src/model.rs b/84_Super_Star_Trek/rust/src/model.rs
    deleted file mode 100644
    index aa08d7345..000000000
    --- a/84_Super_Star_Trek/rust/src/model.rs
    +++ /dev/null
    @@ -1,355 +0,0 @@
    -use std::{ops::{Mul, Add}, fmt::Display, collections::{HashMap, HashSet}};
    -
    -use rand::Rng;
    -
    -use crate::view;
    -
    -pub struct Galaxy {
    -    pub stardate: f32,
    -    pub final_stardate: f32,
    -    pub quadrants: Vec,
    -    pub scanned: HashSet,
    -    pub enterprise: Enterprise
    -}
    -
    -pub struct Quadrant {
    -    pub stars: Vec,
    -    pub star_base: Option,
    -    pub klingons: Vec
    -}
    -
    -pub struct StarBase {
    -    pub sector: Pos,
    -    pub repair_delay: f32,
    -}
    -
    -pub struct Klingon {
    -    pub sector: Pos,
    -    pub 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 {
    -    pub destroyed: bool,
    -    pub damaged: HashMap,
    -    pub quadrant: Pos,
    -    pub sector: Pos,
    -    pub photon_torpedoes: u8,
    -    pub total_energy: u16,
    -    pub shields: u16,
    -}
    -impl Enterprise {
    -    fn take_hit(&mut self, sector: Pos, hit_strength: u16) {
    -        if self.destroyed {
    -            return;
    -        }
    -        
    -        view::enterprise_hit(&hit_strength, sector);
    -
    -        if self.shields <= hit_strength {
    -            view::enterprise_destroyed();
    -            self.destroyed = true;
    -            return;
    -        }
    -
    -        self.shields -= hit_strength;
    -
    -        view::shields_hit(self.shields);
    -        
    -        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::KEYS[rng.gen_range(0..systems::KEYS.len())].to_string();
    -        let damage = hit_past_shield + rng.gen::() * 0.5;
    -        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.1 {
    -            self.damaged.remove(system);
    -            return true;
    -        }
    -    
    -        self.damaged.entry(system.to_string()).and_modify(|d| *d += amount);
    -        return false;
    -    }
    -
    -    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;
    -        }
    -        return false;
    -    }
    -}
    -
    -pub mod systems {
    -
    -    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 LONG_RANGE_SCAN: &str = "LRS";
    -    pub const COMPUTER: &str = "COM";
    -    pub const PHASERS: &str = "PHA";
    -    pub const TORPEDOES: &str = "TOR";
    -
    -    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 {
    -        match key {
    -            SHORT_RANGE_SCAN => "Short Range Scanners".into(),
    -            WARP_ENGINES => "Warp Engines".into(),
    -            SHIELD_CONTROL => "Shield Control".into(),
    -            DAMAGE_CONTROL => "Damage Control".into(),
    -            LONG_RANGE_SCAN => "Long Range Scanners".into(),
    -            COMPUTER => "Library-Computer".into(),
    -            PHASERS => "Phaser Control".into(),
    -            TORPEDOES => "Photon Tubes".into(),
    -            _ => "Unknown".into()
    -        }
    -    }
    -}
    -
    -#[derive(PartialEq, Clone, Copy, Debug, Hash, Eq)]
    -pub struct Pos(pub u8, pub u8);
    -
    -impl Pos {
    -    pub fn as_index(&self) -> usize {
    -        (self.0 * 8 + self.1).into()
    -    }
    -
    -    pub fn abs_diff(&self, other: Pos) -> u8 {
    -        self.0.abs_diff(other.0) + self.1.abs_diff(other.1)
    -    }
    -
    -    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() 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 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)
    -    }
    -
    -    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 {
    -    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 {
    -        write!(f, "{} , {}", self.0 + 1, self.1 + 1)
    -    }
    -}
    -
    -pub const COURSES : [(f32, f32); 9] = [
    -    (0., 1.),
    -    (-1., 1.),
    -    (-1., 0.),
    -    (-1., -1.),
    -    (0., -1.),
    -    (1., -1.),
    -    (1., 0.),
    -    (1., 1.),
    -    (0., 1.), // course 9 is equal to course 1
    -];
    -
    -#[derive(PartialEq)]
    -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;
    -        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 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);
    -
    -        Galaxy { 
    -            stardate,
    -            final_stardate: stardate + rng.gen_range(25..=35) as f32,
    -            quadrants, 
    -            scanned,
    -            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();
    -        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(StarBase { sector: quadrant.find_empty_sector(), repair_delay: rng.gen::() * 0.5 });
    -            }
    -
    -            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(), energy: rng.gen_range(100..=300) as f32 });
    -                }
    -
    -            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(sector) {
    -            SectorStatus::StarBase
    -        } else if self.has_klingon(sector) {
    -            SectorStatus::Klingon
    -        } else {
    -            SectorStatus::Empty
    -        }
    -    }
    -
    -    fn is_starbase(&self, sector: Pos) -> bool {
    -        match &self.star_base {
    -            None => false,
    -            Some(p) => p.sector == sector
    -        }
    -    }
    -
    -    fn has_klingon(&self, sector: Pos) -> bool {
    -        let klingons = &self.klingons;
    -        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 {
    -        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
    -            }
    -        }
    -    }
    -
    -    pub fn docked_at_starbase(&self, enterprise_sector: Pos) -> bool {
    -        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
    deleted file mode 100644
    index caf6b74d2..000000000
    --- a/84_Super_Star_Trek/rust/src/view.rs
    +++ /dev/null
    @@ -1,635 +0,0 @@
    -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";
    -    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 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)
    -    }
    -}
    -
    -pub fn title() {
    -    println!("
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -          *************************************
    -          *                                   *
    -          *                                   *
    -          *      * * SUPER STAR TREK * *      *
    -          *                                   *
    -          *                                   *
    -          *************************************
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -    ");
    -}
    -
    -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!("
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -                                    ,------*------,
    -                    ,-------------   '---  ------'
    -                     '-------- --'      / /
    -                         ,---' '-------/ /--,
    -                          '----------------'
    -
    -                    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();
    -    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 {:.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)
    -}
    -
    -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 >> 2)) as usize],
    -        SUB_REGION_NAMES[(quadrant.1 % 4) as usize])
    -}
    -
    -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) {
    -    println!("\nNow entering {} quadrant . . .\n", quadrant_name(quadrant))
    -}
    -
    -pub fn short_range_scan(model: &Galaxy) {
    -    let quadrant = &model.quadrants[model.enterprise.quadrant.as_index()];
    -    let mut condition = "GREEN";
    -    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";
    -    }
    -
    -    let data : [String; 8] = [
    -        format!("Stardate           {:.1}", model.stardate),
    -        format!("Condition          {}", 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 x in 0..=7 {
    -        for y 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[x 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 {:.1}.
    -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_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) {
    -    println!("{hit_strength} unit hit on Enterprise from sector {from_sector}");
    -}
    -
    -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 {}.'", sector, quadrant);
    -}
    -
    -pub fn condition_red() {
    -    println!("COMBAT AREA      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.")
    -}
    -
    -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.'")
    -}
    -
    -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} !'")
    -}
    -
    -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.")
    -}
    -
    -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;
    -    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 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();
    -
    -            if y >= 0 && y < 8 && x >= 0 && x < 8 {
    -                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.as_ref().map_or("0", |_| "1");
    -                stars = format!("{}", quadrant.stars.len());
    -            }
    -
    -            print!(": {}{}{} ", klingons, star_bases, stars)
    -        }
    -        println!(":");
    -        println!("{:-^19}", "");
    -    } 
    -
    -    seen
    -}
    -
    -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!!")
    -}
    -
    -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]);
    -    }    
    -}
    -
    -pub 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 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()];
    -                print!(" {}{}{}  ", quadrant.klingons.len(), quadrant.star_base.as_ref().map_or("0", |_| "1"), quadrant.stars.len())
    -            } else {
    -                print!(" ***  ");
    -            }
    -        }
    -        println!(
    -"\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")
    -}
    -
    -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:.1} 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!("*** Klingon destroyed ***")
    -}
    -
    -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'")
    -}
    -
    -pub fn no_torpedoes_remaining() {
    -    println!("All photon torpedoes expended")
    -}
    -
    -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!!")
    -    }
    -}
    -
    -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:'")
    -}
    -
    -pub fn direction_distance(dir: f32, dist: u8) {
    -    println!(
    -"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:.1} 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")
    -}
    -
    -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/85_Synonym/python/synonym.py b/85_Synonym/python/synonym.py
    index 0680bb78a..6d1636e6c 100644
    --- a/85_Synonym/python/synonym.py
    +++ b/85_Synonym/python/synonym.py
    @@ -53,7 +53,7 @@ def print_right() -> None:
         print(random.choice(right_words))
     
     
    -def ask_question(question_number: int) -> None:
    +def ask_question(question_number):
         words = synonym_words[question_number]
         clues = words[:]
         base_word = clues.pop(0)
    diff --git a/85_Synonym/rust/Cargo.lock b/85_Synonym/rust/Cargo.lock
    deleted file mode 100644
    index 4fe2abbea..000000000
    --- a/85_Synonym/rust/Cargo.lock
    +++ /dev/null
    @@ -1,75 +0,0 @@
    -# 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/85_Synonym/rust/Cargo.toml b/85_Synonym/rust/Cargo.toml
    deleted file mode 100644
    index 3b1d02f52..000000000
    --- a/85_Synonym/rust/Cargo.toml
    +++ /dev/null
    @@ -1,9 +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]
    -rand = "0.8.5"
    diff --git a/85_Synonym/rust/README.md b/85_Synonym/rust/README.md
    deleted file mode 100644
    index 4c54b94cb..000000000
    --- a/85_Synonym/rust/README.md
    +++ /dev/null
    @@ -1,3 +0,0 @@
    -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
    deleted file mode 100644
    index 184f51bd9..000000000
    --- a/85_Synonym/rust/src/main.rs
    +++ /dev/null
    @@ -1,102 +0,0 @@
    -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
    -////////////////////////////////////////////////////////////
    diff --git a/86_Target/csharp/Target.csproj b/86_Target/csharp/Target.csproj
    index 9f0cf96b8..ea8ff5263 100644
    --- a/86_Target/csharp/Target.csproj
    +++ b/86_Target/csharp/Target.csproj
    @@ -2,7 +2,7 @@
     
       
         Exe
    -    net6.0
    +    net5.0
       
     
       
    diff --git a/86_Target/perl/README.md b/86_Target/perl/README.md
    index eca6b9fa7..e69c8b819 100644
    --- a/86_Target/perl/README.md
    +++ b/86_Target/perl/README.md
    @@ -1,9 +1,3 @@
     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.
    diff --git a/86_Target/perl/target.pl b/86_Target/perl/target.pl
    deleted file mode 100644
    index cb552a39d..000000000
    --- a/86_Target/perl/target.pl
    +++ /dev/null
    @@ -1,107 +0,0 @@
    -#!/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";
    -}
    diff --git a/86_Target/python/target.py b/86_Target/python/target.py
    index 122c82d11..f10f0a567 100644
    --- a/86_Target/python/target.py
    +++ b/86_Target/python/target.py
    @@ -8,7 +8,6 @@
     
     import math
     import random
    -from typing import List
     
     PAGE_WIDTH = 64
     
    @@ -42,7 +41,7 @@ def print_instructions() -> None:
         print()
     
     
    -def prompt() -> List[float]:
    +def prompt():
         while True:
             response = input("INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE? ")
             if "," not in response:
    @@ -55,14 +54,14 @@ def prompt() -> List[float]:
             return [float(t) for t in terms]
     
     
    -def next_target() -> None:
    +def next_target():
         for _ in range(5):
             print()
         print("NEXT TARGET...")
         print()
     
     
    -def describe_miss(x, y, z, x1, y1, z1, d) -> None:
    +def describe_miss(x, y, z, x1, y1, z1, d):
         x2 = x1 - x
         y2 = y1 - y
         z2 = z1 - z
    @@ -89,7 +88,7 @@ def describe_miss(x, y, z, x1, y1, z1, d) -> None:
         print()
     
     
    -def do_shot_loop(p1, x, y, z) -> None:
    +def do_shot_loop(p1, x, y, z):
         shot_count = 0
         while True:
             shot_count += 1
    @@ -138,11 +137,11 @@ def do_shot_loop(p1, x, y, z) -> None:
                 describe_miss(x, y, z, x1, y1, z1, distance)
     
     
    -def show_radians(a, b) -> None:
    +def show_radians(a, b):
         print(f"RADIANS FROM X AXIS = {a:.4f}   FROM Z AXIS = {b:.4f}")
     
     
    -def play_game() -> None:
    +def play_game():
         while True:
             a = random.uniform(0, 2 * math.pi)  # random angle
             b = random.uniform(0, 2 * math.pi)  # random angle
    diff --git a/87_3-D_Plot/rust/Cargo.lock b/87_3-D_Plot/rust/Cargo.lock
    deleted file mode 100644
    index b21cc6a2d..000000000
    --- a/87_3-D_Plot/rust/Cargo.lock
    +++ /dev/null
    @@ -1,7 +0,0 @@
    -# 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
    deleted file mode 100644
    index 7d75412a6..000000000
    --- a/87_3-D_Plot/rust/Cargo.toml
    +++ /dev/null
    @@ -1,6 +0,0 @@
    -[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
    deleted file mode 100644
    index ebd66dfa2..000000000
    --- a/87_3-D_Plot/rust/src/main.rs
    +++ /dev/null
    @@ -1,68 +0,0 @@
    -/** 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/88_3-D_Tic-Tac-Toe/README.md b/88_3-D_Tic-Tac-Toe/README.md
    index 2ab13480d..969de3d83 100644
    --- a/88_3-D_Tic-Tac-Toe/README.md
    +++ b/88_3-D_Tic-Tac-Toe/README.md
    @@ -15,8 +15,6 @@ 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 6f1cbe64e..0057619fb 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]] = 5;
    +    xa[ma[i][j]] = s;
         m = ma[i][j];
         print("MACHINE TAKES");
         show_square(m);
    diff --git a/88_3-D_Tic-Tac-Toe/python/qubit.py b/88_3-D_Tic-Tac-Toe/python/qubit.py
    index e0dd531e8..4081e70d3 100644
    --- a/88_3-D_Tic-Tac-Toe/python/qubit.py
    +++ b/88_3-D_Tic-Tac-Toe/python/qubit.py
    @@ -1,11 +1,10 @@
    -#!/usr/bin/env python3
    +#!/usr/bin/python3
     
     # Ported from the BASIC source for 3D Tic Tac Toe
     # in BASIC Computer Games, by David H. Ahl
     # The code originated from Dartmouth College
     
     from enum import Enum
    -from typing import Optional, Tuple, Union
     
     
     class Move(Enum):
    @@ -32,7 +31,8 @@ class Player(Enum):
     class TicTacToe3D:
         """The game logic for 3D Tic Tac Toe and the machine opponent"""
     
    -    def __init__(self) -> None:
    +    def __init__(self):
    +
             # 4x4x4 board keeps track of which player occupies each place
             # and used by machine to work out its strategy
             self.board = [0] * 64
    @@ -120,7 +120,7 @@ def __init__(self) -> None:
                 [12, 25, 38, 51],
             ]
     
    -    def get(self, x, y, z) -> Player:
    +    def get(self, x, y, z):
             m = self.board[4 * (4 * z + y) + x]
             if m == 40:
                 return Player.MACHINE
    @@ -129,81 +129,88 @@ def get(self, x, y, z) -> Player:
             else:
                 return Player.EMPTY
     
    -    def move_3d(self, x, y, z, player) -> bool:
    +    def move3D(self, x, y, z, player):
             m = 4 * (4 * z + y) + x
             return self.move(m, player)
     
    -    def move(self, m, player) -> bool:
    +    def move(self, m, player):
             if self.board[m] > 1:
                 return False
     
    -        self.board[m] = 40 if player == Player.MACHINE else 8
    +        if player == Player.MACHINE:
    +            self.board[m] = 40
    +        else:
    +            self.board[m] = 8
             return True
     
    -    def get_3d_position(self, m) -> Tuple[int, int, int]:
    +    def get3DPosition(self, m):
             x = m % 4
             y = (m // 4) % 4
             z = m // 16
             return x, y, z
     
    -    def evaluate_lines(self) -> None:
    +    def evaluateLines(self):
             self.lineValues = [0] * 76
             for j in range(76):
    -            value = sum(self.board[self.lines[j][k]] for k in range(4))
    +            value = 0
    +            for k in range(4):
    +                value += self.board[self.lines[j][k]]
                 self.lineValues[j] = value
     
    -    def strategy_mark_line(self, i) -> None:
    +    def strategyMarkLine(self, i):
             for j in range(4):
                 m = self.lines[i][j]
                 if self.board[m] == 0:
                     self.board[m] = 1
     
    -    def clear_strategy_marks(self) -> None:
    +    def clearStrategyMarks(self):
             for i in range(64):
                 if self.board[i] == 1:
                     self.board[i] = 0
     
    -    def mark_and_move(self, vlow, vhigh, vmove) -> Optional[Tuple[Move, int]]:
    +    def markAndMove(self, vlow, vhigh, vmove):
             """
             mark lines that can potentially win the game for the human
             or the machine and choose best place to play
             """
             for i in range(76):
    -            value = sum(self.board[self.lines[i][j]] for j in range(4))
    +            value = 0
    +            for j in range(4):
    +                value += self.board[self.lines[i][j]]
                 self.lineValues[i] = value
                 if vlow <= value < vhigh:
                     if value > vlow:
    -                    return self.move_triple(i)
    -                self.strategy_mark_line(i)
    -        self.evaluate_lines()
    +                    return self.moveTriple(i)
    +                self.strategyMarkLine(i)
    +        self.evaluateLines()
     
             for i in range(76):
                 value = self.lineValues[i]
    -            if value in [4, vmove]:
    -                return self.move_diagonals(i, 1)
    +            if value == 4 or value == vmove:
    +                return self.moveDiagonals(i, 1)
             return None
     
    -    def machine_move(self) -> Union[None, Tuple[Move, int], Tuple[Move, int, int]]:
    +    def machineMove(self):
             """machine works out what move to play"""
    -        self.clear_strategy_marks()
    +        self.clearStrategyMarks()
     
    -        self.evaluate_lines()
    +        self.evaluateLines()
             for value, event in [
    -            (32, self.human_win),
    -            (120, self.machine_win),
    -            (24, self.block_human_win),
    +            (32, self.humanWin),
    +            (120, self.machineWin),
    +            (24, self.blockHumanWin),
             ]:
                 for i in range(76):
                     if self.lineValues[i] == value:
                         return event(i)
     
    -        m = self.mark_and_move(80, 88, 43)
    +        m = self.markAndMove(80, 88, 43)
             if m is not None:
                 return m
     
    -        self.clear_strategy_marks()
    +        self.clearStrategyMarks()
     
    -        m = self.mark_and_move(16, 24, 11)
    +        m = self.markAndMove(16, 24, 11)
             if m is not None:
                 return m
     
    @@ -215,49 +222,56 @@ def machine_move(self) -> Union[None, Tuple[Move, int], Tuple[Move, int, int]]:
                 if (32 <= value < 40) or (72 <= value < 80):
                     for s in [1, 0]:
                         for i in range(4 * k, 4 * k + 4):
    -                        m = self.move_diagonals(i, s)
    +                        m = self.moveDiagonals(i, s)
                             if m is not None:
                                 return m
     
    -        self.clear_strategy_marks()
    +        self.clearStrategyMarks()
     
             for y in self.corners:
                 if self.board[y] == 0:
                     return (Move.MOVES, y)
     
    -        return next(
    -            ((Move.LIKES, i) for i in range(64) if self.board[i] == 0),
    -            (Move.DRAW, -1),
    -        )
    +        for i in range(64):
    +            if self.board[i] == 0:
    +                return (Move.LIKES, i)
    +
    +        return (Move.DRAW, -1)
     
    -    def human_win(self, i) -> Tuple[Move, int, int]:
    +    def humanWin(self, i):
             return (Move.HUMAN_WIN, -1, i)
     
    -    def machine_win(self, i) -> Optional[Tuple[Move, int, int]]:
    +    def machineWin(self, i):
             for j in range(4):
                 m = self.lines[i][j]
                 if self.board[m] == 0:
                     return (Move.MACHINE_WIN, m, i)
             return None
     
    -    def block_human_win(self, i) -> Optional[Tuple[Move, int]]:
    +    def blockHumanWin(self, i):
             for j in range(4):
                 m = self.lines[i][j]
                 if self.board[m] == 0:
                     return (Move.NICE_TRY, m)
             return None
     
    -    def move_triple(self, i) -> Tuple[Move, int]:
    +    def moveTriple(self, i):
             """make two lines-of-3 or prevent human from doing this"""
             for j in range(4):
                 m = self.lines[i][j]
                 if self.board[m] == 1:
    -                return (Move.YOU_FOX, m) if self.lineValues[i] < 40 else (Move.GET_OUT, m)
    +                if self.lineValues[i] < 40:
    +                    return (Move.YOU_FOX, m)
    +                else:
    +                    return (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]]:
    -        jrange = [1, 2] if 0 < (i % 4) < 3 else [0, 3]
    +    def moveDiagonals(self, i, s):
    +        if 0 < (i % 4) < 3:
    +            jrange = [1, 2]
    +        else:
    +            jrange = [0, 3]
             for j in jrange:
                 m = self.lines[i][j]
                 if self.board[m] == s:
    @@ -266,15 +280,15 @@ def move_diagonals(self, i, s) -> Optional[Tuple[Move, int]]:
     
     
     class Qubit:
    -    def move_code(self, board, m) -> str:
    -        x, y, z = board.get_3d_position(m)
    +    def moveCode(self, board, m):
    +        x, y, z = board.get3DPosition(m)
             return f"{z + 1:d}{y + 1:d}{x + 1:d}"
     
    -    def show_win(self, board, i) -> None:
    +    def showWin(self, board, i):
             for m in board.lines[i]:
    -            print(self.move_code(board, m))
    +            print(self.moveCode(board, m))
     
    -    def show_board(self, board) -> None:
    +    def showBoard(self, board):
             c = " YM"
             for z in range(4):
                 for y in range(4):
    @@ -285,21 +299,21 @@ def show_board(self, board) -> None:
                     print("\n")
                 print("\n")
     
    -    def human_move(self, board) -> bool:
    -        print()
    +    def humanMove(self, board):
    +        print("")
             c = "1234"
             while True:
                 h = input("Your move?\n")
                 if h == "1":
                     return False
                 if h == "0":
    -                self.show_board(board)
    +                self.showBoard(board)
                     continue
                 if (len(h) == 3) and (h[0] in c) and (h[1] in c) and (h[2] in c):
                     x = c.find(h[2])
                     y = c.find(h[1])
                     z = c.find(h[0])
    -                if board.move_3d(x, y, z, Player.HUMAN):
    +                if board.move3D(x, y, z, Player.HUMAN):
                         break
     
                     print("That square is used. Try again.")
    @@ -308,7 +322,7 @@ def human_move(self, board) -> bool:
     
             return True
     
    -    def play(self) -> None:
    +    def play(self):
             print("Qubic\n")
             print("Create Computing Morristown, New Jersey\n\n\n")
             while True:
    @@ -342,7 +356,7 @@ def play(self) -> None:
                         break
                     print("Incorrect answer. Please type 'yes' or 'no'.")
     
    -            skip_human = s[0] in "nN"
    +            skipHuman = s[0] in "nN"
     
                 move_text = [
                     "Machine moves to",
    @@ -354,19 +368,22 @@ def play(self) -> None:
                 ]
     
                 while True:
    -                if not skip_human and not self.human_move(board):
    +                if not skipHuman and not self.humanMove(board):
                         break
    -                skip_human = False
    +                skipHuman = False
     
    -                m = board.machine_move()
    -                assert m is not None
    +                m = board.machineMove()
                     if m[0] == Move.HUMAN_WIN:
                         print("You win as follows,")
    -                    self.show_win(board, m[2])  # type: ignore
    +                    self.showWin(board, m[2])
                         break
                     elif m[0] == Move.MACHINE_WIN:
    -                    print(f"Machine moves to {self.move_code(board, m[1])}, and wins as follows")
    -                    self.show_win(board, m[2])  # type: ignore
    +                    print(
    +                        "Machine moves to {}, and wins as follows".format(
    +                            self.moveCode(board, m[1])
    +                        )
    +                    )
    +                    self.showWin(board, m[2])
                         break
                     elif m[0] == Move.DRAW:
                         print("The game is a draw.")
    @@ -376,10 +393,10 @@ def play(self) -> None:
                         break
                     else:
                         print(move_text[m[0].value - Move.MOVES.value])
    -                    print(self.move_code(board, m[1]))
    +                    print(self.moveCode(board, m[1]))
                         board.move(m[1], Player.MACHINE)
     
    -                self.show_board(board)
    +                self.showBoard(board)
     
                 print(" ")
                 while True:
    diff --git a/89_Tic-Tac-Toe/python/TicTacToe_Hard.py b/89_Tic-Tac-Toe/python/TicTacToe_Hard.py
    index 8b3e50ab9..400ec7f1b 100644
    --- a/89_Tic-Tac-Toe/python/TicTacToe_Hard.py
    +++ b/89_Tic-Tac-Toe/python/TicTacToe_Hard.py
    @@ -1,16 +1,15 @@
    -from typing import List, Tuple, Union
    -
    -
     class TicTacToe:
    -    def __init__(self, pick, sz=3) -> None:
    +    def __init__(self, pick, sz=3):
             self.pick = pick
             self.dim_sz = sz
             self.board = self.clear_board()
     
    -    def clear_board(self) -> List[List[str]]:
    -        return [["blur" for _ in range(self.dim_sz)] for _ in range(self.dim_sz)]
    +    def clear_board(self):
    +        board = [["blur" for i in range(self.dim_sz)] for j in range(self.dim_sz)]
    +        # made a 3x3 by-default board
    +        return board
     
    -    def move_record(self, r, c) -> Union[str, bool]:
    +    def move_record(self, r, c):
             if r > self.dim_sz or c > self.dim_sz:
                 return "Out of Bounds"
             if self.board[r][c] != "blur":
    @@ -18,7 +17,7 @@ def move_record(self, r, c) -> Union[str, bool]:
             self.board[r][c] = self.pick
             return True
     
    -    def check_win(self) -> int:  # 1 you won, 0 computer won, -1 tie
    +    def check_win(self):  # 1 you won, 0 computer won, -1 tie
             # Flag syntax -> first player no. ,
             # User is Player#1 ;
             # Check set 1 -> row and '\' diagonal & Check set 2 -> col and '/' diagonal
    @@ -84,12 +83,17 @@ def check_win(self) -> int:  # 1 you won, 0 computer won, -1 tie
     
             if flag11 or flag12:
                 return 1
    -        return 0 if flag21 or flag22 else -1
    +        if flag21 or flag22:
    +            return 0
    +
    +        return -1
     
    -    def next_move(self) -> Union[Tuple[int, int], Tuple[List[int], List[int]]]:
    +    def next_move(self):
             available_moves = []  # will carry all available moves
             player_win_spot = []  # if player (user Wins)
    -        comp_pick = "X" if self.pick == "O" else "O"
    +        comp_pick = "O"
    +        if self.pick == "O":
    +            comp_pick = "X"
             for i in range(0, self.dim_sz):
                 for j in range(0, self.dim_sz):
     
    @@ -106,16 +110,18 @@ def next_move(self) -> Union[Tuple[int, int], Tuple[List[int], List[int]]]:
                             player_win_spot.append(t)
                         self.board[i][j] = "blur"
     
    -        if player_win_spot:
    +        if len(player_win_spot) != 0:
                 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]
    +        # print(AvailableMoves)
             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 not available_moves:
    +        if len(available_moves) == 0:
                 return -1, -1
     
             c1, c2 = self.dim_sz // 2, self.dim_sz // 2
    +        # print(c1,c2,self.dim_sz)
             if (c1, c2) in available_moves:  # CENTER
                 self.board[c1][c2] = comp_pick
                 return c1, c2
    @@ -157,30 +163,34 @@ def next_move(self) -> Union[Tuple[int, int], Tuple[List[int], List[int]]]:
                     ) in available_moves:  # RIGHT TOP TO RIGHT BOTTOM
                         self.board[c1 - gap + i][c2 + gap] = comp_pick
                         return c1 - gap + i, c2 + gap
    -        raise RuntimeError("No moves available")
     
     
    -def display(game: TicTacToe) -> None:
    +def display(Game: TicTacToe) -> None:
         line1 = ""
    -    for i in range(0, game.dim_sz):
    -        for j in range(0, game.dim_sz - 1):
    -            if game.board[i][j] == "blur":
    -                line1 = f"{line1}    |"
    +    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 + "    |"
                 else:
    -                line1 = f"{line1}  {game.board[i][j]} |"
    -        if game.board[i][game.dim_sz - 1] == "blur":
    +                line1 = line1 + "  " + Game.board[i][j] + " |"
    +        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 = line1 + "  " + Game.board[i][Game.dim_sz - 1] + " \n"
    +        # line1 = line1 + " " + Game.board[i][Game.dim_sz-1] + "\n"
         print(line1, "\n\n")
     
     
    -def main() -> None:
    -    pick = input("Pick 'X' or 'O' ").strip().upper()
    -    game = TicTacToe("O") if pick == "O" else TicTacToe("X")
    -    display(game=game)
    +def play() -> None:
    +    Pick = input("Pick 'X' or 'O' ").strip().upper()
    +    if Pick == "O":
    +        Game = TicTacToe("O")
    +    else:
    +        Game = TicTacToe("X")
    +    display(Game=Game)
         while True:
    -        temp: Union[bool, str] = False
    +        # Display(Game)
    +        temp = False
             while not temp:
                 move = list(
                     map(
    @@ -188,25 +198,25 @@ def main() -> None:
                         input("Make A Move in Grid System from (0,0) to (2,2) ").split(),
                     )
                 )
    -            temp = game.move_record(move[0], move[1])
    +            temp = Game.move_record(move[0], move[1])
                 if not temp:
                     print(temp)
     
    -        if game.check_win() == 1:
    +        if Game.check_win() == 1:
                 print("You Won!")
                 break
             print("Your Move:- ")
    -        display(game)
    -        C1, C2 = game.next_move()
    +        display(Game)
    +        C1, C2 = Game.next_move()
             if C1 == -1 and C2 == -1:
                 print("Game Tie!")
                 break
    -        if game.check_win() == 0:
    +        if Game.check_win() == 0:
                 print("You lost!")
                 break
             print("Computer's Move :-")
    -        display(game)
    +        display(Game)
     
     
     if __name__ == "__main__":
    -    main()
    +    play()
    diff --git a/89_Tic-Tac-Toe/python/tictactoe2.py b/89_Tic-Tac-Toe/python/tictactoe2.py
    index e6fce18a2..519cd7d31 100755
    --- a/89_Tic-Tac-Toe/python/tictactoe2.py
    +++ b/89_Tic-Tac-Toe/python/tictactoe2.py
    @@ -52,15 +52,14 @@ def line_170(board, g, h, j, k):
     
     def line_150(board, g, h, j, k):
         if board[k] != g:  # line 150
    -        return (
    -            -1
    -            if (
    -                board[k] == h  # line 160
    -                or board[k + 6] != g  # line 161
    -                or board[k + 3] != g
    -            )
    -            else k + 3
    -        )
    +        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
         elif board[k + 6] != g:  # line 152
             if board[k + 6] != 0 or board[k + 3] != g:  # line 165
                 return -1  # Goto 170
    @@ -71,7 +70,16 @@ def line_150(board, g, h, j, k):
     
     
     def line_120(board, g, h, j, k):
    -    pass
    +    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
     
     
     def line_118(board, g, h):
    @@ -115,13 +123,12 @@ def think(board, g, h, moves):
     def render_board(board, space_mapping):
         vertical_divider = "!"
         horizontal_divider = "---+---+---"
    -    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])),
    -    ]
    +    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]))
         return "\n".join(lines)
     
     
    @@ -184,7 +191,7 @@ def prompt_player(board):
             return move
     
     
    -def main() -> None:
    +def play():
         print(" " * 30 + "TIC-TAC-TOE")
         print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
         print("\n\n")
    @@ -240,4 +247,4 @@ def main() -> None:
     
     
     if __name__ == "__main__":
    -    main()
    +    play()
    diff --git a/89_Tic-Tac-Toe/rust/Cargo.lock b/89_Tic-Tac-Toe/rust/Cargo.lock
    deleted file mode 100644
    index b21cc6a2d..000000000
    --- a/89_Tic-Tac-Toe/rust/Cargo.lock
    +++ /dev/null
    @@ -1,7 +0,0 @@
    -# 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/lua/tower.lua b/90_Tower/lua/tower.lua
    deleted file mode 100644
    index b86539a48..000000000
    --- a/90_Tower/lua/tower.lua
    +++ /dev/null
    @@ -1,268 +0,0 @@
    -print [[
    -            
    -            TOWERS
    -CREATIVE COMPUTING  MORRISTOWN, NEW JERSY
    -
    -
    -]]
    -
    -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()
    diff --git a/90_Tower/python/test_tower.py b/90_Tower/python/test_tower.py
    new file mode 100644
    index 000000000..3fa4771b6
    --- /dev/null
    +++ b/90_Tower/python/test_tower.py
    @@ -0,0 +1,49 @@
    +import unittest
    +
    +import tower
    +
    +
    +class TowerTestCase(unittest.TestCase):
    +    def test_something(self):
    +        t = tower.Tower()
    +        self.assertTrue(t.empty())
    +
    +        d = tower.Disk(3)
    +        t.add(d)
    +        self.assertFalse(t.empty())
    +
    +        d5 = tower.Disk(5)
    +        self.assertRaises(Exception, t.add, d5)
    +        self.assertFalse(t.empty())
    +
    +    def test_oksize(self):
    +        t = tower.Tower()
    +        self.assertTrue(t.empty())
    +
    +        d5 = tower.Disk(5)
    +        t.add(d5)
    +        self.assertFalse(t.empty())
    +
    +        d3 = tower.Disk(3)
    +        t.add(d3)
    +        self.assertFalse(t.empty())
    +
    +        self.assertEqual(t.top(), d3)
    +        self.assertEqual(t.pop(), d3)
    +        self.assertEqual(t.pop(), d5)
    +
    +    def test_game(self):
    +        g = tower.Game()
    +        self.assertEqual(g.moves(), 0)
    +        self.assertFalse(g.winner())
    +
    +    def test_format(self):
    +        t = tower.Tower()
    +        d3 = tower.Disk(3)
    +        d5 = tower.Disk(5)
    +        t.add(d5)
    +        t.add(d3)
    +
    +
    +if __name__ == "__main__":
    +    unittest.main()
    diff --git a/90_Tower/python/tower.py b/90_Tower/python/tower.py
    index d0059e86f..982f8bb32 100644
    --- a/90_Tower/python/tower.py
    +++ b/90_Tower/python/tower.py
    @@ -1,50 +1,51 @@
     import sys
    -from typing import List, Optional
     
     
     class Disk:
    -    def __init__(self, size: int) -> None:
    +    def __init__(self, size):
             self.__size = size
     
    -    def size(self) -> int:
    +    def size(self):
             return self.__size
     
         def print(self) -> None:
    -        print(f"[ {self.size()} ]")
    +        print("[ %s ]" % self.size())
     
     
     class Tower:
    -    def __init__(self) -> None:
    -        self.__disks: List[Disk] = []
    +    def __init__(self):
    +        self.__disks = []
     
    -    def empty(self) -> bool:
    +    def empty(self):
             return len(self.__disks) == 0
     
    -    def top(self) -> Optional[Disk]:
    -        return None if self.empty() else self.__disks[-1]
    +    def top(self):
    +        if self.empty():
    +            return None
    +        else:
    +            return self.__disks[-1]
     
    -    def add(self, disk: Disk) -> None:
    +    def add(self, disk):
             if not self.empty():
                 t = self.top()
    -            assert t is not None  # cannot happen as it's not empty
                 if disk.size() > t.size():
                     raise Exception(
                         "YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE, IT MIGHT CRUSH IT!"
                     )
             self.__disks.append(disk)
     
    -    def pop(self) -> Disk:
    +    def pop(self):
             if self.empty():
                 raise Exception("empty pop")
             return self.__disks.pop()
     
         def print(self) -> None:
    -        r = f'Needle: [{", ".join([str(x.size()) for x in self.__disks])}]'
    +        r = "Needle: [%s]" % (", ".join([str(x.size()) for x in self.__disks]))
             print(r)
     
     
     class Game:
    -    def __init__(self) -> None:
    +    def __init__(self):
             # use fewer sizes to make debugging easier
             # self.__sizes = [3, 5, 7]  # ,9,11,13,15]
             self.__sizes = [3, 5, 7, 9, 11, 13, 15]
    @@ -59,23 +60,23 @@ def __init__(self) -> None:
                 disk = Disk(size)
                 self.__towers[0].add(disk)
     
    -    def winner(self) -> bool:
    +    def winner(self):
             return self.__towers[0].empty() and self.__towers[1].empty()
     
         def print(self) -> None:
             for t in self.__towers:
                 t.print()
     
    -    def moves(self) -> int:
    +    def moves(self):
             return self.__moves
     
    -    def which_disk(self) -> int:
    +    def which_disk(self):
             w = int(input("WHICH DISK WOULD YOU LIKE TO MOVE\n"))
             if w in self.__sizes:
                 return w
             raise Exception()
     
    -    def pick_disk(self) -> Optional[Tower]:
    +    def pick_disk(self):
             which = None
             while which is None:
                 try:
    @@ -84,7 +85,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
    @@ -92,7 +93,7 @@ def pick_disk(self) -> Optional[Tower]:
                 assert valids[0].top().size() == which
                 return valids[0]
     
    -    def which_tower(self) -> Optional[Tower]:
    +    def which_tower(self):
             try:
                 needle = int(input("PLACE DISK ON WHICH NEEDLE\n"))
                 tower = self.__towers[needle - 1]
    @@ -104,7 +105,7 @@ def which_tower(self) -> Optional[Tower]:
             else:
                 return tower
     
    -    def take_turn(self) -> None:
    +    def take_turn(self):
             from_tower = None
             while from_tower is None:
                 from_tower = self.pick_disk()
    diff --git a/90_Tower/rust/Cargo.lock b/90_Tower/rust/Cargo.lock
    deleted file mode 100644
    index b21cc6a2d..000000000
    --- a/90_Tower/rust/Cargo.lock
    +++ /dev/null
    @@ -1,7 +0,0 @@
    -# 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.toml b/90_Tower/rust/Cargo.toml
    deleted file mode 100644
    index 1ec696335..000000000
    --- a/90_Tower/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/90_Tower/rust/src/disk.rs b/90_Tower/rust/src/disk.rs
    deleted file mode 100644
    index 9d5b4b6d5..000000000
    --- a/90_Tower/rust/src/disk.rs
    +++ /dev/null
    @@ -1,28 +0,0 @@
    -pub struct Disk {
    -    pub size: u8,
    -}
    -
    -impl Disk {
    -    pub fn new(size: u8) -> Self {
    -        Disk { size }
    -    }
    -
    -    pub fn draw(&self) {
    -        let draw_space = || {
    -            let space_amount = (15 - self.size) / 2;
    -
    -            if space_amount > 0 {
    -                for _ in 0..space_amount {
    -                    print!(" ");
    -                }
    -            }
    -        };
    -
    -        draw_space();
    -        for _ in 0..self.size {
    -            print!("*");
    -        }
    -        draw_space();
    -        print!("   ");
    -    }
    -}
    diff --git a/90_Tower/rust/src/game.rs b/90_Tower/rust/src/game.rs
    deleted file mode 100644
    index 50ef0fe1c..000000000
    --- a/90_Tower/rust/src/game.rs
    +++ /dev/null
    @@ -1,138 +0,0 @@
    -use crate::{
    -    disk::Disk,
    -    needle::Needle,
    -    util::{self, prompt, PromptResult},
    -};
    -
    -pub struct Game {
    -    pub needles: Vec,
    -    disk_count: u8,
    -    moves: usize,
    -}
    -
    -impl Game {
    -    pub fn new() -> Self {
    -        let mut needles = Vec::new();
    -        let disk_count = util::get_disk_count();
    -
    -        for i in 1..=3 {
    -            let disks = match i {
    -                1 => {
    -                    let mut disks = Vec::new();
    -
    -                    let mut half_size = 7;
    -                    for _ in (1..=disk_count).rev() {
    -                        disks.push(Disk::new(half_size * 2 + 1));
    -                        half_size -= 1;
    -                    }
    -
    -                    disks
    -                }
    -                2 | 3 => Vec::new(),
    -                _ => panic!("THERE MUST BE EXACTLY THREE NEEDLES!"),
    -            };
    -
    -            needles.push(Needle { disks, number: i });
    -        }
    -
    -        Game {
    -            needles,
    -            disk_count,
    -            moves: 0,
    -        }
    -    }
    -
    -    pub fn update(&mut self) -> bool {
    -        self.draw();
    -
    -        loop {
    -            let (disk_index, from_needle_index) = self.get_disk_to_move();
    -            let to_needle_index = self.ask_which_needle();
    -
    -            if from_needle_index == to_needle_index {
    -                println!("DISK IS ALREADY AT THAT NEEDLE!");
    -                break;
    -            }
    -
    -            let to_needle = &self.needles[to_needle_index];
    -
    -            if to_needle.disks.len() == 0
    -                || to_needle.disks[0].size > self.needles[from_needle_index].disks[disk_index].size
    -            {
    -                self.move_disk(disk_index, from_needle_index, to_needle_index);
    -                break;
    -            } else {
    -                println!("CAN'T PLACE ON A SMALLER DISK!");
    -            }
    -        }
    -
    -        if self.needles[2].disks.len() == self.disk_count as usize {
    -            self.draw();
    -            println!("CONGRATULATIONS!!");
    -            println!("YOU HAVE PERFORMED THE TASK IN {} MOVES.", self.moves);
    -            return true;
    -        }
    -
    -        false
    -    }
    -
    -    pub fn draw(&self) {
    -        println!("");
    -        for r in (1..=7).rev() {
    -            for n in &self.needles {
    -                n.draw(r)
    -            }
    -            println!("");
    -        }
    -        println!("");
    -    }
    -
    -    fn get_disk_to_move(&self) -> (usize, usize) {
    -        loop {
    -            if let PromptResult::Number(n) = prompt(true, "WHICH DISK WOULD YOU LIKE TO MOVE?") {
    -                let smallest_disk = 15 - ((self.disk_count - 1) * 2);
    -
    -                if n < smallest_disk as i32 || n > 15 || (n % 2) == 0 {
    -                    println!("PLEASE ENTER A VALID DISK!")
    -                } else {
    -                    for (n_i, needle) in self.needles.iter().enumerate() {
    -                        if let Some((i, _)) = needle
    -                            .disks
    -                            .iter()
    -                            .enumerate()
    -                            .find(|(_, disk)| disk.size == n as u8)
    -                        {
    -                            if i == (needle.disks.len() - 1) {
    -                                return (i, n_i);
    -                            }
    -
    -                            println!("THAT DISK IS BELOW ANOTHER ONE. MAKE ANOTHER CHOICE.");
    -                        }
    -                    }
    -                }
    -            }
    -        }
    -    }
    -
    -    fn ask_which_needle(&self) -> usize {
    -        loop {
    -            if let PromptResult::Number(n) = prompt(true, "PLACE DISK ON WHICH NEEDLE?") {
    -                if n <= 0 || n > 3 {
    -                    println!("PLEASE ENTER A VALID NEEDLE.");
    -                } else {
    -                    return (n - 1) as usize;
    -                }
    -            }
    -        }
    -    }
    -
    -    fn move_disk(&mut self, disk: usize, from: usize, to: usize) {
    -        let from = &mut self.needles[from];
    -        let size = from.disks[disk].size;
    -
    -        from.disks.remove(disk);
    -        self.needles[to].add(size);
    -
    -        self.moves += 1;
    -    }
    -}
    diff --git a/90_Tower/rust/src/main.rs b/90_Tower/rust/src/main.rs
    deleted file mode 100644
    index 5ec26079d..000000000
    --- a/90_Tower/rust/src/main.rs
    +++ /dev/null
    @@ -1,50 +0,0 @@
    -use game::Game;
    -use util::PromptResult;
    -
    -mod disk;
    -mod game;
    -mod needle;
    -mod util;
    -
    -fn main() {
    -    println!("\n\n\t\tTOWERS");
    -    println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
    -
    -    println!("TOWERS OF HANOI PUZZLE\n");
    -
    -    println!("YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT");
    -    println!("TOWER, ON AT A TIME, NEVER PUTTING A LARGER DISK ON A");
    -    println!("SMALLER DISK.\n");
    -
    -    let mut quit = false;
    -
    -    while !quit {
    -        let mut game = Game::new();
    -
    -        println!("");
    -        println!(
    -            r#"IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.
    -3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,
    -7 THE NEXT, AND SO ON, UP TO 15.  IF YOU DO THE PUZZLE WITH
    -2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15.  WITH 3 DISKS
    -THE CODE NAMES WOULD BE 11, 13 AND 15, ETC.  THE NEEDLES
    -ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3.  WE WILL
    -START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM
    -TO NEEDLE 3.
    -
    -GOOD LUCK!"#
    -        );
    -
    -        loop {
    -            if game.update() {
    -                break;
    -            }
    -        }
    -
    -        if let PromptResult::YesNo(r) = util::prompt(false, "TRY AGAIN (YES OR NO)?") {
    -            quit = !r;
    -        }
    -    }
    -
    -    println!("THANKS FOR THE GAME!");
    -}
    diff --git a/90_Tower/rust/src/needle.rs b/90_Tower/rust/src/needle.rs
    deleted file mode 100644
    index b2286eaf6..000000000
    --- a/90_Tower/rust/src/needle.rs
    +++ /dev/null
    @@ -1,26 +0,0 @@
    -use crate::disk::Disk;
    -
    -pub struct Needle {
    -    pub disks: Vec,
    -    pub number: u8,
    -}
    -
    -impl Needle {
    -    pub fn draw(&self, row: u8) {
    -        let row = row as usize;
    -
    -        if self.disks.len() >= row {
    -            self.disks[row - 1].draw();
    -        } else {
    -            let offset = "       ";
    -
    -            print!("{offset}");
    -            print!("*");
    -            print!("{offset}   ");
    -        }
    -    }
    -
    -    pub fn add(&mut self, size: u8) {
    -        self.disks.push(Disk { size });
    -    }
    -}
    diff --git a/90_Tower/rust/src/util.rs b/90_Tower/rust/src/util.rs
    deleted file mode 100644
    index 9feacf94a..000000000
    --- a/90_Tower/rust/src/util.rs
    +++ /dev/null
    @@ -1,51 +0,0 @@
    -use std::io;
    -
    -pub enum PromptResult {
    -    Number(i32),
    -    YesNo(bool),
    -}
    -
    -pub fn prompt(numeric: bool, msg: &str) -> PromptResult {
    -    use PromptResult::*;
    -    loop {
    -        println!("{}", msg);
    -
    -        let mut input = String::new();
    -
    -        io::stdin()
    -            .read_line(&mut input)
    -            .expect("Failed to read line.");
    -
    -        let input = input.trim().to_string();
    -
    -        if numeric {
    -            if let Ok(n) = input.parse::() {
    -                return Number(n);
    -            }
    -
    -            println!("PLEASE ENTER A NUMBER.")
    -        } else {
    -            match input.to_uppercase().as_str() {
    -                "YES" | "Y" => return YesNo(true),
    -                "NO" | "N" => return YesNo(false),
    -                _ => println!("PLEASE ENTER (Y)ES OR (N)O."),
    -            }
    -        }
    -    }
    -}
    -
    -pub fn get_disk_count() -> u8 {
    -    loop {
    -        if let PromptResult::Number(n) =
    -            prompt(true, "HOW MANY DISKS DO YOU WANT TO MOVE (7 IS MAX)?")
    -        {
    -            if n <= 2 {
    -                println!("THERE MUST BE AT LEAST 3 DISKS!")
    -            } else if n > 7 {
    -                println!("THERE CAN'T BE MORE THAN 7 DISKS!")
    -            } else {
    -                return n as u8;
    -            }
    -        }
    -    }
    -}
    diff --git a/91_Train/lua/train.lua b/91_Train/lua/train.lua
    deleted file mode 100644
    index 50214fa90..000000000
    --- a/91_Train/lua/train.lua
    +++ /dev/null
    @@ -1,59 +0,0 @@
    -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 = 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) )
    -
    -    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
    diff --git a/91_Train/python/train.py b/91_Train/python/train.py
    index 2affcc0a1..d7ac55d87 100644
    --- a/91_Train/python/train.py
    +++ b/91_Train/python/train.py
    @@ -6,14 +6,14 @@
     import random
     
     
    -def play_game() -> None:
    +def play_game():
         """Play one round of the game"""
         car_speed = random.randint(40, 65)
         time_difference = random.randint(5, 20)
         train_speed = random.randint(20, 39)
         print("\nA car travelling", car_speed, "MPH can make a certain trip in")
         print(time_difference, "hours less than a train travelling at", train_speed, "MPH")
    -    time_answer: float = 0
    +    time_answer = 0
         while time_answer == 0:
             try:
                 time_answer = float(input("How long does the trip take by car "))
    diff --git a/91_Train/rust/Cargo.lock b/91_Train/rust/Cargo.lock
    deleted file mode 100644
    index 4fe2abbea..000000000
    --- a/91_Train/rust/Cargo.lock
    +++ /dev/null
    @@ -1,75 +0,0 @@
    -# 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/91_Train/rust/Cargo.toml b/91_Train/rust/Cargo.toml
    deleted file mode 100644
    index f2fa11b7b..000000000
    --- a/91_Train/rust/Cargo.toml
    +++ /dev/null
    @@ -1,10 +0,0 @@
    -[package]
    -name = "rust"
    -version = "0.1.0"
    -authors = ["AnthonyMichaelTDM <68485672+AnthonyMichaelTDM@users.noreply.github.com>"]
    -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/91_Train/rust/README.md b/91_Train/rust/README.md
    deleted file mode 100644
    index 7e85f9a15..000000000
    --- a/91_Train/rust/README.md
    +++ /dev/null
    @@ -1,3 +0,0 @@
    -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
    -
    -Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)
    diff --git a/91_Train/rust/src/lib.rs b/91_Train/rust/src/lib.rs
    deleted file mode 100644
    index d796a20a5..000000000
    --- a/91_Train/rust/src/lib.rs
    +++ /dev/null
    @@ -1,155 +0,0 @@
    -/*
    - lib.rs contains all the logic of the program
    -*/
    -use rand::{Rng, prelude::thread_rng}; //rng
    -use std::error::Error; //better errors
    -use std::io::{self, Write}; //io interactions
    -use std::{str::FromStr, fmt::Display}; //traits
    -
    -//DATA
    -
    -/// handles setup for the game
    -pub struct Config {
    -}
    -impl Config {
    -    /// creates and returns a new Config from user input
    -    pub fn new() -> Result> {
    -        //DATA
    -        let config: Config = Config { 
    -        };
    -        
    -        //return new config
    -        return Ok(config);
    -    }
    -}
    -
    -/// run the program
    -pub fn run(_config: &Config) -> Result<(), Box> {
    -    //DATA
    -    let mut rng = thread_rng();
    -    
    -    let mut speed_train_1;
    -    let mut time_difference;
    -    let mut speed_train_2;
    -
    -    let mut guess;
    -    let mut answer;
    -    
    -    let mut error:f32; 
    -
    -    //Game loop
    -    loop {
    -        //initialize variables
    -        speed_train_1 =  rng.gen_range(40..65);
    -        time_difference = rng.gen_range(5..20); 
    -        speed_train_2 = rng.gen_range(20..39);
    -
    -        //print starting message / conditions
    -        println!("A CAR TRAVELING {} MPH CAN MAKE A CERTAIN TRIP IN\n{} HOURS LESS THAN A TRAIN TRAVELING AT {} MPH",speed_train_1,time_difference,speed_train_2);
    -        println!();
    -
    -        //get guess
    -        guess = loop {
    -            match get_number_from_input("HOW LONG DOES THE TRIP TAKE BY CAR?",0,-1) {
    -                Ok(num) => break num,
    -                Err(err) => {
    -                    eprintln!("{}",err);
    -                    continue;
    -                },
    -            }
    -        };
    -
    -        //calculate answer and error
    -        answer = time_difference * speed_train_2 / (speed_train_1 - speed_train_2);
    -        error = ((answer - guess) as isize).abs() as f32 * 100.0/(guess as f32) + 0.5;
    -
    -        //check guess against answer
    -        if error > 5.0 {
    -            println!("SORRY, YOU WERE OFF BY {} PERCENT.", error);
    -            println!("CORRECT ANSWER IS {} HOURS.",answer);
    -        } else {
    -            println!("GOOD! ANSWER WITHIN {} PERCENT.", error);
    -        }
    -
    -        //ask user if they want to go again
    -        match get_string_from_user_input("ANOTHER PROBLEM (Y/N)") {
    -            Ok(s) => if !s.to_uppercase().eq("Y") {break;} else {continue;},
    -            _ => break,
    -        }
    -    }
    -
    -    //return to main
    -    Ok(())
    -}
    -
    -/// gets a string from user input
    -fn get_string_from_user_input(prompt: &str) -> Result> {
    -    //DATA
    -    let mut raw_input = String::new();
    -
    -    //print prompt
    -    print!("{}", prompt);
    -    //make sure it's printed before getting input
    -    io::stdout().flush().expect("couldn't flush stdout");
    -
    -    //read user input from standard input, and store it to raw_input, then return it or an error as needed
    -    raw_input.clear(); //clear input
    -    match io::stdin().read_line(&mut raw_input) {
    -        Ok(_num_bytes_read) => return Ok(String::from(raw_input.trim())),
    -        Err(err) => return Err(format!("ERROR: CANNOT READ INPUT!: {}", err).into()),
    -    }
    -}
    -/// generic function to get a number from the passed string (user input)
    -/// pass a min lower  than the max to have minimum and maximum bounds
    -/// pass a min higher than the max to only have a minimum bound
    -/// pass a min equal   to  the max to only have a maximum bound
    -/// 
    -/// Errors:
    -/// no number on user input
    -fn get_number_from_input(prompt: &str, min:T, max:T) -> Result> {
    -    //DATA
    -    let raw_input: String;
    -    let processed_input: String;
    -
    -    
    -    //input loop
    -    raw_input = loop {
    -        match get_string_from_user_input(prompt) {
    -            Ok(input) => break input,
    -            Err(e) => {
    -                eprintln!("{}",e);
    -                continue;
    -            },
    -        }
    -    };
    -
    -    //filter out non-numeric characters from user input
    -    processed_input = raw_input.chars().filter(|c| c.is_numeric()).collect();
    -
    -    //from input, try to read a number
    -    match processed_input.trim().parse() {
    -        Ok(i) => {
    -            //what bounds must the input fall into
    -            if min < max {  //have a min and max bound: [min,max]
    -                if i >= min && i <= max {//is input valid, within bounds
    -                    return Ok(i); //exit the loop with the value i, returning it
    -                } else { //print error message specific to this case
    -                    return Err(format!("ONLY BETWEEN {} AND {}, PLEASE!", min, max).into());
    -                } 
    -            } else if min > max { //only a min bound: [min, infinity)
    -                if i >= min {
    -                    return Ok(i);
    -                } else {
    -                    return Err(format!("NO LESS THAN {}, PLEASE!", min).into());
    -                }
    -            } else { //only a max bound: (-infinity, max]
    -                if i <= max {
    -                    return Ok(i);
    -                } else {
    -                    return Err(format!("NO MORE THAN {}, PLEASE!", max).into());
    -                }
    -            }
    -        },
    -        Err(_e) => return Err(format!("Error: couldn't find a valid number in {}",raw_input).into()),
    -    }
    -}
    diff --git a/91_Train/rust/src/main.rs b/91_Train/rust/src/main.rs
    deleted file mode 100644
    index 438f69be1..000000000
    --- a/91_Train/rust/src/main.rs
    +++ /dev/null
    @@ -1,41 +0,0 @@
    -use std::process;//allows for some better error handling
    -
    -mod lib; //allows access to lib.rs
    -use lib::Config;
    -
    -/// main function
    -/// responsibilities:
    -/// - Calling the command line logic with the argument values
    -/// - Setting up any other configuration
    -/// - Calling a run function in lib.rs
    -/// - Handling the error if run returns an error
    -fn main() {
    -    //greet user
    -    welcome();
    -
    -    // set up other configuration
    -    let mut config = Config::new().unwrap_or_else(|err| {
    -        eprintln!("Problem configuring program: {}", err);
    -        process::exit(1);
    -    });
    -
    -    // run the program
    -    if let Err(e) = lib::run(&mut config) {
    -        eprintln!("Application Error: {}", e); //use the eprintln! macro to output to standard error
    -        process::exit(1); //exit the program with an error code
    -    }
    -
    -    //end of program
    -    println!("THANKS FOR PLAYING!");
    -}
    -
    -/// print the welcome message
    -fn welcome() {
    -    println!("
    -                                Train
    -              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
    -
    -
    -TIME - SPEED DISTANCE EXERCISE
    -    ");
    -}
    diff --git a/92_Trap/python/trap.py b/92_Trap/python/trap.py
    index a85be68e6..5f74a7603 100644
    --- a/92_Trap/python/trap.py
    +++ b/92_Trap/python/trap.py
    @@ -10,7 +10,7 @@
     guess_max = 6
     
     
    -def play_game() -> None:
    +def play_game():
         """Play one round of the game"""
     
         number_computer = random.randint(1, number_max)
    @@ -24,10 +24,11 @@ def play_game() -> None:
                         int(item)
                         for item in input("\nGuess # " + str(turn) + " ? ").split(",")
                     ]
    -                if len(user_input) != 2:
    -                    raise ValueError
    -                if sum(1 < x < number_max for x in user_input) == 2:
    -                    user_guess = user_input
    +                if len(user_input) == 2:
    +                    if sum(1 < x < number_max for x in user_input) == 2:
    +                        user_guess = user_input
    +                    else:
    +                        raise ValueError
                     else:
                         raise ValueError
                 except (ValueError, IndexError):
    diff --git a/92_Trap/rust/Cargo.lock b/92_Trap/rust/Cargo.lock
    deleted file mode 100644
    index 4fe2abbea..000000000
    --- a/92_Trap/rust/Cargo.lock
    +++ /dev/null
    @@ -1,75 +0,0 @@
    -# 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.toml b/92_Trap/rust/Cargo.toml
    deleted file mode 100644
    index ed59870f5..000000000
    --- a/92_Trap/rust/Cargo.toml
    +++ /dev/null
    @@ -1,9 +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]
    -rand="0.8.5"
    diff --git a/92_Trap/rust/README.md b/92_Trap/rust/README.md
    deleted file mode 100644
    index 362bf9221..000000000
    --- a/92_Trap/rust/README.md
    +++ /dev/null
    @@ -1,3 +0,0 @@
    -Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
    -
    -Conversion to [Rust](https://www.rust-lang.org/) by Uğur Küpeli [ugurkupeli](https://github.com/ugurkupeli)
    \ No newline at end of file
    diff --git a/92_Trap/rust/src/main.rs b/92_Trap/rust/src/main.rs
    deleted file mode 100644
    index 5fc898767..000000000
    --- a/92_Trap/rust/src/main.rs
    +++ /dev/null
    @@ -1,90 +0,0 @@
    -use std::io::stdin;
    -
    -use rand::Rng;
    -
    -fn main() {
    -    println!("\n\t\tTRAP");
    -    println!("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
    -
    -    let max_guess = 6;
    -    let max_number = 100;
    -
    -    prompt_instructions();
    -
    -    loop {
    -        let number = rand::thread_rng().gen_range(1..(max_number + 1));
    -        let mut guesses = 1u8;
    -
    -        loop {
    -            let (min, max) = prompt_numbers(guesses);
    -
    -            if min == number && max == number {
    -                println!("\nYou got it!!!");
    -                break;
    -            } else if (min..=max).contains(&number) {
    -                println!("You have trapped my number.");
    -            } else if number < min {
    -                println!("My number is smaller than your trap numbers.");
    -            } else if number > max {
    -                println!("My number is bigger than your trap numbers.");
    -            }
    -
    -            guesses += 1;
    -            if guesses > max_guess {
    -                println!("\nSorry, that was {max_guess} guesses. Number was {number}");
    -                break;
    -            }
    -        }
    -
    -        println!("\nTry again.");
    -    }
    -}
    -
    -fn prompt_instructions() {
    -    println!("Instructions?\t");
    -
    -    let mut input = String::new();
    -    if let Ok(_) = stdin().read_line(&mut input) {
    -        match input.to_uppercase().trim() {
    -            "YES" | "Y" => {
    -                println!("\nI am thinking of a number between 1 and 100");
    -                println!("Try to guess my number. On each guess,");
    -                println!("you are to enter 2 numbers, trying to trap");
    -                println!("my number between the two numbers. I will");
    -                println!("tell you if you have trapped my number, if my");
    -                println!("number is larger than your two numbers, or if");
    -                println!("my number is smaller than your two numbers.");
    -                println!("If you want to guess one single number, type");
    -                println!("your guess for both your trap numbers.");
    -                println!("You get 6 guesses to get my number.");
    -            }
    -            _ => (),
    -        }
    -    }
    -}
    -
    -fn prompt_numbers(guess: u8) -> (u8, u8) {
    -    loop {
    -        let mut nums: Vec = Vec::new();
    -        println!("\nGuess # {guess} ?");
    -
    -        let mut input = String::new();
    -        if let Ok(_) = stdin().read_line(&mut input) {
    -            let input: Vec<&str> = input.trim().split(",").collect();
    -
    -            for string in input {
    -                if let Ok(number) = string.parse::() {
    -                    nums.push(number);
    -                } else {
    -                    break;
    -                }
    -            }
    -
    -            if nums.len() == 2 {
    -                if nums[0] <= nums[1] {
    -                    return (nums[0], nums[1]);
    -                }
    -            }
    -        }
    -    }
    -}
    diff --git a/93_23_Matches/README.md b/93_23_Matches/README.md
    index e4ece5fd5..8ef8d6f8a 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
     
    -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.
    +(please note any difficulties or challenges in porting here)
    diff --git a/93_23_Matches/csharp/23Matches.cs b/93_23_Matches/csharp/23Matches.cs
    deleted file mode 100644
    index f2aeeaf8b..000000000
    --- a/93_23_Matches/csharp/23Matches.cs
    +++ /dev/null
    @@ -1,167 +0,0 @@
    -using System;
    -
    -namespace Program
    -{
    -  class Program
    -  {
    -
    -    // Initialize 3 public variables so that they can be ascessed anywhere in the code
    -    public static int numberOfMatches;
    -    public static int numberOfMatchesRemovedByPlayer;
    -    public static bool playerGoesFirst = false; // a flag to show if the player won the coin toss
    -    static void Main(string[] args)
    -    {
    -      // Print introduction text
    -
    -      // Prints the title with 31 spaces placed in front of the text using the PadLeft() string function
    -      Console.WriteLine("23 MATCHES".PadLeft(31));
    -      Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".PadLeft(15));
    -      
    -      // Print 3 blank lines with \n escape sequence
    -      Console.Write("\n\n\n");
    -      Console.WriteLine(" THIS IS A GAME CALLED '23 MATCHES'.");
    -      Console.Write("\n");
    -
    -      Console.WriteLine("WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE");
    -      Console.WriteLine("MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE");
    -      Console.WriteLine("THE LAST MATCH.");
    -      Console.Write("\n");
    -      Console.WriteLine("LET'S FLIP A COIN TO SEE WHO GOES FIRST.");
    -      Console.WriteLine("IF IT COMES UP HEADS, I WILL WIN THE TOSS.");
    -      Console.Write("\n");
    -
    -      // Set the number of matches to 23
    -      numberOfMatches = 23;
    -
    -      // Create a random class object to generate the coin toss
    -      Random random = new Random();
    -      // Generates a random number between 0.0 and 1.0
    -      // Multiplies that number by 2 and then
    -      // Converts it into an integer giving either a 0 or a 1
    -      int coinTossResult = (int)(2 * random.NextDouble()); 
    -
    -      if (coinTossResult == 1)
    -      {
    -        Console.WriteLine("TAILS! YOU GO FIRST. ");
    -        // Sets the player coin toss flag to true
    -        playerGoesFirst = true;
    -        PlayerTurn();
    -      }
    -      else
    -      {
    -        Console.WriteLine("HEADS! I WIN! HA! HA!");
    -        Console.WriteLine("PREPARE TO LOSE, MEATBALL-NOSE!!");
    -        Console.Write("\n");
    -        Console.WriteLine("I TAKE 2 MATCHES");
    -        numberOfMatches = numberOfMatches - 2;
    -      }
    -
    -      // loops the code until there is 1 or fewer matches
    -      do
    -      {
    -        // Checks if the player has already gone 
    -        // because they won the coin toss
    -        // if they have not then the player can go
    -        if (playerGoesFirst == false)
    -        {
    -          Console.Write("THE NUMBER OF MATCHES IS NOW " + numberOfMatches);
    -          PlayerTurn();
    -        }
    -        // sets the coint toss flag to false since
    -        // this is only needed on the first loop of the code
    -        playerGoesFirst = false;
    -        ComputerTurn();        
    -      } while (numberOfMatches > 1);
    -
    -    }
    -
    -    static void PlayerTurn()
    -    {
    -      Console.WriteLine("\n");
    -      Console.WriteLine("YOUR TURN -- YOU MAY TAKE 1, 2, OR 3 MATCHES.");
    -      Console.Write("HOW MANY DO YOU WISH TO REMOVE ?? ");
    -      // Get player input
    -      numberOfMatchesRemovedByPlayer = ReadPlayerInput();
    -      // If the input is invalid (not 1, 2, or 3)
    -      // then ask the player to input again
    -      while (numberOfMatchesRemovedByPlayer > 3 || numberOfMatchesRemovedByPlayer <= 0)
    -      {
    -        Console.WriteLine("VERY FUNNY! DUMMY!");
    -        Console.WriteLine("DO YOU WANT TO PLAY OR GOOF AROUND?");
    -        Console.Write("NOW, HOW MANY MATCHES DO YOU WANT                 ?? ");
    -        numberOfMatchesRemovedByPlayer = ReadPlayerInput();
    -      }
    -
    -      // Remove the player specified number of matches
    -      numberOfMatches = numberOfMatches - numberOfMatchesRemovedByPlayer;
    -
    -      Console.WriteLine("THE ARE NOW " + numberOfMatches + " MATCHES REMAINING");      
    -    }
    -    static void ComputerTurn()
    -    {
    -      // Initialize the numberOfMatchesRemovedByComputer
    -      int numberOfMatchesRemovedByComputer = 0;
    -      switch (numberOfMatches)
    -      {
    -        case 4:
    -          numberOfMatchesRemovedByComputer = 3;
    -          break;
    -        case 3:
    -          numberOfMatchesRemovedByComputer = 2;
    -          break;
    -        case 2:
    -          numberOfMatchesRemovedByComputer = 1;
    -          break;
    -        case 1: case 0: // If the computer losses call this case
    -          Console.WriteLine("YOU WON, FLOPPY EARS !");
    -          Console.WriteLine("THING YOU'RE PRETTY SMART !");
    -          Console.WriteLine("LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!");
    -          break;
    -        default: // If there are > than 4 matches call this case
    -          numberOfMatchesRemovedByComputer = 4 - numberOfMatchesRemovedByPlayer;
    -          break;
    -      }
    -      // If the numberOfMatchesRemovedByComputer has been updated run this code,
    -      // if not them the computer has lost
    -      if (numberOfMatchesRemovedByComputer != 0)
    -      {
    -        Console.WriteLine("MY TURN ! I REMOVE " + numberOfMatchesRemovedByComputer + " MATCHES");
    -        numberOfMatches = numberOfMatches - numberOfMatchesRemovedByComputer;
    -        // If there are less than or equal to 1 matches
    -        // then the player has lost        
    -        if (numberOfMatches <= 1)
    -        {
    -          Console.Write("\n");
    -          Console.WriteLine("YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!");
    -          Console.WriteLine("HA ! HA ! I BEAT YOU !!!");
    -          Console.Write("\n");
    -          Console.WriteLine("GOOD BYE LOSER!");
    -        }
    -      }
    -    }
    -
    -
    -    // This method handles the player input 
    -    // and will handle inncorrect input
    -    static int ReadPlayerInput()
    -    {
    -      // Read user input and convert to integer
    -      int playerInput = 0;
    -      // Try to read player input
    -      try
    -      {
    -        playerInput = Convert.ToInt32(Console.ReadLine());
    -      }
    -      // If there is an error in the player input
    -      catch (System.Exception)
    -      {
    -        Console.WriteLine("?REENTER");
    -        Console.Write("?? ");
    -        // Ask the player to reenter their input
    -        playerInput = ReadPlayerInput();
    -      }
    -      return playerInput;      
    -    }
    -
    -  }
    -}
    \ No newline at end of file
    diff --git a/93_23_Matches/csharp/23matches.csproj b/93_23_Matches/csharp/23matches.csproj
    new file mode 100644
    index 000000000..11091f717
    --- /dev/null
    +++ b/93_23_Matches/csharp/23matches.csproj
    @@ -0,0 +1,9 @@
    +
    +
    +  
    +    Exe
    +    netcoreapp3.1
    +    _23matches
    +  
    +
    +
    diff --git a/93_23_Matches/csharp/23matches.sln b/93_23_Matches/csharp/23matches.sln
    new file mode 100644
    index 000000000..78fce16eb
    --- /dev/null
    +++ b/93_23_Matches/csharp/23matches.sln
    @@ -0,0 +1,25 @@
    +
    +Microsoft Visual Studio Solution File, Format Version 12.00
    +# Visual Studio Version 16
    +VisualStudioVersion = 16.0.32002.261
    +MinimumVisualStudioVersion = 10.0.40219.1
    +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "23matches", "23matches.csproj", "{9DBE7354-0749-4750-9224-5F9F95C64905}"
    +EndProject
    +Global
    +	GlobalSection(SolutionConfigurationPlatforms) = preSolution
    +		Debug|Any CPU = Debug|Any CPU
    +		Release|Any CPU = Release|Any CPU
    +	EndGlobalSection
    +	GlobalSection(ProjectConfigurationPlatforms) = postSolution
    +		{9DBE7354-0749-4750-9224-5F9F95C64905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
    +		{9DBE7354-0749-4750-9224-5F9F95C64905}.Debug|Any CPU.Build.0 = Debug|Any CPU
    +		{9DBE7354-0749-4750-9224-5F9F95C64905}.Release|Any CPU.ActiveCfg = Release|Any CPU
    +		{9DBE7354-0749-4750-9224-5F9F95C64905}.Release|Any CPU.Build.0 = Release|Any CPU
    +	EndGlobalSection
    +	GlobalSection(SolutionProperties) = preSolution
    +		HideSolutionNode = FALSE
    +	EndGlobalSection
    +	GlobalSection(ExtensibilityGlobals) = postSolution
    +		SolutionGuid = {0A87AE2F-68AC-4354-9C8D-578209D41174}
    +	EndGlobalSection
    +EndGlobal
    diff --git a/93_23_Matches/csharp/Goto.Program.cs b/93_23_Matches/csharp/Goto.Program.cs
    new file mode 100644
    index 000000000..e23be8a47
    --- /dev/null
    +++ b/93_23_Matches/csharp/Goto.Program.cs
    @@ -0,0 +1,129 @@
    +using System;
    +using System.Threading;
    +
    +namespace _23matches
    +{
    +    class Program
    +    {
    +        /// 
    +        /// Mimics the "goto" version of the original program
    +        /// 
    +        /// 
    +        static void Main(string[] args)
    +        {
    +            Random random = new Random();
    +        StartNewGame:
    +            Console.WriteLine("23 MATCHES".PadLeft(31));
    +            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".PadLeft(15));
    +            Console.WriteLine();
    +            Console.WriteLine();
    +            Console.WriteLine();
    +            Console.WriteLine("THIS IS A GAME CALLED '23 MATCHES'.");
    +            Console.WriteLine();
    +            Console.WriteLine("WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE");
    +            Console.WriteLine("MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE");
    +            Console.WriteLine("THE LAST MATCH.");
    +            Console.WriteLine();
    +            Console.WriteLine("Input exit to close the program.");
    +            Console.WriteLine("Input cls Screen Clear.");
    +            Console.WriteLine();
    +            Console.WriteLine();
    +            Console.WriteLine("LET'S FLIP A COIN TO SEE WHO GOES FIRST.");
    +            Console.WriteLine("IF IT COMES UP HEADS, I WILL WIN THE TOSS.");
    +            Console.WriteLine();
    +        StartTheGame:
    +            string command;
    +            int N = 23;
    +            int K = 0;
    +            int Q = random.Next(2);
    +            if (Q == 1)
    +                goto ComputerFirst;
    +            else
    +                goto PlayerFirst;
    +
    +            ComputerFirst:
    +            Console.WriteLine("HEADS! I WIN! HA! HA!");
    +            Console.WriteLine("PREPARE TO LOSE, MEATBALL-NOSE!!");
    +            Console.WriteLine();
    +            int ain = random.Next(1, 3);
    +            Console.WriteLine($"I TAKE {ain} MATCHES");
    +            N = N - ain;
    +            goto PlayersProceed;
    +
    +        PlayerFirst:
    +            Console.WriteLine("TAILS! YOU GO FIRST. ");
    +            Console.WriteLine();
    +            goto PlayersSpeak;
    +
    +        PlayersProceed:
    +            Console.WriteLine($"THE NUMBER OF MATCHES IS NOW {N}");
    +            Console.WriteLine();
    +            Console.WriteLine("YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.");
    +            Console.WriteLine("HOW MANY DO YOU WISH TO REMOVE ");
    +            goto PlayersSpeak;
    +
    +        PlayersSpeak:
    +            command = Console.ReadLine().ToLower();
    +            if (command.Equals("exit"))
    +            {
    +                System.Diagnostics.Process tt = System.Diagnostics.Process.GetProcessById(System.Diagnostics.Process.GetCurrentProcess().Id);
    +                tt.Kill();
    +            }
    +            if (command.Equals("cls"))
    +            {
    +                Console.Clear();
    +                goto PlayersProceed;
    +            }
    +            try
    +            {
    +                K = Convert.ToInt32(command);
    +            }
    +            catch (System.Exception)
    +            {
    +                goto PlayerInputError;
    +            }
    +            if (K > 3 || K <= 0)
    +                goto PlayerInputError;
    +            N = N - K;
    +            Console.WriteLine($"THERE ARE NOW {N} MATCHES REMAINING.");
    +            if (N == 4 || N == 3 || N == 2)
    +                goto TheComputerSpeaks;
    +            else if (N <= 1)
    +                goto ThePlayerWins;
    +            else
    +                goto TheComputerSpeaks;
    +
    +            TheComputerSpeaks:
    +            int Z = 4 - K;
    +            Console.WriteLine($"MY TURN ! I REMOVE {Z} MATCHES");
    +            N = N - Z;
    +            if (N <= 1)
    +                goto TheComputerWins;
    +            else
    +                goto PlayersProceed;
    +
    +            PlayerInputError:
    +            Console.WriteLine("VERY FUNNY! DUMMY!");
    +            Console.WriteLine("DO YOU WANT TO PLAY OR GOOF AROUND?");
    +            Console.WriteLine("NOW, HOW MANY MATCHES DO YOU WANT ");
    +            goto PlayersSpeak;
    +        ThePlayerWins:
    +            Console.WriteLine("YOU WON, FLOPPY EARS !");
    +            Console.WriteLine("THINK YOU'RE PRETTY SMART !");
    +            Console.WriteLine("LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!");
    +            Console.WriteLine();
    +            Console.WriteLine();
    +            goto StartTheGame;
    +        TheComputerWins:
    +            Console.WriteLine();
    +            Console.WriteLine("YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!");
    +            Console.WriteLine("HA ! HA ! I BEAT YOU !!!");
    +            Console.WriteLine();
    +            Console.WriteLine("GOOD BYE LOSER!");
    +            Console.WriteLine();
    +            Console.WriteLine();
    +            goto StartNewGame;
    +
    +        }
    +    }
    +}
    diff --git a/93_23_Matches/csharp/ObjectOrientedVersion.Program.cs b/93_23_Matches/csharp/ObjectOrientedVersion.Program.cs
    new file mode 100644
    index 000000000..7b88d7b77
    --- /dev/null
    +++ b/93_23_Matches/csharp/ObjectOrientedVersion.Program.cs
    @@ -0,0 +1,161 @@
    +using System;
    +using System.Threading;
    +
    +namespace _23matches
    +{
    +    class ObjectOrientedVersion_Program
    +    {
    +        /// 
    +        /// Object-oriented version
    +        /// 
    +        /// 
    +        static void Main_Two(string[] args)
    +        {
    +            Game game = new Game();
    +            game.GameRun();
    +        }
    +    }
    +    public class Game
    +    {
    +        string command;
    +        int N;
    +        int K;
    +        Random random = new Random();
    +        public void GameRun()
    +        {
    +            StartNewGame();
    +            StartTheGame();
    +        }
    +        void StartNewGame()
    +        {
    +            Console.WriteLine("23 MATCHES".PadLeft(31));
    +            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".PadLeft(15));
    +            Console.WriteLine();
    +            Console.WriteLine();
    +            Console.WriteLine();
    +            Console.WriteLine("THIS IS A GAME CALLED '23 MATCHES'.");
    +            Console.WriteLine();
    +            Console.WriteLine("WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE");
    +            Console.WriteLine("MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE");
    +            Console.WriteLine("THE LAST MATCH.");
    +            Console.WriteLine();
    +            Console.WriteLine("Input exit to close the program.");
    +            Console.WriteLine("Input cls Screen Clear.");
    +            Console.WriteLine();
    +            Console.WriteLine();
    +            Console.WriteLine("LET'S FLIP A COIN TO SEE WHO GOES FIRST.");
    +            Console.WriteLine("IF IT COMES UP HEADS, I WILL WIN THE TOSS.");
    +            Console.WriteLine();
    +        }
    +        void StartTheGame()
    +        {
    +            N = 23;
    +            K = 0;
    +            int Q = random.Next(2);
    +            if (Q == 1)
    +                ComputerFirst();
    +            else
    +            {
    +                PlayerFirst();
    +            }
    +        }
    +        void ComputerFirst()
    +        {//210
    +            Console.WriteLine("HEADS! I WIN! HA! HA!");
    +            Console.WriteLine("PREPARE TO LOSE, MEATBALL-NOSE!!");
    +            Console.WriteLine();
    +            int ain = random.Next(1, 3);
    +            Console.WriteLine($"I TAKE {ain} MATCHES");
    +            N = N - ain;
    +            PlayersProceed();
    +        }
    +        void PlayerFirst()
    +        {
    +            Console.WriteLine("TAILS! YOU GO FIRST. ");
    +            Console.WriteLine();
    +            PlayersSpeak();
    +        }
    +        void PlayersProceed()
    +        {
    +            Console.WriteLine($"THE NUMBER OF MATCHES IS NOW {N}");
    +            Console.WriteLine();
    +            PlayersSpeak();
    +        }
    +        void RemindsPlayersToEnter()
    +        {
    +            Console.WriteLine("YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.");
    +            Console.WriteLine("HOW MANY DO YOU WISH TO REMOVE ");
    +        }
    +        void PlayersSpeak()
    +        {
    +            RemindsPlayersToEnter();
    +            command = Console.ReadLine().ToLower();
    +            if (command.Equals("exit"))
    +            {
    +                System.Diagnostics.Process tt = System.Diagnostics.Process.GetProcessById(System.Diagnostics.Process.GetCurrentProcess().Id);
    +                tt.Kill();
    +            }
    +            if (command.Equals("cls"))
    +            {
    +                Console.Clear();
    +                PlayersSpeak();
    +            }
    +            try
    +            {
    +                K = Convert.ToInt32(command);
    +            }
    +            catch (System.Exception)
    +            {
    +                PlayerInputError();
    +            }
    +            if (K > 3 || K <= 0)
    +                PlayerInputError();
    +            N = N - K;
    +            Console.WriteLine($"THERE ARE NOW {N} MATCHES REMAINING.");
    +            if (N == 4 || N == 3 || N == 2)
    +                TheComputerSpeaks(N);
    +            else if (N <= 1)
    +                ThePlayerWins();
    +            else
    +                TheComputerSpeaks(4 - K);
    +
    +        }
    +        void PlayerInputError()
    +        {
    +            Console.WriteLine("VERY FUNNY! DUMMY!");
    +            Console.WriteLine("DO YOU WANT TO PLAY OR GOOF AROUND?");
    +            Console.WriteLine("NOW, HOW MANY MATCHES DO YOU WANT ");
    +            PlayersSpeak();
    +        }
    +        void TheComputerSpeaks(int ain)
    +        {
    +            int Z = ain;
    +            Console.WriteLine($"MY TURN ! I REMOVE {Z} MATCHES");//390
    +            N = N - Z;
    +            if (N <= 1)
    +                TheComputerWins();
    +            else
    +                PlayersProceed();
    +        }
    +        void ThePlayerWins()
    +        {
    +            Console.WriteLine("YOU WON, FLOPPY EARS !");
    +            Console.WriteLine("THINK YOU'RE PRETTY SMART !");
    +            Console.WriteLine("LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!");
    +            Console.WriteLine();
    +            Console.WriteLine();
    +            StartTheGame();
    +        }
    +        void TheComputerWins()
    +        {
    +            Console.WriteLine();
    +            Console.WriteLine("YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!");
    +            Console.WriteLine("HA ! HA ! I BEAT YOU !!!");
    +            Console.WriteLine();
    +            Console.WriteLine("GOOD BYE LOSER!");
    +            Console.WriteLine();
    +            Console.WriteLine();
    +            GameRun();
    +        }
    +    }
    +}
    diff --git a/93_23_Matches/csharp/README.md b/93_23_Matches/csharp/README.md
    new file mode 100644
    index 000000000..fd759c067
    --- /dev/null
    +++ b/93_23_Matches/csharp/README.md
    @@ -0,0 +1,5 @@
    +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
    +
    +Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
    +
    +The program is available in two versions, a "goto" version that mimics the original program and an "object-oriented" version.
    diff --git a/93_23_Matches/csharp/csharp.csproj b/93_23_Matches/csharp/csharp.csproj
    deleted file mode 100644
    index 74abf5c97..000000000
    --- a/93_23_Matches/csharp/csharp.csproj
    +++ /dev/null
    @@ -1,10 +0,0 @@
    -
    -
    -  
    -    Exe
    -    net6.0
    -    enable
    -    enable
    -  
    -
    -
    diff --git a/93_23_Matches/python/23matches.py b/93_23_Matches/python/23matches.py
    index 293cfa1f3..5488f08b1 100755
    --- a/93_23_Matches/python/23matches.py
    +++ b/93_23_Matches/python/23matches.py
    @@ -6,7 +6,7 @@
     import random
     
     
    -def play_game() -> None:
    +def play_game():
         """Play one round of the game"""
     
         matches = 23
    @@ -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 -= choice_human
    +            matches = 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 -= choice_computer
    +            matches = matches - choice_computer
                 if matches == 0:
                     print("You won, floppy ears !")
                     print("Think you're pretty smart !")
    diff --git a/93_23_Matches/ruby/23_matches.rb b/93_23_Matches/ruby/23_matches.rb
    deleted file mode 100644
    index c362a9c00..000000000
    --- a/93_23_Matches/ruby/23_matches.rb
    +++ /dev/null
    @@ -1,88 +0,0 @@
    -class Matches
    -    def initialize
    -        puts " " * 31 + "23 MATCHES"
    -        puts "This is a game called '23 Matches'."
    -        puts "When it is your turn, you may take one, two, or three"
    -        puts "matches. The object of the game is not to have to take"
    -        puts "the last match."
    -        puts "Let's flip a coin to see who goes first."
    -        puts "If it comes up heads, I will win the toss."
    -
    -        while true
    -            play_game
    -            print "Play again? (yes or no) "
    -            answer = gets.chomp!.upcase
    -            break unless ["Y", "YES"].include? answer
    -        end
    -    end
    -
    -    private
    -        def play_game
    -            matches = 23
    -            humans_turn = rand(0..1) == 1
    -            if humans_turn
    -                puts "Tails! You go first."
    -                prompt_human = "How many do you wish to remove? "
    -            else
    -                puts "Heads! I win! Ha! Ha!"
    -                puts "Prepare to lose, meatball-nose!!"
    -            end
    -
    -            choice_human = 2
    -
    -            while matches > 0
    -                if humans_turn
    -                    choice_human = 0
    -                    if matches == 1
    -                        choice_human = 1
    -                    end
    -
    -                    while choice_human == 0
    -                        print "#{prompt_human}[1,2,3] "
    -                        choice_human = gets.chomp!
    -
    -                        if ![1, 2, 3].include?(choice_human.to_i) || choice_human.to_i > matches
    -                            choice_human = 0
    -                            puts "Very funny! Dummy!"
    -                            puts "Do you want to play or goof around?"
    -                            prompt_human = "Now, how many matches do you want "
    -                        end
    -                    end
    -
    -                    matches = matches - choice_human.to_i
    -
    -                    if matches == 0
    -                        puts "You poor boob! You took the last match! I gotcha!!"
    -                        puts "Ha ! Ha ! I beat you !!"
    -                        puts "Good bye loser!"
    -                    else
    -                        puts "There are now #{matches} matches remaining."
    -                    end
    -                else
    -                    choice_computer = 4 - choice_human.to_i
    -                    if matches == 1
    -                        choice_computer = 1
    -                    elsif (1 < matches) && (matches < 4)
    -                        choice_computer = matches - 1
    -                    end
    -
    -                    matches = matches - choice_computer
    -                    if matches == 0
    -                        puts "You won, floppy ears !"
    -                        puts "Think you're pretty smart !"
    -                        puts "Let's play again and I'll blow your shoes off !!"
    -                    else
    -                        puts "My turn ! I remove #{choice_computer} matches"
    -                        puts "The number of matches is now #{matches}"
    -                    end
    -                end
    -
    -                humans_turn = !humans_turn
    -                prompt_human = "Your turn -- you may take 1, 2 or 3 matches.\nHow many do you wish to remove "
    -            end
    -        end
    -end
    -
    -if __FILE__ == $0
    -    Matches.new
    -end
    \ No newline at end of file
    diff --git a/93_23_Matches/rust/Cargo.lock b/93_23_Matches/rust/Cargo.lock
    deleted file mode 100644
    index 96e2f79ef..000000000
    --- a/93_23_Matches/rust/Cargo.lock
    +++ /dev/null
    @@ -1,16 +0,0 @@
    -# 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
    deleted file mode 100644
    index a4227bbd4..000000000
    --- a/93_23_Matches/rust/Cargo.toml
    +++ /dev/null
    @@ -1,9 +0,0 @@
    -[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
    deleted file mode 100644
    index 6249450a1..000000000
    --- a/93_23_Matches/rust/README.md
    +++ /dev/null
    @@ -1,3 +0,0 @@
    -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
    deleted file mode 100644
    index a14c39f58..000000000
    --- a/93_23_Matches/rust/src/main.rs
    +++ /dev/null
    @@ -1,108 +0,0 @@
    -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
    -    }
    -}
    diff --git a/94_War/python/cards.json b/94_War/python/cards.json
    deleted file mode 100644
    index b27e9bd4f..000000000
    --- a/94_War/python/cards.json
    +++ /dev/null
    @@ -1,54 +0,0 @@
    -[
    -    "S-2",
    -    "H-2",
    -    "C-2",
    -    "D-2",
    -    "S-3",
    -    "H-3",
    -    "C-3",
    -    "D-3",
    -    "S-4",
    -    "H-4",
    -    "C-4",
    -    "D-4",
    -    "S-5",
    -    "H-5",
    -    "C-5",
    -    "D-5",
    -    "S-6",
    -    "H-6",
    -    "C-6",
    -    "D-6",
    -    "S-7",
    -    "H-7",
    -    "C-7",
    -    "D-7",
    -    "S-8",
    -    "H-8",
    -    "C-8",
    -    "D-8",
    -    "S-9",
    -    "H-9",
    -    "C-9",
    -    "D-9",
    -    "S-10",
    -    "H-10",
    -    "C-10",
    -    "D-10",
    -    "S-J",
    -    "H-J",
    -    "C-J",
    -    "D-J",
    -    "S-Q",
    -    "H-Q",
    -    "C-Q",
    -    "D-Q",
    -    "S-K",
    -    "H-K",
    -    "C-K",
    -    "D-K",
    -    "S-A",
    -    "H-A",
    -    "C-A",
    -    "D-A"
    -]
    diff --git a/94_War/python/war.py b/94_War/python/war.py
    index 48137c383..f8d34004a 100755
    --- a/94_War/python/war.py
    +++ b/94_War/python/war.py
    @@ -1,27 +1,75 @@
     #!/usr/bin/env python3
    +# WAR
    +#
    +# Converted from BASIC to Python by Trevor Hobson
     
    -"""
    -WAR
    -
    -Converted from BASIC to Python by Trevor Hobson
    -"""
    -
    -import json
     import random
    -from pathlib import Path
    -from typing import List
     
     
    -def card_value(input: str) -> int:
    +def card_value(input):
         return ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"].index(
             input.split("-")[1]
         )
     
     
    -def play_game() -> None:
    +cards = [
    +    "S-2",
    +    "H-2",
    +    "C-2",
    +    "D-2",
    +    "S-3",
    +    "H-3",
    +    "C-3",
    +    "D-3",
    +    "S-4",
    +    "H-4",
    +    "C-4",
    +    "D-4",
    +    "S-5",
    +    "H-5",
    +    "C-5",
    +    "D-5",
    +    "S-6",
    +    "H-6",
    +    "C-6",
    +    "D-6",
    +    "S-7",
    +    "H-7",
    +    "C-7",
    +    "D-7",
    +    "S-8",
    +    "H-8",
    +    "C-8",
    +    "D-8",
    +    "S-9",
    +    "H-9",
    +    "C-9",
    +    "D-9",
    +    "S-10",
    +    "H-10",
    +    "C-10",
    +    "D-10",
    +    "S-J",
    +    "H-J",
    +    "C-J",
    +    "D-J",
    +    "S-Q",
    +    "H-Q",
    +    "C-Q",
    +    "D-Q",
    +    "S-K",
    +    "H-K",
    +    "C-K",
    +    "D-K",
    +    "S-A",
    +    "H-A",
    +    "C-A",
    +    "D-A",
    +]
    +
    +
    +def play_game():
         """Play one round of the game"""
    -    with open(Path(__file__).parent / "cards.json") as f:
    -        cards: List[str] = json.load(f)
     
         random.shuffle(cards)
         score_you = 0
    diff --git a/94_War/rust/Cargo.lock b/94_War/rust/Cargo.lock
    deleted file mode 100644
    index 4fe2abbea..000000000
    --- a/94_War/rust/Cargo.lock
    +++ /dev/null
    @@ -1,75 +0,0 @@
    -# 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/python/test_weekday.py b/95_Weekday/python/test_weekday.py
    new file mode 100644
    index 000000000..67185b728
    --- /dev/null
    +++ b/95_Weekday/python/test_weekday.py
    @@ -0,0 +1,49 @@
    +import datetime
    +
    +import pytest
    +from weekday import calculate_day_of_week
    +
    +
    +@pytest.mark.parametrize(
    +    ("year", "month", "day"),
    +    [
    +        (yr, m, d)
    +        for yr in range(1600, 2021)
    +        for m in range(1, 12)
    +        for d in range(1, 28)
    +    ],
    +)
    +@pytest.mark.slow  # Those are 125,037 tests!
    +def test_weekday_calc(year, month, day):
    +    dt = datetime.date(year, month, day)
    +    python_weekday = dt.weekday()  # Monday = 0, Sunday = 6
    +
    +    basic_weekday = calculate_day_of_week(year, month, day)  # Sunday = 1, Saturday = 7
    +
    +    if ((python_weekday + 2) % 7) != (basic_weekday % 7):
    +        print(f"testing yr {year} month {month} day {day}")
    +        print(f"python says {python_weekday}")
    +        print(f"BASIC says {basic_weekday}")
    +        assert False
    +
    +
    +@pytest.mark.parametrize(
    +    ("year", "month", "day"),
    +    [
    +        (yr, m, d)
    +        for yr in range(2016, 2021)
    +        for m in range(1, 12)
    +        for d in range(1, 28)
    +    ],
    +)
    +def test_weekday_calc_4_years(year, month, day):
    +    dt = datetime.date(year, month, day)
    +    python_weekday = dt.weekday()  # Monday = 0, Sunday = 6
    +
    +    basic_weekday = calculate_day_of_week(year, month, day)  # Sunday = 1, Saturday = 7
    +
    +    if ((python_weekday + 2) % 7) != (basic_weekday % 7):
    +        print(f"testing yr {year} month {month} day {day}")
    +        print(f"python says {python_weekday}")
    +        print(f"BASIC says {basic_weekday}")
    +        assert False
    diff --git a/95_Weekday/python/weekday.py b/95_Weekday/python/weekday.py
    index 0a6b0aabd..6da78bb26 100644
    --- a/95_Weekday/python/weekday.py
    +++ b/95_Weekday/python/weekday.py
    @@ -12,30 +12,35 @@
     """
     
     import datetime
    -from typing import Tuple
     
     GET_TODAY_FROM_SYSTEM = True
     
     
    -def get_date_from_user(prompt: str) -> Tuple[int, int, int]:
    +def print_with_tab(space_count: int, s: str) -> None:
    +    if space_count > 0:
    +        spaces = " " * space_count
    +    else:
    +        spaces = ""
    +    print(spaces + s)
    +
    +
    +def get_date_from_user(prompt):
         while True:
             print(prompt)
             date_str = input()
             try:
                 month_num, day_num, year_num = (int(x) for x in date_str.split(","))
    -            return month_num, day_num, year_num
             except Exception:
                 print("I COULDN'T UNDERSTAND THAT. TRY AGAIN.")
    +        return month_num, day_num, year_num
     
     
    -def get_date_from_system() -> Tuple[int, int, int]:
    -    dt = datetime.datetime.now()
    +def get_date_from_system():
    +    dt = datetime.datetime.today()
         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!"
    +def get_day_of_week(weekday_index, day):
         day_names = {
             1: "SUNDAY",
             2: "MONDAY",
    @@ -46,19 +51,25 @@ 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]
     
     
    -def previous_day(b) -> int:
    +def previous_day(b):
         if b == 0:
             b = 6
         return b - 1
     
     
    -def is_leap_year(year: int) -> bool:
    +def is_leap_year(year):
         if (year % 4) != 0:
             return False
    -    return True if (year % 100) != 0 else year % 400 == 0
    +    if (year % 100) != 0:
    +        return True
    +    if (year % 400) != 0:
    +        return False
    +    return True
     
     
     def adjust_day_for_leap_year(b, year):
    @@ -82,9 +93,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 = days_available // 365
    +    years_used = int(days_available / 365)
         days_available -= years_used * 365
    -    months_used = days_available // 30
    +    months_used = int(days_available / 30)
         days_used = days_available - (months_used * 30)
         years_remain = years_remain - years_used
         months_remain = months_remain - months_used
    @@ -102,7 +113,7 @@ def deduct_time(frac, days, years_remain, months_remain, days_remain):
     
     def time_report(msg, years, months, days):
         leading_spaces = 23 - len(msg)
    -    print(" " * leading_spaces + f"{msg}\t{years}\t{months}\t{days}")
    +    print_with_tab(leading_spaces, msg + f"\t{years}\t{months}\t{days}")
     
     
     def make_occupation_label(years):
    @@ -130,14 +141,17 @@ def calculate_day_of_week(year, month, day):
         return b
     
     
    -def end() -> None:
    +def end():
         for _ in range(5):
             print()
     
     
     def main() -> None:
    -    print(" " * 32 + "WEEKDAY")
    -    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n")
    +    print_with_tab(32, "WEEKDAY")
    +    print_with_tab(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.")
         print()
    @@ -212,8 +226,8 @@ def main() -> None:
             print("***HAPPY BIRTHDAY***")
     
         # print report
    -    print(" " * 23 + "\tYEARS\tMONTHS\tDAYS")
    -    print(" " * 23 + "\t-----\t------\t----")
    +    print_with_tab(23, "\tYEARS\tMONTHS\tDAYS")
    +    print_with_tab(23, "\t-----\t------\t----")
         print(f"YOUR AGE (IF BIRTHDATE)\t{el_years}\t{el_months}\t{el_days}")
     
         life_days = (el_years * 365) + (el_months * 30) + el_days + int(el_months / 2)
    @@ -234,16 +248,18 @@ 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(f"YOU HAVE {label}", used_years, used_months, used_days)
    +    time_report("YOU HAVE " + label, used_years, used_months, used_days)
         time_report("YOU HAVE RELAXED", rem_years, rem_months, rem_days)
     
         print()
     
         # Calculate retirement date
         e = year + 65
    -    print(" " * 16 + f"***  YOU MAY RETIRE IN {e} ***")
    +    print_with_tab(16, f"***  YOU MAY RETIRE IN {e} ***")
         end()
     
     
     if __name__ == "__main__":
         main()
    +
    +    # test_harness()
    diff --git a/95_Weekday/rust/Cargo.lock b/95_Weekday/rust/Cargo.lock
    deleted file mode 100644
    index b21cc6a2d..000000000
    --- a/95_Weekday/rust/Cargo.lock
    +++ /dev/null
    @@ -1,7 +0,0 @@
    -# 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/csharp/Program.cs b/96_Word/csharp/Program.cs
    index 2e2749608..76fb3582d 100644
    --- a/96_Word/csharp/Program.cs
    +++ b/96_Word/csharp/Program.cs
    @@ -40,7 +40,7 @@ private string get_guess()
                     if ((guess.Length != 5) || (guess.Equals("?")) || (!guess.All(char.IsLetter)))
                     {
                         guess = "";
    -                    Console.WriteLine("You must guess a five letter word. Start again.");
    +                    Console.WriteLine("You must guess a give letter word. Start again.");
                     }
                 }
     
    diff --git a/96_Word/javascript/word.html b/96_Word/javascript/word.html
    new file mode 100644
    index 000000000..02419ce4a
    --- /dev/null
    +++ b/96_Word/javascript/word.html
    @@ -0,0 +1,10 @@
    +
    +
    +WORD
    +
    +
    +
    +
    
    +
    +
    +
    diff --git a/96_Word/javascript/word.js b/96_Word/javascript/word.js
    new file mode 100644
    index 000000000..3d7e3a5ac
    --- /dev/null
    +++ b/96_Word/javascript/word.js
    @@ -0,0 +1,148 @@
    +// WORD
    +//
    +// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
    +//
    +
    +function print(str)
    +{
    +    document.getElementById("output").appendChild(document.createTextNode(str));
    +}
    +
    +function input()
    +{
    +
    +    return new Promise(function (resolve) {
    +                       const input_element = document.createElement("INPUT");
    +
    +                       print("? ");
    +                       input_element.setAttribute("type", "text");
    +                       input_element.setAttribute("length", "50");
    +                       document.getElementById("output").appendChild(input_element);
    +                       input_element.focus();
    +                       input_element.addEventListener("keydown", function (event) {
    +                                                      if (event.keyCode === 13) {
    +                                                          const input_str = input_element.value;
    +                                                          document.getElementById("output").removeChild(input_element);
    +                                                          print(input_str);
    +                                                          print("\n");
    +                                                          resolve(input_str);
    +                                                      }
    +                                                      });
    +                       });
    +}
    +
    +function tab(space)
    +{
    +    let str = "";
    +    while (space-- > 0)
    +        str += " ";
    +    return str;
    +}
    +
    +// These are the words that the game knows about> If you want a bigger challenge you could add more words to the array
    +const WORDS = ["DINKY", "SMOKE", "WATER", "GLASS", "TRAIN",
    +             "MIGHT", "FIRST", "CANDY", "CHAMP", "WOULD",
    +             "CLUMP", "DOPEY"];
    +const WORD_COUNT = WORDS.length;
    +
    +// Main control section
    +async function main()
    +{
    +    print(tab(33) + "WORD\n");
    +    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
    +    print("\n");
    +    print("\n");
    +    print("\n");
    +    print("I AM THINKING OF A WORD -- YOU GUESS IT.  I WILL GIVE YOU\n");
    +    print("CLUES TO HELP YOU GET IT.  GOOD LUCK!!\n");
    +    print("\n");
    +    print("\n");
    +    outer: while (1) {
    +        print("\n");
    +        print("\n");
    +        print("YOU ARE STARTING A NEW GAME...\n");
    +
    +        const secretWord = WORDS[Math.floor(Math.random() * WORD_COUNT)];
    +
    +        let guessCount = 0;
    +        // This array holds the letters which have been found in the correct position across all guesses
    +        // For instance if the word is "PLAIN" and the guesses so far are
    +        // "SHALL" ("A" correct) and "CLIMB" ("L" correct) then it will hold "-LA--"
    +        const knownLetters = [];
    +        for (let i = 0; i < 5; i++)
    +            knownLetters[i] = "-";
    +
    +        let guess = undefined;
    +        while (1) {
    +            print("GUESS A FIVE LETTER WORD");
    +            guess = (await input()).toUpperCase();
    +            guessCount++;
    +            if (secretWord === guess) {
    +                // The player has guessed correctly
    +                break;
    +            }
    +
    +            if (guess.charAt(0) === "?") {
    +                // Player has given up
    +                print("THE SECRET WORD IS " + secretWord + "\n");
    +                print("\n");
    +                // Start a new game by going to the start of the outer while loop
    +                continue outer;
    +            }
    +
    +            if (guess.length !== 5) {
    +                print("YOU MUST GUESS A 5 LETTER WORD.  START AGAIN.\n");
    +                print("\n");
    +                guessCount--;
    +                continue;
    +            }
    +
    +            // Two things happen in this double loop:
    +            // 1. Letters which are in both the guessed and secret words are put in the lettersInCommon array
    +            // 2. Letters which are in the correct position in the guessed word are added to the knownLetters array
    +            let lettersInCommonCount = 0;
    +            const lettersInCommon = [];
    +            for (let i = 0; i < 5; i++) {// loop round characters in secret word
    +                let secretWordCharacter = secretWord.charAt(i);
    +                for (let j = 0; j < 5; j++) {// loop round characters in guessed word
    +                    let guessedWordCharacter = guess.charAt(j);
    +                    if (secretWordCharacter === guessedWordCharacter) {
    +                        lettersInCommon[lettersInCommonCount] = guessedWordCharacter;
    +                        if (i === j) {
    +                            // Letter is in the exact position so add to the known letters array
    +                            knownLetters[j] = guessedWordCharacter;
    +                        }
    +                        lettersInCommonCount++;
    +                    }
    +                }
    +            }
    +
    +            const lettersInCommonText = lettersInCommon.join("");
    +            print("THERE WERE " + lettersInCommonCount + " MATCHES AND THE COMMON LETTERS WERE... " + lettersInCommonText + "\n");
    +
    +            const knownLettersText = knownLetters.join("");
    +            print("FROM THE EXACT LETTER MATCHES, YOU KNOW............ " + knownLettersText + "\n");
    +
    +            if (knownLettersText === secretWord) {
    +                guess = knownLettersText;
    +                break;
    +            }
    +
    +            if (lettersInCommonCount <= 1) {
    +                print("\n");
    +                print("IF YOU GIVE UP, TYPE '?' FOR YOUR NEXT GUESS.\n");
    +                print("\n");
    +            }
    +        }
    +
    +        print("YOU HAVE GUESSED THE WORD.  IT TOOK " + guessCount + " GUESSES!\n");
    +        print("\n");
    +
    +        print("WANT TO PLAY AGAIN");
    +        const playAgainResponse = (await input()).toUpperCase();
    +        if (playAgainResponse !== "YES")
    +            break;
    +    }
    +}
    +
    +main();
    diff --git a/96_Word/javascript/word.mjs b/96_Word/javascript/word.mjs
    deleted file mode 100644
    index e4a1bd8ed..000000000
    --- a/96_Word/javascript/word.mjs
    +++ /dev/null
    @@ -1,114 +0,0 @@
    -#!/usr/bin/env node
    -// WORD
    -//
    -// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
    -
    -import { print, tab, input } from '../../00_Common/javascript/common.mjs';
    -
    -// These are the words that the game knows about> If you want a bigger challenge you could add more words to the array
    -const WORDS = ["DINKY", "SMOKE", "WATER", "GLASS", "TRAIN",
    -             "MIGHT", "FIRST", "CANDY", "CHAMP", "WOULD",
    -             "CLUMP", "DOPEY"];
    -const WORD_COUNT = WORDS.length;
    -
    -// Main control section
    -async function main()
    -{
    -    print(tab(33) + "WORD\n");
    -    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
    -    print("\n");
    -    print("\n");
    -    print("\n");
    -    print("I AM THINKING OF A WORD -- YOU GUESS IT.  I WILL GIVE YOU\n");
    -    print("CLUES TO HELP YOU GET IT.  GOOD LUCK!!\n");
    -    print("\n");
    -    print("\n");
    -    outer: while (1) {
    -        print("\n");
    -        print("\n");
    -        print("YOU ARE STARTING A NEW GAME...\n");
    -
    -        const secretWord = WORDS[Math.floor(Math.random() * WORD_COUNT)];
    -
    -        let guessCount = 0;
    -        // This array holds the letters which have been found in the correct position across all guesses
    -        // For instance if the word is "PLAIN" and the guesses so far are
    -        // "SHALL" ("A" correct) and "CLIMB" ("L" correct) then it will hold "-LA--"
    -        const knownLetters = [];
    -        for (let i = 0; i < 5; i++)
    -            knownLetters[i] = "-";
    -
    -        let guess = undefined;
    -        while (1) {
    -            print("GUESS A FIVE LETTER WORD:");
    -            guess = (await input()).toUpperCase();
    -            guessCount++;
    -            if (secretWord === guess) {
    -                // The player has guessed correctly
    -                break;
    -            }
    -
    -            if (guess.charAt(0) === "?") {
    -                // Player has given up
    -                print("THE SECRET WORD IS " + secretWord + "\n");
    -                print("\n");
    -                // Start a new game by going to the start of the outer while loop
    -                continue outer;
    -            }
    -
    -            if (guess.length !== 5) {
    -                print("YOU MUST GUESS A 5 LETTER WORD.  START AGAIN.\n");
    -                print("\n");
    -                guessCount--;
    -                continue;
    -            }
    -
    -            // Two things happen in this double loop:
    -            // 1. Letters which are in both the guessed and secret words are put in the lettersInCommon array
    -            // 2. Letters which are in the correct position in the guessed word are added to the knownLetters array
    -            let lettersInCommonCount = 0;
    -            const lettersInCommon = [];
    -            for (let i = 0; i < 5; i++) {// loop round characters in secret word
    -                let secretWordCharacter = secretWord.charAt(i);
    -                for (let j = 0; j < 5; j++) {// loop round characters in guessed word
    -                    let guessedWordCharacter = guess.charAt(j);
    -                    if (secretWordCharacter === guessedWordCharacter) {
    -                        lettersInCommon[lettersInCommonCount] = guessedWordCharacter;
    -                        if (i === j) {
    -                            // Letter is in the exact position so add to the known letters array
    -                            knownLetters[j] = guessedWordCharacter;
    -                        }
    -                        lettersInCommonCount++;
    -                    }
    -                }
    -            }
    -
    -            const lettersInCommonText = lettersInCommon.join("");
    -            print("THERE WERE " + lettersInCommonCount + " MATCHES AND THE COMMON LETTERS WERE... " + lettersInCommonText + "\n");
    -
    -            const knownLettersText = knownLetters.join("");
    -            print("FROM THE EXACT LETTER MATCHES, YOU KNOW............ " + knownLettersText + "\n");
    -
    -            if (knownLettersText === secretWord) {
    -                guess = knownLettersText;
    -                break;
    -            }
    -
    -            if (lettersInCommonCount <= 1) {
    -                print("\n");
    -                print("IF YOU GIVE UP, TYPE '?' FOR YOUR NEXT GUESS.\n");
    -                print("\n");
    -            }
    -        }
    -
    -        print("YOU HAVE GUESSED THE WORD.  IT TOOK " + guessCount + " GUESSES!\n");
    -        print("\n");
    -
    -        print("WANT TO PLAY AGAIN");
    -        const playAgainResponse = (await input()).toUpperCase();
    -        if (playAgainResponse !== "YES")
    -            break;
    -    }
    -}
    -
    -main();
    diff --git a/96_Word/python/word.py b/96_Word/python/word.py
    old mode 100755
    new mode 100644
    index 5ff7604a0..fcb3fc11c
    --- a/96_Word/python/word.py
    +++ b/96_Word/python/word.py
    @@ -1,10 +1,7 @@
     #!/usr/bin/env python3
    -
    -"""
    -WORD
    -
    -Converted from BASIC to Python by Trevor Hobson
    -"""
    +# WORD
    +#
    +# Converted from BASIC to Python by Trevor Hobson
     
     import random
     
    @@ -24,7 +21,7 @@
     ]
     
     
    -def play_game() -> None:
    +def play_game():
         """Play one round of the game"""
     
         random.shuffle(words)
    @@ -35,7 +32,7 @@ def play_game() -> None:
         print("You are starting a new game...")
         while True:
             guess_word = ""
    -        while not guess_word:
    +        while guess_word == "":
                 guess_word = input("\nGuess a five letter word. ").upper()
                 if guess_word == "?":
                     break
    @@ -57,15 +54,16 @@ def play_game() -> None:
                             if i == j:
                                 guess_progress[j] = guess_word[i]
                 print(
    -                f"There were {matches}",
    -                f"matches and the common letters were... {common_letters}",
    +                "There were",
    +                matches,
    +                "matches and the common letters were... " + common_letters,
                 )
                 print(
                     "From the exact letter matches, you know............ "
                     + "".join(guess_progress)
                 )
                 if "".join(guess_progress) == guess_word:
    -                print(f"\nYou have guessed the word. It took {guess_count} guesses!")
    +                print("\nYou have guessed the word. It took", guess_count, "guesses!")
                     break
                 elif matches == 0:
                     print("\nIf you give up, type '?' for you next guess.")
    diff --git a/96_Word/rust/Cargo.lock b/96_Word/rust/Cargo.lock
    deleted file mode 100644
    index 4fe2abbea..000000000
    --- a/96_Word/rust/Cargo.lock
    +++ /dev/null
    @@ -1,75 +0,0 @@
    -# 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/96_Word/rust/Cargo.toml b/96_Word/rust/Cargo.toml
    deleted file mode 100644
    index 3b1d02f52..000000000
    --- a/96_Word/rust/Cargo.toml
    +++ /dev/null
    @@ -1,9 +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]
    -rand = "0.8.5"
    diff --git a/96_Word/rust/src/main.rs b/96_Word/rust/src/main.rs
    deleted file mode 100644
    index 707779a94..000000000
    --- a/96_Word/rust/src/main.rs
    +++ /dev/null
    @@ -1,52 +0,0 @@
    -use crate::word_game::WordGame;
    -use std::io;
    -mod progress;
    -mod word_game;
    -
    -fn main() {
    -    println!("\n\n~~WORD~~");
    -    println!("Creative Computing Morristown, New Jersey");
    -
    -    println!("\nI am thinking of a word -- you guess it.");
    -    println!("I will give you clues to help you get it.");
    -    println!("Good luck!!\n");
    -
    -    let mut quit = false;
    -
    -    while quit == false {
    -        let mut game = WordGame::new();
    -        let mut game_over = false;
    -
    -        while game_over == false {
    -            game_over = game.tick();
    -        }
    -
    -        quit = !play_again();
    -    }
    -}
    -
    -fn play_again() -> bool {
    -    let mut again = true;
    -    let mut valid_response = false;
    -
    -    while valid_response == false {
    -        println!("Want to play again? (Y/n)");
    -
    -        let mut response = String::new();
    -
    -        io::stdin()
    -            .read_line(&mut response)
    -            .expect("Failed to read line.");
    -
    -        match response.trim().to_uppercase().as_str() {
    -            "Y" | "YES" => valid_response = true,
    -            "N" | "NO" => {
    -                again = false;
    -                valid_response = true;
    -            }
    -            _ => (),
    -        }
    -    }
    -
    -    again
    -}
    diff --git a/96_Word/rust/src/progress.rs b/96_Word/rust/src/progress.rs
    deleted file mode 100644
    index 46bf4d396..000000000
    --- a/96_Word/rust/src/progress.rs
    +++ /dev/null
    @@ -1,29 +0,0 @@
    -pub struct Progress {
    -    chars: [char; 5],
    -}
    -
    -impl Progress {
    -    pub fn new() -> Self {
    -        Progress { chars: ['-'; 5] }
    -    }
    -
    -    pub fn set_char_at(&mut self, c: char, i: usize) {
    -        self.chars[i] = c;
    -    }
    -
    -    pub fn print(&self) {
    -        for c in self.chars {
    -            print!("{}", c);
    -        }
    -    }
    -
    -    pub fn done(&self) -> bool {
    -        for c in self.chars {
    -            if c == '-' {
    -                return false;
    -            }
    -        }
    -
    -        true
    -    }
    -}
    diff --git a/96_Word/rust/src/word_game.rs b/96_Word/rust/src/word_game.rs
    deleted file mode 100644
    index 6df72acb8..000000000
    --- a/96_Word/rust/src/word_game.rs
    +++ /dev/null
    @@ -1,113 +0,0 @@
    -use crate::progress::Progress;
    -use rand::Rng;
    -use std::io;
    -
    -pub struct WordGame<'a> {
    -    word: &'a str,
    -    progress: Progress,
    -    guess: String,
    -    guesses: usize,
    -}
    -
    -impl WordGame<'_> {
    -    pub fn new() -> Self {
    -        const WORDS: [&str; 12] = [
    -            "DINKY", "SMOKE", "WATER", "GRASS", "TRAIN", "MIGHT", "FIRST", "CANDY", "CHAMP",
    -            "WOULD", "CLUMP", "DOPEY",
    -        ];
    -
    -        println!("\nYou are starting a new game...");
    -
    -        let random_index: usize = rand::thread_rng().gen_range(0..WORDS.len());
    -
    -        //println!("word is: {}", WORDS[random_index]);
    -
    -        WordGame {
    -            word: WORDS[random_index],
    -            progress: Progress::new(),
    -            guess: String::new(),
    -            guesses: 0,
    -        }
    -    }
    -
    -    pub fn tick(&mut self) -> bool {
    -        self.guesses += 1;
    -
    -        println!("\n\nGuess a five letter word?");
    -
    -        let mut game_over = false;
    -
    -        if WordGame::<'_>::read_guess(self) {
    -            game_over = WordGame::<'_>::process_guess(self);
    -        }
    -
    -        game_over
    -    }
    -
    -    fn read_guess(&mut self) -> bool {
    -        let mut guess = String::new();
    -
    -        io::stdin()
    -            .read_line(&mut guess)
    -            .expect("Failed to read line.");
    -
    -        let invalid_input = |message: &str| {
    -            println!("\n{} Guess again.", message);
    -            return false;
    -        };
    -
    -        let guess = guess.trim();
    -
    -        for c in guess.chars() {
    -            if c.is_numeric() {
    -                return invalid_input("Your guess cannot include numbers.");
    -            }
    -            if !c.is_ascii_alphabetic() {
    -                return invalid_input("Your guess must only include ASCII characters.");
    -            }
    -        }
    -
    -        if guess.len() != 5 {
    -            return invalid_input("You must guess a 5 letter word.");
    -        }
    -
    -        self.guess = guess.to_string();
    -
    -        true
    -    }
    -
    -    fn process_guess<'a>(&mut self) -> bool {
    -        let guess = self.guess.to_uppercase();
    -
    -        let mut matches: Vec = Vec::new();
    -
    -        for (i, c) in guess.chars().enumerate() {
    -            if self.word.contains(c) {
    -                matches.push(c);
    -
    -                if self.word.chars().nth(i).unwrap() == c {
    -                    self.progress.set_char_at(c, i);
    -                }
    -            }
    -        }
    -
    -        println!(
    -            "There were {} matches and the common letters were....{}",
    -            matches.len(),
    -            matches.into_iter().collect::()
    -        );
    -
    -        print!("From the exact letter matches you know....");
    -        self.progress.print();
    -
    -        if self.progress.done() {
    -            println!(
    -                "\n\nYou have guessed the word. It took {} guesses!\n",
    -                self.guesses
    -            );
    -            return true;
    -        }
    -
    -        false
    -    }
    -}
    diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md
    index 1d25fe417..a03348ea5 100644
    --- a/HOW_TO_RUN_THE_GAMES.md
    +++ b/HOW_TO_RUN_THE_GAMES.md
    @@ -23,15 +23,16 @@ 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 [IntelJ][def]
    +**TIP:** You can build all the java and kotlin games at once
    +using the instructions in the [buildJvm directory](buildJvm/README.md)
    +
    +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/)
     
     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/)).
     
     1. Navigate to the corresponding directory.
     1. Compile the program with `javac`:
    -   * eg. `**```python
    -   javac
    -   ```** AceyDuceyGame.java`
    +   * eg. `javac AceyDuceyGame.java`
     1. Run the compiled program with `java`:
        * eg. `java AceyDuceyGame`
     
    @@ -57,20 +58,14 @@ _Hint: Normally javascript files have a `*.js` extension. We are using `*.mjs` t
     
     ## kotlin
     
    -Kotlin programs are compiled with the Kotlin compiler, and run with the java runtime, just like java programs.
    -In addition to the java runtime you will need the `kotlinc` compiler, which can be installed using [these instructions](https://kotlinlang.org/docs/command-line.html).
    -
    -1. Navigate to the corresponding directory.
    -1. Compile the program with `kotlinc`:
    -   * eg. `kotlinc AceyDuceyGame.kt -include-runtime -d AceyDuceyGame.jar`
    -1. Run the compiled program with `java`:
    -   * eg. `java -jar AceyDuceyGame.jar`
    +Use the directions in [buildJvm](buildJvm/README.md) to build for kotlin. You can also use those directions to
    +build java games.
     
     ## pascal
     
     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_o**bject-oriented_ (in the `/object-pascal`directories) examples.
    +The pascal examples include both *simple* (single-file) and *object-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`
    @@ -94,9 +89,7 @@ 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/).
    @@ -112,13 +105,3 @@ If you don't already have a ruby interpreter, you can download it from the [ruby
     ## vbnet
     
     Follow the same steps as for the [csharp](#csharp) translations. This can be run with `dotnet` or `Visual Studio`.
    -
    -## rust
    -
    -If you don't already have Rust on your computer, you can follow the instruction on [Rust Book](https://doc.rust-lang.org/book/ch01-01-installation.html)
    -
    -1. From the command-line, navigate to the corresponding directory.
    -2. Run the following command.
    -   * `cargo run`
    -
    -[def]: https://www.jetbrains.com/idea/
    diff --git a/README.md b/README.md
    index 3b54d4471..1628f6f1c 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://archive.org/details/basiccomputergam0000unse) (pdf)
    +- [Read the original book](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf) (pdf)
     - [Play the original games in your browser](https://troypress.com/wp-content/uploads/user/js-basic/index.html)
     
     ### Where can we discuss it?
    @@ -30,8 +30,6 @@ Each project has subfolders corresponding to the languages we’d like to see th
     
     > 📢 Note that in March 2022 we removed Pascal / Object Pascal and replaced it with Rust as we couldn’t determine if Pascal is effectively memory safe. We’ve also added Lua, as it made the top 20 in TIOBE (as of 2022) and it is both memory safe and a scripting language. The Pascal ports were moved to the alternate languages folder.
     
    -> ⚠️ Please note that we have decided, as a project, that we **do not want any IDE-specific or build-specific files in the repository.** Please refrain from committing any files to the repository that only exist to work with a specific IDE or a specific build system.
    -
     ### Alternate Languages
     
     If you wish to port one of the programs to a language not in our list – that is, a language which is either not memory safe, or not a general purpose scripting language, you can do so via the `00_Alternate_Languages` folder. Place your port in the appropriate game subfolder, in a subfolder named for the language. Please note that these ports are appreciated, but they will not count toward the donation total at the end of the project.
    @@ -52,9 +50,7 @@ But first, a few guidelines:
     
     - **Use lots of comments to explain what is going on**. Comment liberally! If there were clever tricks in the original code, decompose those tricks into simpler (even if more verbose) code, and use comments to explain what’s happening and why. If there is something particularly tricky about a program, edit the **Porting Notes** section of the `readme.md` to let everyone know. Those `GOTO`s can be very pesky..
     
    -- **Please don’t get _too_ fancy**. Definitely use the most recent versions and features of the target language, but also try to keep the code samples simple and explainable – the goal is to teach programming in the target language, not necessarily demonstrate the cleverest one-line tricks, or big system "enterprise" coding techniques designed for thousands of lines of code.
    -
    -- **Please don't check in any build specific or IDE specific files**. We want the repository to be simple and clean, so we have ruled out including any IDE or build system specific files from the repository. Git related files are OK, as we are using Git and this is GitHub. 😉
    +- **Don’t get _too_ fancy**. Definitely use the most recent versions and features of the target language, but also try to keep the code samples simple and explainable – the goal is to teach programming in the target language, not necessarily demonstrate the cleverest one-line tricks.
     
     ### Emulation and Bugfixes
     
    @@ -71,108 +67,3 @@ 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 | 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 | 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 | 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 | 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 | 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 | 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 | x | -| 44_Hangman | 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 | 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 | 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 | 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 | 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 | 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 | 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 | x | -| 86_Target | 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 | -| 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 | 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 | - -
    diff --git a/basic-computer-games-gradle b/basic-computer-games-gradle deleted file mode 160000 index 367112cc0..000000000 --- a/basic-computer-games-gradle +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 367112cc067a3623bcca174e354ed671c73c8acb diff --git a/buildJvm/README.md b/buildJvm/README.md new file mode 100644 index 000000000..42e540a35 --- /dev/null +++ b/buildJvm/README.md @@ -0,0 +1,175 @@ +# JVM gradle scripts + +## Quickstart +You will need to install openjdk 17, because some games use advanced Java features. +We should be using version 17 anyway, because anything less than 17 is deprecated. + +Build all the games: +```shell + cd buildJvm + ./gradlew -q clean assemble installDist distributeBin distributeLib +``` + +Then, run a game: + +### Mac or linux: +```shell +build/distrib/bin/build_53_King_kotlin +``` +### Windows +[not tested yet] + +```shell +build\distrib\bin\build_53_King_kotlin.bat +``` + +--- +## Using an IDE to work on JVM games + +You can open the entire Basic Computer Games project in an IDE, with any IDE capable +of importing from a gradle project. + +### IntelliJ / Android Studio + +1. (Optional) If you want to make changes, or contribute a new kotlin or java version +of one of the games, use [github "fork"](https://docs.github.com/en/get-started/quickstart/fork-a-repo) +to create your own editable fork of the project. +2. Check out the code using `File` -> `New` -> `Project from Version Control` + 1. Enter the URL of the project. For the main project this will be `https://github.com/coding-horror/basic-computer-games.git`, for your +own fork this will be `https://github.com/YOURNAMEHERE/basic-computer-games.git` + 2. Choose a directory for the clone to live in +3. Click `Clone` + +The project will open, and eventually you will get a little alert box in the bottom right corner saying "Gradle build script found". + +Click the "Load" link in the alert box, to load the gradle project. + +You should see all the games appear on the left side of the screen. If you have loaded +your own fork, you can modify, commit and push your changes to github. + +If you are using the main `coding-horror` branch, you can still make and run your own changes. If +your git skills are up to the task, you might even fork the project and change your +local clone to point to your new forked project. + + +--- +## Adding a new game + +These are build scripts for all JVM games contributed so far. +New games can be added: +- Create a new `build_NUMBER_NAME_[java/kotlin]` directory +- Add a `build.gradle` file to that directory. +All `build.gradle` files under `build_NUMBER_*` are identical. +- Add a `gradle.properties` file to that directory, defining the source +directory for the java or kotlin file, and the class that contains the `main` method. +- Add an entry in `settings.gradle` + +The `build.gradle` file **should** be identical to all the other `build.gradle` files +in all the other subprojects: +```groovy + sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } + } + application { + mainClass = gameMain + } +``` + +The `gradle.properties` file should look like this: + + gameSource=91_Train/java/src + gameMain=Train + +where `gameSource` is the root of the source code directory, and `gameMain` is the main class. + +The `settings.gradle` must be maintained as a list of all subprojects. Add your new +project to the list. + +```groovy +include ":build_91_Train_java" +``` + +### Adding a game with tests + +You can add tests for JVM games with a `build.gradle` looking a little different. +Use the build files from `03_Animal` as a template to add tests: + +```groovy +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } + test { + java { + srcDirs "../../$gameTest" + } + } +} + +application { + mainClass = gameMain +} + +dependencies { + testImplementation(project(":build_00_utilities").sourceSets.test.output) +} +``` + +The gradle.properties needs an additional directory name for the tests, as `gameTest` : +``` +gameSource=03_Animal/java/src +gameTest=03_Animal/java/test +gameMain=Animal +``` + +Each project should have its own test, and shouldn't share test source directories +with other projects, even if they are for the same game. + +Tests are constructed by subclassing `ConsoleTest`. This allows you to use the +`assertConversation` function to check for correct interactive conversations. +```kotlin +import com.pcholt.console.testutils.ConsoleTest +import org.junit.Test + +class AnimalJavaTest : ConsoleTest() { + @Test + fun `should have a simple conversation`() { + assertConversation( + """ + WHAT'S YOUR NAME? {PAUL} + YOUR NAME IS PAUL? {YES} + THANKS FOR PLAYING + """ + ) { + // The game's Main method + main() + } + } +} +``` + +Curly brackets are the expected user input. +Note - this is actually just a way of defining the expected input as "PAUL" and "YES" +and not that the input happens at the exact prompt position. Thus this is equivalent: +```kotlin +""" +{PAUL} {YES} WHAT'S YOUR NAME? +YOUR NAME IS PAUL? +THANKS FOR PLAYING +""" +``` + +Amounts of whitespace are not counted, but whitespace is significant: You will get a failure if +your game emits `"NAME?"` when it expects `"NAME ?"`. + +Run all the tests from within the buildJvm project directory: +```bash +cd buildJvm +./gradlew test +``` diff --git a/buildJvm/build.gradle.kts b/buildJvm/build.gradle.kts new file mode 100644 index 000000000..0d37953de --- /dev/null +++ b/buildJvm/build.gradle.kts @@ -0,0 +1,63 @@ +plugins { + kotlin("jvm") version "1.6.0" + id("application") +} + +version = "unspecified" + +repositories { + mavenCentral() + google() +} + +dependencies { + implementation(kotlin("stdlib")) +} + + +task("distributeBin", Copy::class) { + from(filesType("bin")) + into("$buildDir/distrib/bin") + duplicatesStrategy = DuplicatesStrategy.WARN + dependsOn(":build_94_War_kotlin:installDist") +} + +task("distributeLib", Copy::class) { + from(filesType("lib")) + into("$buildDir/distrib/lib") + duplicatesStrategy = DuplicatesStrategy.WARN + dependsOn("installDist") +} + +task("copyAll") { + dependsOn( + ":distributeBin", + ":distributeLib" + ) +} + +subprojects { + apply(plugin = "application") + apply(plugin = "kotlin") + apply(plugin = "java") + repositories { + mavenCentral() + } + dependencies { + testImplementation("junit:junit:4.13.2") + testImplementation("com.github.stefanbirkner:system-rules:1.19.0") + testImplementation("com.google.truth:truth:1.1.3") + } + java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } + } + +} + +fun filesType(type: String) = + fileTree("$buildDir/..").files.filter { + it.path.contains("build/install/build_.*/$type".toRegex()) + && it.isFile + } diff --git a/buildJvm/build_00_utilities/build.gradle b/buildJvm/build_00_utilities/build.gradle new file mode 100644 index 000000000..72b8b8c4f --- /dev/null +++ b/buildJvm/build_00_utilities/build.gradle @@ -0,0 +1,7 @@ +sourceSets { + test { + java { + srcDirs "../../$testSource" + } + } +} diff --git a/buildJvm/build_00_utilities/gradle.properties b/buildJvm/build_00_utilities/gradle.properties new file mode 100644 index 000000000..2ad9bb1a4 --- /dev/null +++ b/buildJvm/build_00_utilities/gradle.properties @@ -0,0 +1 @@ +testSource=00_Utilities/jvmTestUtils/kotlin/test diff --git a/buildJvm/build_01_Acey_Ducey_java/build.gradle b/buildJvm/build_01_Acey_Ducey_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_01_Acey_Ducey_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_01_Acey_Ducey_java/gradle.properties b/buildJvm/build_01_Acey_Ducey_java/gradle.properties new file mode 100644 index 000000000..fbf1902a9 --- /dev/null +++ b/buildJvm/build_01_Acey_Ducey_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=01_Acey_Ducey/java/src +gameMain=AceyDuceyGame diff --git a/buildJvm/build_01_Acey_Ducey_java17/build.gradle b/buildJvm/build_01_Acey_Ducey_java17/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_01_Acey_Ducey_java17/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_01_Acey_Ducey_java17/gradle.properties b/buildJvm/build_01_Acey_Ducey_java17/gradle.properties new file mode 100644 index 000000000..d708d9647 --- /dev/null +++ b/buildJvm/build_01_Acey_Ducey_java17/gradle.properties @@ -0,0 +1,2 @@ +gameSource=01_Acey_Ducey/java/src +gameMain=AceyDucey17 diff --git a/buildJvm/build_01_Acey_Ducey_kotlin/build.gradle b/buildJvm/build_01_Acey_Ducey_kotlin/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_01_Acey_Ducey_kotlin/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_01_Acey_Ducey_kotlin/gradle.properties b/buildJvm/build_01_Acey_Ducey_kotlin/gradle.properties new file mode 100644 index 000000000..c456df918 --- /dev/null +++ b/buildJvm/build_01_Acey_Ducey_kotlin/gradle.properties @@ -0,0 +1,2 @@ +gameSource=01_Acey_Ducey/kotlin +gameMain=AceyduceyKt diff --git a/buildJvm/build_02_Amazing_java/build.gradle b/buildJvm/build_02_Amazing_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_02_Amazing_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_02_Amazing_java/gradle.properties b/buildJvm/build_02_Amazing_java/gradle.properties new file mode 100644 index 000000000..aa5f3f7b2 --- /dev/null +++ b/buildJvm/build_02_Amazing_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=02_Amazing/java +gameMain=AmazingGame diff --git a/buildJvm/build_03_Animal_java/build.gradle b/buildJvm/build_03_Animal_java/build.gradle new file mode 100644 index 000000000..cc4475267 --- /dev/null +++ b/buildJvm/build_03_Animal_java/build.gradle @@ -0,0 +1,20 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } + test { + java { + srcDirs "../../$gameTest" + } + } +} + +application { + mainClass = gameMain +} + +dependencies { + testImplementation(project(":build_00_utilities").sourceSets.test.output) +} diff --git a/buildJvm/build_03_Animal_java/gradle.properties b/buildJvm/build_03_Animal_java/gradle.properties new file mode 100644 index 000000000..496fc2d79 --- /dev/null +++ b/buildJvm/build_03_Animal_java/gradle.properties @@ -0,0 +1,3 @@ +gameSource=03_Animal/java/src +gameTest=03_Animal/java/test +gameMain=Animal diff --git a/buildJvm/build_03_Animal_kotlin/build.gradle b/buildJvm/build_03_Animal_kotlin/build.gradle new file mode 100644 index 000000000..cc4475267 --- /dev/null +++ b/buildJvm/build_03_Animal_kotlin/build.gradle @@ -0,0 +1,20 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } + test { + java { + srcDirs "../../$gameTest" + } + } +} + +application { + mainClass = gameMain +} + +dependencies { + testImplementation(project(":build_00_utilities").sourceSets.test.output) +} diff --git a/buildJvm/build_03_Animal_kotlin/gradle.properties b/buildJvm/build_03_Animal_kotlin/gradle.properties new file mode 100644 index 000000000..a3fdf99fe --- /dev/null +++ b/buildJvm/build_03_Animal_kotlin/gradle.properties @@ -0,0 +1,3 @@ +gameSource=03_Animal/kotlin/src +gameTest=03_Animal/kotlin/test +gameMain=AnimalKt diff --git a/buildJvm/build_04_Awari_java/build.gradle b/buildJvm/build_04_Awari_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_04_Awari_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_04_Awari_java/gradle.properties b/buildJvm/build_04_Awari_java/gradle.properties new file mode 100644 index 000000000..423fdc34a --- /dev/null +++ b/buildJvm/build_04_Awari_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=04_Awari/java +gameMain=AwariGame diff --git a/buildJvm/build_05_Bagels_java/build.gradle b/buildJvm/build_05_Bagels_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_05_Bagels_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_05_Bagels_java/gradle.properties b/buildJvm/build_05_Bagels_java/gradle.properties new file mode 100644 index 000000000..b1b8273d0 --- /dev/null +++ b/buildJvm/build_05_Bagels_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=05_Bagels/java +gameMain=Bagels diff --git a/buildJvm/build_06_Banner_java/build.gradle b/buildJvm/build_06_Banner_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_06_Banner_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_06_Banner_java/gradle.properties b/buildJvm/build_06_Banner_java/gradle.properties new file mode 100644 index 000000000..8808e9aa9 --- /dev/null +++ b/buildJvm/build_06_Banner_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=06_Banner/java +gameMain=Banner diff --git a/buildJvm/build_07_Basketball_java/build.gradle b/buildJvm/build_07_Basketball_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_07_Basketball_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_07_Basketball_java/gradle.properties b/buildJvm/build_07_Basketball_java/gradle.properties new file mode 100644 index 000000000..c648f9006 --- /dev/null +++ b/buildJvm/build_07_Basketball_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=07_Basketball/java +gameMain=Basketball diff --git a/buildJvm/build_08_Batnum_java/build.gradle b/buildJvm/build_08_Batnum_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_08_Batnum_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_08_Batnum_java/gradle.properties b/buildJvm/build_08_Batnum_java/gradle.properties new file mode 100644 index 000000000..87a3671f2 --- /dev/null +++ b/buildJvm/build_08_Batnum_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=08_Batnum/java/src +gameMain=BatnumGame diff --git a/buildJvm/build_09_Battle_java/build.gradle b/buildJvm/build_09_Battle_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_09_Battle_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_09_Battle_java/gradle.properties b/buildJvm/build_09_Battle_java/gradle.properties new file mode 100644 index 000000000..d694e2df9 --- /dev/null +++ b/buildJvm/build_09_Battle_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=09_Battle/java +gameMain=Battle diff --git a/buildJvm/build_10_Blackjack_java/build.gradle b/buildJvm/build_10_Blackjack_java/build.gradle new file mode 100644 index 000000000..fe39dad3a --- /dev/null +++ b/buildJvm/build_10_Blackjack_java/build.gradle @@ -0,0 +1,32 @@ +plugins { + id 'application' +} + +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } + test { + java { + srcDirs "../../$testSource" + } + } +} + +repositories { + mavenCentral() +} + +application { + mainClass = gameMain +} + +test { + useJUnitPlatform() +} + +dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' +} diff --git a/buildJvm/build_10_Blackjack_java/gradle.properties b/buildJvm/build_10_Blackjack_java/gradle.properties new file mode 100644 index 000000000..c66d391f5 --- /dev/null +++ b/buildJvm/build_10_Blackjack_java/gradle.properties @@ -0,0 +1,3 @@ +gameSource=10_Blackjack/java/src +testSource=10_Blackjack/java/test +gameMain=Blackjack diff --git a/buildJvm/build_11_Bombardment_java/build.gradle b/buildJvm/build_11_Bombardment_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_11_Bombardment_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_11_Bombardment_java/gradle.properties b/buildJvm/build_11_Bombardment_java/gradle.properties new file mode 100644 index 000000000..1aaa839b4 --- /dev/null +++ b/buildJvm/build_11_Bombardment_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=11_Bombardment/java/src +gameMain=BombardmentGame diff --git a/buildJvm/build_12_Bombs_Away_java/build.gradle b/buildJvm/build_12_Bombs_Away_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_12_Bombs_Away_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_12_Bombs_Away_java/gradle.properties b/buildJvm/build_12_Bombs_Away_java/gradle.properties new file mode 100644 index 000000000..2f2b785a4 --- /dev/null +++ b/buildJvm/build_12_Bombs_Away_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=12_Bombs_Away/java/src +gameMain=BombsAwayGame diff --git a/buildJvm/build_13_Bounce_java/build.gradle b/buildJvm/build_13_Bounce_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_13_Bounce_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_13_Bounce_java/gradle.properties b/buildJvm/build_13_Bounce_java/gradle.properties new file mode 100644 index 000000000..b69fbc282 --- /dev/null +++ b/buildJvm/build_13_Bounce_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=13_Bounce/java +gameMain=Bounce diff --git a/buildJvm/build_14_Bowling_java/build.gradle b/buildJvm/build_14_Bowling_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_14_Bowling_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_14_Bowling_java/gradle.properties b/buildJvm/build_14_Bowling_java/gradle.properties new file mode 100644 index 000000000..2570015c7 --- /dev/null +++ b/buildJvm/build_14_Bowling_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=14_Bowling/java +gameMain=Bowling diff --git a/buildJvm/build_15_Boxing_java/build.gradle b/buildJvm/build_15_Boxing_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_15_Boxing_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_15_Boxing_java/gradle.properties b/buildJvm/build_15_Boxing_java/gradle.properties new file mode 100644 index 000000000..2c8ca8fc2 --- /dev/null +++ b/buildJvm/build_15_Boxing_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=15_Boxing/java +gameMain=BoxingGame diff --git a/buildJvm/build_16_Bug_java/build.gradle b/buildJvm/build_16_Bug_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_16_Bug_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_16_Bug_java/gradle.properties b/buildJvm/build_16_Bug_java/gradle.properties new file mode 100644 index 000000000..215d60ef0 --- /dev/null +++ b/buildJvm/build_16_Bug_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=16_Bug/java/src +gameMain=BugGame diff --git a/buildJvm/build_18_Bullseye_java/build.gradle b/buildJvm/build_18_Bullseye_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_18_Bullseye_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_18_Bullseye_java/gradle.properties b/buildJvm/build_18_Bullseye_java/gradle.properties new file mode 100644 index 000000000..912db9b64 --- /dev/null +++ b/buildJvm/build_18_Bullseye_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=18_Bullseye/java/src +gameMain=BullseyeGame diff --git a/buildJvm/build_19_Bunny_java/build.gradle b/buildJvm/build_19_Bunny_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_19_Bunny_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_19_Bunny_java/gradle.properties b/buildJvm/build_19_Bunny_java/gradle.properties new file mode 100644 index 000000000..a480589c4 --- /dev/null +++ b/buildJvm/build_19_Bunny_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=19_Bunny/java/src +gameMain=Bunny diff --git a/buildJvm/build_20_Buzzword_java/build.gradle b/buildJvm/build_20_Buzzword_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_20_Buzzword_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_20_Buzzword_java/gradle.properties b/buildJvm/build_20_Buzzword_java/gradle.properties new file mode 100644 index 000000000..ce73aa674 --- /dev/null +++ b/buildJvm/build_20_Buzzword_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=20_Buzzword/java/src +gameMain=Buzzword diff --git a/buildJvm/build_21_Calendar_java/build.gradle b/buildJvm/build_21_Calendar_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_21_Calendar_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_21_Calendar_java/gradle.properties b/buildJvm/build_21_Calendar_java/gradle.properties new file mode 100644 index 000000000..048bcabf8 --- /dev/null +++ b/buildJvm/build_21_Calendar_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=21_Calendar/java +gameMain=Calendar diff --git a/buildJvm/build_22_Change_java/build.gradle b/buildJvm/build_22_Change_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_22_Change_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_22_Change_java/gradle.properties b/buildJvm/build_22_Change_java/gradle.properties new file mode 100644 index 000000000..737243aec --- /dev/null +++ b/buildJvm/build_22_Change_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=22_Change/java/src +gameMain=ChangeGame diff --git a/buildJvm/build_24_Chemist_java/build.gradle b/buildJvm/build_24_Chemist_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_24_Chemist_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_24_Chemist_java/gradle.properties b/buildJvm/build_24_Chemist_java/gradle.properties new file mode 100644 index 000000000..e4a4a594c --- /dev/null +++ b/buildJvm/build_24_Chemist_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=24_Chemist/java/src +gameMain=ChemistGame diff --git a/buildJvm/build_25_Chief_java/build.gradle b/buildJvm/build_25_Chief_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_25_Chief_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_25_Chief_java/gradle.properties b/buildJvm/build_25_Chief_java/gradle.properties new file mode 100644 index 000000000..e0eed8634 --- /dev/null +++ b/buildJvm/build_25_Chief_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=25_Chief/java/src +gameMain=ChiefGame diff --git a/buildJvm/build_26_Chomp_java/build.gradle b/buildJvm/build_26_Chomp_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_26_Chomp_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_26_Chomp_java/gradle.properties b/buildJvm/build_26_Chomp_java/gradle.properties new file mode 100644 index 000000000..15f18276a --- /dev/null +++ b/buildJvm/build_26_Chomp_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=26_Chomp/java +gameMain=Chomp diff --git a/buildJvm/build_27_Civil_War_java/build.gradle b/buildJvm/build_27_Civil_War_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_27_Civil_War_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_27_Civil_War_java/gradle.properties b/buildJvm/build_27_Civil_War_java/gradle.properties new file mode 100644 index 000000000..eaf00ff10 --- /dev/null +++ b/buildJvm/build_27_Civil_War_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=27_Civil_War/java/src +gameMain=CivilWar diff --git a/buildJvm/build_28_Combat_java/build.gradle b/buildJvm/build_28_Combat_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_28_Combat_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_28_Combat_java/gradle.properties b/buildJvm/build_28_Combat_java/gradle.properties new file mode 100644 index 000000000..5dfb010cb --- /dev/null +++ b/buildJvm/build_28_Combat_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=28_Combat/java +gameMain=Combat diff --git a/buildJvm/build_29_Craps_java/build.gradle b/buildJvm/build_29_Craps_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_29_Craps_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_29_Craps_java/gradle.properties b/buildJvm/build_29_Craps_java/gradle.properties new file mode 100644 index 000000000..32b614fe6 --- /dev/null +++ b/buildJvm/build_29_Craps_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=29_Craps/java/src +gameMain=Craps diff --git a/buildJvm/build_30_Cube_java/build.gradle b/buildJvm/build_30_Cube_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_30_Cube_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_30_Cube_java/gradle.properties b/buildJvm/build_30_Cube_java/gradle.properties new file mode 100644 index 000000000..13f1b6e51 --- /dev/null +++ b/buildJvm/build_30_Cube_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=30_Cube/java/src +gameMain=Cube diff --git a/buildJvm/build_31_Depth_Charge_java/build.gradle b/buildJvm/build_31_Depth_Charge_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_31_Depth_Charge_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_31_Depth_Charge_java/gradle.properties b/buildJvm/build_31_Depth_Charge_java/gradle.properties new file mode 100644 index 000000000..239dfcb75 --- /dev/null +++ b/buildJvm/build_31_Depth_Charge_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=31_Depth_Charge/java +gameMain=DepthCharge diff --git a/buildJvm/build_32_Diamond_java/build.gradle b/buildJvm/build_32_Diamond_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_32_Diamond_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_32_Diamond_java/gradle.properties b/buildJvm/build_32_Diamond_java/gradle.properties new file mode 100644 index 000000000..7581c0dee --- /dev/null +++ b/buildJvm/build_32_Diamond_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=32_Diamond/java +gameMain=Diamond diff --git a/buildJvm/build_33_Dice_java/build.gradle b/buildJvm/build_33_Dice_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_33_Dice_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_33_Dice_java/gradle.properties b/buildJvm/build_33_Dice_java/gradle.properties new file mode 100644 index 000000000..77cfe4285 --- /dev/null +++ b/buildJvm/build_33_Dice_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=33_Dice/java/src +gameMain=DiceGame diff --git a/buildJvm/build_34_Digits_java/build.gradle b/buildJvm/build_34_Digits_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_34_Digits_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_34_Digits_java/gradle.properties b/buildJvm/build_34_Digits_java/gradle.properties new file mode 100644 index 000000000..ec084f564 --- /dev/null +++ b/buildJvm/build_34_Digits_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=34_Digits/java +gameMain=Digits diff --git a/buildJvm/build_36_Flip_Flop_java/build.gradle b/buildJvm/build_36_Flip_Flop_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_36_Flip_Flop_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_36_Flip_Flop_java/gradle.properties b/buildJvm/build_36_Flip_Flop_java/gradle.properties new file mode 100644 index 000000000..d60259c16 --- /dev/null +++ b/buildJvm/build_36_Flip_Flop_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=36_Flip_Flop/java +gameMain=FlipFlop diff --git a/buildJvm/build_38_Fur_Trader_java/build.gradle b/buildJvm/build_38_Fur_Trader_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_38_Fur_Trader_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_38_Fur_Trader_java/gradle.properties b/buildJvm/build_38_Fur_Trader_java/gradle.properties new file mode 100644 index 000000000..4ff34b338 --- /dev/null +++ b/buildJvm/build_38_Fur_Trader_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=38_Fur_Trader/java/src +gameMain=FurTraderGame diff --git a/buildJvm/build_40_Gomoko_java/build.gradle b/buildJvm/build_40_Gomoko_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_40_Gomoko_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_40_Gomoko_java/gradle.properties b/buildJvm/build_40_Gomoko_java/gradle.properties new file mode 100644 index 000000000..e755deb60 --- /dev/null +++ b/buildJvm/build_40_Gomoko_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=40_Gomoko/java +gameMain=Gomoko diff --git a/buildJvm/build_41_Guess_java/build.gradle b/buildJvm/build_41_Guess_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_41_Guess_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_41_Guess_java/gradle.properties b/buildJvm/build_41_Guess_java/gradle.properties new file mode 100644 index 000000000..19b97033a --- /dev/null +++ b/buildJvm/build_41_Guess_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=41_Guess/java/src +gameMain=GuessGame diff --git a/buildJvm/build_42_Gunner_java/build.gradle b/buildJvm/build_42_Gunner_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_42_Gunner_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_42_Gunner_java/gradle.properties b/buildJvm/build_42_Gunner_java/gradle.properties new file mode 100644 index 000000000..0e6429c66 --- /dev/null +++ b/buildJvm/build_42_Gunner_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=42_Gunner/java +gameMain=Gunner diff --git a/buildJvm/build_43_Hammurabi_java/build.gradle b/buildJvm/build_43_Hammurabi_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_43_Hammurabi_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_43_Hammurabi_java/gradle.properties b/buildJvm/build_43_Hammurabi_java/gradle.properties new file mode 100644 index 000000000..3374d23ec --- /dev/null +++ b/buildJvm/build_43_Hammurabi_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=43_Hammurabi/java/src +gameMain=HamurabiGame diff --git a/buildJvm/build_44_Hangman_java/build.gradle b/buildJvm/build_44_Hangman_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_44_Hangman_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_44_Hangman_java/gradle.properties b/buildJvm/build_44_Hangman_java/gradle.properties new file mode 100644 index 000000000..8fb150178 --- /dev/null +++ b/buildJvm/build_44_Hangman_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=44_Hangman/java +gameMain=Hangman diff --git a/buildJvm/build_45_Hello_java/build.gradle b/buildJvm/build_45_Hello_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_45_Hello_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_45_Hello_java/gradle.properties b/buildJvm/build_45_Hello_java/gradle.properties new file mode 100644 index 000000000..2caf52cdf --- /dev/null +++ b/buildJvm/build_45_Hello_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=45_Hello/java +gameMain=Hello diff --git a/buildJvm/build_47_Hi-Lo_java/build.gradle b/buildJvm/build_47_Hi-Lo_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_47_Hi-Lo_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_47_Hi-Lo_java/gradle.properties b/buildJvm/build_47_Hi-Lo_java/gradle.properties new file mode 100644 index 000000000..f464c19e4 --- /dev/null +++ b/buildJvm/build_47_Hi-Lo_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=47_Hi-Lo/java/src +gameMain=HiLoGame diff --git a/buildJvm/build_47_Hi-Lo_kotlin/build.gradle b/buildJvm/build_47_Hi-Lo_kotlin/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_47_Hi-Lo_kotlin/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_47_Hi-Lo_kotlin/gradle.properties b/buildJvm/build_47_Hi-Lo_kotlin/gradle.properties new file mode 100644 index 000000000..0ecd0e05f --- /dev/null +++ b/buildJvm/build_47_Hi-Lo_kotlin/gradle.properties @@ -0,0 +1,2 @@ +gameSource=47_Hi-Lo/kotlin +gameMain=HiLoKt diff --git a/buildJvm/build_48_High_IQ_java/build.gradle b/buildJvm/build_48_High_IQ_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_48_High_IQ_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_48_High_IQ_java/gradle.properties b/buildJvm/build_48_High_IQ_java/gradle.properties new file mode 100644 index 000000000..ec7588fcb --- /dev/null +++ b/buildJvm/build_48_High_IQ_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=48_High_IQ/java/src +gameMain=HighIQGame diff --git a/buildJvm/build_51_Hurkle_java/build.gradle b/buildJvm/build_51_Hurkle_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_51_Hurkle_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_51_Hurkle_java/gradle.properties b/buildJvm/build_51_Hurkle_java/gradle.properties new file mode 100644 index 000000000..7151e8d4d --- /dev/null +++ b/buildJvm/build_51_Hurkle_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=51_Hurkle/java/src +gameMain=HurkleGame diff --git a/buildJvm/build_52_Kinema_java/build.gradle b/buildJvm/build_52_Kinema_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_52_Kinema_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_52_Kinema_java/gradle.properties b/buildJvm/build_52_Kinema_java/gradle.properties new file mode 100644 index 000000000..bfa9a2573 --- /dev/null +++ b/buildJvm/build_52_Kinema_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=52_Kinema/java/src +gameMain=KinemaGame diff --git a/buildJvm/build_53_King_kotlin/build.gradle b/buildJvm/build_53_King_kotlin/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_53_King_kotlin/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_53_King_kotlin/gradle.properties b/buildJvm/build_53_King_kotlin/gradle.properties new file mode 100644 index 000000000..4b90ac8df --- /dev/null +++ b/buildJvm/build_53_King_kotlin/gradle.properties @@ -0,0 +1,2 @@ +gameSource=53_King/kotlin +gameMain=king53.KingKt diff --git a/buildJvm/build_54_Letter_java/build.gradle b/buildJvm/build_54_Letter_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_54_Letter_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_54_Letter_java/gradle.properties b/buildJvm/build_54_Letter_java/gradle.properties new file mode 100644 index 000000000..37511a56c --- /dev/null +++ b/buildJvm/build_54_Letter_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=54_Letter/java/src +gameMain=LetterGame diff --git a/buildJvm/build_57_Literature_Quiz_java/build.gradle b/buildJvm/build_57_Literature_Quiz_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_57_Literature_Quiz_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_57_Literature_Quiz_java/gradle.properties b/buildJvm/build_57_Literature_Quiz_java/gradle.properties new file mode 100644 index 000000000..0102ba469 --- /dev/null +++ b/buildJvm/build_57_Literature_Quiz_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=57_Literature_Quiz/java/src +gameMain=LiteratureQuizGame diff --git a/buildJvm/build_58_Love_java/build.gradle b/buildJvm/build_58_Love_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_58_Love_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_58_Love_java/gradle.properties b/buildJvm/build_58_Love_java/gradle.properties new file mode 100644 index 000000000..620ea65f4 --- /dev/null +++ b/buildJvm/build_58_Love_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=58_Love/java/src +gameMain=Love diff --git a/buildJvm/build_61_Math_Dice_java/build.gradle b/buildJvm/build_61_Math_Dice_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_61_Math_Dice_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_61_Math_Dice_java/gradle.properties b/buildJvm/build_61_Math_Dice_java/gradle.properties new file mode 100644 index 000000000..7644f2be4 --- /dev/null +++ b/buildJvm/build_61_Math_Dice_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=61_Math_Dice/java +gameMain=MathDice diff --git a/buildJvm/build_62_Mugwump_java/build.gradle b/buildJvm/build_62_Mugwump_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_62_Mugwump_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_62_Mugwump_java/gradle.properties b/buildJvm/build_62_Mugwump_java/gradle.properties new file mode 100644 index 000000000..5ad87d0b0 --- /dev/null +++ b/buildJvm/build_62_Mugwump_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=62_Mugwump/java/src +gameMain=Mugwump diff --git a/buildJvm/build_63_Name_java/build.gradle b/buildJvm/build_63_Name_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_63_Name_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_63_Name_java/gradle.properties b/buildJvm/build_63_Name_java/gradle.properties new file mode 100644 index 000000000..e5c44f967 --- /dev/null +++ b/buildJvm/build_63_Name_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=63_Name/java +gameMain=Name diff --git a/buildJvm/build_64_Nicomachus_java/build.gradle b/buildJvm/build_64_Nicomachus_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_64_Nicomachus_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_64_Nicomachus_java/gradle.properties b/buildJvm/build_64_Nicomachus_java/gradle.properties new file mode 100644 index 000000000..4d385abc2 --- /dev/null +++ b/buildJvm/build_64_Nicomachus_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=64_Nicomachus/java/src +gameMain=Nicomachus diff --git a/buildJvm/build_66_Number1_java/build.gradle b/buildJvm/build_66_Number1_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_66_Number1_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_66_Number1_java/gradle.properties b/buildJvm/build_66_Number1_java/gradle.properties new file mode 100644 index 000000000..ab62d4b86 --- /dev/null +++ b/buildJvm/build_66_Number1_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=66_Number/java/1 +gameMain=Number diff --git a/buildJvm/build_66_Number2_java/build.gradle b/buildJvm/build_66_Number2_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_66_Number2_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_66_Number2_java/gradle.properties b/buildJvm/build_66_Number2_java/gradle.properties new file mode 100644 index 000000000..cc390231a --- /dev/null +++ b/buildJvm/build_66_Number2_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=66_Number/java/2 +gameMain=Number diff --git a/buildJvm/build_67_One_Check_java/build.gradle b/buildJvm/build_67_One_Check_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_67_One_Check_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_67_One_Check_java/gradle.properties b/buildJvm/build_67_One_Check_java/gradle.properties new file mode 100644 index 000000000..995bd254e --- /dev/null +++ b/buildJvm/build_67_One_Check_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=67_One_Check/java +gameMain=OneCheck diff --git a/buildJvm/build_68_Orbit_java/build.gradle b/buildJvm/build_68_Orbit_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_68_Orbit_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_68_Orbit_java/gradle.properties b/buildJvm/build_68_Orbit_java/gradle.properties new file mode 100644 index 000000000..aa1fe24eb --- /dev/null +++ b/buildJvm/build_68_Orbit_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=68_Orbit/java +gameMain=Orbit diff --git a/buildJvm/build_69_Pizza_java/build.gradle b/buildJvm/build_69_Pizza_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_69_Pizza_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_69_Pizza_java/gradle.properties b/buildJvm/build_69_Pizza_java/gradle.properties new file mode 100644 index 000000000..959746a6a --- /dev/null +++ b/buildJvm/build_69_Pizza_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=69_Pizza/java/src +gameMain=PizzaGame diff --git a/buildJvm/build_70_Poetry_java/build.gradle b/buildJvm/build_70_Poetry_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_70_Poetry_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_70_Poetry_java/gradle.properties b/buildJvm/build_70_Poetry_java/gradle.properties new file mode 100644 index 000000000..4d8d8585c --- /dev/null +++ b/buildJvm/build_70_Poetry_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=70_Poetry/java +gameMain=Poetry diff --git a/buildJvm/build_71_Poker_java/build.gradle b/buildJvm/build_71_Poker_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_71_Poker_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_71_Poker_java/gradle.properties b/buildJvm/build_71_Poker_java/gradle.properties new file mode 100644 index 000000000..07033ee52 --- /dev/null +++ b/buildJvm/build_71_Poker_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=71_Poker/java +gameMain=Poker diff --git a/buildJvm/build_73_Reverse_java/build.gradle b/buildJvm/build_73_Reverse_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_73_Reverse_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_73_Reverse_java/gradle.properties b/buildJvm/build_73_Reverse_java/gradle.properties new file mode 100644 index 000000000..6ddce57d0 --- /dev/null +++ b/buildJvm/build_73_Reverse_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=73_Reverse/java +gameMain=Reverse diff --git a/buildJvm/build_74_Rock_Scissors_Paper_java/build.gradle b/buildJvm/build_74_Rock_Scissors_Paper_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_74_Rock_Scissors_Paper_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_74_Rock_Scissors_Paper_java/gradle.properties b/buildJvm/build_74_Rock_Scissors_Paper_java/gradle.properties new file mode 100644 index 000000000..1cdf93a7f --- /dev/null +++ b/buildJvm/build_74_Rock_Scissors_Paper_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=74_Rock_Scissors_Paper/java/src +gameMain=RockScissors diff --git a/buildJvm/build_75_Roulette_iterative_java/build.gradle b/buildJvm/build_75_Roulette_iterative_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_75_Roulette_iterative_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_75_Roulette_iterative_java/gradle.properties b/buildJvm/build_75_Roulette_iterative_java/gradle.properties new file mode 100644 index 000000000..e765d3a48 --- /dev/null +++ b/buildJvm/build_75_Roulette_iterative_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=75_Roulette/java/iterative +gameMain=Roulette diff --git a/buildJvm/build_75_Roulette_oop_java/build.gradle b/buildJvm/build_75_Roulette_oop_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_75_Roulette_oop_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_75_Roulette_oop_java/gradle.properties b/buildJvm/build_75_Roulette_oop_java/gradle.properties new file mode 100644 index 000000000..d476e11dc --- /dev/null +++ b/buildJvm/build_75_Roulette_oop_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=75_Roulette/java/oop +gameMain=Roulette diff --git a/buildJvm/build_76_Russian_Roulette_java/build.gradle b/buildJvm/build_76_Russian_Roulette_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_76_Russian_Roulette_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_76_Russian_Roulette_java/gradle.properties b/buildJvm/build_76_Russian_Roulette_java/gradle.properties new file mode 100644 index 000000000..89078da09 --- /dev/null +++ b/buildJvm/build_76_Russian_Roulette_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=76_Russian_Roulette/java/src +gameMain=RussianRoulette diff --git a/buildJvm/build_78_Sine_Wave_java/build.gradle b/buildJvm/build_78_Sine_Wave_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_78_Sine_Wave_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_78_Sine_Wave_java/gradle.properties b/buildJvm/build_78_Sine_Wave_java/gradle.properties new file mode 100644 index 000000000..c5adb119e --- /dev/null +++ b/buildJvm/build_78_Sine_Wave_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=78_Sine_Wave/java/src +gameMain=SineWave diff --git a/buildJvm/build_80_Slots_java/build.gradle b/buildJvm/build_80_Slots_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_80_Slots_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_80_Slots_java/gradle.properties b/buildJvm/build_80_Slots_java/gradle.properties new file mode 100644 index 000000000..f4930f1e6 --- /dev/null +++ b/buildJvm/build_80_Slots_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=80_Slots/java/src +gameMain=SlotsGame diff --git a/buildJvm/build_81_Splat_java/build.gradle b/buildJvm/build_81_Splat_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_81_Splat_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_81_Splat_java/gradle.properties b/buildJvm/build_81_Splat_java/gradle.properties new file mode 100644 index 000000000..0fa5a0c4c --- /dev/null +++ b/buildJvm/build_81_Splat_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=81_Splat/java/src +gameMain=Splat diff --git a/buildJvm/build_82_Stars_java/build.gradle b/buildJvm/build_82_Stars_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_82_Stars_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_82_Stars_java/gradle.properties b/buildJvm/build_82_Stars_java/gradle.properties new file mode 100644 index 000000000..5f2e51f6d --- /dev/null +++ b/buildJvm/build_82_Stars_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=82_Stars/java/src +gameMain=StarsGame diff --git a/buildJvm/build_83_Stock_Market_java/build.gradle b/buildJvm/build_83_Stock_Market_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_83_Stock_Market_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_83_Stock_Market_java/gradle.properties b/buildJvm/build_83_Stock_Market_java/gradle.properties new file mode 100644 index 000000000..73b7dc1fd --- /dev/null +++ b/buildJvm/build_83_Stock_Market_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=83_Stock_Market/java +gameMain=StockMarket diff --git a/buildJvm/build_85_Synonym_java/build.gradle b/buildJvm/build_85_Synonym_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_85_Synonym_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_85_Synonym_java/gradle.properties b/buildJvm/build_85_Synonym_java/gradle.properties new file mode 100644 index 000000000..448430db3 --- /dev/null +++ b/buildJvm/build_85_Synonym_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=85_Synonym/java/src +gameMain=SynonymGame diff --git a/buildJvm/build_85_Synonym_kotlin/build.gradle b/buildJvm/build_85_Synonym_kotlin/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_85_Synonym_kotlin/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_85_Synonym_kotlin/gradle.properties b/buildJvm/build_85_Synonym_kotlin/gradle.properties new file mode 100644 index 000000000..eb7434723 --- /dev/null +++ b/buildJvm/build_85_Synonym_kotlin/gradle.properties @@ -0,0 +1,2 @@ +gameSource=85_Synonym/kotlin +gameMain=SynonymKt diff --git a/buildJvm/build_86_Target_java/build.gradle b/buildJvm/build_86_Target_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_86_Target_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_86_Target_java/gradle.properties b/buildJvm/build_86_Target_java/gradle.properties new file mode 100644 index 000000000..cdb506acf --- /dev/null +++ b/buildJvm/build_86_Target_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=86_Target/java +gameMain=Target diff --git a/buildJvm/build_87_3-D_Plot_java/build.gradle b/buildJvm/build_87_3-D_Plot_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_87_3-D_Plot_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_87_3-D_Plot_java/gradle.properties b/buildJvm/build_87_3-D_Plot_java/gradle.properties new file mode 100644 index 000000000..fb6ce1a90 --- /dev/null +++ b/buildJvm/build_87_3-D_Plot_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=87_3-D_Plot/java +gameMain=Plot3D diff --git a/buildJvm/build_89_Tic-Tac-Toe_java/build.gradle b/buildJvm/build_89_Tic-Tac-Toe_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_89_Tic-Tac-Toe_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_89_Tic-Tac-Toe_java/gradle.properties b/buildJvm/build_89_Tic-Tac-Toe_java/gradle.properties new file mode 100644 index 000000000..5f342b1de --- /dev/null +++ b/buildJvm/build_89_Tic-Tac-Toe_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=89_Tic-Tac-Toe/java/src +gameMain=TicTacToe2 diff --git a/buildJvm/build_89_Tic-Tac-Toe_kotlin/build.gradle b/buildJvm/build_89_Tic-Tac-Toe_kotlin/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_89_Tic-Tac-Toe_kotlin/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_89_Tic-Tac-Toe_kotlin/gradle.properties b/buildJvm/build_89_Tic-Tac-Toe_kotlin/gradle.properties new file mode 100644 index 000000000..dce0b4f3e --- /dev/null +++ b/buildJvm/build_89_Tic-Tac-Toe_kotlin/gradle.properties @@ -0,0 +1,2 @@ +gameSource=89_Tic-Tac-Toe/kotlin +gameMain=TicTacToe2Kt diff --git a/buildJvm/build_90_Tower_java/build.gradle b/buildJvm/build_90_Tower_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_90_Tower_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_90_Tower_java/gradle.properties b/buildJvm/build_90_Tower_java/gradle.properties new file mode 100644 index 000000000..faf3c4378 --- /dev/null +++ b/buildJvm/build_90_Tower_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=90_Tower/java +gameMain=Tower diff --git a/buildJvm/build_91_Train_java/build.gradle b/buildJvm/build_91_Train_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_91_Train_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_91_Train_java/gradle.properties b/buildJvm/build_91_Train_java/gradle.properties new file mode 100644 index 000000000..8e315af22 --- /dev/null +++ b/buildJvm/build_91_Train_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=91_Train/java/src +gameMain=Train diff --git a/buildJvm/build_92_Trap_java/build.gradle b/buildJvm/build_92_Trap_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_92_Trap_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_92_Trap_java/gradle.properties b/buildJvm/build_92_Trap_java/gradle.properties new file mode 100644 index 000000000..3b4e9a752 --- /dev/null +++ b/buildJvm/build_92_Trap_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=92_Trap/java/src +gameMain=TrapGame diff --git a/buildJvm/build_93_23_Matches_java/build.gradle b/buildJvm/build_93_23_Matches_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_93_23_Matches_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_93_23_Matches_java/gradle.properties b/buildJvm/build_93_23_Matches_java/gradle.properties new file mode 100644 index 000000000..b9ae6b7bc --- /dev/null +++ b/buildJvm/build_93_23_Matches_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=93_23_Matches/java +gameMain=TwentyThreeMatchesGame diff --git a/buildJvm/build_94_War_java/build.gradle b/buildJvm/build_94_War_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_94_War_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_94_War_java/gradle.properties b/buildJvm/build_94_War_java/gradle.properties new file mode 100644 index 000000000..3cf5ec6d9 --- /dev/null +++ b/buildJvm/build_94_War_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=94_War/java +gameMain=War diff --git a/buildJvm/build_94_War_kotlin/build.gradle b/buildJvm/build_94_War_kotlin/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_94_War_kotlin/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_94_War_kotlin/gradle.properties b/buildJvm/build_94_War_kotlin/gradle.properties new file mode 100644 index 000000000..e9fdd4bcb --- /dev/null +++ b/buildJvm/build_94_War_kotlin/gradle.properties @@ -0,0 +1,2 @@ +gameSource=94_War/kotlin +gameMain=WarKt diff --git a/buildJvm/build_95_Weekday_java/build.gradle b/buildJvm/build_95_Weekday_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_95_Weekday_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_95_Weekday_java/gradle.properties b/buildJvm/build_95_Weekday_java/gradle.properties new file mode 100644 index 000000000..bef38fdd8 --- /dev/null +++ b/buildJvm/build_95_Weekday_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=95_Weekday/java +gameMain=Weekday diff --git a/buildJvm/build_96_Word_java/build.gradle b/buildJvm/build_96_Word_java/build.gradle new file mode 100644 index 000000000..132b05dd7 --- /dev/null +++ b/buildJvm/build_96_Word_java/build.gradle @@ -0,0 +1,11 @@ +sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } +} + +application { + mainClass = gameMain +} diff --git a/buildJvm/build_96_Word_java/gradle.properties b/buildJvm/build_96_Word_java/gradle.properties new file mode 100644 index 000000000..82d745870 --- /dev/null +++ b/buildJvm/build_96_Word_java/gradle.properties @@ -0,0 +1,2 @@ +gameSource=96_Word/java +gameMain=Word diff --git a/53_King/csharp/Resources/InsufficientReserves.txt b/buildJvm/gradle.properties similarity index 100% rename from 53_King/csharp/Resources/InsufficientReserves.txt rename to buildJvm/gradle.properties diff --git a/buildJvm/gradle/wrapper/gradle-wrapper.jar b/buildJvm/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..7454180f2 Binary files /dev/null and b/buildJvm/gradle/wrapper/gradle-wrapper.jar differ diff --git a/buildJvm/gradle/wrapper/gradle-wrapper.properties b/buildJvm/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..ffed3a254 --- /dev/null +++ b/buildJvm/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/buildJvm/gradlew b/buildJvm/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/buildJvm/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/buildJvm/gradlew.bat b/buildJvm/gradlew.bat new file mode 100644 index 000000000..ac1b06f93 --- /dev/null +++ b/buildJvm/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/buildJvm/settings.gradle b/buildJvm/settings.gradle new file mode 100644 index 000000000..c9a3de0a5 --- /dev/null +++ b/buildJvm/settings.gradle @@ -0,0 +1,93 @@ +rootProject.name = 'BasicComputerGames' + +include ":build_00_utilities" + +include ":build_01_Acey_Ducey_kotlin" +include ":build_03_Animal_kotlin" +include ":build_53_King_kotlin" +include ":build_47_Hi-Lo_kotlin" +include ":build_53_King_kotlin" +include ":build_85_Synonym_kotlin" +include ":build_89_Tic-Tac-Toe_kotlin" +include ":build_94_War_kotlin" + +include ":build_01_Acey_Ducey_java" +include ":build_01_Acey_Ducey_java17" +include ":build_02_Amazing_java" +include ":build_03_Animal_java" +include ":build_04_Awari_java" +include ":build_05_Bagels_java" +include ":build_06_Banner_java" +include ":build_07_Basketball_java" +include ":build_08_Batnum_java" +include ":build_09_Battle_java" +include ":build_10_Blackjack_java" +include ":build_11_Bombardment_java" +include ":build_12_Bombs_Away_java" +include ":build_13_Bounce_java" +include ":build_14_Bowling_java" +include ":build_15_Boxing_java" +include ":build_16_Bug_java" +include ":build_18_Bullseye_java" +include ":build_19_Bunny_java" +include ":build_20_Buzzword_java" +include ":build_21_Calendar_java" +include ":build_22_Change_java" +include ":build_24_Chemist_java" +include ":build_25_Chief_java" +include ":build_26_Chomp_java" +include ":build_27_Civil_War_java" +include ":build_28_Combat_java" +include ":build_29_Craps_java" +include ":build_30_Cube_java" +include ":build_31_Depth_Charge_java" +include ":build_32_Diamond_java" +include ":build_33_Dice_java" +include ":build_34_Digits_java" +include ":build_36_Flip_Flop_java" +include ":build_38_Fur_Trader_java" +include ":build_40_Gomoko_java" +include ":build_41_Guess_java" +include ":build_42_Gunner_java" +include ":build_43_Hammurabi_java" +include ":build_44_Hangman_java" +include ":build_45_Hello_java" +include ":build_47_Hi-Lo_java" +include ":build_48_High_IQ_java" +include ":build_51_Hurkle_java" +include ":build_52_Kinema_java" +include ":build_54_Letter_java" +include ":build_57_Literature_Quiz_java" +include ":build_58_Love_java" +include ":build_61_Math_Dice_java" +include ":build_62_Mugwump_java" +include ":build_63_Name_java" +include ":build_64_Nicomachus_java" +include ":build_66_Number1_java" +include ":build_66_Number2_java" +include ":build_67_One_Check_java" +include ":build_68_Orbit_java" +include ":build_69_Pizza_java" +include ":build_70_Poetry_java" +include ":build_71_Poker_java" +include ":build_73_Reverse_java" +include ":build_74_Rock_Scissors_Paper_java" +include ":build_75_Roulette_iterative_java" +include ":build_75_Roulette_oop_java" +include ":build_76_Russian_Roulette_java" +include ":build_78_Sine_Wave_java" +include ":build_80_Slots_java" +include ":build_81_Splat_java" +include ":build_82_Stars_java" +include ":build_83_Stock_Market_java" +include ":build_85_Synonym_java" +include ":build_86_Target_java" +include ":build_87_3-D_Plot_java" +include ":build_89_Tic-Tac-Toe_java" +include ":build_90_Tower_java" +include ":build_91_Train_java" +include ":build_92_Trap_java" +include ":build_93_23_Matches_java" +include ":build_94_War_java" +include ":build_95_Weekday_java" +include ":build_96_Word_java" diff --git a/index.html b/index.html index cb9ea8d35..d64b517e3 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -BASIC Computer Games
    \ No newline at end of file +BASIC Computer Games

    BASIC Computer Games

    \ No newline at end of file

    BASIC Computer Games