From 5ac95df4184a7effc39255d9736d59b8c09c8d1d Mon Sep 17 00:00:00 2001 From: NezumiRonin Date: Tue, 9 Mar 2021 21:59:33 -0600 Subject: [PATCH 001/331] Create russianroulette.pl Horrible use of gotos in PERL (or any language), but it was converted automatically with a Perl Script. --- 76 Russian Roulette/perl/russianroulette.pl | 39 +++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 76 Russian Roulette/perl/russianroulette.pl diff --git a/76 Russian Roulette/perl/russianroulette.pl b/76 Russian Roulette/perl/russianroulette.pl new file mode 100644 index 00000000..0fa0cff7 --- /dev/null +++ b/76 Russian Roulette/perl/russianroulette.pl @@ -0,0 +1,39 @@ +#!/usr/bin/perl +#use strict; +# Automatic converted by bas2perl.pl + +print ' 'x28 . "RUSSIAN ROULETTE\n"; +print ' 'x15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n"; print "\n"; print "\n"; +print "THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\n"; +Line10: +print "\n"; print "HERE IS A REVOLVER.\n"; +Line20: +print "TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER.\n"; +print "TYPE '2' TO GIVE UP.\n"; +print "GO"; +$N=0; +Line30: +print "? "; chomp($I = ); +if ($I ne 2) { goto Line35; } +print " CHICKEN!!!!!\n"; +goto Line72; +Line35: +$N=$N+1; +if (rand(1)>.833333) { goto Line70; } +if ($N>10) { goto Line80; } +print "- CLICK -\n"; +print "\n"; goto Line30; +Line70: +print " BANG!!!!! YOU'RE DEAD!\n"; +print "CONDOLENCES WILL BE SENT TO YOUR RELATIVES.\n"; +Line72: +print "\n"; print "\n"; print "\n"; +print "...NEXT VICTIM...\n"; goto Line20; +Line80: +print "YOU WIN!!!!!\n"; +print "LET SOMEONE ELSE BLOW HIS BRAINS OUT.\n"; +goto Line10; +exit; + + From ede6acee55f7f2ba6bc2705a4751da7d33befb68 Mon Sep 17 00:00:00 2001 From: Pat Ludwig Date: Sun, 2 Jan 2022 16:41:07 -0600 Subject: [PATCH 002/331] 82_Stars perl implementation --- 82_Stars/perl/stars.pl | 56 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100755 82_Stars/perl/stars.pl diff --git a/82_Stars/perl/stars.pl b/82_Stars/perl/stars.pl new file mode 100755 index 00000000..6c1b5392 --- /dev/null +++ b/82_Stars/perl/stars.pl @@ -0,0 +1,56 @@ +#!/usr/bin/perl + +use v5.11; # for say and use strict +use warnings; + +my $MAX_NUMBER = 100; +my $MAX_GUESSES = 7; + +print<<__END_OF_INTRO; + Stars + Creative Computing Morristown, New Jersey + + + +__END_OF_INTRO + +print "Do you want instructions? "; +chomp( my $answer = <> ); +if ( $answer !~ /^N/i ) { + print<<__END_OF_INSTRUCTIONS; +I am thinking of a whole number from 1 to $MAX_NUMBER +Try to guess my number. After you guess, I +will type one or more stars (*). The more +stars I type, the closer you are to my number. +One star (*) means far away, seven stars (*******) +means really close! You get $MAX_GUESSES guesses. +__END_OF_INSTRUCTIONS +} + + +while (1) { + my $number_to_guess = int(rand($MAX_NUMBER) + 1); + say "\n\nOK, I am thinking of a number, start guessing."; + + my $guess_number = 1; + while ( $guess_number <= $MAX_GUESSES ) { + print "\nYour Guess? "; + chomp( my $guess = <> ); + last if $guess == $number_to_guess; + $guess_number++; + my $difference = abs $guess - $number_to_guess; + print '*' if $difference < 2; + print '*' if $difference < 4; + print '*' if $difference < 8; + print '*' if $difference < 16; + print '*' if $difference < 32; + print '*' if $difference < 64; + print "*\n"; + } + if ( $guess_number > $MAX_GUESSES ) { # didn't guess + say "\nSorry, that's $MAX_GUESSES guesses, number was $number_to_guess"; + } else { # winner! + say '*' x 50, '!!!'; + say "You got it in $guess_number guesses!!! Let's play again..."; + } +} From 1c6984aa6935ef33026a540e0f7adff70fce1d97 Mon Sep 17 00:00:00 2001 From: RibTips <36372030+ribtips@users.noreply.github.com> Date: Sun, 2 Jan 2022 18:19:53 -0500 Subject: [PATCH 003/331] MathDice in perl A version of MathDice written in perl --- 61_Math_Dice/perl/mathdice.pl | 121 ++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 61_Math_Dice/perl/mathdice.pl diff --git a/61_Math_Dice/perl/mathdice.pl b/61_Math_Dice/perl/mathdice.pl new file mode 100644 index 00000000..f5a92459 --- /dev/null +++ b/61_Math_Dice/perl/mathdice.pl @@ -0,0 +1,121 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +&main; + +# Main subroutine + +sub main { + &print_intro; + while (1==1) { + &game_play; #function that actually plays the game + } +} + +sub game_play { + my $num = 0; + my $sum = 0; + my $tries = 0; + until ($num == 2) { # there are 2 dice rolls so we do it until the num equals 2 + $num++; + my $roll = 1+int rand(6); # getting a random number between 1 and 6 + &print_dice($roll); # function call to print out the dice + $sum = $sum + $roll; # keeping track of the summary + #print "Sum: $sum Roll: $roll\n"; + if ($num == 1) { + print " +\n"; # if its the first roll then print an addition sign + } + if ($num == 2) { + print " =\n"; # if its the second roll print the equals sign and wait for an answer + my $answer = ; + chomp($answer); + if ($answer == 0) { + die "You input '0', Thanks for playing!\n"; + } + elsif ($answer == $sum) { + print "RIGHT!\nTHE DICE ROLL AGAIN\n"; + } + else { # code execution if they don't get the right answer + print "NO,COUNT THE SPOTS AND GIVE ANOTHER ANSWER\n"; + $answer = ; + chomp($answer); + if ($answer == $sum){ + print "RIGHT!\nTHE DICE ROLL AGAIN\n"; + } + else { + print "N0, THE ANSWER IS $sum\n"; + } + + } + } + } +} + +sub print_dice { + my $roll = shift; + print " -----\n"; + if ($roll == 1) { + &print_blank; + &print_one_mid; + &print_blank; + } + if ($roll == 2) { + &print_one_left; + &print_blank; + &print_one_right; + } + if ($roll == 3) { + &print_one_left; + &print_one_mid; + &print_one_right; + } + if ($roll == 4) { + &print_two; + &print_blank; + &print_two; + } + if ($roll == 5) { + &print_two; + &print_one_mid; + &print_two; + } + if ($roll == 6) { + &print_two; + &print_two; + &print_two; + } + print " -----\n"; +} + +sub print_one_left { + print "I * I\n"; +} + +sub print_one_mid { + print "I * I\n"; +} + +sub print_one_right { + print "I * I\n"; +} + +sub print_two { + print "I * * I\n"; +} + +sub print_blank { + print "I I\n"; +} + +sub print_intro { + my $spaces = " "x31; + print "$spaces MATH DICE\n"; + $spaces = " "x15; + print "$spaces CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; + print "THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.\n"; + print "WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION\n"; + print "MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.\n"; + print "TO CONCLUDE THE LESSON, TYPE '0' AS YOUR ANSWER.\n\n\n"; +} From e8ec059b498d1b7d67cb449bba5fb7aff70a8617 Mon Sep 17 00:00:00 2001 From: Bastiaan Veelo Date: Mon, 3 Jan 2022 00:21:00 +0100 Subject: [PATCH 004/331] Fix minor typo in Basic source of Acey-Ducey. As compared to the printed version. --- 01_Acey_Ducey/aceyducey.bas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01_Acey_Ducey/aceyducey.bas b/01_Acey_Ducey/aceyducey.bas index 2c8b1c3b..0b6f72db 100644 --- a/01_Acey_Ducey/aceyducey.bas +++ b/01_Acey_Ducey/aceyducey.bas @@ -10,7 +10,7 @@ 80 PRINT"IF YOU DO NOT WANT TO BET, INPUT A 0" 100 N=100 110 Q=100 -120 PRINT "YOU NOW HAVE";Q;"DOLLARS." +120 PRINT "YOU NOW HAVE ";Q;" DOLLARS." 130 PRINT 140 GOTO 260 210 Q=Q+M From b3b460779e33809cfefa89f96243609cacacbc8c Mon Sep 17 00:00:00 2001 From: Josh Gribbon Date: Sun, 2 Jan 2022 18:50:20 -0500 Subject: [PATCH 005/331] Move folder for consistency --- {90 Tower => 90_Tower}/csharp/Tower.sln | 0 {90 Tower => 90_Tower}/csharp/Tower/Game.cs | 0 {90 Tower => 90_Tower}/csharp/Tower/Models/Needle.cs | 0 {90 Tower => 90_Tower}/csharp/Tower/Models/Towers.cs | 0 {90 Tower => 90_Tower}/csharp/Tower/Program.cs | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/Congratulations.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskCountPrompt.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskCountQuit.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskCountRetry.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskNotInPlay.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskPrompt.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskQuit.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskRetry.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskUnavailable.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/IllegalMove.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/Instructions.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/Intro.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/NeedlePrompt.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/NeedleQuit.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/NeedleRetry.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/PlayAgainPrompt.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/Strings.cs | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/TaskFinished.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/Thanks.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/Title.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/TooManyMoves.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Resources/YesNoPrompt.txt | 0 {90 Tower => 90_Tower}/csharp/Tower/Tower.csproj | 0 {90 Tower => 90_Tower}/csharp/Tower/UI/Input.cs | 0 {90 Tower => 90_Tower}/csharp/Tower/UI/Prompt.cs | 0 {90 Tower => 90_Tower}/csharp/Tower/UI/TowerDisplay.cs | 0 31 files changed, 0 insertions(+), 0 deletions(-) rename {90 Tower => 90_Tower}/csharp/Tower.sln (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Game.cs (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Models/Needle.cs (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Models/Towers.cs (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Program.cs (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/Congratulations.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskCountPrompt.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskCountQuit.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskCountRetry.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskNotInPlay.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskPrompt.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskQuit.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskRetry.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/DiskUnavailable.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/IllegalMove.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/Instructions.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/Intro.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/NeedlePrompt.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/NeedleQuit.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/NeedleRetry.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/PlayAgainPrompt.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/Strings.cs (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/TaskFinished.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/Thanks.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/Title.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/TooManyMoves.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Resources/YesNoPrompt.txt (100%) rename {90 Tower => 90_Tower}/csharp/Tower/Tower.csproj (100%) rename {90 Tower => 90_Tower}/csharp/Tower/UI/Input.cs (100%) rename {90 Tower => 90_Tower}/csharp/Tower/UI/Prompt.cs (100%) rename {90 Tower => 90_Tower}/csharp/Tower/UI/TowerDisplay.cs (100%) diff --git a/90 Tower/csharp/Tower.sln b/90_Tower/csharp/Tower.sln similarity index 100% rename from 90 Tower/csharp/Tower.sln rename to 90_Tower/csharp/Tower.sln diff --git a/90 Tower/csharp/Tower/Game.cs b/90_Tower/csharp/Tower/Game.cs similarity index 100% rename from 90 Tower/csharp/Tower/Game.cs rename to 90_Tower/csharp/Tower/Game.cs diff --git a/90 Tower/csharp/Tower/Models/Needle.cs b/90_Tower/csharp/Tower/Models/Needle.cs similarity index 100% rename from 90 Tower/csharp/Tower/Models/Needle.cs rename to 90_Tower/csharp/Tower/Models/Needle.cs diff --git a/90 Tower/csharp/Tower/Models/Towers.cs b/90_Tower/csharp/Tower/Models/Towers.cs similarity index 100% rename from 90 Tower/csharp/Tower/Models/Towers.cs rename to 90_Tower/csharp/Tower/Models/Towers.cs diff --git a/90 Tower/csharp/Tower/Program.cs b/90_Tower/csharp/Tower/Program.cs similarity index 100% rename from 90 Tower/csharp/Tower/Program.cs rename to 90_Tower/csharp/Tower/Program.cs diff --git a/90 Tower/csharp/Tower/Resources/Congratulations.txt b/90_Tower/csharp/Tower/Resources/Congratulations.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/Congratulations.txt rename to 90_Tower/csharp/Tower/Resources/Congratulations.txt diff --git a/90 Tower/csharp/Tower/Resources/DiskCountPrompt.txt b/90_Tower/csharp/Tower/Resources/DiskCountPrompt.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/DiskCountPrompt.txt rename to 90_Tower/csharp/Tower/Resources/DiskCountPrompt.txt diff --git a/90 Tower/csharp/Tower/Resources/DiskCountQuit.txt b/90_Tower/csharp/Tower/Resources/DiskCountQuit.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/DiskCountQuit.txt rename to 90_Tower/csharp/Tower/Resources/DiskCountQuit.txt diff --git a/90 Tower/csharp/Tower/Resources/DiskCountRetry.txt b/90_Tower/csharp/Tower/Resources/DiskCountRetry.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/DiskCountRetry.txt rename to 90_Tower/csharp/Tower/Resources/DiskCountRetry.txt diff --git a/90 Tower/csharp/Tower/Resources/DiskNotInPlay.txt b/90_Tower/csharp/Tower/Resources/DiskNotInPlay.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/DiskNotInPlay.txt rename to 90_Tower/csharp/Tower/Resources/DiskNotInPlay.txt diff --git a/90 Tower/csharp/Tower/Resources/DiskPrompt.txt b/90_Tower/csharp/Tower/Resources/DiskPrompt.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/DiskPrompt.txt rename to 90_Tower/csharp/Tower/Resources/DiskPrompt.txt diff --git a/90 Tower/csharp/Tower/Resources/DiskQuit.txt b/90_Tower/csharp/Tower/Resources/DiskQuit.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/DiskQuit.txt rename to 90_Tower/csharp/Tower/Resources/DiskQuit.txt diff --git a/90 Tower/csharp/Tower/Resources/DiskRetry.txt b/90_Tower/csharp/Tower/Resources/DiskRetry.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/DiskRetry.txt rename to 90_Tower/csharp/Tower/Resources/DiskRetry.txt diff --git a/90 Tower/csharp/Tower/Resources/DiskUnavailable.txt b/90_Tower/csharp/Tower/Resources/DiskUnavailable.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/DiskUnavailable.txt rename to 90_Tower/csharp/Tower/Resources/DiskUnavailable.txt diff --git a/90 Tower/csharp/Tower/Resources/IllegalMove.txt b/90_Tower/csharp/Tower/Resources/IllegalMove.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/IllegalMove.txt rename to 90_Tower/csharp/Tower/Resources/IllegalMove.txt diff --git a/90 Tower/csharp/Tower/Resources/Instructions.txt b/90_Tower/csharp/Tower/Resources/Instructions.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/Instructions.txt rename to 90_Tower/csharp/Tower/Resources/Instructions.txt diff --git a/90 Tower/csharp/Tower/Resources/Intro.txt b/90_Tower/csharp/Tower/Resources/Intro.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/Intro.txt rename to 90_Tower/csharp/Tower/Resources/Intro.txt diff --git a/90 Tower/csharp/Tower/Resources/NeedlePrompt.txt b/90_Tower/csharp/Tower/Resources/NeedlePrompt.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/NeedlePrompt.txt rename to 90_Tower/csharp/Tower/Resources/NeedlePrompt.txt diff --git a/90 Tower/csharp/Tower/Resources/NeedleQuit.txt b/90_Tower/csharp/Tower/Resources/NeedleQuit.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/NeedleQuit.txt rename to 90_Tower/csharp/Tower/Resources/NeedleQuit.txt diff --git a/90 Tower/csharp/Tower/Resources/NeedleRetry.txt b/90_Tower/csharp/Tower/Resources/NeedleRetry.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/NeedleRetry.txt rename to 90_Tower/csharp/Tower/Resources/NeedleRetry.txt diff --git a/90 Tower/csharp/Tower/Resources/PlayAgainPrompt.txt b/90_Tower/csharp/Tower/Resources/PlayAgainPrompt.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/PlayAgainPrompt.txt rename to 90_Tower/csharp/Tower/Resources/PlayAgainPrompt.txt diff --git a/90 Tower/csharp/Tower/Resources/Strings.cs b/90_Tower/csharp/Tower/Resources/Strings.cs similarity index 100% rename from 90 Tower/csharp/Tower/Resources/Strings.cs rename to 90_Tower/csharp/Tower/Resources/Strings.cs diff --git a/90 Tower/csharp/Tower/Resources/TaskFinished.txt b/90_Tower/csharp/Tower/Resources/TaskFinished.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/TaskFinished.txt rename to 90_Tower/csharp/Tower/Resources/TaskFinished.txt diff --git a/90 Tower/csharp/Tower/Resources/Thanks.txt b/90_Tower/csharp/Tower/Resources/Thanks.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/Thanks.txt rename to 90_Tower/csharp/Tower/Resources/Thanks.txt diff --git a/90 Tower/csharp/Tower/Resources/Title.txt b/90_Tower/csharp/Tower/Resources/Title.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/Title.txt rename to 90_Tower/csharp/Tower/Resources/Title.txt diff --git a/90 Tower/csharp/Tower/Resources/TooManyMoves.txt b/90_Tower/csharp/Tower/Resources/TooManyMoves.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/TooManyMoves.txt rename to 90_Tower/csharp/Tower/Resources/TooManyMoves.txt diff --git a/90 Tower/csharp/Tower/Resources/YesNoPrompt.txt b/90_Tower/csharp/Tower/Resources/YesNoPrompt.txt similarity index 100% rename from 90 Tower/csharp/Tower/Resources/YesNoPrompt.txt rename to 90_Tower/csharp/Tower/Resources/YesNoPrompt.txt diff --git a/90 Tower/csharp/Tower/Tower.csproj b/90_Tower/csharp/Tower/Tower.csproj similarity index 100% rename from 90 Tower/csharp/Tower/Tower.csproj rename to 90_Tower/csharp/Tower/Tower.csproj diff --git a/90 Tower/csharp/Tower/UI/Input.cs b/90_Tower/csharp/Tower/UI/Input.cs similarity index 100% rename from 90 Tower/csharp/Tower/UI/Input.cs rename to 90_Tower/csharp/Tower/UI/Input.cs diff --git a/90 Tower/csharp/Tower/UI/Prompt.cs b/90_Tower/csharp/Tower/UI/Prompt.cs similarity index 100% rename from 90 Tower/csharp/Tower/UI/Prompt.cs rename to 90_Tower/csharp/Tower/UI/Prompt.cs diff --git a/90 Tower/csharp/Tower/UI/TowerDisplay.cs b/90_Tower/csharp/Tower/UI/TowerDisplay.cs similarity index 100% rename from 90 Tower/csharp/Tower/UI/TowerDisplay.cs rename to 90_Tower/csharp/Tower/UI/TowerDisplay.cs From 7e3304c907635ac2424737ca91e2c94d09c5e336 Mon Sep 17 00:00:00 2001 From: LukasMurdock Date: Sun, 2 Jan 2022 19:06:19 -0500 Subject: [PATCH 006/331] add 1-16 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 16:Bug “If you elect to see all the pictures, this program has the ability of consuming well over six feet of terminal paper per run. We can only suggest recycling the paper by using the other side.” --- 01_Acey_Ducey/README.md | 13 +++++++++++-- 02_Amazing/README.md | 11 +++++++++-- 03_Animal/README.md | 17 ++++++++++++++++- 04_Awari/README.md | 33 ++++++++++++++++++++++++++++++++- 05_Bagels/README.md | 15 ++++++++++++++- 06_Banner/README.md | 9 ++++++++- 07_Basketball/README.md | 25 ++++++++++++++++++++++++- 08_Batnum/README.md | 17 +++++++++++++++-- 09_Battle/README.md | 22 +++++++++++++++++++++- 10_Blackjack/README.md | 13 +++++++++++-- 11_Bombardment/README.md | 13 +++++++++++-- 12_Bombs_Away/README.md | 11 +++++++++-- 13_Bounce/README.md | 13 +++++++++++-- 14_Bowling/README.md | 15 +++++++++++++-- 15_Boxing/README.md | 13 +++++++++++-- 16_Bug/README.md | 15 +++++++++++++-- 16 files changed, 229 insertions(+), 26 deletions(-) diff --git a/01_Acey_Ducey/README.md b/01_Acey_Ducey/README.md index 071a80e3..3434eb8e 100644 --- a/01_Acey_Ducey/README.md +++ b/01_Acey_Ducey/README.md @@ -1,7 +1,16 @@ ### Acey Ducey -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=2 +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; you may want to alter this value if you want to start with more or less than $100. The game keeps going on until you lose all your money or interrupt the program. + +The original program author was Bill Palmby of Prairie View, Illinois. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=2) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=17) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/02_Amazing/README.md b/02_Amazing/README.md index 1e646723..8f7b271b 100644 --- a/02_Amazing/README.md +++ b/02_Amazing/README.md @@ -1,7 +1,14 @@ ### Amazing -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=3 +This program will print out a different maze every time it is run and guarantees only one path through. You can choose the dimensions of the maze — i.e. the number of squares wide and long. + +The original program author was Jack Hauber of Windsor, Connecticut. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=3) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=18) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/03_Animal/README.md b/03_Animal/README.md index 69256d87..defaa735 100644 --- a/03_Animal/README.md +++ b/03_Animal/README.md @@ -1,7 +1,22 @@ ### Animal +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 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 system allows, you may modify the program to save and 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 MAMMAL.” + +This program can be easily modified to deal with categories of things other than animals by simply modifying the initial data and the dialogue references to animals. In an educational environment, this would be a valuable program to teach the distinguishing characteristics 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. + +--- + As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=4 +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=4) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=19) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/04_Awari/README.md b/04_Awari/README.md index 9356db80..a4b4d2da 100644 --- a/04_Awari/README.md +++ b/04_Awari/README.md @@ -1,7 +1,38 @@ ### Awari +Awari is an ancient African game played with seven sticks and thirty-six stones or beans laid out as shown above. The board is divided into six compartments or pits on each side. In addition, there are two special home pits at the ends. + +A move is made by taking all the beans from any (non-empty) pit on your own side. Starting from the pit to the right of this one, these beans are ‘sown’ one in each pit working around the board anticlockwise. + +A turn consists of one or two moves. If the last bean of your move is sown in your own home you may take a second move. + +If the last bean sown in a move lands in an empty pit, provided that the opposite pit is not empty, all the beans in the opposite pit, together with the last bean sown are ‘captured’ and moved to the player’s home. + +When either side is empty, the game is finished. The player with the most beans in his home has won. + +In the computer version, the board is printed as 14 numbers representing the 14 pits. + +``` + 3 3 3 3 3 3 +0 0 + 3 3 3 3 3 3 +``` + +The pits on your (lower) side are numbered 1-6 from left to right. The pits on my (the computer’s) side are numbered from my left (your right). + +To make a move you type in the number of a pit. If the last bean lands in your home, the computer types ‘AGAIN?’ and then you type in your second move. + +The computer’s move is typed, followed by a diagram of the board in its new state. The computer always offers you the first move. This is considered to be a slight advantage. + +There is a learning mechanism in the program that causes the play of the computer to improve as it playes more games. + +The original version of Awari is adopted from one originally written by Geoff Wyvill of Bradford, Yorkshire, England. + +--- + As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=6 +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=6) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=21) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/05_Bagels/README.md b/05_Bagels/README.md index e550e084..51d324bb 100644 --- a/05_Bagels/README.md +++ b/05_Bagels/README.md @@ -1,7 +1,20 @@ ### Bagels +In this game, the computer picks a 3-digit secret number using the digits 0 to 9 and you attempt to guess what it is. You are allowed up to twenty guesses. No digit is repeated. After each guess the computer will give you clues about your guess as follows: + +- PICO One digit is correct, but in the wrong place +- FERMI One digit is in the correct place +- BAGELS No digit is correct + +You will learn to draw inferences from the clues and, with practice, you’ll learn to improve your score. There are several good strategies for playing Bagels. After you have found a good strategy, see if you can improve it. Or try a different strategy altogether to see if it is any better. While the program allows up to twenty guesses, if you use a good strategy it should not take more than eight guesses to get any number. + +The original authors of this program are D. Resek and P. Rowe of the Lawrence Hall of Science, Berkeley, California. + +--- + As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=9 +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=9) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=21) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/06_Banner/README.md b/06_Banner/README.md index ac26214e..960b76cb 100644 --- a/06_Banner/README.md +++ b/06_Banner/README.md @@ -1,7 +1,14 @@ ### Banner +This program creates a large banner on a terminal of any message you input. The letters may be any dimension of you wish although the letter height plus distance from left-hand side should not exceed 6 inches. Experiment with the height and width until you get a pleasing effect on whatever terminal you are using. + +This program was written by Leonard Rosendust of Brooklyn, New York. + +--- + As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=10 +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=10) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=25) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/07_Basketball/README.md b/07_Basketball/README.md index ef44f631..158cba43 100644 --- a/07_Basketball/README.md +++ b/07_Basketball/README.md @@ -1,7 +1,30 @@ ### Basketball +This program simulates a game of basketball between Dartmouth College and an opponent of your choice. You are the Dartmouth captain and control the type of shot and defense during the course of the game. + +There are four types of shots: +1. Long Jump Shot (30ft) +2. Short Jump Shot (15ft) +3. Lay Up +4. Set Shot + +Both teams use the same defense, but you may call it: +- Enter (6): Press +- Enter (6.5): Man-to-man +- Enter (7): Zone +- Enter (7.5): None + +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!) + +Charles Bacheller of Dartmouth College was the original author of this game. + +--- + As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=12 +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=12) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=27) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/08_Batnum/README.md b/08_Batnum/README.md index 4590dcf8..e5b4db83 100644 --- a/08_Batnum/README.md +++ b/08_Batnum/README.md @@ -1,7 +1,20 @@ ### Batnum -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=14 +The game starts with an imaginary pile of objects, coins for example. You and your opponent (the computer) alternately remove objects from the pile. You specify in advance the minimum and maximum number of objects that can be taken on each turn. You also specify in advance how winning is defined: +1. To take the last object +2. To avoid taking the last object + +You may also determine whether you or the computer go first. + +The strategy of this game is based on modulo arithmetic. If the maximum number of objects a player may remove in a turn is M, then to gain a winning position a player at the end of his turn must leave a stack of 1 modulo (M+1) coins. If you don’t understand this, play the game 23 Matches first, then BATNUM, and have fun! + +BATNUM is a generalized version of a great number of manual remove-the-object games. The original computer version was written by one of the two originators of the BASIC language, John Kemeny of Dartmouth College. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=14) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=29) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/09_Battle/README.md b/09_Battle/README.md index 0f5ada08..815cacd2 100644 --- a/09_Battle/README.md +++ b/09_Battle/README.md @@ -1,7 +1,27 @@ ### Battle +BATTLE is based on the popular game Battleship which is primarily played to familiarize people with the location and designation of points on a coordinate plane. + +BATTLE first randomly sets up the bad guy’s fleet disposition on a 6 by 6 matrix or grid. The fleet consists of six ships: +- Two destroyers (ships number 1 and 2) which are two units long +- Two cruisers (ships number 3 and 4) which are three units long +- Two aircraft carriers (ships number 5 and 6) which are four units long + +The program then prints out this fleet disposition in a coded or disguised format (see the sample computer print-out). You then proceed to sink the various ships by typing in the coordinates (two digits. each from 1 to 6, separated by a comma) of the place where you want to drop a bomb, if you’ll excuse the expression. The computer gives the appropriate response (splash, hit, etc.) which you should record on a 6 by 6 matrix. You are thus building a representation of the actual fleet disposition which you will hopefully use to decode the coded fleet disposition printed out by the computer. Each time a ship is sunk, the computer prints out which ships have been sunk so far and also gives you a “SPLASH/HIT RATIO.” + +The first thing you should learn is how to locate and designate positions on the matrix, and specifically the difference between “3,4” and “4,3.” Our method corresponds to the location of points on the coordinate plane rather than the location of numbers in a standard algebraic matrix: the first number gives the column counting from left to right and the second number gives the row counting from bottom to top. + +The second thing you should learn about is the splash/hit ratio. “What is a ratio?” A good reply is “It’s a fraction or quotient.” Specifically, the spash/hit ratio is the number of splashes divided by the number of hits. If you had 9 splashes and 15 hits, the ratio would be 9/15 or 3/5, both of which are correct. The computer would give this splash/hit ratio as .6. + +The main objective and primary education benefit of BATTLE comes from attempting to decode the bas guys’ fleet disposition code. To do this, you must make a comparison between the coded matrix and the actual matrix which you construct as you play the game. + +The original author of both the program and these descriptive notes is Ray Westergard of Lawrence Hall of Science, Berkeley, California. + +--- + As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=15 +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=15) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=30) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/10_Blackjack/README.md b/10_Blackjack/README.md index 3b3466bd..43cf263c 100644 --- a/10_Blackjack/README.md +++ b/10_Blackjack/README.md @@ -1,7 +1,16 @@ ### Blackjack -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=18 +This is a simulation of the card game of Blackjack or 21, Las Vegas style. This rather comprehensive version allows for up to seven players. On each hand a player may get another card (a hit), stand, split a hand in the event two identical cards were received or double down. Also, the dealer will ask for an insurance bet if he has an exposed ace. + +Cards are automatically reshuffled as the 51st card is reached. For greater realism, you may wish to change this to the 41st card. Actually, fanatical purists will want to modify the program so it uses three decks of cards instead of just one. + +This program originally surfaced at Digital Equipment Corp.; the author is unknown. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=18) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=33) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/11_Bombardment/README.md b/11_Bombardment/README.md index 6b4f6468..4ab31b05 100644 --- a/11_Bombardment/README.md +++ b/11_Bombardment/README.md @@ -1,7 +1,16 @@ ### Bombardment -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=22 +BOMBARDMENT is played on two, 5x5 grids or boards with 25 outpost locations numbered 1 to 25. Both you and the computer have four platoons of troops that can be located at any four outposts on your respective grids. + +At the start of the game, you locate (or hide) your four platoons on your grid. The computer does the same on it’s grid. You then take turns firing missiles or bombs at each other’s outposts trying to destroy all four platoons. The one who finds all four opponents’ platoons first, wins. + +This program was slightly modified from the original written by Martin Burdash of Parlin, New Jersey. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=22) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=37) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/12_Bombs_Away/README.md b/12_Bombs_Away/README.md index 1cdb7212..0baa3558 100644 --- a/12_Bombs_Away/README.md +++ b/12_Bombs_Away/README.md @@ -1,7 +1,14 @@ ### Bombs Away -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=24 +In this program, you fly a World War II bomber for one of the four protagonists of the war. You then pick your target or the type of plane you are flying. Depending on your flying experience and the quality of enemy defenders, you then may accomplish your mission, get shot down, or make it back through enemy fire. In any case, you get a change to fly again. + +David Ahl modified the original program which was created by David Sherman while a student at Curtis Jr. High School, Sudbury, Massachusetts. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=24) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=39) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/13_Bounce/README.md b/13_Bounce/README.md index cf17c363..396b534d 100644 --- a/13_Bounce/README.md +++ b/13_Bounce/README.md @@ -1,7 +1,16 @@ ### Bounce -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=25 +This program plots a bouncing ball. Most computer plots run along the paper in the terminal (top to bottom); however, this plot is drawn horizontally on the paper (left to right). + +You may specify the initial velocity of the ball and the coefficient of elasticity of the ball (a superball is about 0.85 — other balls are much less). You also specify the time increment to be used in “strobing” the flight of the ball. In other words, it is as though the ball is thrown up in a darkened room and you flash a light at fixed time intervals and photograph the progress of the ball. + +The program was originally written by Val Skalabrin while he was at DEC. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=25) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=40) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/14_Bowling/README.md b/14_Bowling/README.md index 0270868b..99a7fade 100644 --- a/14_Bowling/README.md +++ b/14_Bowling/README.md @@ -1,7 +1,18 @@ ### Bowling -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=26 +This is a simulated bowling game for up to four players. You play 10 frames. To roll the ball, you simply type “ROLL.” After each roll, the computer will show you a diagram of the remaining pins (“0” means the pin is down, “+” means it is still standing), and it will give you a roll analysis: +- GUTTER +- STRIKE +- SPARE +- ERROR (on second ball if pins still standing) + +Bowling was written by Paul Peraino while a student at Woodrow Wilson High School, San Francisco, California. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=26) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=41) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/15_Boxing/README.md b/15_Boxing/README.md index 380dd047..e3440676 100644 --- a/15_Boxing/README.md +++ b/15_Boxing/README.md @@ -1,7 +1,16 @@ ### Boxing -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=28 +This program simulates a three-round Olympic boxing match. The computer coaches one of the boxers and determines his punches and defences, while you do the same for your boxer. At the start of the match, you may specify your man’s best punch and his vulnerability. + +There are approximately seven major punches per round, although this may be varied. The best out if three rounds wins. + +Jesse Lynch of St. Paul, Minnesota created this program. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=28) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=43) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/16_Bug/README.md b/16_Bug/README.md index 2ce4c19a..136123ce 100644 --- a/16_Bug/README.md +++ b/16_Bug/README.md @@ -1,7 +1,18 @@ ### Bug -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=30 +The object of this game is to finish your drawing of a bug before the computer finishes. + +You and the computer roll a die alternately with each number standing for a part of the bug. You must add the parts in the right order; in other words, you cannot have a neck until you have a body, you cannot have a head until you have a neck, and so on. After each new part has been added, you have the option of seeing pictures of the two bugs. + +If you elect to see all the pictures, this program has the ability of consuming well over six feet of terminal paper per run. We can only suggest recycling the paper by using the other side. + +Brian Leibowitz wrote this program while in the 7th grade at Harrison Jr-Se High School in Harrison, New York. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=30) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=45) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html From 48522ba27d7fa7ba2a55684126743af66feb1883 Mon Sep 17 00:00:00 2001 From: John Long Date: Sun, 2 Jan 2022 16:26:25 -0800 Subject: [PATCH 007/331] Add Kotlin version of Animal Animal fascinated me as a kid. I wrote a version in Modula-2 for a Junior High School project. Didn't realize at the time I was studying binary trees. --- 03_Animal/kotlin/Animal.kt | 119 +++++++++++++++++++++++++++++++++++++ 03_Animal/kotlin/README.md | 3 + 2 files changed, 122 insertions(+) create mode 100644 03_Animal/kotlin/Animal.kt create mode 100644 03_Animal/kotlin/README.md diff --git a/03_Animal/kotlin/Animal.kt b/03_Animal/kotlin/Animal.kt new file mode 100644 index 00000000..bac9af08 --- /dev/null +++ b/03_Animal/kotlin/Animal.kt @@ -0,0 +1,119 @@ +/** + * ANIMAL + * + * + * Converted from BASIC to Kotlin by John Long (@patimen) + * + * Animal is basically a perfect example of a binary tree. Implement it + * as such, with the QuestionNode either having an answer if it is a terminal node + * or a Question + */ + +fun main() { + printIntro() + val rootQuestionNode = + QuestionOrAnswer(question = Question("DOES IT SWIM", QuestionOrAnswer("FISH"), QuestionOrAnswer("BIRD"))) + while (true) { + val choice = ask("ARE YOU THINKING OF AN ANIMAL") + when { + choice == "LIST" -> printKnownAnimals(rootQuestionNode) + choice.startsWith("Q") -> return + choice.startsWith("Y") -> { + // A wrong answer means it's a new animal! + val wrongAnswer = rootQuestionNode.getWrongAnswer() + if (wrongAnswer == null) { + // The computer got the right answer! + println("WHY NOT TRY ANOTHER ANIMAL?") + } else { + // Get a new question to ask next time + wrongAnswer.askForInformationAndSave() + } + } + } + } +} + +// Takes care of asking a question (on the same line) and getting +// an answer or a blank string +fun ask(question: String): String { + print("$question? ") + return readLine()?.uppercase() ?: "" +} + +// Special case for a "yes or no" question, returns true of yes +fun askYesOrNo(question: String): Boolean { + return generateSequence { + print("$question? ") + readLine() + }.firstNotNullOf { yesOrNo(it) } +} + +// If neither Y (true) or N (false), return null, so the above sequence +// will just keep executing until it gets the answer +private fun yesOrNo(string: String): Boolean? = + when (string.uppercase().firstOrNull()) { + 'Y' -> true + 'N' -> false + else -> null + } + +private fun printKnownAnimals(question: QuestionOrAnswer) { + println("\nANIMALS I ALREADY KNOW ARE:") + val animals = question.getAnswers().chunked(4) + animals.forEach { line -> + // The '*' in front of line.toTypedArray() "spreads" the array as a list of parameters instead + System.out.printf("%-15s".repeat(line.size), *line.toTypedArray()) + println() + } +} + +private fun printIntro() { + println(" ANIMAL") + println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + println("\n\n") + println("PLAY 'GUESS THE ANIMAL'") + println("\n") + println("THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.") +} + +class QuestionOrAnswer(private var answer: String? = null, var question: Question? = null) { + fun getAnswers(): List = answer?.let { listOf(it) } ?: question!!.getAnswers() + fun getWrongAnswer(): QuestionOrAnswer? { + if (answer != null) { + // "takeUnless" will return null if the answer is "yes". In this case + // we will return the "wrong answer", aka the terminal answer that was incorrect + return this.takeUnless { askYesOrNo("IS IT A $answer") } + } + return question?.getWrongAnswer() + } + + fun askForInformationAndSave() { + //Failed to get it right and ran out of questions + //Let's ask the user for the new information + val newAnimal = ask("THE ANIMAL YOU WERE THINKING OF WAS A") + val newQuestion = ask("PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A \n$newAnimal FROM A $answer\n") + val newAnswer = askYesOrNo("FOR A $newAnimal THE ANSWER WOULD BE") + + val trueAnswer = if (newAnswer) newAnimal else answer + val falseAnswer = if (newAnswer) answer else newAnimal + // Replace our answer with null and set the question with the data we just got + // This makes it a question instead of an answer + this.answer = null + this.question = Question(newQuestion, QuestionOrAnswer(trueAnswer), QuestionOrAnswer(falseAnswer)) + } +} + +class Question( + private val question: String, + private val trueAnswer: QuestionOrAnswer, + private val falseAnswer: QuestionOrAnswer +) { + fun getAnswers(): List = trueAnswer.getAnswers() + falseAnswer.getAnswers() + + fun getWrongAnswer(): QuestionOrAnswer? = + if (askYesOrNo(question)) { + trueAnswer.getWrongAnswer() + } else { + falseAnswer.getWrongAnswer() + } +} diff --git a/03_Animal/kotlin/README.md b/03_Animal/kotlin/README.md new file mode 100644 index 00000000..f43a5b70 --- /dev/null +++ b/03_Animal/kotlin/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Kotlin](https://kotlinlang.org/) From 436f904abfd74af8f9faa775ce4f60932d47f63c Mon Sep 17 00:00:00 2001 From: Pat Ludwig Date: Sun, 2 Jan 2022 18:31:50 -0600 Subject: [PATCH 008/331] Adjust spacing to match original Various minor tweaks --- 61_Math_Dice/perl/mathdice.pl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/61_Math_Dice/perl/mathdice.pl b/61_Math_Dice/perl/mathdice.pl index f5a92459..4a2b6f6e 100644 --- a/61_Math_Dice/perl/mathdice.pl +++ b/61_Math_Dice/perl/mathdice.pl @@ -25,24 +25,25 @@ sub game_play { $sum = $sum + $roll; # keeping track of the summary #print "Sum: $sum Roll: $roll\n"; if ($num == 1) { - print " +\n"; # if its the first roll then print an addition sign + print "\n +\n\n"; # if its the first roll then print an addition sign } if ($num == 2) { - print " =\n"; # if its the second roll print the equals sign and wait for an answer + print " =? "; # if its the second roll print the equals sign and wait for an answer my $answer = ; chomp($answer); if ($answer == 0) { die "You input '0', Thanks for playing!\n"; } elsif ($answer == $sum) { - print "RIGHT!\nTHE DICE ROLL AGAIN\n"; + print "RIGHT!\n\nTHE DICE ROLL AGAIN\n\n"; } else { # code execution if they don't get the right answer print "NO,COUNT THE SPOTS AND GIVE ANOTHER ANSWER\n"; + print " =? "; $answer = ; chomp($answer); if ($answer == $sum){ - print "RIGHT!\nTHE DICE ROLL AGAIN\n"; + print "RIGHT!\n\nTHE DICE ROLL AGAIN\n\n"; } else { print "N0, THE ANSWER IS $sum\n"; From 90b0abe4c601fb46b3e284ed7b738353ea675885 Mon Sep 17 00:00:00 2001 From: Chris Aitchison Date: Mon, 3 Jan 2022 11:52:17 +1100 Subject: [PATCH 009/331] Add Ruby implementation of Rock Scissors Paper --- 74_Rock_Scissors_Paper/ruby/rockscissors.rb | 80 +++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 74_Rock_Scissors_Paper/ruby/rockscissors.rb diff --git a/74_Rock_Scissors_Paper/ruby/rockscissors.rb b/74_Rock_Scissors_Paper/ruby/rockscissors.rb new file mode 100644 index 00000000..9b24ac9a --- /dev/null +++ b/74_Rock_Scissors_Paper/ruby/rockscissors.rb @@ -0,0 +1,80 @@ +SCREEN_WIDTH = 72 + +MOVE_WORDS = { + 1 => 'PAPER', + 2 => 'SCISSORS', + 3 => 'ROCK' +} + +WIN_TABLE = { + 1 => 3, + 2 => 1, + 3 => 2 +} + +def center_text(text) + text.rjust((SCREEN_WIDTH / 2) + (text.size / 2)) +end + +def ask_for_number_of_games + loop do + puts "HOW MANY GAMES" + response = STDIN.gets.to_i + return response if response > 0 and response < 11 + puts "SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY." + end +end + +def ask_for_human_move + loop do + puts "3=ROCK...2=SCISSORS...1=PAPER" + puts "1...2...3...WHAT'S YOUR CHOICE" + response = STDIN.gets.to_i + return response if [1,2,3].include?(response) + puts "INVALID" + end +end + +def calculate_result(human_move, computer_move) + return 'TIE' if human_move == computer_move + return 'WIN' if WIN_TABLE[human_move] == computer_move + 'LOSE' +end + +puts center_text('GAME OF ROCK, SCISSORS, PAPER') +puts center_text('CREATIVE COMPUTING MORRISTOWN, NEW JERSEY') +puts +puts +puts + +number_of_games = ask_for_number_of_games +games_won = 0 +games_lost = 0 + +number_of_games.times do |game_number| + puts + puts "GAME NUMBER #{game_number + 1}" + computer_move = rand(3) + 1 + human_move = ask_for_human_move + puts "THIS IS MY CHOICE..." + puts "...#{MOVE_WORDS[computer_move]}" + + case calculate_result(human_move, computer_move) + when 'WIN' + puts "YOU WIN!!!" + games_won += 1 + when 'TIE' + puts "TIE GAME. NO WINNER." + when 'LOSE' + puts "WOW! I WIN!!!" + games_lost = games_lost += 1 + end +end + +puts +puts "HERE IS THE FINAL GAME SCORE:" +puts "I HAVE WON #{games_lost} GAME(S)." +puts "YOU HAVE WON #{games_won} GAME(S)." +puts "AND #{number_of_games - (games_lost + games_won)} GAME(S) ENDED IN A TIE." +puts "THANKS FOR PLAYING!!" + From d6446929121c7fc05cfc7e2c4e2e168205d648bd Mon Sep 17 00:00:00 2001 From: Alaa Sarhan Date: Sun, 2 Jan 2022 08:13:52 +0100 Subject: [PATCH 010/331] implement the 13th game - Bounce in ruby --- 13_Bounce/ruby/bounce.rb | 181 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 13_Bounce/ruby/bounce.rb diff --git a/13_Bounce/ruby/bounce.rb b/13_Bounce/ruby/bounce.rb new file mode 100644 index 00000000..97c42999 --- /dev/null +++ b/13_Bounce/ruby/bounce.rb @@ -0,0 +1,181 @@ +## Global constants + +# Gravity accelaration (F/S^2) ~= 32 +G = 32 + +# Used to indent the plotting of ball positions +# so that the height digits don't affect +# where we start plotting ball positions +BALL_PLOT_INDENT = "\t" + +# The deviation between current plotted height and the actual +# height of the ball that we will accept to plot the ball in +# that plotted height +BALL_PLOT_DEVIATION = 0.25 + +# The step we will take as we move down vertically while +# plotting ball positions +BALL_PLOT_HEIGHT_STEP = 0.5 + + +## Helper functions + +# Calculates the bounce speed (up) of the ball for a given +# bounce number and coefficient +def calc_velocity_for_bounce(v0, bounce, coefficient) + v = v0 * coefficient**bounce +end + +# Check https://physics.stackexchange.com/a/333436 for nice explanation +def calc_bounce_total_time(v0, bounce, coefficient) + v = calc_velocity_for_bounce(v0, bounce, coefficient) + t = 2 * v / G +end + +# Check https://physics.stackexchange.com/a/333436 for nice explanation +def calc_ball_height(v0, bounce, coefficient, t) + v = calc_velocity_for_bounce(v0, bounce, coefficient) + h = v * t - 0.5 * G * t**2 +end + +def heighest_position_in_next_bounce(time_in_bounce, i) + time_in_next_bounce = time_in_bounce[i+1] + return -1 if time_in_next_bounce.nil? + return calc_ball_height(v0, i, c, time_in_next_bounce / 2) unless time_in_next_bounce.nil? +end + +def intro + puts <<~INSTRUCTIONS + 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). + INSTRUCTIONS +end + + +## Plottin functions + +def plot_header + puts + puts "FEET" +end + +def plot_bouncing_ball(strobbing_time, v0, c) + ## Initializing helper values + + # How many bounces we want to plot + # original BASIC version is 70 / (V / (16 * S2)) + # 70 is assumed to be an arbitrary number higher than 2G and 16 is 1/2G + bounces_to_plot = (G**2 / (v0 / strobbing_time)).to_i + + # Holds the total time the ball spends in the air in every bounce + time_in_bounce = bounces_to_plot.times.map { |i| calc_bounce_total_time v0, i, c } + + plot_width = 0 + + # Calculate the highest position for the ball after the very first bounce + plot_y = (calc_ball_height(v0, 0, c, v0/G) + 0.5).to_i + + while plot_y >= 0 do + # We will print only whole-number heights + print plot_y.to_i if plot_y.to_i === plot_y + + print BALL_PLOT_INDENT + + bounces_to_plot.times { |i| + (0..time_in_bounce[i]).step(strobbing_time) { |t| + ball_pos = calc_ball_height v0, i, c, t + + # If the ball is within the acceptable deviation + # from the current height, we will plot it + if (plot_y - ball_pos).abs <= BALL_PLOT_DEVIATION then + print "0" + else + print " " + end + + # Increment the plot width when we are plotting height = 0 + # which will definitely be the longest since it never gets + # skipped by line 98 + plot_width += 1 if plot_y == 0 + } + + if heighest_position_in_next_bounce(time_in_bounce, i) < plot_y then + # If we got no more ball positions at or above current height, we can skip + # the rest of the bounces and move down to the next height to plot + puts + break + end + } + + plot_y -= BALL_PLOT_HEIGHT_STEP + end + + # Return plot_width to be used by the plot_footer + plot_width +end + +def plot_footer (plot_width, strobbing_time) + # Dotted separator line + puts + print BALL_PLOT_INDENT + (plot_width).times { |_| print "." } + puts + + # Time values line + print BALL_PLOT_INDENT + points_in_sec = (1 / strobbing_time).to_i + plot_width.times { |i| + if i % points_in_sec == 0 then + print (i / points_in_sec).to_i + else + print " " + end + } + puts + + # Time unit line + print BALL_PLOT_INDENT + (plot_width / 2 - 4).to_i.times { |_| print " " } + puts "SECONDS" + puts +end + +def game_loop + # Read strobing, velocity and coefficient parameters from user input + puts "TIME INCREMENT (SEC)" + strobbing_time = gets.to_f + + puts "VELOCITY (FPS)" + v0 = gets.to_f + + puts "COEFFICIENT" + c = gets.to_f + + ## Plotting + plot_header + + plot_width = plot_bouncing_ball strobbing_time, v0, c + + plot_footer plot_width, strobbing_time +end + +## Entry point +begin + intro + while true + game_loop + end +rescue SystemExit, Interrupt + exit +rescue => exception + p exception +end \ No newline at end of file From 3f42a1b4d63f18cb927a3a08ffce8b5900171058 Mon Sep 17 00:00:00 2001 From: Alaa Sarhan Date: Mon, 3 Jan 2022 02:06:08 +0100 Subject: [PATCH 011/331] add newline eof --- 13_Bounce/ruby/bounce.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/13_Bounce/ruby/bounce.rb b/13_Bounce/ruby/bounce.rb index 97c42999..9740509d 100644 --- a/13_Bounce/ruby/bounce.rb +++ b/13_Bounce/ruby/bounce.rb @@ -178,4 +178,4 @@ rescue SystemExit, Interrupt exit rescue => exception p exception -end \ No newline at end of file +end From 807d6e5bf53f5b216f8d24874f08a40e6731a3d3 Mon Sep 17 00:00:00 2001 From: Alaa Sarhan Date: Mon, 3 Jan 2022 02:15:59 +0100 Subject: [PATCH 012/331] fix missing parameters --- 13_Bounce/ruby/bounce.rb | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/13_Bounce/ruby/bounce.rb b/13_Bounce/ruby/bounce.rb index 9740509d..339c7851 100644 --- a/13_Bounce/ruby/bounce.rb +++ b/13_Bounce/ruby/bounce.rb @@ -38,7 +38,7 @@ def calc_ball_height(v0, bounce, coefficient, t) h = v * t - 0.5 * G * t**2 end -def heighest_position_in_next_bounce(time_in_bounce, i) +def heighest_position_in_next_bounce(time_in_bounce, v0, i, c) time_in_next_bounce = time_in_bounce[i+1] return -1 if time_in_next_bounce.nil? return calc_ball_height(v0, i, c, time_in_next_bounce / 2) unless time_in_next_bounce.nil? @@ -82,11 +82,12 @@ def plot_bouncing_ball(strobbing_time, v0, c) plot_width = 0 # Calculate the highest position for the ball after the very first bounce - plot_y = (calc_ball_height(v0, 0, c, v0/G) + 0.5).to_i + plotted_height = (calc_ball_height(v0, 0, c, v0/G) + 0.5).to_i - while plot_y >= 0 do + ## Plotting bouncing ball + while plotted_height >= 0 do # We will print only whole-number heights - print plot_y.to_i if plot_y.to_i === plot_y + print plotted_height.to_i if plotted_height.to_i === plotted_height print BALL_PLOT_INDENT @@ -96,7 +97,7 @@ def plot_bouncing_ball(strobbing_time, v0, c) # If the ball is within the acceptable deviation # from the current height, we will plot it - if (plot_y - ball_pos).abs <= BALL_PLOT_DEVIATION then + if (plotted_height - ball_pos).abs <= BALL_PLOT_DEVIATION then print "0" else print " " @@ -105,10 +106,10 @@ def plot_bouncing_ball(strobbing_time, v0, c) # Increment the plot width when we are plotting height = 0 # which will definitely be the longest since it never gets # skipped by line 98 - plot_width += 1 if plot_y == 0 + plot_width += 1 if plotted_height == 0 } - if heighest_position_in_next_bounce(time_in_bounce, i) < plot_y then + if heighest_position_in_next_bounce(time_in_bounce, v0, i, c) < plotted_height then # If we got no more ball positions at or above current height, we can skip # the rest of the bounces and move down to the next height to plot puts @@ -116,7 +117,7 @@ def plot_bouncing_ball(strobbing_time, v0, c) end } - plot_y -= BALL_PLOT_HEIGHT_STEP + plotted_height -= BALL_PLOT_HEIGHT_STEP end # Return plot_width to be used by the plot_footer @@ -160,7 +161,7 @@ def game_loop puts "COEFFICIENT" c = gets.to_f - ## Plotting + # Plotting plot_header plot_width = plot_bouncing_ball strobbing_time, v0, c @@ -168,7 +169,9 @@ def game_loop plot_footer plot_width, strobbing_time end -## Entry point + +## Game entry point + begin intro while true From e2d2cfcc8449cba7fe86c7ba44238d5d0fc8d817 Mon Sep 17 00:00:00 2001 From: Josh Gribbon Date: Sun, 2 Jan 2022 20:55:24 -0500 Subject: [PATCH 013/331] Add script to find missing implementations --- find-missing-implementations.js | 85 +++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 find-missing-implementations.js diff --git a/find-missing-implementations.js b/find-missing-implementations.js new file mode 100644 index 00000000..04cf3f84 --- /dev/null +++ b/find-missing-implementations.js @@ -0,0 +1,85 @@ +/** + * Program to find games that are missing solutions in a given language + * + * Scan each game folder, check for a folder for each language, and also make + * sure there's at least one file of the expected extension and not just a + * readme or something + */ + +const fs = require("fs"); +const glob = require("glob"); + +// relative path to the repository root +const ROOT_PATH = "."; + +const languages = [ + { name: "csharp", extension: "cs" }, + { name: "java", extension: "java" }, + { name: "javascript", extension: "js" }, + { name: "pascal", extension: "pas" }, + { name: "perl", extension: "pl" }, + { name: "python", extension: "py" }, + { name: "ruby", extension: "rb" }, + { name: "vbnet", extension: "vb" }, +]; + +const getFilesRecursive = async (path, extension) => { + return new Promise((resolve, reject) => { + glob(`${path}/**/*.${extension}`, (err, matches) => { + if (err) { + reject(err); + } + resolve(matches); + }); + }); +}; + +const getPuzzleFolders = () => { + return fs + .readdirSync(ROOT_PATH, { withFileTypes: true }) + .filter((dirEntry) => dirEntry.isDirectory()) + .filter((dirEntry) => ![".git", "node_modules"].includes(dirEntry.name)) + .map((dirEntry) => dirEntry.name); +}; + +(async () => { + let missingGames = {}; + let missingLanguageCounts = {}; + const puzzles = getPuzzleFolders(); + for (const puzzle of puzzles) { + for (const { name: language, extension } of languages) { + const files = await getFilesRecursive( + `${ROOT_PATH}/${puzzle}/${language}`, + extension + ); + if (files.length === 0) { + if (!missingGames[puzzle]) { + missingGames[puzzle] = []; + } + if (!missingLanguageCounts[language]) { + missingLanguageCounts[language] = 0; + } + missingGames[puzzle].push(language); + missingLanguageCounts[language]++; + } + } + } + const missingCount = Object.values(missingGames).flat().length; + if (missingCount === 0) { + console.log("All games have solutions for all languages"); + } else { + console.log(`Missing ${missingCount} implementations:`); + + console.log(`\nMissing languages by game:`); + for (const [puzzle, languages] of Object.entries(missingGames)) { + console.log(`${puzzle}: ${languages.join(", ")}`); + } + + console.log(`\nBy language:`); + for (const [language, count] of Object.entries(missingLanguageCounts)) { + console.log(`${language}: ${count} missing`); + } + } +})(); + +return; From 3fd1d6b0af88b84d295a14205709315de5369a8b Mon Sep 17 00:00:00 2001 From: Toby Donaldson Date: Sun, 2 Jan 2022 22:57:42 -0800 Subject: [PATCH 014/331] added evenwins.py --- 35_Even_Wins/python/evenwins.py | 206 ++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 35_Even_Wins/python/evenwins.py diff --git a/35_Even_Wins/python/evenwins.py b/35_Even_Wins/python/evenwins.py new file mode 100644 index 00000000..fba20024 --- /dev/null +++ b/35_Even_Wins/python/evenwins.py @@ -0,0 +1,206 @@ +# 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. +# + +import random + +# global variables +marbles_in_middle = -1 +human_marbles = -1 +computer_marbles = -1 +whose_turn = '' + +# Only called during development for serious errors that are due to mistakes +# in the program. Should never be called during a regular game. +def serious_error(msg): + print('serious_error: ' + msg) + exit(1) + +def welcome_screen(): + print('Welcome to Even Wins!') + print('Based on evenwins.bas from Creative Computing') + print() + print('Even Wins is a two-person game. You start with') + print('27 marbles in the middle of the table.') + print() + print('Players alternate taking marbles from the middle.') + print('A player can take 1 to 4 marbles on their turn, and') + print('turns cannot be skipped. The game ends when there are') + print('no marbles left, and the winner is the one with an even') + print('number of marbles.') + print() + +def marbles_str(n): + if n == 1: return '1 marble' + return f'{n} marbles' + +def choose_first_player(): + global whose_turn + while True: + ans = input('Do you want to play first? (y/n) --> ') + if ans == 'y': + whose_turn = 'human' + return + elif ans == 'n': + whose_turn = 'computer' + return + else: + print() + print('Please enter "y" if you want to play first,') + print('or "n" if you want to play second.') + print() + +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}') + +# Converts a string s to an int, if possible. +def to_int(s): + try: + n = int(s) + return True, n + except: + return False, 0 + +def print_board(): + global marbles_in_middle + global human_marbles + global computer_marbles + print() + 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(): + 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() + print(f' Please enter a whole number from 1 to {max_choice}') + print() + continue + if n < 1: + print() + print(' You must take at least 1 marble!') + print() + continue + if n > max_choice: + print() + print(f' You can take at most {marbles_str(max_choice)}') + print() + continue + print() + print(f'Okay, taking {marbles_str(n)} ...') + marbles_in_middle -= n + human_marbles += n + return + +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() + if human_marbles % 2 == 0: + print('You are the winner! Congratulations!') + else: + print('The computer wins: all hail mighty silicon!') + print('') + +def computer_turn(): + global marbles_in_middle + global computer_marbles + + print("It's the computer's turn ...") + max_choice = min(4, marbles_in_middle) + + # choose at random + n = random.randint(1, max_choice) + print(f'Computer takes {marbles_str(n)} ...') + marbles_in_middle -= n + computer_marbles += n + +def play_game(): + global marbles_in_middle + global human_marbles + global computer_marbles + + # initialize the game state + marbles_in_middle = 27 + human_marbles = 0 + computer_marbles = 0 + print_board() + + while True: + if marbles_in_middle == 0: + game_over() + return + elif whose_turn == 'human': + human_turn() + print_board() + next_player() + elif whose_turn == 'computer': + computer_turn() + print_board() + next_player() + else: + serious_error(f'play_game: unknown player {whose_turn}') + +def main(): + global whose_turn + + welcome_screen() + + while True: + 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) --> ') + if again == 'y': + print() + print("Ok, let's play again ...") + print() + else: + print() + print('Ok, thanks for playing ... goodbye!') + print() + return + +if __name__ == '__main__': + main() From bd6c6ead8dae6eb9e63b92f0cfec7c54bb25d802 Mon Sep 17 00:00:00 2001 From: John Long Date: Sun, 2 Jan 2022 23:02:01 -0800 Subject: [PATCH 015/331] Add Kotlin to War --- 94_War/kotlin/README.md | 3 ++ 94_War/kotlin/War.kt | 108 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 94_War/kotlin/README.md create mode 100644 94_War/kotlin/War.kt diff --git a/94_War/kotlin/README.md b/94_War/kotlin/README.md new file mode 100644 index 00000000..f43a5b70 --- /dev/null +++ b/94_War/kotlin/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Kotlin](https://kotlinlang.org/) diff --git a/94_War/kotlin/War.kt b/94_War/kotlin/War.kt new file mode 100644 index 00000000..0b8b9ee3 --- /dev/null +++ b/94_War/kotlin/War.kt @@ -0,0 +1,108 @@ +/** + * Converted FROM BASIC to Kotlin by John Long, with hints from the Java by Nahid Mondol. + * + */ + +val suits = listOf("S", "H", "C", "D") +val ranks = listOf("2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A") + +// Create the deck programmatically +val fullDeck = suits.flatMap { suit -> + ranks.map { rank -> + Card(suit, rank) + } +} + +class Card(private val suit: String, private val rank: String) { + // Allow comparison of cards to each other + operator fun compareTo(other: Card): Int = this.rankValue.compareTo(other.rankValue) + // We can figure relative rank by the order in the ranks value + private val rankValue: Int = ranks.indexOf(rank) + override fun toString(): String = "$suit-$rank" +} + +fun main() { + introMessage() + showDirectionsBasedOnInput() + playGame() + println("THANKS FOR PLAYING. IT WAS FUN.") +} + +private fun introMessage() { + println("\t WAR") + println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + println("THIS IS THE CARD GAME OF WAR. EACH CARD IS GIVEN BY SUIT-#") + print("AS S-7 FOR SPADE 7. DO YOU WANT DIRECTIONS? ") +} + +private fun showDirectionsBasedOnInput() { + if (getYesOrNo()) { + println("THE COMPUTER GIVES YOU AND IT A 'CARD'. THE HIGHER CARD") + println("(NUMERICALLY) WINS. THE GAME ENDS WHEN YOU CHOOSE NOT TO ") + println("CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\n") + } +} + +// Stay in loop until player chooses an option, then return "true" for yes or "false" for no +private fun getYesOrNo() = generateSequence { readln() }.firstNotNullOf { it.asYesOrNo } + +// Since this returns null for an incorrect value, above firstNotNullOf will keep looping until +// we get something valid +private val String.asYesOrNo: Boolean? + get() = + when (this.lowercase()) { + "yes" -> true + "no" -> false + else -> { + println("YES OR NO, PLEASE. ") + null + } + } + + +private fun playGame() { + // Shuffle the deck than break it into 26 pairs + val pairs = fullDeck.shuffled().chunked(2) + val score = Score(0, 0) + val lastPlayerCard = pairs.last().first() + // We use "destructuring" to extract the pair of cards directly to a variable here + pairs.forEach { (playerCard, computerCard) -> + println("YOU: $playerCard\tCOMPUTER: $computerCard") + when { + playerCard > computerCard -> score.playerWins() + computerCard > playerCard -> score.computerWins() + else -> println("TIE. NO SCORE CHANGE.") + } + // Doesn't make sense to ask to continue if we have no more cards left to deal + if (playerCard != lastPlayerCard) { + println("DO YOU WANT TO CONTINUE") + if (!getYesOrNo()) { + return + } + } + } + score.printFinalScore() + return +} + + +class Score(private var player: Int, private var computer: Int) { + fun playerWins() { + player++ + printScore("YOU WIN.") + } + + fun computerWins() { + computer++ + printScore("THE COMPUTER WINS!!!") + } + + private fun printScore(text: String) { + println("$text YOU HAVE $player AND THE COMPUTER HAS $computer") + } + + // Only print if you go through the whole deck + fun printFinalScore() { + println("WE HAVE RUN OUT OF CARDS. FINAL SCORE: YOU: $player THE COMPUTER:$computer") + } +} From 76c5e1e995e71c12508e7417c7a8ce72cc446a84 Mon Sep 17 00:00:00 2001 From: LukasMurdock Date: Mon, 3 Jan 2022 02:13:21 -0500 Subject: [PATCH 016/331] add 17-96 --- 17_Bullfight/README.md | 22 +++++++- 18_Bullseye/README.md | 33 ++++++++++- 19_Bunny/README.md | 5 +- 20_Buzzword/README.md | 11 +++- 21_Calendar/README.md | 20 ++++++- 22_Change/README.md | 9 ++- 23_Checkers/README.md | 13 ++++- 24_Chemist/README.md | 11 +++- 25_Chief/README.md | 13 ++++- 26_Chomp/README.md | 13 ++++- 27_Civil_War/README.md | 15 ++++- 28_Combat/README.md | 13 ++++- 29_Craps/README.md | 16 +++++- 30_Cube/README.md | 11 +++- 31_Depth_Charge/README.md | 13 ++++- 32_Diamond/README.md | 11 +++- 33_Dice/README.md | 18 +++++- 34_Digits/README.md | 14 ++++- 35_Even_Wins/README.md | 15 ++++- 36_Flip_Flop/README.md | 25 ++++++++- 37_Football/README.md | 15 ++++- 38_Fur_Trader/README.md | 13 ++++- 39_Golf/README.md | 12 +++- 40_Gomoko/README.md | 13 ++++- 41_Guess/README.md | 13 ++++- 42_Gunner/README.md | 13 ++++- 43_Hammurabi/README.md | 19 ++++++- 44_Hangman/README.md | 23 +++++++- 45_Hello/README.md | 13 ++++- 46_Hexapawn/README.md | 13 ++++- 47_Hi-Lo/README.md | 18 +++++- 48_High_IQ/README.md | 13 ++++- 49_Hockey/README.md | 13 ++++- 50_Horserace/README.md | 11 +++- 51_Hurkle/README.md | 13 ++++- 52_Kinema/README.md | 16 +++++- 53_King/README.md | 15 ++++- 54_Letter/README.md | 11 +++- 55_Life/README.md | 32 ++++++++++- 56_Life_for_Two/README.md | 41 +++++++++++++- 57_Literature_Quiz/README.md | 11 +++- 58_Love/README.md | 11 +++- 59_Lunar_LEM_Rocket/README.md | 21 ++++++- 60_Mastermind/README.md | 26 ++++++++- 61_Math_Dice/README.md | 11 +++- 62_Mugwump/README.md | 15 ++++- 63_Name/README.md | 11 +++- 64_Nicomachus/README.md | 15 ++++- 65_Nim/README.md | 24 +++++++- 66_Number/README.md | 11 +++- 67_One_Check/README.md | 26 ++++++++- 68_Orbit/README.md | 54 +++++++++++++++++- 69_Pizza/README.md | 13 ++++- 70_Poetry/README.md | 26 ++++++++- 71_Poker/README.md | 13 ++++- 72_Queen/README.md | 13 ++++- 73_Reverse/README.md | 28 +++++++++- 74_Rock_Scissors_Paper/README.md | 18 +++++- 75_Roulette/README.md | 13 ++++- 76_Russian_Roulette/README.md | 11 +++- 77_Salvo/README.md | 22 +++++++- 78_Sine_Wave/README.md | 9 ++- 79_Slalom/README.md | 13 ++++- 80_Slots/README.md | 15 ++++- 81_Splat/README.md | 13 ++++- 82_Stars/README.md | 13 ++++- 83_Stock_Market/README.md | 13 ++++- 84_Super_Star_Trek/README.md | 96 +++++++++++++++++++++++++++++++- 85_Synonym/README.md | 19 ++++++- 86_Target/README.md | 13 ++++- 87_3-D_Plot/README.md | 13 ++++- 89_Tic-Tac-Toe/README.md | 22 +++++++- 90_Tower/README.md | 17 +++++- 91_Train/README.md | 13 ++++- 92_Trap/README.md | 16 +++++- 93_23_Matches/README.md | 15 ++++- 94_War/README.md | 11 +++- 95_Weekday/README.md | 13 ++++- 96_Word/README.md | 13 ++++- 79 files changed, 1201 insertions(+), 160 deletions(-) diff --git a/17_Bullfight/README.md b/17_Bullfight/README.md index c666ea37..d31bc4e2 100644 --- a/17_Bullfight/README.md +++ b/17_Bullfight/README.md @@ -1,7 +1,25 @@ ### Bullfight -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=32 +In this simulated bullfight, you are the matador — i.e., the one with the principle role and the one who must kill the bull or be killed (or run from the ring). + +On each pass of the bull, you may try: +- 0: Veronica (dangerous inside move of the cape) +- 1: Less dangerous outside move of the cape +- 2: Ordinary swirl of the cape + +Or you may try to kill the bull: +- 4: Over the horns +- 5: In the chest + +The crowd will determine what award you deserve, posthumously if necessary. The braver you are, the better the reward you receive. It’s nice to stay alive too. The better the job the picadores and toreadores do, the better your chances. + +David Sweet of Dartmouth wrote the original version of this program. It was then modified by students at Lexington High School and finally by Steve North of Creative Computing. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=32) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=47) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/18_Bullseye/README.md b/18_Bullseye/README.md index 789ad793..0c42872e 100644 --- a/18_Bullseye/README.md +++ b/18_Bullseye/README.md @@ -1,7 +1,36 @@ ### Bullseye -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=34 +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. + +You have a choice of three methods of throwing: + +| Throw | Description | Probable Score | +|-------|--------------------|---------------------------| +| 1 | Fast overarm | Bullseye or complete miss | +| 2 | Controlled overarm | 10, 20, or 30 points | +| 3 | Underarm | Anything | + +You will find after playing a while that different players will swear by different strategies. However, considering the expected score per throw by always using throw 3: + +| Score (S) | Probability (P) | S x P | +|-----------|-----------------|-------| +| 40 | 1.00-.95 = .05 | 2 | +| 30 | .95-.75 = .20 | 6 | +| 30 | .75-.45 = .30 | 6 | +| 10 | .45-.05 = .40 | 4 | +| 0 | .05-.00 = .05 | 0 | + +Expected score per throw = 18 + +Calculate the expected score for the other throws and you may be surprised! + +The program was written by David Ahl of Creative Computing. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=34) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=49) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/19_Bunny/README.md b/19_Bunny/README.md index 4df27297..8d980287 100644 --- a/19_Bunny/README.md +++ b/19_Bunny/README.md @@ -1,7 +1,8 @@ ### Bunny -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=35 +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=35) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=50) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/20_Buzzword/README.md b/20_Buzzword/README.md index 034d7e5f..22e76f6f 100644 --- a/20_Buzzword/README.md +++ b/20_Buzzword/README.md @@ -1,7 +1,14 @@ ### Buzzword -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=36 +This program is an invaluable aid for preparing speeches and briefings about educational 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. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=36) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=51) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/21_Calendar/README.md b/21_Calendar/README.md index b6198acc..5a93d50d 100644 --- a/21_Calendar/README.md +++ b/21_Calendar/README.md @@ -1,7 +1,23 @@ ### Calendar -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=37 +This program prints out a calendar for any year. You must specify the starting day of the week of the year: +- 0: Sunday +- -1: Monday +- -2: Tuesday +- -3: Wednesday +- -4: Thursday +- -5: Friday +- -6: Saturday + +You can determine this by using the program WEEKDAY. You must also make two changes for leap years. The program listing describes the necessary changes. Running the program produces a nice 12-month calendar. + +The program was written by Geoffrey Chase of the Abbey, Portsmouth, Rhode Island. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=37) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=52) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/22_Change/README.md b/22_Change/README.md index 1a0f1297..840714a4 100644 --- a/22_Change/README.md +++ b/22_Change/README.md @@ -1,7 +1,12 @@ ### Change -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=39 +In this program, the computer pretends it is the cashier at your friendly neighborhood candy store. You tell it the cost of the item(s) you are buying, the amount of your payment, and it will automatically (!) determine your correct change. Aren’t machines wonderful? Dennis Lunder of People’s Computer Company wrote this program. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=39) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=54) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/23_Checkers/README.md b/23_Checkers/README.md index 0a3c57a2..d6936ea9 100644 --- a/23_Checkers/README.md +++ b/23_Checkers/README.md @@ -1,7 +1,16 @@ ### Checkers -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=40 +This program plays checkers. The pieces played by the computer are marked with an “X”, yours are marked “O”. A move is made by specifying the coordinates of the piece to be moved (X, Y). Home (0,0) is in the bottom left and X specifies distance to the right of home (i.e., column) and Y specifies distance above home (i.e. row). You then specify where you wish to move to. + +THe original version of the program by Alan Segal was not able to recognize (or permit) a double or triple jump. If you tried one, it was likely that your piece would disappear altogether! + +Steve North of Creative Computing rectified this problem and Lawrence Neal contributed modifications to allow the program to tell which player has won the game. The computer does not play a particularly good game but we leave it to _you_ to improve that. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=40) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=55) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/24_Chemist/README.md b/24_Chemist/README.md index afd39752..95db3f66 100644 --- a/24_Chemist/README.md +++ b/24_Chemist/README.md @@ -1,7 +1,14 @@ ### Chemist -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=42 +The fictitious chemical, kryptocyanic acid, can only be diluted by the ratio of 7 parts water to 3 parts acid. Any other ratio causes an unstable compound which soon explodes. Given an amount of acid, you must determine how much water to add to the dilution. If you’re more than 5% off, you lose one of your nine lives. The program continues to play until you lose all nine lives or until it is interrupted. + +It was originally written by Wayne Teeter of Ridgecrest, California. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=42) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=57) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/25_Chief/README.md b/25_Chief/README.md index f90a7121..5cb044c0 100644 --- a/25_Chief/README.md +++ b/25_Chief/README.md @@ -1,7 +1,16 @@ ### Chief -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=43 +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. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=43) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=58) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/26_Chomp/README.md b/26_Chomp/README.md index 3774589a..e9a8b5ce 100644 --- a/26_Chomp/README.md +++ b/26_Chomp/README.md @@ -1,7 +1,16 @@ ### Chomp -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=44 +This program is an adaptation of a mathematical game originally described by Martin Gardner in the January 1973 issue of _Scientific American_. Up to a 9x9 grid is set up by you with the upper left square in a poison square. This grid is the cookie. Players alternately chomp away at the cookie from the lower right. To take a chomp, input a row and column number of one of the squares remaining on the cookie. All of the squares below and to the right of that square, including that square, disappear. + +Any number of people can play — the computer is only the moderator; it is not a player. Two-person strategies are interesting to work out but strategies when three or more people are playing are the real challenge. + +The computer version of the game was written by Peter Sessions of People’s Computer Company. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=44) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=59) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/27_Civil_War/README.md b/27_Civil_War/README.md index 9f3e4126..17d6816f 100644 --- a/27_Civil_War/README.md +++ b/27_Civil_War/README.md @@ -1,7 +1,18 @@ ### Civil War -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=46 +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. + +You may play Civil War alone in which case the program simulates the Union general. Or two players may play in which case the computer becomes the moderator. + +Civil War was written in 1968 by three Students in Lexington High School, Massachusetts: L. Cram, L. Goodie, and D. Hibbard. It was modified into a 2-player game by G. Paul and R. Hess of TIES, St. Paul, Minnesota. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=46) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=61) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/28_Combat/README.md b/28_Combat/README.md index cc4be30a..32b2af65 100644 --- a/28_Combat/README.md +++ b/28_Combat/README.md @@ -1,7 +1,16 @@ ### Combat -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=50 +In this game, you are fighting a small-scale war with the computer. You have 72,000 troops which you first ust distribute among your Army, Navy, and Air Force. You may distribute them in any way you choose as long as you don’t use more than 72,000. + +You then attack your opponent (the computer) and input which service and the number of men you wish to use. The computer then tells you the outcome of the battle, gives you the current statistics and allows you to determine your next move. + +After the second battle, it is decided from the total statistics whether you win or lose or if a treaty is signed. + +This program was created by Bob Dores of Milton, Massachusetts. + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=50) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=65) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/29_Craps/README.md b/29_Craps/README.md index 673957f4..7372b99f 100644 --- a/29_Craps/README.md +++ b/29_Craps/README.md @@ -1,7 +1,19 @@ ### Craps -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=52 +This game simulates the game 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 on a computer at DEC. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=52) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=67) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/30_Cube/README.md b/30_Cube/README.md index 067606e3..41973db1 100644 --- a/30_Cube/README.md +++ b/30_Cube/README.md @@ -1,7 +1,14 @@ ### Cube -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=53 +CUBE is a game played on the facing sides of a cube with a side dimension of 2. A location is designated by three numbers — e.g., 1, 2, 1. The object is to travel from 1, 1, 1 to 3, 3, 3 by moving one horizontal or vertical (not diagonal) square at a time without striking one of 5 randomly placed landmines. You are staked to $500; prior to each play of the game you may make a wager whether you will reach your destination. You lose if you hit a mine or try to make an illegal move — i.e., change more than one digit from your previous position. + +Cube was created by Jerimac Ratliff of Fort Worth, Texas. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=53) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=68) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/31_Depth_Charge/README.md b/31_Depth_Charge/README.md index 4c11da12..1a0ed7a4 100644 --- a/31_Depth_Charge/README.md +++ b/31_Depth_Charge/README.md @@ -1,7 +1,16 @@ ### Depth Charge -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=55 +In this program you are captain of the destroyer USS Computer. An enemy submarine has been causing trouble and your mission is to destroy it. You may select the seize of the “cube” of water you wish to search in. The computer then determines how many depth charges you get to destroy the submarine. + +Each depth charge is exploded by you specifying a trio of numbers; the first two are the surface coordinates (X,Y), the third is the depth. After each depth charge, your sonar observer will tell you where the explosion was relative to the submarine. + +Dana Noftle wrote this program while a student at Acton High School, Acton, Massachusetts. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=55) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=70) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/32_Diamond/README.md b/32_Diamond/README.md index 36bdb9e2..1f155ba3 100644 --- a/32_Diamond/README.md +++ b/32_Diamond/README.md @@ -1,7 +1,14 @@ ### Diamond -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=56 +This program fills an 8.5x11 piece of paper with diamonds (plotted on a hard-copy terminal, of course). The program asks for an odd number to be input in the range 5 to 31. The diamonds printed will be this number of characters high and wide. The number of diamonds across the page will vary from 12 for 5-character wide diamonds to 1 for a diamond 31-characters wide. You can change the content of the pattern if you wish. + +The program was written by David Ahl of Creative Computing. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=56) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=71) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/33_Dice/README.md b/33_Dice/README.md index 27cc7029..71406a01 100644 --- a/33_Dice/README.md +++ b/33_Dice/README.md @@ -1,7 +1,21 @@ ### Dice -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=57 +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. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=57) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=72) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/34_Digits/README.md b/34_Digits/README.md index e2cf78a9..b1c96819 100644 --- a/34_Digits/README.md +++ b/34_Digits/README.md @@ -1,7 +1,17 @@ ### Digits -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=58 +The player writes down a set of 30 numbers (0, 1, or 2) at random prior to playing the game. The computer program, using pattern recognition techniques, attempts to guess the next number in your list. + +The computer asks for 10 numbers at a time. It always guesses first and then examines the next number to see if it guessed correctly. By pure luck (or chance or probability), the computer ought to be right 10 times. It is uncanny how much better it generally does than that! + +This program originated at Dartmouth; original author unknown. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=58) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=73) + Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/35_Even_Wins/README.md b/35_Even_Wins/README.md index 71c7d18e..9db7654b 100644 --- a/35_Even_Wins/README.md +++ b/35_Even_Wins/README.md @@ -1,7 +1,18 @@ ### Even Wins -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=60 +This is a game between you and the computer. To play, an odd number of objects (marbles, chips, matches) are placed in a row. You take turns with the computer picking up between one and four objects each turn. The game ends when there are no objects left, and the winner is the one with an even number of objects picked up. + +Two versions of this game are included. While to the player they appear similar, the programming approach is quite different. EVEN WINS, the first version, is deterministic — i.e., the computer plays by fixed, good rules and is impossible to beat if you don’t know how to play the game. It always starts with 27 objects, although you may change this. + +The second version, GAME OF EVEN WINS, is much more interesting because the computer starts out only knowing the rules of the game. Using simple techniques of artificial intelligence (cybernetics), the computer gradually learns to play this game from its mistakes until it plays a very good game. After 20 games, the computer is a challenge to beat. Variation in the human’s style of play seems to make the computer learn more quickly. If you plot the learning curve of this program, it closely resembles classical human learning curves from psychological experiments. + +Eric Peters at DEC wrote the GAME OF EVEN WINS. The original author of EVEN WINS is unknown. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=60) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=75) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/36_Flip_Flop/README.md b/36_Flip_Flop/README.md index 689e6f7a..5f32111d 100644 --- a/36_Flip_Flop/README.md +++ b/36_Flip_Flop/README.md @@ -1,7 +1,28 @@ ### Flip Flop -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=63 +The object of this game is to change a row of ten X’s + +``` +X X X X X X X X X X +``` + +to a row of ten 0’s + +``` +0 0 0 0 0 0 0 0 0 0 +``` + +by typing in a number corresponding to the position of an “X” in the line. On some numbers one position will change while on other numbers, two will change. For example, inputting a 3 may reverse the X and 0 in position 3, but it might possibly reverse some of other position too! You ought to be able to change all 10 in 12 or fewer moves. Can you figure out a good winning strategy? + +To reset the line to all X’s (same game), type 0 (zero). To start a new game at any point, type 11. + +The original author of this game was Micheal Kass of New Hyde Park, New York. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=63) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=78) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/37_Football/README.md b/37_Football/README.md index ccfe99e3..7f791861 100644 --- a/37_Football/README.md +++ b/37_Football/README.md @@ -1,7 +1,18 @@ ### Football -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=64 +Football is probably the most popular simulated sports game. I have seen some people play to elect to play computerized football in preference to watching a football game on television. + +Two versions of football are presented. The first is somewhat “traditional” in that you, the player, are playing against the computer. You have a choice of seven offensive plays. On defense the computer seems to play a zone defence, but you have no choice of plays. The computer program presents the necessary rules as you play, and it is also the referee and determines penalties when an infraction is committed. FTBALL was written by John Kemeny at Dartmouth. + +IN the second version of football, the computer referees a game played between two human players. Each player gets a list of twenty plays with a code value for each one. This list should be kept confidential from your opponent. The codes can be changes in data. All twenty plays are offensive; a defensive play is specified by defending against a type of offensive play. A defense is good for other similar types of plays, for example, a defense against a flare pass is very good against a screen pass but much less good against a half-back option. + +This game was originally written by Raymond Miseyka of Butler, Pennsylvania. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=64) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=79) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/38_Fur_Trader/README.md b/38_Fur_Trader/README.md index 503c089b..676b605b 100644 --- a/38_Fur_Trader/README.md +++ b/38_Fur_Trader/README.md @@ -1,7 +1,16 @@ ### Fur Trader -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=69 +You are the leader of a French fur trading expedition in 1776 leaving the Ontario area to sell furs and get supplies for the next year. You have a choice of three forts at which you may trade. The cost of supplies and the amount you recieve for your furs will depend upon the fort you choose. You also specify what types of furs that you have to trade. + +The game goes on and on until you elect to trade no longer. + +Author of the program is Dan Bachor, University of Calgary, Alberta, Canada. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=69) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=84) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/39_Golf/README.md b/39_Golf/README.md index a2292d02..28da3594 100644 --- a/39_Golf/README.md +++ b/39_Golf/README.md @@ -1,7 +1,15 @@ ### Golf -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=71 +This is a single player golf game. In other words it’s you against the golf course (the computer). The program asks for your handicap (maximum of 30) and your area of difficulty. You have a bag of 29 clubs plus a putter. On the course you have to contend with rough, trees, on and off fairway, sand traps, and water hazards. In addition, you can hook, slice, go out of bounds, or hit too far. On putting, you determine the potency factor (or percent of swing). Until you get the swing of the game (no pun intended), you’ll probably was to use a fairly high handicap. + +Steve North of Creative Computing modified the original version of this game, the author of which is unknown. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=71) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=86) + Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/40_Gomoko/README.md b/40_Gomoko/README.md index 3f32ea2a..9b6ad6b6 100644 --- a/40_Gomoko/README.md +++ b/40_Gomoko/README.md @@ -1,7 +1,16 @@ ### Gomoko -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=74 +GOMOKO or GOMOKU is a traditional game of the Orient. It is played by two people on a board of intersecting lines (19 left-to-right lines, 19 top-to-bottom lines, 361 intersections in all). Players take turns. During his turn, a player may cover one intersection with a marker; (one player uses white markers; the other player uses black markers). The object of the game is to get five adjacent markers in a row, horizontally, vertically or along either diagonal. + +Unfortunately, this program does not make the computer a very good player. It does not know when you are about to win or even who has won. But some of its moves may surprise you. + +The original author of this program is Peter Sessions of People’s Computer Company. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=74) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=89) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/41_Guess/README.md b/41_Guess/README.md index e9876af9..cb041db7 100644 --- a/41_Guess/README.md +++ b/41_Guess/README.md @@ -1,7 +1,16 @@ ### Guess -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=75 +In Program GUESS, the computer chooses a random integer between 0 and any limit you set. You must then try to guess the number the computer has chosen using the clues provided 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, Massachusetts. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=75) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=90) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/42_Gunner/README.md b/42_Gunner/README.md index 4969ff20..0621ec54 100644 --- a/42_Gunner/README.md +++ b/42_Gunner/README.md @@ -1,7 +1,16 @@ ### Gunner -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=77 +GUNNER allows you to adjust the fire of a field artillery weapon to hit a stationary target. You specify the number of degrees of elevation of your weapon; 45 degrees provides maximum range with values under or over 45 degrees providing less range. + +You get up to five shots to destroy the enemy before he destroys you. Gun range varies between 20,000 and 60,000 yards and burst radius is 100 yards. You must specify elevation within approximately 0.2 degrees to get a hit. + +Tom Kloos of the Oregon Museum of Science and Industry in Portland, Oregon originally wrote GUNNER. Extensive modifications were added by David Ahl. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=77) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=92) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/43_Hammurabi/README.md b/43_Hammurabi/README.md index 22378ac0..c92b7ee3 100644 --- a/43_Hammurabi/README.md +++ b/43_Hammurabi/README.md @@ -1,7 +1,22 @@ ### Hammurabi -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=78 +In this game you direct the administrator of Sumeria, Hammurabi, how to manage the city. The city initially has 1,000 acres, 100 people and 3,000 bushels of grain in storage. + +You may buy and sell land with your neighboring city-states for bushels of grain — the price will vary between 17 and 26 bushels per acre. You also must use grain to feed your people and as seed to plant the next year’s crop. + +You will quickly find that a certain number of people can only tend a certain amount of land and that people starve if they are not fed enough. You also have the unexpected to contend with such as a plague, rats destroying stored grain, and variable harvests. + +You will also find that managing just the few resources in this game is not a trivial job over a period of say ten years. The crisis of population density rears its head very rapidly. + +This program was originally written in Focal at DEC; author unknown. David Ahl converted it to BASIC and added the 10-year performance assessment. If you wish to change any of the factors, the extensive remarks in the program should make modification fairly straightforward. + +Note for trivia buffs: somewhere along the line an m was dropped out of the spelling of Hammurabi in hte Ahl version of the computer program. This error has spread far and wide until a generation of students now think that Hammurabi is the incorrect spelling. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=78) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=93) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/44_Hangman/README.md b/44_Hangman/README.md index e44b0c0a..ee533251 100644 --- a/44_Hangman/README.md +++ b/44_Hangman/README.md @@ -1,7 +1,26 @@ ### Hangman -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=80 +This is a simulation of the word guessing game, hangman. The computer picks a word, tells you how many letters in the word it has picked and then you guess a letter in the word. If you are right, the computer tells you where that letter belongs; if your letter is wrong, the computer starts to hang you. You get ten guesses before you are completely hanged: +1. Head +2. Body +3. Right Arm +4. Left Arm +5. Right Leg +6. Left Leg +7. Right Hand +8. Left Hand +9. Right Foot +10. Left Foot + +You may add words in Data statements; however if you do, you must also change the random word selector. + +David Ahl modified this program into its current form from the one created by Kenneth Aupperle of Melville, New York. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=80) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=95) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/45_Hello/README.md b/45_Hello/README.md index 7c72beca..117db0ce 100644 --- a/45_Hello/README.md +++ b/45_Hello/README.md @@ -1,7 +1,16 @@ ### Hello -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=82 +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. + +David Ahl is the author of HELLO. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=82) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=97) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/46_Hexapawn/README.md b/46_Hexapawn/README.md index 6380a1b3..0197fa14 100644 --- a/46_Hexapawn/README.md +++ b/46_Hexapawn/README.md @@ -1,7 +1,16 @@ ### Hexapawn -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=83 +The game of Hexapawn and a method to learn a strategy for playing the game was described in Martin Gardner’s “Mathematical Games” column in the March 1962 issue of _Scientific American_. The method described in the article was for a hypothetical learning machine composed of match boxes and colored beads. This has been generalized in the program HEX. + +The program learns by elimination of bad moves. All positions encountered by the program and acceptable moves from them are stored in an array. When the program encounters an unfamiliar position, the position and all legal moves from it are added to the list. If the program loses a game, it erases the move that led to defeat. If it hits a position from which all moves have been deleted (they all led to defeat), it erases the move that got it there and resigns. Eventually, the program learns to play extremely well and, indeed, is unbeatable. The learning strategy could be adopted to other simple games with a finite number of moves (tic-tac-toe, small board checkers, or other chess-based games). + +The original version of this program was written by R.A. Kaapke. It was subsequently modified by Jeff Dalton and finally by Steve North of Creative Computing. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=83) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=98) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/47_Hi-Lo/README.md b/47_Hi-Lo/README.md index cf2f93be..7fb37221 100644 --- a/47_Hi-Lo/README.md +++ b/47_Hi-Lo/README.md @@ -1,7 +1,21 @@ ### Hi-Lo -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=85 +This game is an adaptation of the game GUESS; however, instead of just guessing a number between 1 and 100, in this game you win dollars when you guess the number. The directions, in the words of the author, are as follows: +1. There is an amount of money, between one and one hundred dollars, in the “HI-LO” jackpot. +2. You will have six chances in which to guess the amount of money in the jackpot. +3. After each guess, the computer will tell whether the guess was too high or too low. +4. If the correct amount of money is not guessed after six chances, the computer will print the amount in the jackpot. +5. If the correct amount of money is guessed within the six chance limit, the computer will register this amount. +6. After each sequence of guesses, you have the choice of playing again or ending the program. If a new game is played, a new amount of money will constitute the jackpot. +7. If youwin more than once, then your earnings are totalled. + +The author is Dean ALtman of Fort Worth, Texas. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=85) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=100) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/48_High_IQ/README.md b/48_High_IQ/README.md index 3da523da..7dee9c95 100644 --- a/48_High_IQ/README.md +++ b/48_High_IQ/README.md @@ -1,7 +1,16 @@ ### High IQ -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=86 +This is a computerized version of an old European solitaire game of logic. The game starts with a pegboard shaped like a cross having pegs in every hole but the center. The object is to remove all 32 pegs, or as many as possible, by jumping into an empty hole, then removing the jumped peg. + +There are several different winning strategies for playing, and of course, each strategy can be played eight different ways on the board. Can you find a consistent winner? + +Charles Lund wrote this game while at The American School in The Hague, Netherlands. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=86) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=101) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/49_Hockey/README.md b/49_Hockey/README.md index 8d83017d..41e6950e 100644 --- a/49_Hockey/README.md +++ b/49_Hockey/README.md @@ -1,7 +1,16 @@ ### Hockey -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=88 +This is a simulation of a ice hockey game. The computer, in this case, moderates and referees the pay between two human opponents. Of course, one person could play both sides. + +The program asks for team names, player names, and even the name of the referee. Four types of shot are permitted and a shot may be aimed at one of four areas. You are also asked about passing. The game is very comprehensive with lots of action, face offs, blocks, passes, 4 on 2 situations, and so on. Unfortunately there are no penalties. + +The original author is Robert Puopolo; modifications by Steve North of Creative Computing. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=88) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=103) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/50_Horserace/README.md b/50_Horserace/README.md index ce781ffd..00e24df5 100644 --- a/50_Horserace/README.md +++ b/50_Horserace/README.md @@ -1,7 +1,14 @@ ### Horserace -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=92 +This program simulates a one-mile horse race for three-year old throughbreds. Up to ten people may place bets on the race up to $10,000 each. However, you may only bet to win. You place your bet by inputting the number of the horse, a comma, and the amount of your bet. The computer then shows the position of the horses at seven points around the track and at the finish. Payoffs and winnings are shown at the end. + +The program was written by Laurie Chevalier while a student at South Portland High School. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=92) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=107) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/51_Hurkle/README.md b/51_Hurkle/README.md index 1a13ac8e..0204e405 100644 --- a/51_Hurkle/README.md +++ b/51_Hurkle/README.md @@ -1,7 +1,16 @@ ### Hurkle -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=94 +Hurkle? A Hurkle is a happy beast and lives in another galaxy on a planet named Lirht that has three moons. Hurkle are favorite pets of the Gwik, the dominant race of Lihrt and … well, to find out more, read “The Hurkle is a Happy Beast,” a story in the book _A Way Home_ by Theodore Sturgeon. + +In this program a shy hurkle is hiding on a 10 by 10 grid. Homebase is point 0,0 in the _Southwest_ corner. Your guess as to the gridpoint where the hurkle is hiding should be a pair of whole numbers, separated by a comma. After each try, the computer will tell you the approximate direction to go look for the Hurkle. You get five guesses to find him; you may change this number, although four guesses is actually enough. + +This program was written by Bob Albrecht of People’s Computer Company. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=94) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=109) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/52_Kinema/README.md b/52_Kinema/README.md index d3c74687..31a69199 100644 --- a/52_Kinema/README.md +++ b/52_Kinema/README.md @@ -1,7 +1,19 @@ ### Kinema -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=95 +This program tests your fundamental knowledge of kinematics. It presents a simple problem: a ball is thrown straight up into the air at some random velocity. You then must answer three questions about the flight of the ball: +1. How high will it go? +2. How long until it returns to earth? +3. What will be its velocity after a random number of seconds? + +The computer evaluates your performance; within 15% of the correct answer is considered close enough. After each run, the computer gives you another problem until you interrupt it. + +KINEMA was shorted from the original Huntington Computer Project Program, KINERV, by Richard Pav of Patchogue High School, Patchogue, New York. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=95) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=110) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/53_King/README.md b/53_King/README.md index cf570189..eb0ba8ab 100644 --- a/53_King/README.md +++ b/53_King/README.md @@ -1,7 +1,18 @@ ### King -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=96 +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 author of this program is James A. Storer who wrote it while a student at Lexington High School. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=96) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=111) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/54_Letter/README.md b/54_Letter/README.md index eef18d38..fab67494 100644 --- a/54_Letter/README.md +++ b/54_Letter/README.md @@ -1,7 +1,14 @@ ### Letter -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=99 +LETTER is similar to the game GUESS in which you guess a number chosen by the computer; in this program, the computer picks a random letter of the alphabet and you must guess which one it is using the clues provided as you go along. It should not take you more than five guesses to get the mystery letter. + +The program which appears here is loosely based on the original written by Bob Albrect of People’s Computer Company. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=99) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=114) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/55_Life/README.md b/55_Life/README.md index e6a2b702..149bf25d 100644 --- a/55_Life/README.md +++ b/55_Life/README.md @@ -1,7 +1,35 @@ ### Life -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=100 +The Game of Life was originally described in _Scientific American_, October 1970, in an article by Martin Gardner. The game itself was originated by John Conway of Gonville and Caius College, University of Cambridge England. + +In the “manual” game, organisms exist in the form of counters (chips or checkers) on a large checkerboard and die or reproduce according to some simple genetic rules. Conway’s criteria for choosing his genetic laws were carefully delineated as follows: +1. There should be no initial pattern for which there is a simple proof that the population can grow without limit. +2. There should be simple initial patterns that apparently do grow without limit. +3. There should be simple initial patterns that grow and change for a considerable period of time before coming to an end in three possible ways: + 1. Fading away completely (from overcrowding or from becoming too sparse) + 2. Settling into a stable configuration that remains unchanged thereafter + 3. Entering an oscillating phase in which they repeat an endless cycle of two or more periods + +In brief, the rules should be such as to make the behavior of the population relatively unpredictable. Conway’s genetic laws are delightfully simple. First note that each cell of the checkerboard (assumed to be an infinite plane) has eight neighboring cells, four adjacent orthogonally, four adjacent diagonally. The rules are: +1. Survivals. Every counter with two or three neighboring counters survives for the next generation. +2. Deaths. Each counter with four or more neighbors dies (is removed) from overpopulation. Every counter with one neighbor or none dies from isolation. +3. Births. Each empty cell adjacent to exactly three neighbors — no more — is a birth cell. A counter is placed on it at the next move. + +It is important to understand that all births and deaths occur simultaneously. Together they constitute a single generation or, as we shall call it, a “move” in the complete “life history” of the initial configuration. + +You will find the population constantly undergoing unusual, sometimes beautiful and always unexpected change. In a few cases the society eventually dies out (all counters vanishing), although this may not happen until after a great many generations. Most starting patterns either reach stable figures — Conway calls them “still lifes” — that cannot change or patterns that oscillate forever. Patterns with no initial symmetry tend to become symmetrical. Once this happens the symmetry cannot be lost, although it may increase in richness. + +Conway used a DEC PDP-7 with a graphic display to observe long-lived populations. You’ll probably find this more enjoyable to watch on a CRT than a hard-copy terminal. + +Since MITS 8K BASIC does not have LINE INPUT, to enter leading blanks in the patter, type a “.” at the start of the line. This will be converted to a space by BASIC, but it permits you to type leading spaces. Typing DONE indicates that you are finished entering the pattern. See sample run. + +Clark Baker of Project DELTA originally wrote this version of LIFE which was further modified by Steve North of Creative Computing. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=100) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=115) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/56_Life_for_Two/README.md b/56_Life_for_Two/README.md index 34030043..d880653d 100644 --- a/56_Life_for_Two/README.md +++ b/56_Life_for_Two/README.md @@ -1,7 +1,44 @@ ### Life for Two -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=102 +LIFE-2 is based on Conway’s game of Life. You must be familiar with the rules of LIFE before attempting to play LIFE-2. + +There are two players; the game is played on a 5x5 board and each player has a symbol to represent his own pieces of ‘life.’ Live cells belonging to player 1 are represented by `*` and live cells belonging to player 2 are represented by the symbol `#`. + +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 | | | | | | +| 2 | | | * | | | +| 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 | | | | | | +| 2 | | | | | | +| 3 | | | # | # | | +| 4 | | | | | | +| 5 | | | | | | + +On the first most each player positions 3 pieces of life on the board by typing in the co-ordinates of the pieces. (In the event of the same cell being chosen by both players that cell is left empty.) + +The board is then adjusted to the next generation and printed out. + +On each subsequent turn each player places one piece on the board, the object being to annihilate his opponent’s pieces. The board is adjusted for the next generation and printed out after both players have entered their new piece. + +The game continues until one player has no more live pieces. The computer will then print out the board and declare the winner. + +The idea for this game, the game itself, and the above write-up were written by Brian Wyvill of Bradford University in Yorkshire, England. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=102) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=117) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/57_Literature_Quiz/README.md b/57_Literature_Quiz/README.md index 54605904..2e55251f 100644 --- a/57_Literature_Quiz/README.md +++ b/57_Literature_Quiz/README.md @@ -1,7 +1,14 @@ ### Literature Quiz -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=104 +This is a simple CAI-type program which presents four multiple-choice questions from children’s literature. Running the program is self-explanatory. + +The program was written by Pamela McGinley while at DEC. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=104) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=117) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/58_Love/README.md b/58_Love/README.md index 35fb6f7d..1b2431aa 100644 --- a/58_Love/README.md +++ b/58_Love/README.md @@ -1,7 +1,14 @@ ### Love -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=105 +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 love program was created by David Ahl. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=105) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=120) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/59_Lunar_LEM_Rocket/README.md b/59_Lunar_LEM_Rocket/README.md index eced07e0..9d1890ac 100644 --- a/59_Lunar_LEM_Rocket/README.md +++ b/59_Lunar_LEM_Rocket/README.md @@ -1,7 +1,24 @@ ### Lunar LEM Rocket -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=106 +This game in its many different versions and names (ROCKET, LUNAR, LEM, and APOLLO) is by far and away the single most popular computer game. It exists in various versions that start you anywhere from 500 feet to 200 miles away from the moon, or other planets, too. Some allow the control of directional stabilization rockets and/or the retro rocket. The three versions presented here represent the most popular of the many variations. + +In most versions of this game, the temptation is to slow up too soon and then have no fuel left for the lower part of the journey. This, of course, is disastrous (as you will find out when you land your own capsule)! + +LUNAR was originally in FOCAL by Jim Storer while a student at Lexington High School and subsequently converted to BASIC by David Ahl. ROCKET was written by Eric Peters at DEC and LEM by William Labaree II of Alexandria, Virginia. + +In this program, you set the burn rate of the retro rockets (pounds of fuel per second) every 10 seconds and attempt to achieve a soft landing on the moon. 200 lbs/sec really puts the brakes on, and 0 lbs/sec is free fall. Ignition occurs a 8 lbs/sec, so _do not_ use burn rates between 1 and 7 lbs/sec. To make the landing more of a challenge, but more closely approximate the real Apollo LEM capsule, you should make the available fuel at the start (N) equal to 16,000 lbs, and the weight of the capsule (M) equal to 32,500 lbs. + +#### LEM +This is the most comprehensive of the three versions and permits you to control the time interval of firing, the thrust, and the attitude angle. It also allows you to work in the metric or English system of measurement. The instructions in the program dialog are very complete, so you shouldn’t have any trouble. + +#### ROCKET +In this version, you start 500 feet above the lunar surface and control the burn rate in 1-second bursts. Each unit of fuel slows your descent by 1 ft/sec. The maximum thrust of your engine is 30 ft/sec/sec. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=106) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=121) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/60_Mastermind/README.md b/60_Mastermind/README.md index d78cf527..e9bf1c3c 100644 --- a/60_Mastermind/README.md +++ b/60_Mastermind/README.md @@ -1,7 +1,29 @@ ### MasterMind -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=110 +In that Match-April 1976 issue of _Creative_ we published a computerized version of Master Mind, a logic game. Master Mind is played by two people—one is called the code-maker; the other, the code-breaker. At the beginning of the game the code-maker forms a code, or combination of colored pegs. He hides these from the code-breaker. The code-breaker then attempts to deduce the code, by placing his own guesses, one at a time, on the board. After he makes a guess (by placing a combination of colored pegs on the board) the code-maker then gives the code-breaker clues to indicate how close the guess was to the code. For every peg in the guess that’s the right color but not in the right position, the code-breaker gets a white peg. Note that these black and white pegs do not indicate _which_ pegs in the guess are correct, but merely that they exist. For example, if the code was: +``` +Yellow Red Red Green +``` + +and my guess was +``` +Red Red Yellow Black +``` +I would receive two white pegs and one black peg for the guess. I wouldn’t know (except by comparing previous guesses) which one of the pegs in my guess was the right color in the right position. + +Many people have written computer programs to play Master Mind in the passive role, i.e., the computer is the code maker and the human is the code-breaker. This is relatively trivial; the challenge is writing a program that can also play actively as a code-breaker. + +Actually, the task of getting the computer to deduce the correct combination is not at all difficult. Imagine, for instance, that you made a list of all possible codes. To begin, you select a guess from your list at random. Then, as you receive clues, you cross off from the list those combinations which you know are impossible. For example if your guess is Red Red Green Green and you receive no pegs, then you know that any combination containing either a red or a green peg is impossible and may be crossed of the list. The process is continued until the correct solution is reached or there are no more combinations left on the list (in which case you know that the code-maker made a mistake in giving you the clues somewhere). + +Note that in this particular implementation, we never actually create a list of the combinations, but merely keep track of which ones (in sequential order) may be correct. Using this system, we can easily say that the 523rd combination may be correct, but to actually produce the 523rd combination we have to count all the way from the first combination (or the previous one, if it was lower than 523). Actually, this problem could be simplified to a conversion from base 10 to base (number of colors) and then adjusting the values used in the MID$ function so as not to take a zeroth character from a string if you want to experiment. We did try a version that kept an actual list of all possible combinations (as a string array), which was significantly faster than this version, but which ate tremendous amounts of memory. + +At the beginning of this game, you input the number of colors and number of positions you wish to use (which will directly affect the number of combinations) and the number of rounds you wish to play. While you are playing as the code-breaker, you may type BOARD at any time to get a list of your previous guesses and clues, and QUIT to end the game. Note that this version uses string arrays, but this is merely for convenience and can easily be converted for a BASIC that has no string arrays as long as it has a MID$ function. This is because the string arrays are one-dimensional, never exceed a length greater than the number of positions and the elements never contain more than one character. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=110) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=125) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/61_Math_Dice/README.md b/61_Math_Dice/README.md index f6285a11..a24c9dbe 100644 --- a/61_Math_Dice/README.md +++ b/61_Math_Dice/README.md @@ -1,7 +1,14 @@ ### Math Dice -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=113 +The program presents pictorial drill on addition facts using printed dice with no reading involved. It is good for beginning addition, since the answer can be derived from counting spots on the dice as well as by memorizing math facts or awareness of number concepts. It is especially effective run on a CRT terminal. + +It was originally written by Jim Gerrish, a teacher at the Bernice A. Ray School in Hanover, New Hampshire. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=113) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=128) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/62_Mugwump/README.md b/62_Mugwump/README.md index 421f0112..c67037f2 100644 --- a/62_Mugwump/README.md +++ b/62_Mugwump/README.md @@ -1,7 +1,18 @@ ### Mugwump -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=114 +Your objective in this game is to find the four Mugwumps hiding on various squares of a 10 by 10 grid. Homebase (lower left) is position (0,0) and a guess is a pair of whole numbers (0 to 9), separated by commas. The first number is the number of units to the right of homebase and the second number is the distance above homebase. + +You get ten guesses to locate the four Mugwumps; after each guess, the computer tells you how close you are to each Mugwump. Playing the game with the aid of graph paper and a compass should allow you to find all the Mugwumps in six or seven moves using triangulation similar to Loran radio navigation. + +If you want to make the game somewhat more difficult, you can print the distance to each Mugwump either rounded or truncated to the nearest integer. + +This program was modified slightly by Bob Albrecht of People’s Computer Company. It was originally written by students of Bud Valenti of Project SOLO in Pittsburg, Pennsylvania. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=114) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=129) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/63_Name/README.md b/63_Name/README.md index daa110c1..a3744cdd 100644 --- a/63_Name/README.md +++ b/63_Name/README.md @@ -1,7 +1,14 @@ ### Name -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=116 +NAME is a silly little ice-breaker to get a relationship going between a computer and a shy human. The sorting algorithm used is highly inefficient — as any reader of _Creative Computing_ will recognize, this is the worst possible sort for speed. But the program is good fun and that’s what counts here. + +NAME was originall written by Geoffry Chase of the Abbey, Portsmouth, Rhode Island. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=116) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=131) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/64_Nicomachus/README.md b/64_Nicomachus/README.md index f54f600e..bbe911fc 100644 --- a/64_Nicomachus/README.md +++ b/64_Nicomachus/README.md @@ -1,7 +1,18 @@ ### Nicomachus -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=117 +One of the most ancient forms of arithmetic puzzle is sometimes referred to as a “boomerang.” At some time, everyone has been asked to “think of a number,” and, after going through some process of private calculation, to state the result, after which the questioner promptly tells you the number you originally thought of. There are hundreds of varieties of this puzzle. + +The oldest recorded example appears to be that given in _Arithmetica_ of Nicomachus, who died about the year 120. He tells you to think of any whole number between 1 and 100 and divide it successfully by 3, 5, and 7, telling him the remainder in each case. On receiving this information, he promptly discloses the number you thought of. + +Can you discover a simple method of mentally performing this feat? If not, you can see how the ancient mathematician did it by looking at this program. + +Nicomachus was written by David Ahl. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=117) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=132) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/65_Nim/README.md b/65_Nim/README.md index a47d44e4..867f641d 100644 --- a/65_Nim/README.md +++ b/65_Nim/README.md @@ -1,7 +1,27 @@ ### Nim -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=118 +NIM is one of the oldest two-person games known to man; it is believed to have originated in ancient China. The name, which was coined by the first mathematician to analyze it, comes from an archaic English verb which means to steal or to take away. Objects are arranged in rows between the two opponents as in the following example: +| | | | +|---------|-------|-----------| +| XXXXXXX | Row 1 | 7 Objects | +| XXXXX | Row 2 | 5 Objects | +| XXX | Row 3 | 3 Objects | +| X | Row 4 | 1 Object | + +Opponents take turns removing objects until there are none left. The one who picks up the last object wins. The moves are made according to the following rules: +1. On any given turn only objects from one row may be removed. There is no restriction on which row or on how many objects you remove. Of course, you cannot remove more than are in the row. +2. You cannot skip a move or remove zero objects. + +The winning strategy can be mathematically defined, however, rather than presenting it here, we’d rather let you find it on your own. HINT: Play a few games with the computer and mark down on a piece of paper the number of objects in each stack (in binary!) after each move. Do you see a pattern emerging? + +This game of NIM is from Dartmouth College and allows you to specify any starting size for the four piles and also a win option. To play traditional NIM, you would simply specify 7,5,3 and 1, and win option 1. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=118) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=133) + Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/66_Number/README.md b/66_Number/README.md index 8eb2e9b5..47a9b5cb 100644 --- a/66_Number/README.md +++ b/66_Number/README.md @@ -1,7 +1,14 @@ ### Number -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=121 +In contrast to other number guessing games where you keep guessing until you get the random number selected by the computer (GUESS, TRAP, STARS, etc.), in this game you only get one guess per play and you gain or lose points depending upon how close your guess is to the random number selected by the computer. You occasionally get a jackpot which will double your point count. You win when you get 500 points. + +Tom Adametx wrote this program while a student at Curtis Junior High School in Sudbury, Massachusetts. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=121) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=136) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/67_One_Check/README.md b/67_One_Check/README.md index 0e703692..b3522e15 100644 --- a/67_One_Check/README.md +++ b/67_One_Check/README.md @@ -1,7 +1,29 @@ ### One Check -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=122 +In this game or puzzle, 48 checkers are placed on the two outside spaces of a standard 64-square checkerboard as shown: + +| | | | | | | | | +|---|---|---|---|---|---|---|---| +| ● | ● | ● | ● | ● | ● | ● | ● | +| ● | ● | ● | ● | ● | ● | ● | ● | +| ● | ● | | | | | ● | ● | +| ● | ● | | | | | ● | ● | +| ● | ● | | | | | ● | ● | +| ● | ● | | | | | ● | ● | +| ● | ● | ● | ● | ● | ● | ● | ● | +| ● | ● | ● | ● | ● | ● | ● | ● | + +The object is to remove as many checkers as possible by diagonal jumps (as in standard checkers). + +It is easy to remove 30 to 39 checkers, a challenge to remove 40 to 44, and a substantial feat to remove 45 to 47. + +The program was created and written by David Ahl. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=122) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=137) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/68_Orbit/README.md b/68_Orbit/README.md index 3d7a04cb..df49852b 100644 --- a/68_Orbit/README.md +++ b/68_Orbit/README.md @@ -1,7 +1,57 @@ ### Orbit -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=124 +ORBIT challenges you to visualize spacial positions in polar coordinates. The object is to detonate a Photon explosive within a certain distance of a germ laden Romulan spaceship. This ship is orbiting a planet at a constant altitude and orbital rate (degrees/hour). The location of the ship is hidden by a device that renders the ship invisible, but after each bomb you are told how close to the enemy ship your bomb exploded. The challenge is to hit an invisible moving target with a limited number of shots. + +The planet can be replaced by a point at its center (called the origin); then the ship’s position can be given as a distance form the origin and an angle between its position and the eastern edge of the planet. + +``` +direction +of orbit < ^ ship + \ ╱ + \ ╱ < + |╱ \ + ╱ \ + ╱ \ + ╱ | angle + ╱ / + ╱ / + ╱ / + ╱——————————————————— E + +``` + +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+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. + + +``` + bomb < + ╲ ^ ship + ╲ ╱ + ╲ ╱ < + ╲ ╱ \ + D1 ╲ ╱ \ + ╲ R ╱ \ + ╲ A1 ╱ | A + ╲⌄——— ◝╱ / + ╲ ╱ \ / + ╲ ╱ \ / + ╲╱───────────────────── E + +``` + +ORBIT was originally called SPACE WAR and was written by Jeff Lederer of Project SOLO Pittsburgh, Pennsylvania. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=124) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=139) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/69_Pizza/README.md b/69_Pizza/README.md index fc83503a..671e7237 100644 --- a/69_Pizza/README.md +++ b/69_Pizza/README.md @@ -1,7 +1,16 @@ ### Pizza -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=126 +In this game, you take orders for pizzas from people living in Hyattsville. Armed with a map of the city, you must then tell your delivery boy the address where the pizza is to be delivered. If the pizza is delivered to the correct address, the customer phones you and thanks you; if not, you must give the driver the correct address until the pizza gets delivered. + +Some interesting modifications suggest themselves for this program such as pizzas getting cold after two incorrect delivery attempts or taking three or more orders at a time and figuring out the shortest delivery route. Send us your modifications! + +This program seems to have surfaced originally at the University of Georgia in Athens, Georgia. The author is unknown. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=126) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=141) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/70_Poetry/README.md b/70_Poetry/README.md index fe3c0ea8..b04bb915 100644 --- a/70_Poetry/README.md +++ b/70_Poetry/README.md @@ -1,7 +1,29 @@ ### Poetry -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=128 +This program produces random verse which might loosely be considered in the Japanese Haiku style. It uses 20 phrases in four groups of five phrases each and generally cycles through the groups in order. It inserts commas (random — 19% of the time), indentation (random — 22% of the time), and starts new paragraphs (18% probability but at least once every 20 phrases). + +The phrases in POETRY are somewhat suggestive of Edgar Allen Poe. Try it with phrases from computer technology, from love and romance, from four-year-old children, or from some other project. Send us the output. + +Here are some phrases from nature to try: +``` +Carpet of ferns Mighty Oaks +Morning dew Grace and beauty +Tang of dawn Silently singing +Swaying pines Nature speaking + +Entrances me Untouched, unspoiled +Soothing me Shades of green +Rustling leaves Tranquility +Radiates calm …so peaceful +``` + +The original author of this program is unknown. It was modified and reworked by Jim Bailey, Peggy Ewing, and Dave Ahl at DEC. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=128) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=143) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/71_Poker/README.md b/71_Poker/README.md index b5f7bc83..1bad96d6 100644 --- a/71_Poker/README.md +++ b/71_Poker/README.md @@ -1,7 +1,16 @@ ### Poker -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=129 +You and the computer are opponents in this game of draw poker. At the start of the game, each player is given $200. The game ends when either player runs out of money, although if you go broke the computer will offer to buy back your wristwatch or diamond tie tack. + +The computer opens the betting before the draw; you open the betting after the draw. If you don’t have a hand that’s worth anything and you want to fold, bet 0. Prior to the draw, to check the draw, you may bet .5. Of course, if the computer has made a bet, you must match it in order to draw or, if you have a good hand, you may raise the bet at any time. + +The author is A. Christopher Hall of Trinity College, Hartford, Connecticut. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=129) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=144) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/72_Queen/README.md b/72_Queen/README.md index 44ec90bb..dc62cb59 100644 --- a/72_Queen/README.md +++ b/72_Queen/README.md @@ -1,7 +1,16 @@ ### Queen -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=133 +This game is based on the permissible moves of the chess queen — i.e., along any vertical, horizontal, or diagonal. In this game, the queen can only move to the left, down, and diagonally down to the left. + +The object of the game is to place the queen (one only) in the lower left-hand square (no. 158), by alternating moves between you and the computer. The 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 the right-hand column. That is your first move. The computer is beatable, but it takes some figuring. See if you can devise a winning strategy. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=133) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=148) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/73_Reverse/README.md b/73_Reverse/README.md index 68d83b47..a753e8a8 100644 --- a/73_Reverse/README.md +++ b/73_Reverse/README.md @@ -1,7 +1,31 @@ ### Reverse -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=135 +The game of REVERSE requires you to arrange a list of numbers in numerical order from left to right. To move, you tell the computer how many numbers (counting from the left) to reverse. For example, if the current list is: +``` + 2 3 4 5 1 6 7 8 9 +``` + +and you reverse 4, the result will be: +``` + 5 4 3 2 1 6 7 8 9 +``` +Now if you reverse 5, you win! + +There are many ways to beat the game, but approaches tend to be either algorithmic or heuristic. The game thus offers the player a chance to play with these concepts in a practical (rather than theoretical) context. + +An algorithmic approach guarantees a solution in a predictable number of moves, given the number of items in the list. For example, one method guarantees a solution in 2N - 3 moves when teh list contains N numbers. The essence of an algorithmic approach is that you know in advance what your next move will be. Once could easily program a computer to do this. + +A heuristic approach takes advantage of “partial orderings” in the list at any moment. Using this type of approach, your next move is dependent on the way the list currently appears. This way of solving the problem does not guarantee a solution in a predictable number of moves, but if you are lucky and clever, you may come out ahead of the algorithmic solutions. One could not so easily program this method. + +In practice, many players adopt a “mixed” strategy, with both algorithmic and heuristic features. Is this better than either “pure” strategy? + +The program was created by Peter Sessions of People’s Computer Company and the notes above adapted from his original write-up. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=135) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=150) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/74_Rock_Scissors_Paper/README.md b/74_Rock_Scissors_Paper/README.md index 602dd15b..1b9fa865 100644 --- a/74_Rock_Scissors_Paper/README.md +++ b/74_Rock_Scissors_Paper/README.md @@ -1,7 +1,21 @@ ### Rock, Scissors, Paper -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=137 +Remember the game of rock-scissors-paper. You and your opponent make a motion three times with your fists and then either show: +- a flat hand (paper) +- fist (rock) +- two fingers (scissors) + +Depending upon what is shown, the game is a tie (both show the same) or one person wins. Paper wraps up rock, so it wins. Scissors cut paper, so they win. And rock breaks scissors, so it wins. + +In this computerized version of rock-scissors-paper, you can play up to ten games vs. the computer. + +Charles Lund wrote this game while at the American School in The Hague, Netherlands. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=137) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=152) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/75_Roulette/README.md b/75_Roulette/README.md index f652ee9e..51719248 100644 --- a/75_Roulette/README.md +++ b/75_Roulette/README.md @@ -1,7 +1,16 @@ ### Roulette -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=138 +This game simulates an American Roulette wheel; “American” because it has 38 number compartments (1 to 36, 0 and 00). The European wheel has 37 numbers (1 to 36 and 0). The Bahamas, Puerto Rico, and South American countries are slowly switching to the American wheel because it gives the house a bigger percentage. Odd and even numbers alternate around the wheel, as do red and black. The layout of the wheel insures a highly random number pattern. In fact, roulette wheels are sometimes used to generate tables of random numbers. + +In this game, you may bet from $5 to $500 and you may bet on red or black, odd or even, first or second 18 numbers, a column, or single number. You may place any number of bets on each spin of the wheel. + +There is no long-range winning strategy for playing roulette. However, a good strategy is that of “doubling.” First spin, bet $1 on an even/odds bet (odd, even, red, or black). If you lose, double your bet again to $2. If you lose again, double to $4. Continue to double until you win (i.e, you break even on a losing sequence). As soon as you win, bet $1 again, and after every win, bet $1. Do not ever bet more than $1 unless you are recuperating losses by doubling. Do not ever bet anything but the even odds bets. Good luck! + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=138) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=153) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/76_Russian_Roulette/README.md b/76_Russian_Roulette/README.md index 3385adc8..cf1b64fc 100644 --- a/76_Russian_Roulette/README.md +++ b/76_Russian_Roulette/README.md @@ -1,7 +1,14 @@ ### Russian Roulette -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=141 +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. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=141) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=153) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/77_Salvo/README.md b/77_Salvo/README.md index 82f8a5e2..fbf938ca 100644 --- a/77_Salvo/README.md +++ b/77_Salvo/README.md @@ -1,7 +1,25 @@ ### Salvo -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=142 +The rules are _not_ explained by the program, so read carefully this description by Larry Siegel, the program author. + +SALVO is played on a 10x10 grid or board using an x,y coordinate system. The player has 4 ships: +- battleship (5 squares) +- cruiser (3 squares) +- two destroyers (2 squares each) + +The ships may be placed horizontally, vertically, or diagonally and must not overlap. The ships do not move during the game. + +As long as any square of a battleship still survives, the player is allowed three shots, for a cruiser 2 shots, and for each destroyer 1 shot. Thus, at the beginning of the game the player has 3+2+1+1=7 shots. The players enters all of his shots and the computer tells what was hit. A shot is entered by its grid coordinates, x,y. The winner is the one who sinks all of the opponents ships. + +Important note: Your ships are located and the computer’s ships are located on 2 _separate_ 10x10 boards. + +Author of the program is Lawrence Siegel of Shaker Heights, Ohio. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=142) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=157) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/78_Sine_Wave/README.md b/78_Sine_Wave/README.md index f78ccccf..c38234a2 100644 --- a/78_Sine_Wave/README.md +++ b/78_Sine_Wave/README.md @@ -1,7 +1,12 @@ ### Sine Wave -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=146 +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. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=146) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=161) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/79_Slalom/README.md b/79_Slalom/README.md index 49935ea1..7e46e3a5 100644 --- a/79_Slalom/README.md +++ b/79_Slalom/README.md @@ -1,7 +1,16 @@ ### Slalom -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=147 +This game simulates a slalom run down a course with one to 25 gates. The user picks the number of gates and has some control over his speed down the course. + +If you’re not a skier, here’s your golden opportunity to try it with minimal risk. If you are a skier, here’s something to do while your leg is in a cast. + +SLALOM was written by J. Panek while a student at Dartmouth College. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=147) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=162) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/80_Slots/README.md b/80_Slots/README.md index 1b4a1987..952fa03e 100644 --- a/80_Slots/README.md +++ b/80_Slots/README.md @@ -1,7 +1,18 @@ ### Slots -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=149 +The slot machine or one-arm bandit is a mechanical device that will absorb coins just about as fast as you can feed it. After inserting a coin, you pull a handle that sets three independent reels spinning. If the reels stop with certain symbols appearing in the pay line, you get a certain payoff. The original slot machine, called the Liberty Bell, was invented in 1895 by Charles Fey in San Francisco. Fey refused to sell or lease the manufacturing rights, so H.S. Mills in Chicago built a similar, but much improved machine called the Operators Bell. This has survived nearly unchanged to today. + +On the Operators Bell and other standard slot machines, there are 20 symbols on each wheel but they are not distributed evenly among the objects (cherries, bar, apples, etc.). Of the 8,000 passible combinations, the expected payoff (to the player) is 7,049 or $89.11 for every $100.00 put in, one of the lowest expected payoffs in all casino games. + +In the program here, the payoff is considerably more liberal; indeed it appears to favor the player by 11% — i.e., an expected payoff of $111 for each $100 bet. + +The program was originally written by Fred Mirabella and Bob Harper. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=149) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=164) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/81_Splat/README.md b/81_Splat/README.md index 4b4161ef..24631217 100644 --- a/81_Splat/README.md +++ b/81_Splat/README.md @@ -1,7 +1,16 @@ ### Splat -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=151 +SPLAT simulates a parachute jump in which you try to open your parachute at the last possible moment without going splat! You may select your own terminal velocity or let the computer do it for you. You many also select the acceleration due to gravity or, again, let the computer do it in which case you might wind up on any of eight planets (out to Neptune), the moon, or the sun. + +The computer then tells you the height you’re jumping from and asks for the seconds of free fall. It then divides your free fall time into eight intervals and gives you progress reports on your way down. The computer also keeps track of all prior jumps in the array A and lets you know how you compared with previous successful jumps. If you want to recall information from previous runs, then you should store array A in a disk or take file and read it before each run. + +John Yegge created this program while at the Oak Ridge Associated Universities. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=151) +- [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 diff --git a/82_Stars/README.md b/82_Stars/README.md index cc6c3171..ff067975 100644 --- a/82_Stars/README.md +++ b/82_Stars/README.md @@ -1,7 +1,16 @@ ### Stars -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=153 +In this game, the computer selects a random number from 1 to 100 (or any value you set). 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 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. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=153) +- [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 diff --git a/83_Stock_Market/README.md b/83_Stock_Market/README.md index 6b963c2f..65447e1f 100644 --- a/83_Stock_Market/README.md +++ b/83_Stock_Market/README.md @@ -1,7 +1,16 @@ ### Stock Market -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=154 +This program “plays” the stock market. You will be given $10,000 and may buy or sell stocks. Stock prices and trends are generated randomly; therefore, this model does not represent exactly what happens on the exchange. (Depending upon your point of view, you may feel this is quite a good representation!) + +Every trading day, a table of stocks, their prices, and number of shares in your portfolio is printed. Following this, the initials of each stock are printed followed by a question mark. You indicate your transaction in number of shares — a positive number to buy, negative to sell, or 0 to do no trading. A brokerage fee of 1% is charges on all transactions (a bargain!). Note: Even if the value of a stock drops to zero, it may rebound again — then again, it may not. + +This program was created by D. Pessel, L. Braun, and C. Losik of the Huntington Computer Project at SUNY, Stony Brook, N.Y. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=154) +- [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 diff --git a/84_Super_Star_Trek/README.md b/84_Super_Star_Trek/README.md index 495ce9ae..4a96f528 100644 --- a/84_Super_Star_Trek/README.md +++ b/84_Super_Star_Trek/README.md @@ -1,7 +1,98 @@ ### Super Star Trek -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=157 +#### Brief History +Many versions of Star Trek have been kicking around various college campuses since the late sixties. I recall playing one at Carnegie-Mellon Univ. in 1967 or 68, and a very different one at Berkeley. However, these were a far cry from the one written by Mike Mayfield of Centerline Engineering and/or Custom Data. This was written for an HP2000C and completed in October 1972. It became the “standard” Star Trek in February 1973 when it was put in the HP contributed program library and onto a number of HP Data Center machines. + +In the summer of 1973, I converted the HP version to BASIC-PLUS for DEC’s RSTS-11 compiler and added a few bits and pieces while I was at it. Mary Cole at DEC contributed enormously to this task too. Later that year I published it under the name SPACWE (Space War — in retrospect, an incorrect name) in my book _101 Basic Computer Games_.It is difficult today to find an interactive computer installation that does not have one of these versions of Star Trek available. + +#### Quadrant Nomenclature +Recently, certain critics have professed confusion as to the origin on the “quadrant” nomenclature used on all standard CG (Cartesian Galactic) maps. Naturally, for anyone with the remotest knowledge of history, no explanation is necessary; however, the following synopsis should suffice for the critics: + +As everybody schoolboy knows, most of the intelligent civilizations in the Milky Way had originated galactic designations of their own choosing well before the Third Magellanic Conference, at which the so-called “2⁶ Agreement” was reached. In that historic document, the participant cultures agreed, in all two-dimensional representations of the galaxy, to specify 64 major subdivisions, ordered as an 8 x 8 matrix. This was partially in deference to the Earth culture (which had done much in the initial organization of the Federation), whose century-old galactic maps had landmarks divided into four “quadrants,” designated by ancient “Roman Numerals” (the origin of which has been lost). + +To this day, the official logs of starships originating on near-Earth starbases still refer to the major galactic areas as “quadrants.” + +The relation between the Historical and Standard nomenclatures is shown in the simplified CG map below. + +| | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | +|---|--------------|----|-----|----|------------|----|-----|----| +| 1 | ANTARES | | | | SIRIUS | | | | +| | I | II | III | IV | I | | III | IV | +| 2 | RIGEL | | | | DENEB | | | | +| | I | II | III | IV | I | II | III | IV | +| 3 | PROCYON | | | | CAPELLA | | | | +| | I | II | III | IV | I | II | III | IV | +| 4 | VEGA | | | | BETELGUESE | | | | +| | I | II | III | IV | I | II | III | IV | +| 5 | CANOPUS | | | | ALDEBARA | | | | +| | I | II | III | IV | I | II | III | IV | +| 6 | ALTAIR | | | | REGULUS | | | | +| | I | II | III | IV | I | II | III | IV | +| 7 | SAGITTARIOUS | | | | ARCTURUS | | | | +| | I | II | III | IV | I | II | III | IV | +| 8 | POLLUX | | | | SPICA | | | | +| | I | II | III | IV | I | II | III | IV | + +#### Super Star Trek† Rules and Notes +1. OBJECTIVE: You are Captain of the starship “Enterprise”† with a mission to seek and destroy a fleet of Klingon† warships (usually about 17) which are menacing the United Federation of Planets.† You have a specified number of stardates in which to complete your mission. You also have two or three Federation Starbases† for resupplying your ship. + +2. You will be assigned a starting position somewhere in the galaxy. The galaxy is divided into an 8 x 8 quadrant grid. The astronomical name of a quadrant is called out upon entry into a new region. (See “Quadrant Nomenclature.”) Each quadrant is further divided into an 8 x 8 section grid. + +3. On a section diagram, the following symbols are used: + - `<*>` Enterprise + - `†††` Klingon + - `>!<` Starbase + - `*` Star + +4. You have eight commands available to you (A detailed description of each command is given in the program instructions.) + - `NAV` Navigate the Starship by setting course and warp engine speed. + - `SRS` Short-range sensor scan (one quadrant) + - `LRS` Long-range sensor scan (9 quadrants) + - `PHA` Phaser† control (energy gun) + - `TOR` Photon torpedo control + - `SHE` Shield control (protects against phaser fire) + - `DAM` Damage and state-of-repair report + - `COM` Call library computer + +5. Library computer options are as follows (more complete descriptions are in program instructions): + - `0` Cumulative galactic report + - `1` Status report + - `2` Photon torpedo course data + - `3` Starbase navigation data + - `4` Direction/distance calculator + - `5` Quadrant nomenclature map + +6. Certain reports on the ship’s status are made by officers of the Enterprise who appears on the original TV Show—Spock,† Scott,† Uhura,† Chekov,† etc. + +7. Klingons are non-stationary within their quadrants. If you try to maneuver on them, they will move and fire on you. + +8. Firing and damage notes: + - Phaser fire diminishes with increased distance between combatants. + - If a Klingon zaps you hard enough (relative to your shield strength) he will generally cause damage to some part of your ship with an appropriate “Damage Control” report resulting. + - 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 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!). + +11. While you’re docked at a Starbase, a team of technicians can repair your ship (if you’re willing for them to spend the time required—and the repairmen _always_ underestimate…) + +12. If, to same maneuvering time toward the end of the game, you should cold-bloodedly destroy a Starbase, you get a nasty note from Starfleet Command. If you destroy your _last_ Starbase, you lose the game! (For those who think this is too a harsh penalty, delete line 5360-5390, and you’ll just get a “you dumdum!”-type message on all future status reports.) + +13. End game logic has been “cleaned up” in several spots, and it is possible to get a new command after successfully completing your mission (or, after resigning your old one). + +14. For those of you with certain types of CRT/keyboards setups (e.g. Westinghouse 1600), a “bell” character is inserted at appropriate spots to cause the following items to flash on and off on the screen: + - The Phrase “\*RED\*” (as in Condition: Red) + - The character representing your present quadrant in the cumulative galactic record printout. + +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. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=157) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=166) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html @@ -11,4 +102,3 @@ instructions.txt #### External Links - Super Star Trek in C++ : https://www.codeproject.com/Articles/28399/The-Object-Oriented-Text-Star-Trek-Game-in-C - diff --git a/85_Synonym/README.md b/85_Synonym/README.md index b9a5b79f..66c3c4c3 100644 --- a/85_Synonym/README.md +++ b/85_Synonym/README.md @@ -1,7 +1,20 @@ ### Synonym -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=164 +A synonym of a word is another word (in the English language) which has the same, or very nearly the same, meaning. This program tests your knowledge of synonyms of a few common words. + +The computer chooses a word and asks you for a synonym. The computer then tells you whether you’re right or wrong. If you can’t think of a synonym, type “HELP” which causes a synonym to be printed. + +You may put in words of your choice in the data statements. The number following DATA in Statement 500 is the total number of data statements. In each data statement, the first number is the number of words in that statement. + +Can you think of a way to make this into a more general kind of CAI program for any subject? + +Walt Koetke of Lexington High School, Massachusetts created this program. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=164) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=179) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html @@ -14,4 +27,4 @@ http://www.vintage-basic.net/games.html all of the help. - The player can ask for HELP and then submit that answer. Is it - meant to be a clue, or just giving a correct answer to the player? \ No newline at end of file + meant to be a clue, or just giving a correct answer to the player? diff --git a/86_Target/README.md b/86_Target/README.md index ca5f9177..29e14e64 100644 --- a/86_Target/README.md +++ b/86_Target/README.md @@ -1,7 +1,16 @@ ### Target -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=165 +In this program, you are firing a weapon from a spaceship in 3-dimensional space. Your ship, the Starship Enterprise, is located at the origin (0,0,0) of a set of x,y,z coordinates. You will be told the approximate location of the target in 3-dimensional rectangular coordinates, the approximate angular deviation from the x and z axes in both radians and degrees, and the approximate distance to the target. + +Given this information, you then proceed to shoot at the target. A shot within 20 kilometers of the target destroys it. After each shot, you are given information as to the position of the explosion of your shot and a somewhat improved estimate of the location of the target. Fortunately, this is just practice and the target doesn’t shoot back. After you have attained proficiency, you ought to be able to destroy a target in 3 or 4 shots. However, attaining proficiency might take a while! + +The author is H. David Crockett of Fort Worth, Texas. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=165) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=180) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/87_3-D_Plot/README.md b/87_3-D_Plot/README.md index e7cea9b4..3361976a 100644 --- a/87_3-D_Plot/README.md +++ b/87_3-D_Plot/README.md @@ -1,7 +1,16 @@ ### 3-D Plot -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=167 +3-D PLOT will plot the family of curves of any function. The function Z is plotted as “rising” out of the x-y plane with x and y inside a circle of radius 30. The resultant plot looks almost 3-dimensional. + +You set the function you want plotted in line 5. As with any mathematical plot, some functions come out “prettier” than others. + +The author of this amazingly clever program is Mark Bramhall of DEC. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=167) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=182) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/89_Tic-Tac-Toe/README.md b/89_Tic-Tac-Toe/README.md index b4d04d06..311322fa 100644 --- a/89_Tic-Tac-Toe/README.md +++ b/89_Tic-Tac-Toe/README.md @@ -1,7 +1,25 @@ ### Tic-Tac-Toe -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=171 +The game of tic-tac-toe hardly needs any introduction. In this one, you play versus the computer. Moves are entered by number: +``` +1 2 3 + +4 5 6 + +7 8 9 +``` + +If you make any bad moves, the computer will win; if the computer makes a bad move, you can win; otherwise, the game ends in a tie. + +A second version of the game is included which prints out the board after each move. This is ideally suited to a CRT terminal, particularly if you modify it to not print out a new board after each move, but rather use the cursor to make the move. + +The first program was written by Tom Koos while a student researcher at the Oregon Museum of Science and Industry; it was extensively modified by Steve North of Creative Computing. The author of the second game is Curt Flick of Akron, Ohio. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=171) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=186) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/90_Tower/README.md b/90_Tower/README.md index 6d452f7f..cbd05830 100644 --- a/90_Tower/README.md +++ b/90_Tower/README.md @@ -1,7 +1,20 @@ ### Tower -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=173 +This is a simulation of a game of logic that originated in the middle East. It is sometimes called Pharaoh's Needles, but its most common name is the Towers of Hanoi. + +Legend has it that a secret society of monks live beneath the city of Hanoi. They possess three large towers or needles on which different size gold disks may be placed. Moving one at a time and never placing a large on a smaller disk, the monks endeavor to move the tower of disks from the left needle to the right needle. Legend says when they have finished moving this 64-disk tower, the world will end. How many moves will they have to make to accomplish this? If they can move 1 disk per minute and work 24 hours per day, how many years will it take? + +In the computer puzzle you are faced with three upright needles. On the leftmost needle are placed from two to seven graduated disks, the largest being on bottom and smallest on top. Your object is to move the entire stack of disks to the rightmost needle. However, you many only move one disk at a time and you may never place a larger disk on top of a smaller one. + +In this computer game, the disks are referred to by their size — i.e., the smallest is 3, next 5, 7, 9, 11, 13, and 15. If you play with fewer than 7 disks always use the largest, i.e. with 2 disks you would use nos. 13 and 15. The program instructions are self-explanatory. Good luck! + +Charles Lund wrote this program while at the American School in the Hague, Netherlands. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=173) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=188) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/91_Train/README.md b/91_Train/README.md index c5a249fb..50e7cf6e 100644 --- a/91_Train/README.md +++ b/91_Train/README.md @@ -1,7 +1,16 @@ ### Train -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=175 +TRAIN is a program which uses the computer to generate problems with random initial conditions to teach about the time-speed-distance relationship (distance = rate x time). You then input your answer and the computer verifies your response. + +TRAIN is merely an example of a student-generated problem. Maximum fun (and benefit) comes more from _writing_ programs like this as opposed to solving the specific problem posed. Exchange your program with others—you solve their problem and let them solve yours. + +TRAIN was originally written in FOCAL by one student for use by others in his class. It was submitted to us by Walt Koetke, Lexington High School, Lexington, Mass. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=175) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=190) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/92_Trap/README.md b/92_Trap/README.md index 7778ecb5..18d5db48 100644 --- a/92_Trap/README.md +++ b/92_Trap/README.md @@ -1,7 +1,19 @@ ### Trap -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=176 +This is another in the family of “guess the mystery number” games. In TRAP the computer selects a random number between 1 and 100 (or other limit set). Your object is to find the number. On each guess, you enter 2 numbers trying to trap the mystery number between your two trap numbers. The computer will tell you if you have trapped the number. + +To win the game, you must guess the mystery number by entering it as the same value for both of your trap numbers. You get 6 guesses (this should be changed if you change the guessing limit). + +After you have played GUESS, STARS, and TRAP, compare the guessing strategy you have found best for each game. Do you notice any similarities? What are the differences? Can you write a new guessing game with still another approach? + +TRAP was suggested by a 10-year-old when he was playing GUESS. It was originally programmed by Steve Ullman and extensively modified into its final form by Bob Albrecht of People’s Computer Co. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=176) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=191) + Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/93_23_Matches/README.md b/93_23_Matches/README.md index eb368c88..3e48212e 100644 --- a/93_23_Matches/README.md +++ b/93_23_Matches/README.md @@ -1,7 +1,18 @@ ### 23 Matches -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=177 +In the game of twenty-three matches, you start with 23 matches lying on a table. On each turn, you may take 1, 2, or 3 matches. You alternate moves with the computer and the one who has to take the last match loses. + +The easiest way to devise a winning strategy is to start at the end of the game. Since your wish to leave the last match to your opponent, you would like to have either 4, 3, or 2 on your last turn you so can take away 3, 2, or 1 and leave 1. Consequently, you would like to leave your opponent with 5 on his next to last turn so, no matter what his move, you are left with 4, 3, or 2. Work this backwards to the beginning and you’ll find the game can effectively be won on the first move. Fortunately, the computer gives you the first move, so if you play wisely, you can win. + +After you’ve mastered 23 Matches, move on to BATNUM and then to NUM. + +This version of 23 Matches was originally written by Bob Albrecht of People’s Computer Company. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=177) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=192) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/94_War/README.md b/94_War/README.md index 4345c4ac..a850f73e 100644 --- a/94_War/README.md +++ b/94_War/README.md @@ -1,7 +1,14 @@ ### War -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=178 +This program plays the card game of War. In War, the card deck is shuffled, then two cards are dealt, one to each player. Players compare cards and the higher card (numerically) wins. In case of a tie, no one wins. The game ends when you have gone through the whole deck (52 cards, 26 games) or when you decide to quit. + +The computer gives cards by suit and number, for example, S-7 is the 7 of spades. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=178) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=193) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/95_Weekday/README.md b/95_Weekday/README.md index 16f825a3..445c2c4b 100644 --- a/95_Weekday/README.md +++ b/95_Weekday/README.md @@ -1,7 +1,16 @@ ### Weekday -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=179 +This program gives facts about your date of birth (or some other day of interest). It is not prepared to give information on people born before the use of the current type of calendar, i.e. year 1582. + +You merely enter today’s date in the form—month, day, year and your date of birth in the same form. The computer then tells you the day of the week of your birth date, your age, and how much time you have spent sleeping, eating, working, and relaxing. + +This program was adapted from a GE timesharing program by Tom Kloos at the Oregon Museum of Science and Industry. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=179) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=194) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html diff --git a/96_Word/README.md b/96_Word/README.md index 404135e8..8db22c6c 100644 --- a/96_Word/README.md +++ b/96_Word/README.md @@ -1,7 +1,16 @@ ### Word -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=181 +WORD is a combination of HANGMAN and BAGELS. In this game, the player must guess a word with clues as to a letter position furnished by the computer. However, instead of guessing one letter at a time, in WORD you guess an entire word (or group of 5 letters, such as ABCDE). The computer will tell you if any letters that you have guessed are in the mystery word and if any of them are in the correct position. Armed with these clues, you go on guessing until you get the word or, if you can’t get it, input a “?” and the computer will tell you the mystery word. + +You may change the words in Data Statements, but they must be 5-letter words. + +The author of this program is Charles Reid of Lexington High School, Lexington, Massachusetts. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=181) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=194) Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html From 7f2f34709a5bc0ce28088075591408a3d0eab5c0 Mon Sep 17 00:00:00 2001 From: LukasMurdock Date: Mon, 3 Jan 2022 02:23:34 -0500 Subject: [PATCH 017/331] typo, left out y in originally --- 63_Name/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/63_Name/README.md b/63_Name/README.md index a3744cdd..302cdf07 100644 --- a/63_Name/README.md +++ b/63_Name/README.md @@ -2,7 +2,7 @@ NAME is a silly little ice-breaker to get a relationship going between a computer and a shy human. The sorting algorithm used is highly inefficient — as any reader of _Creative Computing_ will recognize, this is the worst possible sort for speed. But the program is good fun and that’s what counts here. -NAME was originall written by Geoffry Chase of the Abbey, Portsmouth, Rhode Island. +NAME was originally written by Geoffry Chase of the Abbey, Portsmouth, Rhode Island. --- From 87613662a89cc8d4480e00a39af1a361464d275a Mon Sep 17 00:00:00 2001 From: LukasMurdock Date: Mon, 3 Jan 2022 02:26:52 -0500 Subject: [PATCH 018/331] typo, misspelled Geoffrey --- 63_Name/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/63_Name/README.md b/63_Name/README.md index 302cdf07..45bf4e9a 100644 --- a/63_Name/README.md +++ b/63_Name/README.md @@ -2,7 +2,7 @@ NAME is a silly little ice-breaker to get a relationship going between a computer and a shy human. The sorting algorithm used is highly inefficient — as any reader of _Creative Computing_ will recognize, this is the worst possible sort for speed. But the program is good fun and that’s what counts here. -NAME was originally written by Geoffry Chase of the Abbey, Portsmouth, Rhode Island. +NAME was originally written by Geoffrey Chase of the Abbey, Portsmouth, Rhode Island. --- From 5e8b3b2ad2670c0d3b9575a666bde10473db384e Mon Sep 17 00:00:00 2001 From: aviyam Date: Mon, 3 Jan 2022 12:42:36 +0200 Subject: [PATCH 019/331] Fixed 2 issues: 1. Behavior of game play. New cards should be dealt every round. 2. As a result of 1, check that we have at least 3 cards for next round. --- 01_Acey_Ducey/python/acey_ducey_oo.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/01_Acey_Ducey/python/acey_ducey_oo.py b/01_Acey_Ducey/python/acey_ducey_oo.py index d8b7c752..325af4b4 100644 --- a/01_Acey_Ducey/python/acey_ducey_oo.py +++ b/01_Acey_Ducey/python/acey_ducey_oo.py @@ -95,11 +95,14 @@ class Game: self.not_done = False break - if len(self.deck.cards) <= 1: + if len(self.deck.cards) <= 3: print('You ran out of cards. Game over.') self.not_done = False break + self.card_a = self.deck.deal() + self.card_b = self.deck.deal() + if self.money == 0: self.not_done = False From 708155978c73f2a314594f421d930599b99a21f5 Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Mon, 3 Jan 2022 06:23:44 -0500 Subject: [PATCH 020/331] Add Perl port of 90_Tower (Tower of Hanoi) --- 90_Tower/perl/tower.pl | 381 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100755 90_Tower/perl/tower.pl diff --git a/90_Tower/perl/tower.pl b/90_Tower/perl/tower.pl new file mode 100755 index 00000000..f9258eea --- /dev/null +++ b/90_Tower/perl/tower.pl @@ -0,0 +1,381 @@ +#!/usr/bin/env perl + +use 5.010; # To get 'state' and 'say' + +use strict; # Require explicit declaration of variables +use warnings; # Enable optional compiler warnings + +use English; # Use more friendly names for Perl's magic variables +use Term::ReadLine; # Prompt and return user input + +our $VERSION = '0.000_01'; + +# Manifest constant representing the maximum number of disks. We can +# change this within limits. It needs to be at least 3 or the +# explanatory text will contain negative numbers. There is no known +# upper limit, though if it is more than 10 the output lines can be more +# than 80 columns, and if it is more than 49 the disk numbers will be +# more than two digits, which will cause output lines not to align +# properly. +use constant MAX_DISKS => 7; + +print <<'EOD'; + TOWERS + Creative Computing Morristown, New Jersey + + +EOD + +while ( 1 ) { # Iterate until something makes us stop. + + print <<'EOD'; +Towers of Hanoi Puzzle. + +You must transfer the disks from the left to the right +Tower, one at a time, never putting a larger disk on a +smaller disk. + +EOD + + # Get the desired number of disks to work with. + my $size = get_input( + + # Manifest constants do not interpolate into strings. This can + # be worked around using the @{[ ... ]} construction, which + # interpolates any expression. + "How many disks do you want to move (@{[ MAX_DISKS ]} is max)? ", + + sub { + + # Accept any response which is an integer greater than zero + # and less than or equal to the maximum number of disks. + # NOTE that 'and' performs the same operation as &&, but + # binds much more loosely. + return m/ \A [0-9]+ \z /smx && + $ARG > 0 && + $ARG <= MAX_DISKS; + }, + + 3, + "Sorry, but I can't do that job for you.\n", # Warning + <<'EOD', +All right, wise guy, if you can't play the game right, I'll +just take my puzzle and go home. So long. +EOD + ); + + # Expressions can be interpolated using @{[ ... ]} + print <<"EOD"; +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 @{[ MAX_DISKS * 2 + 1 ]}. If you do the puzzle with +2 disks, their code names would be @{[ MAX_DISKS * 2 - 1 ]} and @{[ MAX_DISKS * 2 + 1 ]}. With 3 disks +the code names would be @{[ MAX_DISKS * 2 - 3 ]}, @{[ MAX_DISKS * 2 - 1 ]} and @{[ MAX_DISKS * 2 + 1 ]}, 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! + +EOD + + # Compute the legal disk numbers for this puzzle. The expression + # reads right to left thus: + # * The .. operator generates the integers between and including + # its end points, that is, from MAX_DISKS + 1 - $size to + # MAX_DISKS, inclusive. + # * map { .. } calls the block once for each of its arguments. + # The value of the argument appears in the topic variable $ARG, + # and the result of the block is returned. + # * The list generated by the map {} is assigned to array + # @legal_disks. + my @legal_disks = map { $ARG * 2 + 1 } + MAX_DISKS + 1 - $size .. MAX_DISKS; + + # Generate the board. This is an array of needles, indexed from + # zero. Each needle is represented by a reference to an array + # containing the disks on that needle, bottom to top. + my @board = ( + [ reverse @legal_disks ], + [], + [] + ); + + display( \@board ); # Display the initial board. + + my $moves = 0; # Move counter. + + while ( 1 ) { # Iterate until something makes us stop. + my $disk = get_input( + 'Which disk would you like to move? ', + sub { + # Accept any odd integer in the required range. + # NOTE that 'and' performs the same operation as &&, but + # binds much more loosely. + return m/ \A [0-9]+ \z /smx && + $ARG % 2 && + $ARG >= ( MAX_DISKS + 1 - $size ) * 2 + 1 && + $ARG <= MAX_DISKS * 2 + 1; + }, + 3, + do { # Compound statement and scope for 'local' + + # We want to interpolate @legal_disks into our warning. + # Interpolation of an array places $LIST_SEPARATOR + # between the elements of the array. The default is ' ', + # but we want ', '. We use 'local' to restrict the + # change to the current block and code called by it. + # Failure to localize the change can cause Spooky Action + # at a Distance. + local $LIST_SEPARATOR = ', '; + + "Illegal entry... You may only type @legal_disks\n"; + }, + "Stop wasting my time. Go bother someone else.\n", + ); + + # Return the number (from zero) of the needle which has the + # desired disk on top. If the desired disk is not found, we got + # undef back. In this case we redo the innermost loop. + redo unless defined( my $from = find_disk( $disk, \@board ) ); + + # Find out where the chosen disk goes. + # NOTE that unlike the BASIC implementation, we require the + # needle to be moved. + my $to = get_input( + 'Place disk on which needle? ', + sub { + # Accept integers 1 through 3, but not the current + # location of the disk + return m/ \A [0-9]+ \z /smx && + $ARG > 0 && + $ARG <= 3 && + $ARG != $from + 1; + }, + 2, + <<'EOD', +I'll assume you hit the wrong key this time. But watch it, +I only allow one mistake. +EOD + <<'EOD', +I tried to warn you, but you wouldn't listen. +Bye bye, big shot. +EOD + ) - 1; + + # Check for placing a larger disk on a smaller one. The check is + # that the destination needle has something on it (an empty + # array is false in Boolean context) and that the destination + # needle's top disk ([-1] selects the last element of an array) + # is smaller than the source needle's disk. + if ( @{ $board[$to] } && $board[$to][-1] < $board[$from][-1] ) { + warn <<'EOD'; +You can't place a larger disk on top of a smaller one, +It might crush it! +EOD + redo; + } + + # Remove the selected disk from its needle, and place it on the + # destination needle. + push @{ $board[$to] }, pop @{ $board[$from] }; + + $moves++; # Count another move. + + display( \@board ); # Display the current board. + + # If all the disks are on the last needle, we are done. + if ( @{ $board[2] } == $size ) { + + # Print a success message + print <<"EOD"; +Congratulations! + +You have performed the task in $moves moves. + +EOD + last; # Exit the innermost loop. + + # If the maximum allowed moves have been exceeded + } elsif ( $moves >= 2 ** MAX_DISKS ) { + + # Warn + warn <<"EOD"; +Sorry, but I have orders to stop if you make more than +$moves moves. +EOD + + last; # Exit the innermost loop. + } + } + + say ''; + get_input( + 'Try again? [y/N]: ', + sub { + exit if $ARG eq '' || m/ \A n /smxi; + return m/ \A y /smxi; + }, + ~0, # The 1's complement of 0 = largest possible integer + "Please respond 'y' or 'n'\n", + ); +} + +# Display the board, which is passed in as a reference. +sub display { + my ( $board ) = @_; + say ''; + + # Use a manifest constant for an empty needle. This is global + # despite its appearing to be nested in the subroutine. Perl uses + # 'x' as its string replication operator. The initial 4 blanks + # accommodate the disk number and spacing between needles. + use constant EMPTY_NEEDLE => ' ' x 4 . ' ' x MAX_DISKS . '|' . + ' ' x MAX_DISKS; + + # Iterate over the rows to be printed. + foreach my $inx ( reverse 0 .. MAX_DISKS ) { + + my $line; # Line buffer. + + # Iterate over needles. + foreach my $col ( 0 .. 2 ) { + + # If this position on the needle is occupied + if ( my $disk_num = $board->[$col][$inx] ) { + + # Compute the width of a half disk + my $half_width = ( $disk_num - 1 ) / 2; + + # Compute the graphic for the half disk. Perl uses 'x' + # as its string replication operator. + my $half_disk = '*' x $half_width; + + # Append the disk to the line. The inner sprintf() does + # most of the work; the outer simply pads the graphic to + # the required total width. + $line .= sprintf( '%*s', -( MAX_DISKS * 2 + 5 ), + sprintf( '%*d %s|%s', MAX_DISKS + 3 - $half_width, + $disk_num, $half_disk, $half_disk ) ); + + # Else this position is not occupied + } else { + + # So just append the empty needle. + $line .= EMPTY_NEEDLE; + } + } + + # Remove white space at the end of the line + $line =~ s/ \s+ \z //smx; + + # Display the line + say $line; + } + { # Display the needle numbers + my $line; + foreach my $col ( 0 .. 2 ) { + $line .= sprintf '%*d%*s', MAX_DISKS + 5, $col + 1, + MAX_DISKS, ' '; + } + $line =~ s/ \s+ \z //smx; + say $line; + } + + say ''; # Empty line + + return; +} + +# Find the named disk. The arguments are the disk number (which is +# assumed valid) and a reference to the board. If the disk is found on +# the top of a needle, the needle's index (from zero) is returned. +# Otherwise a warning is issued and undef is returned. +sub find_disk { + my ( $disk, $board ) = @_; + foreach my $inx ( 0 .. 2 ) { + @{ $board->[$inx] } # If the needle is occupied + and $disk == $board->[$inx][-1] # and we want its topmost + and return $inx; # return needle index + } + + # Since we assume the disk number is valid but we did not find it, + # it must not be the topmost disk. + warn "That disk is below another one. Make another choice.\n"; + + return undef; +} + +# Input subroutine. The arguments are: +# * The prompt. +# * Validation code. This recieves the input in the topic variable $ARG, +# and returns a true value if the validation passed, and a false value +# if it failed. +# * The maximum number of tries before dying. +# * The warning message for a validation failure, with trailing "\n". +# * The error message when the number of tries is exceeded, with +# trailing "\n". +# The return is the valid input. We exit if end-of-file is reached, +sub get_input { + my ( $prompt, $validate, $tries, $warning, $error ) = @_; + + # Instantiate the readline object. A state variable is only + # initialized once. + state $term = Term::ReadLine->new( 'tower' ); + + while ( 1 ) { # Iterate until something makes us stop. + + # The input gets read into the localized topic variable. If it + # is undefined, it signals end-of-file, so we exit. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Call the validation code. If it returns a true value, we + # return our input. + return $ARG if $validate->(); + + # Die if we are out of retries. In Perl, 0 is false and all + # other integers are true. + die $error unless --$tries; + + # Warn. + warn $warning; + } +} + +__END__ + +=head1 TITLE + +tower.pl - Play the game 'tower' from Basic Computer Games + +=head1 SYNOPSIS + + tower.pl + +=head1 DETAILS + +This Perl script is a port of C, which is the 90th entry in Basic +Computer Games. + +=head1 PORTED BY + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set expandtab tabstop=4 textwidth=72 : From e9ce5210168b8d87ec6bd8766f6bb339907ec982 Mon Sep 17 00:00:00 2001 From: LukasMurdock Date: Mon, 3 Jan 2022 06:49:10 -0500 Subject: [PATCH 021/331] save 3-D tic-tac-toe --- 88_3-D_Tic-Tac-Toe/README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/88_3-D_Tic-Tac-Toe/README.md b/88_3-D_Tic-Tac-Toe/README.md index e06c4e40..df9cabf4 100644 --- a/88_3-D_Tic-Tac-Toe/README.md +++ b/88_3-D_Tic-Tac-Toe/README.md @@ -1,7 +1,17 @@ ### 3-D Tic-Tac-Toe -As published in Basic Computer Games (1978) -https://www.atariarchives.org/basicgames/showpage.php?page=168 +3-D TIC-TAC-TOE is a game of tic-tac-toe in a 4x4x4 cube. You must get 4 markers in a row or diagonal along any 3-dimensional plane in order to win. + +Each move is indicated by a 3-digit number (digits not separated by commas), with each digit between 1 and 4 inclusive. The digits indicate the level, column, and row, respectively, of the move. You can win if you play correctly; although, it is considerably more difficult than standard, two-dimensional 3x3 tic-tac-toe. + +This version of 3-D TIC-TAC-TOE is from Dartmouth College. + +--- + +As published in Basic Computer Games (1978): +- [Atari Archives](https://www.atariarchives.org/basicgames/showpage.php?page=168) +- [Annarchive](https://annarchive.com/files/Basic_Computer_Games_Microcomputer_Edition.pdf#page=183) + Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html From 711fca294d166bb6deda046695bdcebabb72b278 Mon Sep 17 00:00:00 2001 From: marijnz0r Date: Mon, 3 Jan 2022 12:51:38 +0100 Subject: [PATCH 022/331] Add csharp version of 40_Gunner --- 42_Gunner/csharp/Program.cs | 124 +++++++++++++++++++++++++++++++++ 42_Gunner/csharp/csharp.csproj | 10 +++ 2 files changed, 134 insertions(+) create mode 100644 42_Gunner/csharp/Program.cs create mode 100644 42_Gunner/csharp/csharp.csproj diff --git a/42_Gunner/csharp/Program.cs b/42_Gunner/csharp/Program.cs new file mode 100644 index 00000000..f93c57d5 --- /dev/null +++ b/42_Gunner/csharp/Program.cs @@ -0,0 +1,124 @@ +namespace Gunner +{ + class Program + { + static void Main(string[] args) + { + PrintIntro(); + + string keepPlaying = "Y"; + + while (keepPlaying == "Y") { + PlayGame(); + Console.WriteLine("TRY AGAIN (Y OR N)"); + keepPlaying = Console.ReadLine(); + } + } + + static void PlayGame() + { + int totalAttempts = 0; + int amountOfGames = 0; + + while (amountOfGames < 4) { + + int maximumRange = new Random().Next(0, 40000) + 20000; + Console.WriteLine($"MAXIMUM RANGE OF YOUR GUN IS {maximumRange} YARDS." + Environment.NewLine + Environment.NewLine + Environment.NewLine); + + int distanceToTarget = (int) (maximumRange * (0.1 + 0.8 * new Random().NextDouble())); + Console.WriteLine($"DISTANCE TO THE TARGET IS {distanceToTarget} YARDS."); + + (bool gameWon, int attempts) = HitTheTarget(maximumRange, distanceToTarget); + + if(!gameWon) { + Console.WriteLine(Environment.NewLine + "BOOM !!!! YOU HAVE JUST BEEN DESTROYED" + Environment.NewLine + + "BY THE ENEMY." + Environment.NewLine + Environment.NewLine + Environment.NewLine + ); + PrintReturnToBase(); + break; + } else { + amountOfGames += 1; + totalAttempts += attempts; + + Console.WriteLine($"TOTAL ROUNDS EXPENDED WERE:{totalAttempts}"); + + if (amountOfGames < 4) { + Console.WriteLine("THE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY..."); + } else { + if (totalAttempts > 18) { + PrintReturnToBase(); + } else { + Console.WriteLine($"NICE SHOOTING !!"); + } + } + } + } + } + + static (bool, int) HitTheTarget(int maximumRange, int distanceToTarget) + { + int attempts = 0; + + while (attempts < 6) + { + int elevation = GetElevation(); + + int differenceBetweenTargetAndImpact = CalculateDifferenceBetweenTargetAndImpact(maximumRange, distanceToTarget, elevation); + + if (Math.Abs(differenceBetweenTargetAndImpact) < 100) + { + Console.WriteLine($"*** TARGET DESTROYED *** {attempts} ROUNDS OF AMMUNITION EXPENDED."); + return (true, attempts); + } + else if (differenceBetweenTargetAndImpact > 100) + { + Console.WriteLine($"OVER TARGET BY {Math.Abs(differenceBetweenTargetAndImpact)} YARDS."); + } + else + { + Console.WriteLine($"SHORT OF TARGET BY {Math.Abs(differenceBetweenTargetAndImpact)} YARDS."); + } + + attempts += 1; + } + return (false, attempts); + } + + static int CalculateDifferenceBetweenTargetAndImpact(int maximumRange, int distanceToTarget, int elevation) + { + double weirdNumber = 2 * elevation / 57.3; + double distanceShot = maximumRange * Math.Sin(weirdNumber); + return (int)distanceShot - distanceToTarget; + } + + static void PrintReturnToBase() + { + Console.WriteLine("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!"); + } + + static int GetElevation() + { + Console.WriteLine("ELEVATION"); + int elevation = int.Parse(Console.ReadLine()); + if (elevation > 89) { + Console.WriteLine("MAXIMUM ELEVATION IS 89 DEGREES"); + return GetElevation(); + } + if (elevation < 1) { + Console.WriteLine("MINIMUM ELEVATION IS 1 DEGREE"); + return GetElevation(); + } + return elevation; + } + + static void PrintIntro() + { + Console.WriteLine(new String(' ', 30) + "GUNNER"); + Console.WriteLine(new String(' ', 15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + Environment.NewLine + Environment.NewLine + Environment.NewLine); + Console.WriteLine("YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN"); + Console.WriteLine("CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE"); + Console.WriteLine("WILL PLACE A PROJECTILE ON TARGET. A HIT WITHIN 100 YARDS"); + Console.WriteLine("OF THE TARGET WILL DESTROY IT." + Environment.NewLine); + } + } +} diff --git a/42_Gunner/csharp/csharp.csproj b/42_Gunner/csharp/csharp.csproj new file mode 100644 index 00000000..74abf5c9 --- /dev/null +++ b/42_Gunner/csharp/csharp.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + From 25dcb2a32572d6d7634b618cd297616dcd753755 Mon Sep 17 00:00:00 2001 From: Luminoso-256 <63971285+Luminoso-256@users.noreply.github.com> Date: Mon, 3 Jan 2022 08:31:32 -0600 Subject: [PATCH 023/331] add C# port of 21_calendar --- 21_Calendar/csharp/21_calendar.csproj | 9 ++ 21_Calendar/csharp/21_calendar.sln | 25 +++++ 21_Calendar/csharp/Program.cs | 144 ++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 21_Calendar/csharp/21_calendar.csproj create mode 100644 21_Calendar/csharp/21_calendar.sln create mode 100644 21_Calendar/csharp/Program.cs diff --git a/21_Calendar/csharp/21_calendar.csproj b/21_Calendar/csharp/21_calendar.csproj new file mode 100644 index 00000000..895f2f3f --- /dev/null +++ b/21_Calendar/csharp/21_calendar.csproj @@ -0,0 +1,9 @@ + + + + Exe + net5.0 + _21_calendar + + + diff --git a/21_Calendar/csharp/21_calendar.sln b/21_Calendar/csharp/21_calendar.sln new file mode 100644 index 00000000..d8330a26 --- /dev/null +++ b/21_Calendar/csharp/21_calendar.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31613.86 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "21_calendar", "21_calendar.csproj", "{99AB85E1-A42B-4FEF-8BA6-0ED877F05249}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {99AB85E1-A42B-4FEF-8BA6-0ED877F05249}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {99AB85E1-A42B-4FEF-8BA6-0ED877F05249}.Debug|Any CPU.Build.0 = Debug|Any CPU + {99AB85E1-A42B-4FEF-8BA6-0ED877F05249}.Release|Any CPU.ActiveCfg = Release|Any CPU + {99AB85E1-A42B-4FEF-8BA6-0ED877F05249}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1B423C35-492F-4AF8-97FC-BEC69B44EC8D} + EndGlobalSection +EndGlobal diff --git a/21_Calendar/csharp/Program.cs b/21_Calendar/csharp/Program.cs new file mode 100644 index 00000000..4fd2b177 --- /dev/null +++ b/21_Calendar/csharp/Program.cs @@ -0,0 +1,144 @@ +using System; + +/* + 21_Calendar in C# for basic-computer-games + Converted by luminoso-256 +*/ + +namespace _21_calendar +{ + class Program + { + //basic has a TAB function. We do not by default, so we make our own! + static string Tab(int numspaces) + { + string space = ""; + //loop as many times as there are spaces specified, and add a space each time + while (numspaces > 0) + { + //add the space + space += " "; + //decrement the loop variable so we don't keep going forever! + numspaces--; + } + return space; + } + + static void Main(string[] args) + { + // print the "title" of our program + // the usage of Write*Line* means we do not have to specify a newline (\n) + Console.WriteLine(Tab(32) + "CALENDAR"); + Console.WriteLine(Tab(15) + "CREATE COMPUTING MORRISTOWN, NEW JERSEY"); + //give us some space. + Console.WriteLine(""); + Console.WriteLine(""); + Console.WriteLine(""); + + //establish some variables needed to print out a calculator + + //the length of each month in days. On a leap year, the start of this would be + // 0, 31, 29 to account for Feb. the 0 at the start is for days elapsed to work right in Jan. + int[] monthLengths = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // m in original source + + //the starting day of the month. in 1979 this was monday + // 0 = sun, -1 = mon, -2 = tue, -3 = wed, etc. + int day = -1; // called d in original source + + //how much time in the year has gone by? + int elapsed = 0; // called s in original source + + //loop through printing all the months. + for (int month = 1; month <= 12; month++) //month is called n in original source + { + //pad some space + Console.WriteLine(""); + Console.WriteLine(""); + //increment days elapsed + elapsed += monthLengths[month - 1]; + //build our header for this month of the calendar + string header = "** " + elapsed; + //add padding as needed + while (header.Length < 7) + { + header += " "; + } + for (int i = 1; i <= 18; i++) + { + header += "*"; + } + //determine what month it is, add text accordingly + switch (month) { + case 1: header += " JANUARY "; break; + case 2: header += " FEBRUARY"; break; + case 3: header += " MARCH "; break; + case 4: header += " APRIL "; break; + case 5: header += " MAY "; break; + case 6: header += " JUNE "; break; + case 7: header += " JULY "; break; + case 8: header += " AUGUST "; break; + case 9: header += "SEPTEMBER"; break; + case 10: header += " OCTOBER "; break; + case 11: header += " NOVEMBER"; break; + case 12: header += " DECEMBER"; break; + } + //more padding + for (int i = 1; i <= 18; i++) + { + header += "*"; + } + header += " "; + // how many days left till the year's over? + header += (365 - elapsed) + " **"; // on leap years 366 + Console.WriteLine(header); + //dates + Console.WriteLine(" S M T W T F S"); + Console.WriteLine(" "); + + string weekOutput = ""; + for (int i = 1; i <= 59; i++) + { + weekOutput += "*"; + } + //init some vars ahead of time + int g = 0; + int d2 = 0; + //go through the weeks and days + for (int week = 1; week <= 6; week++) + { + Console.WriteLine(weekOutput); + weekOutput = " "; + for (g = 1; g <= 7; g++) + { + //add one to the day + day++; + d2 = day - elapsed; + //check if we're done with this month + if (d2 > monthLengths[month]) + { + week = 6; + break; + } + //should we print this day? + if (d2 > 0) + { + weekOutput += d2; + } + //padding + while (weekOutput.Length < 4 + 8 * g) + { + weekOutput += " "; + } + } + if (d2 == monthLengths[month]) + { + day += g; + break; + } + } + day -= g; + Console.WriteLine(weekOutput); + } + } + } +} From 6977afdef090628d7c96e4fb23e019cb5657d0cb Mon Sep 17 00:00:00 2001 From: baka0815 Date: Mon, 3 Jan 2022 18:24:09 +0100 Subject: [PATCH 024/331] AceyDucey/pascal: Move Randomize() Randomize() should be called only once and as soon as possible. --- 01_Acey_Ducey/pascal/object-pascal/game.pas | 2 +- 01_Acey_Ducey/pascal/simple/aceyducey.pas | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/01_Acey_Ducey/pascal/object-pascal/game.pas b/01_Acey_Ducey/pascal/object-pascal/game.pas index 1a263159..1e983f7c 100644 --- a/01_Acey_Ducey/pascal/object-pascal/game.pas +++ b/01_Acey_Ducey/pascal/object-pascal/game.pas @@ -85,6 +85,7 @@ end; constructor TGame.Create; begin + Randomize; FDeck:= TDeck.Create; end; @@ -99,7 +100,6 @@ begin ClrScr; PrintGreeting; repeat - Randomize; FStash:= 100; repeat PrintBalance; diff --git a/01_Acey_Ducey/pascal/simple/aceyducey.pas b/01_Acey_Ducey/pascal/simple/aceyducey.pas index 35a9dd64..fa049eb0 100644 --- a/01_Acey_Ducey/pascal/simple/aceyducey.pas +++ b/01_Acey_Ducey/pascal/simple/aceyducey.pas @@ -118,10 +118,10 @@ begin end; begin + Randomize; ClrScr; PrintGreeting; repeat - Randomize; Stash:= 100; repeat PrintBalance; From f57c27f1ead8c1c280caac934bca45f7bef3280e Mon Sep 17 00:00:00 2001 From: Dave Shapiro Date: Mon, 3 Jan 2022 11:21:08 -0700 Subject: [PATCH 025/331] Fix typo in Bombs Away README. --- 12_Bombs_Away/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/12_Bombs_Away/README.md b/12_Bombs_Away/README.md index 0baa3558..b1b60277 100644 --- a/12_Bombs_Away/README.md +++ b/12_Bombs_Away/README.md @@ -1,6 +1,6 @@ ### Bombs Away -In this program, you fly a World War II bomber for one of the four protagonists of the war. You then pick your target or the type of plane you are flying. Depending on your flying experience and the quality of enemy defenders, you then may accomplish your mission, get shot down, or make it back through enemy fire. In any case, you get a change to fly again. +In this program, you fly a World War II bomber for one of the four protagonists of the war. You then pick your target or the type of plane you are flying. Depending on your flying experience and the quality of enemy defenders, you then may accomplish your mission, get shot down, or make it back through enemy fire. In any case, you get a chance to fly again. David Ahl modified the original program which was created by David Sherman while a student at Curtis Jr. High School, Sudbury, Massachusetts. From fd7adde9902574793873cc92d06874a5afc2fde6 Mon Sep 17 00:00:00 2001 From: Dave Shapiro Date: Mon, 3 Jan 2022 11:30:55 -0700 Subject: [PATCH 026/331] Added Bombs Away in C#. This is a Visual Studio 2022 solution and uses the latest language features like file-scoped namespaces. --- 12_Bombs_Away/csharp/BombsAway.sln | 31 +++ .../BombsAwayConsole/BombsAwayConsole.csproj | 14 ++ .../BombsAwayConsole/ConsoleUserInterface.cs | 134 +++++++++++ .../csharp/BombsAwayConsole/Program.cs | 26 +++ .../csharp/BombsAwayGame/AlliesSide.cs | 22 ++ .../csharp/BombsAwayGame/BombsAwayGame.csproj | 9 + .../csharp/BombsAwayGame/EnemyArtillery.cs | 8 + 12_Bombs_Away/csharp/BombsAwayGame/Game.cs | 58 +++++ .../csharp/BombsAwayGame/GermanySide.cs | 21 ++ .../csharp/BombsAwayGame/IUserInterface.cs | 38 ++++ .../csharp/BombsAwayGame/ItalySide.cs | 21 ++ .../csharp/BombsAwayGame/JapanSide.cs | 38 ++++ 12_Bombs_Away/csharp/BombsAwayGame/Mission.cs | 8 + .../csharp/BombsAwayGame/MissionSide.cs | 208 ++++++++++++++++++ 12_Bombs_Away/csharp/BombsAwayGame/Side.cs | 97 ++++++++ 15 files changed, 733 insertions(+) create mode 100644 12_Bombs_Away/csharp/BombsAway.sln create mode 100644 12_Bombs_Away/csharp/BombsAwayConsole/BombsAwayConsole.csproj create mode 100644 12_Bombs_Away/csharp/BombsAwayConsole/ConsoleUserInterface.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayConsole/Program.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/AlliesSide.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/BombsAwayGame.csproj create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/EnemyArtillery.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/Game.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/GermanySide.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/IUserInterface.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/ItalySide.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/JapanSide.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/Mission.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/MissionSide.cs create mode 100644 12_Bombs_Away/csharp/BombsAwayGame/Side.cs diff --git a/12_Bombs_Away/csharp/BombsAway.sln b/12_Bombs_Away/csharp/BombsAway.sln new file mode 100644 index 00000000..8ae70157 --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAway.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32014.148 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BombsAwayConsole", "BombsAwayConsole\BombsAwayConsole.csproj", "{D80015FA-423C-4A16-AA2B-16669245AD59}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BombsAwayGame", "BombsAwayGame\BombsAwayGame.csproj", "{F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D80015FA-423C-4A16-AA2B-16669245AD59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D80015FA-423C-4A16-AA2B-16669245AD59}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D80015FA-423C-4A16-AA2B-16669245AD59}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D80015FA-423C-4A16-AA2B-16669245AD59}.Release|Any CPU.Build.0 = Release|Any CPU + {F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F57AEC18-FEE9-4F08-9F20-DFC56EFE6BFC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {39B2ECFB-037D-4335-BBD2-64892E953DD4} + EndGlobalSection +EndGlobal diff --git a/12_Bombs_Away/csharp/BombsAwayConsole/BombsAwayConsole.csproj b/12_Bombs_Away/csharp/BombsAwayConsole/BombsAwayConsole.csproj new file mode 100644 index 00000000..aae99def --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayConsole/BombsAwayConsole.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + diff --git a/12_Bombs_Away/csharp/BombsAwayConsole/ConsoleUserInterface.cs b/12_Bombs_Away/csharp/BombsAwayConsole/ConsoleUserInterface.cs new file mode 100644 index 00000000..66d6d4d3 --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayConsole/ConsoleUserInterface.cs @@ -0,0 +1,134 @@ +namespace BombsAwayConsole; + +/// +/// Implements by writing to and reading from . +/// +internal class ConsoleUserInterface : BombsAwayGame.IUserInterface +{ + /// + /// Write message to console. + /// + /// Message to display. + public void Output(string message) + { + Console.WriteLine(message); + } + + /// + /// Write choices with affixed indexes, allowing the user to choose by index. + /// + /// Message to display. + /// Choices to display. + /// Choice that user picked. + public int Choose(string message, IList choices) + { + IEnumerable choicesWithIndexes = choices.Select((choice, index) => $"{choice}({index + 1})"); + string choiceText = string.Join(", ", choicesWithIndexes); + Output($"{message} -- {choiceText}"); + + ISet allowedKeys = ConsoleKeysFromList(choices); + ConsoleKey? choice; + do + { + choice = ReadChoice(allowedKeys); + if (choice is null) + { + Output("TRY AGAIN..."); + } + } + while (choice is null); + + return ListIndexFromConsoleKey(choice.Value); + } + + /// + /// Convert the given list to its equivalents. This generates keys that map + /// the first element to , the second element to , + /// and so on, up to the last element of the list. + /// + /// List whose elements will be converted to equivalents. + /// equivalents from . + private ISet ConsoleKeysFromList(IList list) + { + IEnumerable indexes = Enumerable.Range((int)ConsoleKey.D1, list.Count); + return new HashSet(indexes.Cast()); + } + + /// + /// Convert the given console key to its list index equivalent. This assumes the key was generated from + /// + /// + /// Key to convert to its list index equivalent. + /// List index equivalent of key. + private int ListIndexFromConsoleKey(ConsoleKey key) + { + return key - ConsoleKey.D1; + } + + /// + /// Read a key from the console and return it if it is in the given allowed keys. + /// + /// Allowed keys. + /// Key read from , if it is in ; null otherwise./> + private ConsoleKey? ReadChoice(ISet allowedKeys) + { + ConsoleKeyInfo keyInfo = ReadKey(); + return allowedKeys.Contains(keyInfo.Key) ? keyInfo.Key : null; + } + + /// + /// Read key from . + /// + /// Key read from . + private ConsoleKeyInfo ReadKey() + { + ConsoleKeyInfo result = Console.ReadKey(intercept: false); + // Write a blank line to the console so the displayed key is on its own line. + Console.WriteLine(); + return result; + } + + /// + /// Allow user to choose 'Y' or 'N' from . + /// + /// Message to display. + /// True if user chose 'Y', false if user chose 'N'. + public bool ChooseYesOrNo(string message) + { + Output(message); + ConsoleKey? choice; + do + { + choice = ReadChoice(new HashSet(new[] { ConsoleKey.Y, ConsoleKey.N })); + if (choice is null) + { + Output("ENTER Y OR N"); + } + } + while (choice is null); + + return choice.Value == ConsoleKey.Y; + } + + /// + /// Get integer by reading a line from . + /// + /// Integer read from . + public int InputInteger() + { + bool resultIsValid; + int result; + do + { + string? integerText = Console.ReadLine(); + resultIsValid = int.TryParse(integerText, out result); + if (!resultIsValid) + { + Output("PLEASE ENTER A NUMBER"); + } + } + while (!resultIsValid); + + return result; + } +} diff --git a/12_Bombs_Away/csharp/BombsAwayConsole/Program.cs b/12_Bombs_Away/csharp/BombsAwayConsole/Program.cs new file mode 100644 index 00000000..35728cfc --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayConsole/Program.cs @@ -0,0 +1,26 @@ +using BombsAwayConsole; +using BombsAwayGame; + +/// Create and play s using a . +PlayGameWhileUserWantsTo(new ConsoleUserInterface()); + +void PlayGameWhileUserWantsTo(ConsoleUserInterface ui) +{ + do + { + new Game(ui).Play(); + } + while (UserWantsToPlayAgain(ui)); +} + +bool UserWantsToPlayAgain(IUserInterface ui) +{ + bool result = ui.ChooseYesOrNo("ANOTHER MISSION (Y OR N)?"); + if (!result) + { + Console.WriteLine("CHICKEN !!!"); + } + + return result; +} + diff --git a/12_Bombs_Away/csharp/BombsAwayGame/AlliesSide.cs b/12_Bombs_Away/csharp/BombsAwayGame/AlliesSide.cs new file mode 100644 index 00000000..c6c7105b --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/AlliesSide.cs @@ -0,0 +1,22 @@ +namespace BombsAwayGame; + +/// +/// Allies protagonist. Can fly missions in a Liberator, B-29, B-17, or Lancaster. +/// +internal class AlliesSide : MissionSide +{ + public AlliesSide(IUserInterface ui) + : base(ui) + { + } + + protected override string ChooseMissionMessage => "AIRCRAFT"; + + protected override IList AllMissions => new Mission[] + { + new("LIBERATOR", "YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI."), + new("B-29", "YOU'RE DUMPING THE A-BOMB ON HIROSHIMA."), + new("B-17", "YOU'RE CHASING THE BISMARK IN THE NORTH SEA."), + new("LANCASTER", "YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.") + }; +} diff --git a/12_Bombs_Away/csharp/BombsAwayGame/BombsAwayGame.csproj b/12_Bombs_Away/csharp/BombsAwayGame/BombsAwayGame.csproj new file mode 100644 index 00000000..132c02c5 --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/BombsAwayGame.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/12_Bombs_Away/csharp/BombsAwayGame/EnemyArtillery.cs b/12_Bombs_Away/csharp/BombsAwayGame/EnemyArtillery.cs new file mode 100644 index 00000000..a810c8c0 --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/EnemyArtillery.cs @@ -0,0 +1,8 @@ +namespace BombsAwayGame; + +/// +/// Represents enemy artillery. +/// +/// Name of artillery type. +/// Accuracy of artillery. This is the `T` variable in the original BASIC. +internal record class EnemyArtillery(string Name, int Accuracy); diff --git a/12_Bombs_Away/csharp/BombsAwayGame/Game.cs b/12_Bombs_Away/csharp/BombsAwayGame/Game.cs new file mode 100644 index 00000000..d6b5c3e9 --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/Game.cs @@ -0,0 +1,58 @@ +namespace BombsAwayGame; + +/// +/// Plays the Bombs Away game using a supplied . +/// +public class Game +{ + private readonly IUserInterface _ui; + + /// + /// Create game instance using the given UI. + /// + /// UI to use for game. + public Game(IUserInterface ui) + { + _ui = ui; + } + + /// + /// Play game. Choose a side and play the side's logic. + /// + public void Play() + { + _ui.Output("YOU ARE A PILOT IN A WORLD WAR II BOMBER."); + Side side = ChooseSide(); + side.Play(); + } + + /// + /// Represents a . + /// + /// Name of side. + /// Create instance of side that this descriptor represents. + private record class SideDescriptor(string Name, Func CreateSide); + + /// + /// Choose side and return a new instance of that side. + /// + /// New instance of side that was chosen. + private Side ChooseSide() + { + SideDescriptor[] sides = AllSideDescriptors; + string[] sideNames = sides.Select(a => a.Name).ToArray(); + int index = _ui.Choose("WHAT SIDE", sideNames); + return sides[index].CreateSide(); + } + + /// + /// All side descriptors. + /// + private SideDescriptor[] AllSideDescriptors => new SideDescriptor[] + { + new("ITALY", () => new ItalySide(_ui)), + new("ALLIES", () => new AlliesSide(_ui)), + new("JAPAN", () => new JapanSide(_ui)), + new("GERMANY", () => new GermanySide(_ui)), + }; +} diff --git a/12_Bombs_Away/csharp/BombsAwayGame/GermanySide.cs b/12_Bombs_Away/csharp/BombsAwayGame/GermanySide.cs new file mode 100644 index 00000000..99843fce --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/GermanySide.cs @@ -0,0 +1,21 @@ +namespace BombsAwayGame; + +/// +/// Germany protagonist. Can fly missions to Russia, England, and France. +/// +internal class GermanySide : MissionSide +{ + public GermanySide(IUserInterface ui) + : base(ui) + { + } + + protected override string ChooseMissionMessage => "A NAZI, EH? OH WELL. ARE YOU GOING FOR"; + + protected override IList AllMissions => new Mission[] + { + new("RUSSIA", "YOU'RE NEARING STALINGRAD."), + new("ENGLAND", "NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR."), + new("FRANCE", "NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.") + }; +} diff --git a/12_Bombs_Away/csharp/BombsAwayGame/IUserInterface.cs b/12_Bombs_Away/csharp/BombsAwayGame/IUserInterface.cs new file mode 100644 index 00000000..50b7828c --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/IUserInterface.cs @@ -0,0 +1,38 @@ +namespace BombsAwayGame; + +/// +/// Represents an interface for supplying data to the game. +/// +/// +/// Abstracting the UI allows us to concentrate its concerns in one part of our code and to change UI behavior +/// without creating any risk of changing the game logic. It also allows us to supply an automated UI for tests. +/// +public interface IUserInterface +{ + /// + /// Display the given message. + /// + /// Message to display. + void Output(string message); + + /// + /// Choose an item from the given choices. + /// + /// Message to display. + /// Choices to choose from. + /// Index of choice in that user chose. + int Choose(string message, IList choices); + + /// + /// Allow user to choose Yes or No. + /// + /// Message to display. + /// True if user chose Yes, false if user chose No. + bool ChooseYesOrNo(string message); + + /// + /// Get integer from user. + /// + /// Integer supplied by user. + int InputInteger(); +} diff --git a/12_Bombs_Away/csharp/BombsAwayGame/ItalySide.cs b/12_Bombs_Away/csharp/BombsAwayGame/ItalySide.cs new file mode 100644 index 00000000..9f8bcd83 --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/ItalySide.cs @@ -0,0 +1,21 @@ +namespace BombsAwayGame; + +/// +/// Italy protagonist. Can fly missions to Albania, Greece, and North Africa. +/// +internal class ItalySide : MissionSide +{ + public ItalySide(IUserInterface ui) + : base(ui) + { + } + + protected override string ChooseMissionMessage => "YOUR TARGET"; + + protected override IList AllMissions => new Mission[] + { + new("ALBANIA", "SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE."), + new("GREECE", "BE CAREFUL!!!"), + new("NORTH AFRICA", "YOU'RE GOING FOR THE OIL, EH?") + }; +} diff --git a/12_Bombs_Away/csharp/BombsAwayGame/JapanSide.cs b/12_Bombs_Away/csharp/BombsAwayGame/JapanSide.cs new file mode 100644 index 00000000..33abc83b --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/JapanSide.cs @@ -0,0 +1,38 @@ +namespace BombsAwayGame; + +/// +/// Japan protagonist. Flies a kamikaze mission, which has a different logic from s. +/// +internal class JapanSide : Side +{ + public JapanSide(IUserInterface ui) + : base(ui) + { + } + + /// + /// Perform a kamikaze mission. If first kamikaze mission, it will succeed 65% of the time. If it's not + /// first kamikaze mission, perform an enemy counterattack. + /// + public override void Play() + { + UI.Output("YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON."); + + bool isFirstMission = UI.ChooseYesOrNo("YOUR FIRST KAMIKAZE MISSION(Y OR N)?"); + if (!isFirstMission) + { + // LINE 207 of original BASIC: hitRatePercent is initialized to 0, + // but R, the type of artillery, is not initialized at all. Setting + // R = 1, which is to say EnemyArtillery = Guns, gives the same result. + EnemyCounterattack(Guns, hitRatePercent: 0); + } + else if (RandomFrac() > 0.65) + { + MissionSucceeded(); + } + else + { + MissionFailed(); + } + } +} diff --git a/12_Bombs_Away/csharp/BombsAwayGame/Mission.cs b/12_Bombs_Away/csharp/BombsAwayGame/Mission.cs new file mode 100644 index 00000000..c93892fd --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/Mission.cs @@ -0,0 +1,8 @@ +namespace BombsAwayGame; + +/// +/// Represents a mission that can be flown by a . +/// +/// Name of mission. +/// Description of mission. +internal record class Mission(string Name, string Description); diff --git a/12_Bombs_Away/csharp/BombsAwayGame/MissionSide.cs b/12_Bombs_Away/csharp/BombsAwayGame/MissionSide.cs new file mode 100644 index 00000000..b3a54275 --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/MissionSide.cs @@ -0,0 +1,208 @@ +namespace BombsAwayGame; + +/// +/// Represents a protagonist that chooses a standard (non-kamikaze) mission. +/// +internal abstract class MissionSide : Side +{ + /// + /// Create instance using the given UI. + /// + /// UI to use. + public MissionSide(IUserInterface ui) + : base(ui) + { + } + + /// + /// Reasonable upper bound for missions flown previously. + /// + private const int MaxMissionCount = 160; + + /// + /// Choose a mission and attempt it. If attempt fails, perform an enemy counterattack. + /// + public override void Play() + { + Mission mission = ChooseMission(); + UI.Output(mission.Description); + + int missionCount = MissionCountFromUI(); + CommentOnMissionCount(missionCount); + + AttemptMission(missionCount); + } + + /// + /// Choose a mission. + /// + /// Mission chosen. + private Mission ChooseMission() + { + IList missions = AllMissions; + string[] missionNames = missions.Select(a => a.Name).ToArray(); + int index = UI.Choose(ChooseMissionMessage, missionNames); + return missions[index]; + } + + /// + /// Message to display when choosing a mission. + /// + protected abstract string ChooseMissionMessage { get; } + + /// + /// All aviailable missions to choose from. + /// + protected abstract IList AllMissions { get; } + + /// + /// Get mission count from UI. If mission count exceeds a reasonable maximum, ask UI again. + /// + /// Mission count from UI. + private int MissionCountFromUI() + { + const string HowManyMissions = "HOW MANY MISSIONS HAVE YOU FLOWN?"; + string inputMessage = HowManyMissions; + + bool resultIsValid; + int result; + do + { + UI.Output(inputMessage); + result = UI.InputInteger(); + if (result < 0) + { + UI.Output($"NUMBER OF MISSIONS CAN'T BE NEGATIVE."); + resultIsValid = false; + } + else if (result > MaxMissionCount) + { + resultIsValid = false; + UI.Output($"MISSIONS, NOT MILES...{MaxMissionCount} MISSIONS IS HIGH EVEN FOR OLD-TIMERS."); + inputMessage = "NOW THEN, " + HowManyMissions; + } + else + { + resultIsValid = true; + } + } + while (!resultIsValid); + + return result; + } + + /// + /// Display a message about the given mission count, if it is unusually high or low. + /// + /// Mission count to comment on. + private void CommentOnMissionCount(int missionCount) + { + if (missionCount >= 100) + { + UI.Output("THAT'S PUSHING THE ODDS!"); + } + else if (missionCount < 25) + { + UI.Output("FRESH OUT OF TRAINING, EH?"); + } + } + + /// + /// Attempt mission. + /// + /// Number of missions previously flown. Higher mission counts will yield a higher probability of success. + private void AttemptMission(int missionCount) + { + if (missionCount < RandomInteger(0, MaxMissionCount)) + { + MissedTarget(); + } + else + { + MissionSucceeded(); + } + } + + /// + /// Display message indicating that target was missed. Choose enemy artillery and perform a counterattack. + /// + private void MissedTarget() + { + UI.Output("MISSED TARGET BY " + (2 + RandomInteger(0, 30)) + " MILES!"); + UI.Output("NOW YOU'RE REALLY IN FOR IT !!"); + + // Choose enemy and counterattack. + EnemyArtillery enemyArtillery = ChooseEnemyArtillery(); + + if (enemyArtillery == Missiles) + { + EnemyCounterattack(enemyArtillery, hitRatePercent: 0); + } + else + { + int hitRatePercent = EnemyHitRatePercentFromUI(); + if (hitRatePercent < MinEnemyHitRatePercent) + { + UI.Output("YOU LIE, BUT YOU'LL PAY..."); + MissionFailed(); + } + else + { + EnemyCounterattack(enemyArtillery, hitRatePercent); + } + } + } + + /// + /// Choose enemy artillery from UI. + /// + /// Artillery chosen. + private EnemyArtillery ChooseEnemyArtillery() + { + EnemyArtillery[] artilleries = new EnemyArtillery[] { Guns, Missiles, Both }; + string[] artilleryNames = artilleries.Select(a => a.Name).ToArray(); + int index = UI.Choose("DOES THE ENEMY HAVE", artilleryNames); + return artilleries[index]; + } + + /// + /// Minimum allowed hit rate percent. + /// + private const int MinEnemyHitRatePercent = 10; + + /// + /// Maximum allowed hit rate percent. + /// + private const int MaxEnemyHitRatePercent = 50; + + /// + /// Get the enemy hit rate percent from UI. Value must be between zero and . + /// If value is less than , mission fails automatically because the user is + /// assumed to be untruthful. + /// + /// Enemy hit rate percent from UI. + private int EnemyHitRatePercentFromUI() + { + UI.Output($"WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS ({MinEnemyHitRatePercent} TO {MaxEnemyHitRatePercent})"); + + bool resultIsValid; + int result; + do + { + result = UI.InputInteger(); + // Let them enter a number below the stated minimum, as they will be caught and punished. + if (0 <= result && result <= MaxEnemyHitRatePercent) + { + resultIsValid = true; + } + else + { + resultIsValid = false; + UI.Output($"NUMBER MUST BE FROM {MinEnemyHitRatePercent} TO {MaxEnemyHitRatePercent}"); + } + } + while (!resultIsValid); + + return result; + } +} diff --git a/12_Bombs_Away/csharp/BombsAwayGame/Side.cs b/12_Bombs_Away/csharp/BombsAwayGame/Side.cs new file mode 100644 index 00000000..7e643971 --- /dev/null +++ b/12_Bombs_Away/csharp/BombsAwayGame/Side.cs @@ -0,0 +1,97 @@ +namespace BombsAwayGame; + +/// +/// Represents a protagonist in the game. +/// +internal abstract class Side +{ + /// + /// Create instance using the given UI. + /// + /// UI to use. + public Side(IUserInterface ui) + { + UI = ui; + } + + /// + /// Play this side. + /// + public abstract void Play(); + + /// + /// User interface supplied to ctor. + /// + protected IUserInterface UI { get; } + + /// + /// Random-number generator for this play-through. + /// + private readonly Random _random = new(); + + /// + /// Gets a random floating-point number greater than or equal to zero, and less than one. + /// + /// Random floating-point number greater than or equal to zero, and less than one. + protected double RandomFrac() => _random.NextDouble(); + + /// + /// Gets a random integer in a range. + /// + /// The inclusive lower bound of the number returned. + /// The exclusive upper bound of the number returned. + /// Random integer in a range. + protected int RandomInteger(int minValue, int maxValue) => _random.Next(minValue: minValue, maxValue: maxValue); + + /// + /// Display messages indicating the mission succeeded. + /// + protected void MissionSucceeded() + { + UI.Output("DIRECT HIT!!!! " + RandomInteger(0, 100) + " KILLED."); + UI.Output("MISSION SUCCESSFUL."); + } + + /// + /// Gets the Guns type of enemy artillery. + /// + protected EnemyArtillery Guns { get; } = new("GUNS", 0); + + /// + /// Gets the Missiles type of enemy artillery. + /// + protected EnemyArtillery Missiles { get; } = new("MISSILES", 35); + + /// + /// Gets the Both Guns and Missiles type of enemy artillery. + /// + protected EnemyArtillery Both { get; } = new("BOTH", 35); + + /// + /// Perform enemy counterattack using the given artillery and hit rate percent. + /// + /// Enemy artillery to use. + /// Hit rate percent for enemy. + protected void EnemyCounterattack(EnemyArtillery artillery, int hitRatePercent) + { + if (hitRatePercent + artillery.Accuracy > RandomInteger(0, 100)) + { + MissionFailed(); + } + else + { + UI.Output("YOU MADE IT THROUGH TREMENDOUS FLAK!!"); + } + } + + /// + /// Display messages indicating the mission failed. + /// + protected void MissionFailed() + { + UI.Output("* * * * BOOM * * * *"); + UI.Output("YOU HAVE BEEN SHOT DOWN....."); + UI.Output("DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR"); + UI.Output("LAST TRIBUTE..."); + } +} From 26492ed257d5ee5b1352f296015b705dfcd7ad49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Mon, 3 Jan 2022 19:39:53 +0000 Subject: [PATCH 027/331] Add Perl version of 93_23Matches --- 93_23_Matches/perl/23matches.pl | 86 +++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 93_23_Matches/perl/23matches.pl diff --git a/93_23_Matches/perl/23matches.pl b/93_23_Matches/perl/23matches.pl new file mode 100644 index 00000000..c575d9cb --- /dev/null +++ b/93_23_Matches/perl/23matches.pl @@ -0,0 +1,86 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +print ' ' x 31 . "23 MATCHES\n"; +print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n\n\n"; + +print " THIS IS A GAME CALLED '23 MATCHES'.\n\n"; + +print "WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE\n"; +print "MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE\n"; +print "THE LAST MATCH.\n\n"; + +print "LET'S FLIP A COIN TO SEE WHO GOES FIRST.\n"; +print "IF IT COMES UP HEADS, I WILL WIN THE TOSS.\n\n"; + +my $N = 23; +my $Q = int( 2 * rand(5) ); + +if ( $Q == 1 ) { + print "HEADS! I WIN! HA! HA!\n"; + print "PREPARE TO LOSE, MEATBALL-NOSE!!\n\n"; + + print "I TAKE 2 MATCHES\n"; + $N -= 2; + + print "THE NUMBER OF MATCHES IS NOW $N\n\n"; + + print "YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\n"; +} +else { + print "TAILS! YOU GO FIRST.\n\n"; +} + +print "HOW MANY DO YOU WISH TO REMOVE?\n"; + +INPUT: +{ + chomp( my $K = ); + + if ( $K > 3 or $K <= 0 ) { + print "VERY FUNNY! DUMMY!\n"; + print "DO YOU WANT TO PLAY OR GOOF AROUND?\n"; + print "NOW, HOW MANY MATCHES DO YOU WANT?\n"; + redo INPUT; + } + + $N -= $K; + + print "THERE ARE NOW $N MATCHES REMAINING.\n"; + + my $Z; + + if ( $N <= 1 ) { + print "YOU WON, FLOPPY EARS!\n"; + print "THINK YOU'RE PRETTY SMART!\n"; + print "LET'S PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF!!\n"; + exit; + } + elsif ( $N > 4 ) { + $Z = 4 - $K; + } + else { + $Z = $N - 1; + } + + print "MY TURN! I REMOVE $Z MATCHES\n"; + + $N -= $Z; + + if ( $N <= 1 ) { + print "\nYOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\n"; + print "HA! HA! I BEAT YOU!!!\n\n"; + + print "GOOD BYE LOSER!\n"; + } + else { + print "THE NUMBER OF MATCHES IS NOW $N\n\n"; + + print "YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\n"; + print "HOW MANY DO YOU WISH TO REMOVE?\n"; + redo INPUT; + } +} From d77d3ee168913e7cce342c2e3bd9c778c546eb1b Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Mon, 3 Jan 2022 15:14:45 -0500 Subject: [PATCH 028/331] Port 03_Animal to Perl. Replaed array-based simulation of binary tree with hash-based simulation of binary tree. --- 03_Animal/perl/animal.pl | 223 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100755 03_Animal/perl/animal.pl diff --git a/03_Animal/perl/animal.pl b/03_Animal/perl/animal.pl new file mode 100755 index 00000000..a7c8bf9e --- /dev/null +++ b/03_Animal/perl/animal.pl @@ -0,0 +1,223 @@ +#!/usr/bin/env perl + +use 5.010; # To get 'state' and 'say' + +use strict; # Require explicit declaration of variables +use warnings; # Enable optional compiler warnings + +use English; # Use more friendly names for Perl's magic variables +use Term::ReadLine; # Prompt and return user input + +our $VERSION = '0.000_01'; + +# The Perl ref() built-in returns 'HASH' for a hash reference. But we +# make it a manifest constant just to avoid typos. +use constant REF_HASH => ref {}; + +print <<'EOD'; + ANIMAL + Creative Computing Morristown, New Jersey + + + +Play 'Guess the Animal' +Think of an animal and the computer will try to guess it. + +EOD + +# We keep the accumulated data in a tree structure, initialized here. As +# we accumulate animals, we replace the 'yes' or 'no' keys with new hash +# references. +my $database = { + question => 'Does it swim', # Initial question + yes => 'fish', # Result of answering 'y' + no => 'bird', # Result of answering 'n' +}; + +while ( 1 ) { + + my $resp = get_input( + 'Are you thinking of an an animal? [y/n/list]: ' + ); + + if ( $resp =~ m/ \A y /smxi ) { + # If we got an answer beginning with 'y', walk the database + walk_tree( $database ); + } elsif ( $resp =~ m/ \A list \z /smxi ) { + # If we got 'list', list the currently-known animals. + say ''; + say 'Animals I already know are:'; + say " $_" for sort( list_animals( $database ) ); + } +} + +# Get input from the user. The arguments are: +# * The prompt +# * A reference to validation code. This code receives the response in +# $ARG and returns true for a valid response. +# * A warning to print if the response is not valid. This must end in a +# return. +# The first valid response is returned. An end-of-file terminates the +# script. +sub get_input { + my ( $prompt, $validate, $warning ) = @ARG; + + # If no validator is passed, default to one that always returns + # true. + $validate ||= sub { 1 }; + + # Create the readline object. The 'state' causes the variable to be + # initialized only once, no matter how many times this subroutine is + # called. The do { ... } is a compound statement used because we + # need to tweak the created object before we store it. + state $term = do { + my $obj = Term::ReadLine->new( 'animal' ); + $obj->ornaments( 0 ); + $obj; + }; + + while ( 1 ) { # Iterate indefinitely + + # Read the input into the topic variable, localized to prevent + # Spooky Action at a Distance. We exit on undef, which signals + # end-of-file. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Return the input if it is valid. + return $ARG if $validate->(); + + # Issue the warning, and go around the merry-go-round again. + warn $warning; + } +} + +# Get a yes-or-no answer. The argument is the prompt, which will have +# '? [y/n]: ' appended. The donkey work is done by get_input(), which is +# requested to validate the response as beginning with 'y' or 'n', +# case-insensitive. The return is a true value for 'y' and a false value +# for 'n'. +sub get_yes_no { + my ( $prompt ) = @ARG; + state $map_answer = { + n => 0, + y => 1, + }; + my $resp = lc get_input( + "$prompt? [y/n]: ", + sub { m/ \A [yn] /smxi }, + "Please respond 'y' or 'n'\n", + ); + return $map_answer->{ substr $resp, 0, 1 }; +} + +# Recurse through the database, returning the names of all animals in +# it, in an undefined order. +sub list_animals { + my ( $node ) = @ARG; + return $node unless REF_HASH eq ref $node; + return( map { list_animals( $node->{$_} ) } qw{ yes no } ); +} + +# Find or create the desired animal. +# Ask the question stored in the node given in its argument. If the key +# selected by the answer ('yes' or 'no') is another node, recurse. If it +# is an animal name, confirm it, or add a new animal as appropriate. +sub walk_tree { + my ( $node ) = @ARG; + + # Ask the question associated with this node. Turn the true/false + # response into 'yes' or 'no', since those are the names of the + # respective keys. + my $resp = get_yes_no ( $node->{question} ) ? 'yes' : 'no'; + + # Chose the datum for the response. + my $choice = $node->{ $resp }; + + # If the datum is a hash reference + if ( REF_HASH eq ref $choice ) { + + # Recurse into it + walk_tree( $choice ); + + # Otherwise it is an actual animal (i.e. terminal node). Check it. + } else { + + # If this is not the animal the player was thinking of + unless ( get_yes_no( "Is it a $choice" ) ) { + + # Find out what animal the player was thinking of + my $animal = lc get_input( + 'The animal you were thinking of was a ', + ); + + # Get a yes/no question that distinguishes the animal the + # player was thinking of from the animal we found in the + # tree. + say 'Please type in a question that would distinguish a'; + my $question = get_input( "$animal from a $choice: " ); + + # Find out whether the new animal is selected by 'yes' or + # 'no'. If 'no', swap the original animal with the new one + # for convenience. + ( $choice, $animal ) = ( $animal, $choice ) if get_yes_no( + "For a $animal the answer would be", + ); + + # Replace the animal we originally found by a new node + # giving the original animal, the new animal, and the + # question that distinguishes them. + $node->{ $resp } = { + question => $question, + no => $animal, + yes => $choice, + }; + } + + # Find out if the player wants to play again. If not, exit. If + # so, just return. + say ''; + exit unless get_yes_no( 'Why not try another animal' ); + return; + } +} + +__END__ + +=head1 TITLE + +animal.pl - Play the game 'animal' from Basic Computer Games + +=head1 SYNOPSIS + + animal.pl + +=head1 DETAILS + +This Perl script is a port of C, which is the 3ed entry in Basic +Computer Games. + +The original BASIC was greatly complicated by the need to emulate a +binary tree with an array. The implementation using hashes as nodes in +an actual binary tree is much simpler. + +=head1 PORTED BY + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set expandtab tabstop=4 textwidth=72 : From ec189883f96a93d15355dc0c34c47fa9719859e9 Mon Sep 17 00:00:00 2001 From: RibTips <36372030+ribtips@users.noreply.github.com> Date: Mon, 3 Jan 2022 15:59:14 -0500 Subject: [PATCH 029/331] Perl version of Chomp --- 26_Chomp/perl/chomp.pl | 173 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 26_Chomp/perl/chomp.pl diff --git a/26_Chomp/perl/chomp.pl b/26_Chomp/perl/chomp.pl new file mode 100644 index 00000000..34727626 --- /dev/null +++ b/26_Chomp/perl/chomp.pl @@ -0,0 +1,173 @@ +#!/usr/bin/perl + + +my @cookie; + +&main; + +sub main { + my $answer = 1; + until ($answer == 0) { + $answer=&game_play; + } +} + +sub game_play { + + # the initial game set up + &print_intro; + my ($players,$rows,$cols) = &get_user_info; + &create_gameboard($rows,$cols); + &print_gameboard($rows,$cols); + my $game_over = 0; + my $player = 0; + + # continuous loop until the poison pill is swallowed + until ($game_over == 1) { + if ($player > ($players-1)) { #checks to make sure we're just looping thru valid players + $player = 0; + } + $player++; + my ($user_row,$user_col) = &get_player_row_col($player,$rows,$cols); + if ($cookie[$user_row][$user_col] == -1) { + print "YOU LOSE, PLAYER $player\n\n"; + print "AGAIN (1=YES, 0=NO!)\n"; + my $answer=; + chomp($answer); + return($answer); + } + &modify_gameboard($rows,$cols,$user_row,$user_col); + &print_gameboard($rows,$cols); + } + +} + +sub get_player_row_col { + my ($player,$row,$col) = @_; + my @coords; + my $validity="invalid"; + # Getting coordinates from user + until ($validity eq "valid") { + print "PLAYER $player COORDINATES OF CHOMP (ROW,COLUMN)\n"; + my $input=; + chomp($input); + @coords = split/,/,$input; + + #verifying coordinates are valid + if ($coords[0] < 1 || $coords[0] > $row || $coords[1] < 1 || $coords[1] > $col || $cookie[$coords[0]][$coords[1]] == 0) { + print "NO FAIR. YOU'RE TRYING TO CHOMP ON EMPTY SPACE!\n"; + } + else { + $validity="valid"; + } + } + return($coords[0],$coords[1]); +} + +sub get_user_info { + my ($players,$rows,$cols)=0; + until ($players > 0) { + print "HOW MANY PLAYERS\n"; + $players=; + chomp($players); + } + until ($rows > 0 && $rows < 10) { + print "HOW MANY ROWS\n"; + $rows=; + chomp($rows); + if ($rows > 9) { + print "TOO MANY ROWS (9 IS MAXIMUM). NOW, "; + } + } + until ($cols > 0 && $cols < 10) { + print "HOW MANY COLUMNS\n"; + $cols=; + chomp($cols); + if ($cols > 9) { + print "TOO MANY COLUMNS (9 IS MAXIMUM). NOW, "; + } + } + return($players,$rows,$cols); +} + +sub print_intro{ + print ' ' x 33 . "CHOMP\n"; + print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n"; + print "THIS IS THE GAME OF CHOMP (SCIENTIFIC AMERICAN, JAN 1973)\n"; + print "DO YOU WANT THE RULES (1=YES, 0=NO!)"; + my $answer = ; + chomp($answer); + if ($answer == 0) { + return; + } + else { + print "CHOMP IS FOR 1 OR MORE PLAYERS (HUMANS ONLY).\n\n"; + print "HERE'S HOW A BOARD LOOKS (THIS ONE IS 5 BY 7):\n"; + &create_gameboard(5,7); + &print_gameboard(5,7); + print "THE BOARD IS A BIG COOKIE - R ROWS HIGH AND C COLUMNS\n"; + print "WIDE. YOU INPUT R AND C AT THE START. IN THE UPPER LEFT\n"; + print "CORNER OF THE COOKIE IS A POISON SQUARE (P). THE ONE WHO\n"; + print "CHOMPS THE POISON SQUARE LOSES. TO TAKE A CHOMP, TYPE THE\n"; + print "ROW AND COLUMN OF ONE OF THE SQUARES ON THE COOKIE.\n"; + print "ALL OF THE SQUARES BELOW AND TO THE RIGHT OF THAT SQUARE\n"; + print "(INCLUDING THAT SQUARE, TOO) DISAPPEAR -- CHOMP!!\n"; + print "NO FAIR CHOMPING SQUARES THAT HAVE ALREADY BEEN CHOMPED,\n"; + print "OR THAT ARE OUTSIDE THE ORIGINAL DIMENSIONS OF THE COOKIE.\n\n"; + print "HERE WE GO...\n"; + undef @cookie; + } +} + +#initial creation of the gameboard +sub create_gameboard { + my $rows = shift; + my $cols = shift; + foreach my $row (1..($rows)) { + foreach my $col (1..($cols)) { + $cookie[$row][$col]=1; + } + } + $cookie[1][1]=-1; +} + +#modification of the gameboard based on the input from the player +sub modify_gameboard { + my ($rows,$cols,$user_row,$user_col) = @_; + foreach my $row ($user_row..($rows)) { + foreach my $col ($user_col..($cols)) { + $cookie[$row][$col]=" "; + } + } +} + +#prints the gameboard based on the current state of the gameboard +sub print_gameboard { + my ($rows,$cols) = @_; + foreach my $col (1..$cols) { + if ($col == $cols) { + print "$col\n"; + } + elsif ($col == 1) { + print "\t $col "; + } + else { + print "$col "; + } + } + foreach my $row (1..($rows)) { + print "\t$row "; + foreach my $col (1..($cols)) { + if ($cookie[$row][$col] == 1) { + print "* "; + } + if ($cookie[$row][$col] == 0) { + print " "; + } + if ($cookie[$row][$col] == -1) { + print "P "; + } + } + print "\n"; + } +} From d10e80e2c0e0eefca5cd3ecfa368994d5a7f9271 Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Mon, 3 Jan 2022 17:12:34 -0500 Subject: [PATCH 030/331] Ported 73_Reverse to Perl. In a language with list assignments, array slices, and a reverse() built-in, the reversal can be done in one statement. --- 73_Reverse/perl/reverse.pl | 234 +++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100755 73_Reverse/perl/reverse.pl diff --git a/73_Reverse/perl/reverse.pl b/73_Reverse/perl/reverse.pl new file mode 100755 index 00000000..94ef40e6 --- /dev/null +++ b/73_Reverse/perl/reverse.pl @@ -0,0 +1,234 @@ +#!/usr/bin/env perl + +use 5.010; # To get 'state' and 'say' + +use strict; # Require explicit declaration of variables +use warnings; # Enable optional compiler warnings + +use English; # Use more friendly names for Perl's magic variables +use List::Util qw{ shuffle }; # Shuffle an array. +use Term::ReadLine; # Prompt and return user input + +our $VERSION = '0.000_01'; + +# Manifest constant for size of list. +use constant NUMBER_OF_NUMBERS => 9; + +print <<'EOD'; + REVERSE + Creative Computing Morristown, New Jersey + + + +Reverse -- a game of skill + +EOD + +# Display the rules if desired. There is no straightforward way to +# interpolate a manifest constant into a string, but @{[ ... ]} will +# interpolate any expression. +print <<"EOD" if get_yes_no( 'Do you want the rules' ); + +This is the game of 'Reverse'. To win, all you have +to do is arrange a list of numbers (1 through @{[ NUMBER_OF_NUMBERS ]}) +in numerical order from left to right. To move, you +tell me how many numbers (counting from the left) to +reverse. For example, if the current list is: + +2 3 4 5 1 6 7 8 9 + +and you reverse 4, the result will be: + +5 4 3 2 1 6 7 8 9 + +Now if you reverse 5, you win! + +1 2 3 4 5 6 7 8 9 + +No doubt you will like this game, but +if you want to quit, reverse 0 (zero). + +EOD + +while ( 1 ) { # Iterate until something interrupts us. + + # Populate the list with the integers from 1, shuffled. If we + # accidentally generate a winning list, just redo the loop. + my @list = shuffle( 1 .. NUMBER_OF_NUMBERS ); + redo if is_win( \@list ); + + print <<"EOD"; + +Here we go ... The list is: +EOD + + my $moves = 0; # Move counter + + while ( 1 ) { # Iterate until something interrupts us. + print <<"EOD"; + +@list + +EOD + + # Read the number of values to reverse. Zero is special-cased to + # take us out of this loop. + last unless my $max_index = get_input( + 'How many shall I reverse (0 to quit)? ', + sub { + return m/ \A [0-9]+ \z /smx && + $ARG <= NUMBER_OF_NUMBERS; + }, + "Oops! Too many! I can reverse at most " . + NUMBER_OF_NUMBERS, + ); + + --$max_index; # Convert number to reverse to upper index + + # Use a Perl array slice and the reverse() built-in to reverse + # the beginning of the list. + @list[ 0 .. $max_index ] = reverse @list[ 0 .. $max_index ]; + + $moves++; # Count a move + + # If we have not won, iterate again. + next unless is_win( \@list ); + + # Announce the win, and drop out of the loop. + print <<"EOD"; + +You won it in $moves moves!!! +EOD + last; + } + + # Drop out of this loop unless the player wants to play again. + say ''; + last unless get_yes_no( 'Try again' ); +} + +print <<'EOD'; + +O.K. Hope you had fun!! +EOD + +# Get input from the user. The arguments are: +# * The prompt +# * A reference to validation code. This code receives the response in +# $ARG and returns true for a valid response. +# * A warning to print if the response is not valid. This must end in a +# return. +# The first valid response is returned. An end-of-file terminates the +# script. +sub get_input { + my ( $prompt, $validate, $warning ) = @ARG; + + # If no validator is passed, default to one that always returns + # true. + $validate ||= sub { 1 }; + + # Create the readline object. The 'state' causes the variable to be + # initialized only once, no matter how many times this subroutine is + # called. The do { ... } is a compound statement used because we + # need to tweak the created object before we store it. + state $term = do { + my $obj = Term::ReadLine->new( 'reverse' ); + $obj->ornaments( 0 ); + $obj; + }; + + while ( 1 ) { # Iterate indefinitely + + # Read the input into the topic variable, localized to prevent + # Spooky Action at a Distance. We exit on undef, which signals + # end-of-file. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Return the input if it is valid. + return $ARG if $validate->(); + + # Issue the warning, and go around the merry-go-round again. + warn $warning; + } +} + +# Get a yes-or-no answer. The argument is the prompt, which will have +# '? [y/n]: ' appended. The donkey work is done by get_input(), which is +# requested to validate the response as beginning with 'y' or 'n', +# case-insensitive. The return is a true value for 'y' and a false value +# for 'n'. +sub get_yes_no { + my ( $prompt ) = @ARG; + state $map_answer = { + n => 0, + y => 1, + }; + my $resp = lc get_input( + "$prompt? [y/n]: ", + sub { m/ \A [yn] /smxi }, + "Please respond 'y' or 'n'\n", + ); + return $map_answer->{ substr $resp, 0, 1 }; +} + +# Determine if a given list represents a win. The argument is a +# reference to the array containing the list. We return a true value for +# a win, or a false value otherwise. +sub is_win { + my ( $list ) = @_; + my $expect = 1; # We expect the first element to be 1; + + # Iterate over the array. + foreach my $element ( @{ $list } ) { + + # If the element does not have the expected value, we return + # false. We post-increment the expected value en passant. + $element == $expect++ + or return 0; + } + + # All elements had the expected value, so we won. Return a true + # value. + return 1; +} + +__END__ + +=head1 TITLE + +reverse.pl - Play the game 'reverse' from Basic Computer Games + +=head1 SYNOPSIS + + reverse.pl + +=head1 DETAILS + +This Perl script is a port of C, which is the 73rd entry in +Basic Computer Games. + +The cool thing about this port is the fact that, in a language with +array slices, list assignments, and a C built-in, the +reversal is a single assignment statement. + +=head1 PORTED BY + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set expandtab tabstop=4 textwidth=72 : From d32c56800a459936e1d8703c7bd3dbb38cfc2379 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Tue, 4 Jan 2022 10:13:48 +1100 Subject: [PATCH 031/331] initial kotlin implementation of "King" --- 53_King/king_variable_update.bas | 306 ++++++++++++++++ 53_King/kotlin/King.kt | 586 +++++++++++++++++++++++++++++++ 2 files changed, 892 insertions(+) create mode 100644 53_King/king_variable_update.bas create mode 100644 53_King/kotlin/King.kt diff --git a/53_King/king_variable_update.bas b/53_King/king_variable_update.bas new file mode 100644 index 00000000..c88edf93 --- /dev/null +++ b/53_King/king_variable_update.bas @@ -0,0 +1,306 @@ +1 PRINT TAB(34);"KING" +2 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +3 PRINT:PRINT:PRINT +4 PRINT "DO YOU WANT INSTRUCTIONS"; +5 INPUT Z$ +6 YEARS_REQUIRED=8 +10 IF LEFT$(Z$,1)="N" THEN 47 + 11 IF Z$="AGAIN" THEN 1960 + 12 PRINT:PRINT:PRINT + 20 PRINT "CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS" + 22 PRINT "DETINU, RALLODS SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR" + 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" + 30 PRINT "RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES" + 32 PRINT "FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT" + 34 PRINT "FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND" + 36 PRINT "WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD" + 38 PRINT "TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT" + 40 PRINT "THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER" + 42 PRINT "SQUARE MILE TO PLANT." + 44 PRINT "YOUR GOAL IS TO COMPLETE YOUR";YEARS_REQUIRED;"YEAR TERM OF OFFICE." + 46 PRINT "GOOD LUCK!" + +47 PRINT + +50 RALLODS=INT(60000+(1000*RND(1))-(1000*RND(1))) +55 COUNTRYMEN=INT(500+(10*RND(1))-(10*RND(1))) +65 LANDAREA=2000 +100 LANDPRICE=INT(10*RND(1)+95) +102 PRINT +105 PRINT "YOU NOW HAVE ";RALLODS;" RALLODS IN THE TREASURY." +110 PRINT INT(COUNTRYMEN);:PRINT "COUNTRYMEN, "; +115 COST_TO_PLANT=INT(((RND(1)/2)*10+10)) +120 IF FOREIGN_WORKERS=0 THEN 140 +130 PRINT INT(FOREIGN_WORKERS);"FOREIGN WORKERS, "; +140 PRINT "AND";INT(LANDAREA);"SQ. MILES OF LAND." +150 PRINT "THIS YEAR INDUSTRY WILL BUY LAND FOR";LANDPRICE; +152 PRINT "RALLODS PER SQUARE MILE." +155 PRINT "LAND CURRENTLY COSTS";COST_TO_PLANT;"RALLODS PER SQUARE MILE TO PLANT." +162 PRINT + +200 PRINT "HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY"; +210 INPUT SELL_TO_INDUSTRY +215 IF SELL_TO_INDUSTRY<0 THEN 200 +220 IF SELL_TO_INDUSTRY<=LANDAREA-1000 THEN 300 +230 PRINT "*** THINK AGAIN. YOU ONLY HAVE";LANDAREA-1000;"SQUARE MILES OF FARM LAND." + +240 IF EXPLANATION_GIVEN THEN 200 + 250 PRINT:PRINT "(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE" + 260 PRINT "FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES," + 270 PRINT "THICKER TOP SOIL, ETC.)" + 280 EXPLANATION_GIVEN=TRUE +299 GOTO 200 + +300 LANDAREA=INT(LANDAREA-SELL_TO_INDUSTRY) +310 RALLODS=INT(RALLODS+(SELL_TO_INDUSTRY*LANDPRICE)) +320 PRINT "HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN"; +340 INPUT WELFARE +342 IF WELFARE<0 THEN 320 +350 IF WELFARE0 THEN 1002 +602 IF WELFARE<>0 THEN 1002 +604 IF PLANTING_AREA<>0 THEN 1002 +606 IF MONEY_SPENT_ON_POLLUTION_CONTROL<>0 THEN 1002 + +609 PRINT +612 PRINT "GOODBYE." +614 PRINT "(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER" +616 PRINT "'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START" +617 PRINT "OF THE GAME)." +618 STOP + +1000 GOTO 600 + +1002 PRINT +1003 PRINT + +1010 RALLODS=INT(RALLODS-MONEY_SPENT_ON_POLLUTION_CONTROL) +1020 ORIGINAL_RALLODS=RALLODS + +1100 IF INT(WELFARE/100-COUNTRYMEN)>=0 THEN 1120 +1105 IF WELFARE/100<50 THEN 1700 +1110 PRINT INT(COUNTRYMEN-(WELFARE/100));"COUNTRYMEN DIED OF STARVATION" + +1120 POLLUTION_DEATHS=INT(RND(1)*(2000-LANDAREA)) +1122 IF MONEY_SPENT_ON_POLLUTION_CONTROL<25 THEN 1130 +1125 POLLUTION_DEATHS=INT(POLLUTION_DEATHS/(MONEY_SPENT_ON_POLLUTION_CONTROL/25)) + +1130 IF POLLUTION_DEATHS<=0 THEN 1150 +1140 PRINT POLLUTION_DEATHS;"COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION" + +1150 IF INT((WELFARE/100)-COUNTRYMEN)<0 THEN 1170 +1160 IF POLLUTION_DEATHS>0 THEN 1180 +1165 GOTO 1200 + +1170 PRINT " YOU WERE FORCED TO SPEND";INT((POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))*9); +1172 PRINT "RALLODS ON FUNERAL EXPENSES" +1174 DEATHS=INT(POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100))) +1175 RALLODS=INT(RALLODS-((POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))*9)) +1176 GOTO 1185 + +1180 PRINT " YOU WERE FORCED TO SPEND ";INT(POLLUTION_DEATHS*9);"RALLODS ON "; +1181 PRINT "FUNERAL EXPENSES." +1182 DEATHS=POLLUTION_DEATHS +1183 RALLODS=INT(RALLODS-(POLLUTION_DEATHS*9)) + +1185 IF RALLODS>=0 THEN 1194 +1187 PRINT " INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD" +1189 LANDAREA=INT(LANDAREA+(RALLODS/LANDPRICE)) +1190 RALLODS=0 + +1194 COUNTRYMEN=INT(COUNTRYMEN-DEATHS) + +1200 IF SELL_TO_INDUSTRY=0 THEN 1250 +1220 NEW_FOREIGNERS=INT(SELL_TO_INDUSTRY+(RND(1)*10)-(RND(1)*20)) +1224 IF FOREIGN_WORKERS>0 THEN 1230 +1226 NEW_FOREIGNERS=NEW_FOREIGNERS+20 + +1230 PRINT NEW_FOREIGNERS;"WORKERS CAME TO THE COUNTRY AND"; + +1250 IMMIGRATION=INT(((WELFARE/100-COUNTRYMEN)/10)+(MONEY_SPENT_ON_POLLUTION_CONTROL/25)-((2000-LANDAREA)/50)-(POLLUTION_DEATHS/2)) +1255 PRINT ABS(IMMIGRATION);"COUNTRYMEN "; +1260 IF IMMIGRATION<0 THEN 1275 +1265 PRINT "CAME TO"; +1270 GOTO 1280 +1275 PRINT "LEFT"; +1280 PRINT " THE ISLAND." +1290 COUNTRYMEN=INT(COUNTRYMEN+IMMIGRATION) + + +1292 FOREIGN_WORKERS=INT(FOREIGN_WORKERS+NEW_FOREIGNERS) + +1305 CROP_LOSS=INT(((2000-LANDAREA)*((RND(1)+1.5)/2))) +1310 IF FOREIGN_WORKERS=0 THEN 1324 +1320 PRINT "OF ";INT(PLANTING_AREA);"SQ. MILES PLANTED,"; +1324 IF PLANTING_AREA>CROP_LOSS THEN 1330 +1326 CROP_LOSS=PLANTING_AREA +1330 PRINT " YOU HARVESTED ";INT(PLANTING_AREA-CROP_LOSS);"SQ. MILES OF CROPS." +1340 IF CROP_LOSS=0 THEN 1370 +1344 IF T1>=2 THEN 1370 +1350 PRINT " (DUE TO "; +1355 IF T1=0 THEN 1365 +1360 PRINT "INCREASED "; +1365 PRINT "AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)" +1370 AGRICULTURAL_INCOME=INT((PLANTING_AREA-CROP_LOSS)*(LANDPRICE/2)) +1380 PRINT "MAKING";INT(AGRICULTURAL_INCOME);"RALLODS." +1390 RALLODS=INT(RALLODS+AGRICULTURAL_INCOME) + +REM I think tourism calculations are actually wrong in the original code! + +1400 V1=INT(((COUNTRYMEN-IMMIGRATION)*22)+(RND(1)*500)) +1405 V2=INT((2000-LANDAREA)*15) +1410 PRINT " YOU MADE";ABS(INT(V1-V2));"RALLODS FROM TOURIST TRADE." +1420 IF V2=0 THEN 1450 +1425 IF V1-V2>=V3 THEN 1450 +1430 PRINT " DECREASE BECAUSE "; +1435 G1=10*RND(1) +1440 IF G1<=2 THEN 1460 +1442 IF G1<=4 THEN 1465 +1444 IF G1<=6 THEN 1470 +1446 IF G1<=8 THEN 1475 +1448 IF G1<=10 THEN 1480 +1450 V3=INT(RALLODS+V3) +1451 RALLODS=INT(RALLODS+V3) +1452 GOTO 1500 +1460 PRINT "FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION." +1462 GOTO 1450 +1465 PRINT "AIR POLLUTION IS KILLING GAME BIRD POPULATION." +1467 GOTO 1450 +1470 PRINT "MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION." +1472 GOTO 1450 +1475 PRINT "UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS." +1477 GOTO 1450 +1480 PRINT "HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT." +1482 GOTO 1450 +1500 IF DEATHS>200 THEN 1600 +1505 IF COUNTRYMEN<343 THEN 1700 +1510 IF (ORIGINAL_RALLODS/100)>5 THEN 1800 +1515 IF FOREIGN_WORKERS>COUNTRYMEN THEN 1550 +1520 IF YEARS_REQUIRED-1=X5 THEN 1900 +1545 GOTO 2000 +1550 PRINT +1552 PRINT +1560 PRINT "THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER" +1562 PRINT "OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND" +1564 PRINT "TAKEN OVER THE COUNTRY." +1570 IF RND(1)<=.5 THEN 1580 +1574 PRINT "YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW" +1576 PRINT "RESIDING IN PRISON." +1578 GOTO 1590 +1580 PRINT "YOU HAVE BEEN ASSASSINATED." +1590 PRINT +1592 PRINT +1596 STOP +1600 PRINT +1602 PRINT +1610 PRINT DEATHS;"COUNTRYMEN DIED IN ONE YEAR!!!!!" +1615 PRINT "DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY" +1620 PRINT "BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU" +1622 M6=INT(RND(1)*10) +1625 IF M6<=3 THEN 1670 +1630 IF M6<=6 THEN 1680 +1635 IF M6<=10 THEN 1690 +1670 PRINT "ALSO HAD YOUR LEFT EYE GOUGED OUT!" +1672 GOTO 1590 +1680 PRINT "HAVE ALSO GAINED A VERY BAD REPUTATION." +1682 GOTO 1590 +1690 PRINT "HAVE ALSO BEEN DECLARED NATIONAL FINK." +1692 GOTO 1590 + +1700 PRINT +1702 PRINT +1710 PRINT "OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU" +1715 PRINT "WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)" +1720 PRINT "HATE YOUR GUTS." +1730 GOTO 1570 +1800 IF DEATHS-POLLUTION_DEATHS<2 THEN 1515 +1807 PRINT +1815 PRINT "MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID" +1820 PRINT "NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED" +1825 PRINT "OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE" +1830 PRINT "BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE." +1835 PRINT "THE CHOICE IS YOURS." +1840 PRINT "IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER" +1845 PRINT "BEFORE PROCEEDING." +1850 GOTO 1590 +1900 PRINT +1902 PRINT +1920 PRINT "CONGRATULATIONS!!!!!!!!!!!!!!!!!!" +1925 PRINT "YOU HAVE SUCCESFULLY COMPLETED YOUR";YEARS_REQUIRED;"YEAR TERM" +1930 PRINT "OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT" +1935 PRINT "NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD" +1940 PRINT "LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT" +1945 PRINT "PLAYS THIS GAME." +1950 GOTO 1590 + +1960 PRINT "HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED"; +1961 INPUT X5 +1962 IF X5<0 THEN 1590 +1963 IF X5<8 THEN 1969 +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"; +1970 INPUT RALLODS +1971 IF RALLODS<0 THEN 1590 +1975 PRINT "HOW MANY COUNTRYMEN"; +1976 INPUT COUNTRYMEN +1977 IF COUNTRYMEN<0 THEN 1590 +1980 PRINT "HOW MANY WORKERS"; +1981 INPUT FOREIGN_WORKERS +1982 IF FOREIGN_WORKERS<0 THEN 1590 +1990 PRINT "HOW MANY SQUARE MILES OF LAND"; +1991 INPUT LANDAREA +1992 IF LANDAREA<0 THEN 1590 +1993 IF LANDAREA>2000 THEN 1996 +1994 IF LANDAREA>1000 THEN 100 +1996 PRINT " COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND" +1997 PRINT " AND 10,000 SQ. MILES OF FOREST LAND." +1998 GOTO 1990 + +2000 X5=X5+1 +2020 DEATHS=0 +2040 GOTO 100 +2046 END diff --git a/53_King/kotlin/King.kt b/53_King/kotlin/King.kt new file mode 100644 index 00000000..2200a9be --- /dev/null +++ b/53_King/kotlin/King.kt @@ -0,0 +1,586 @@ +import kotlin.math.abs +import kotlin.random.Random +import kotlin.system.exitProcess + +lateinit var gameState: GameState +const val INCLUDE_BUGS_FROM_ORIGINAL = false + +val rnd: Double get() = Random.nextDouble() +fun tab(i: Int) = " ".repeat(i) +class EndOfInputException : Throwable() + +fun main() { + header() + + print("DO YOU WANT INSTRUCTIONS? ") + readLine()?.apply { + gameState = if (startsWith("AGAIN")) loadOldGame() else GameState() + if (startsWith("Y")) instructions(gameState.yearsRequired) + } + ?: throw EndOfInputException() + + try { + with(gameState) { + while(currentYear < yearsRequired) { + recalculateLandCost() + displayStatus() + inputLandSale() + performLandSale() + inputWelfare() + performWelfare() + inputPlantingArea() + performPlanting() + inputPollutionControl() + if (zeroInput()) { + displayExitMessage() + exitProcess(0) + } + simulateOneYear() + currentYear ++ + } + } + win(gameState.yearsRequired) + } catch (e: GameEndingException) { + e.displayConsequences() + } +} + +private fun header() { + println("${tab(34)}KING") + println("${tab(14)}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + println() + println() + println() +} + +fun instructions(yearsRequired: Int) { + println(""" + + + 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 $yearsRequired YEAR TERM OF OFFICE. + GOOD LUCK! + """.trimIndent() + ) +} + +fun loadOldGame(): GameState = GameState().apply { + + do { + var retry = false + print("HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED? ") + currentYear = numberInput() + + if (currentYear <= 0) + throw GameEndingException.DataEntryValidation() + + if (currentYear >= yearsRequired) { + println(" COME ON, YOUR TERM IN OFFICE IS ONLY $yearsRequired YEARS.") + retry = true + } + } while (retry) + + print("HOW MUCH DID YOU HAVE IN THE TREASURY? ") + rallods = numberInput() + if (rallods < 0) + throw GameEndingException.DataEntryValidation() + + print("HOW MANY WORKERS? ") + foreignWorkers = numberInput() + if (foreignWorkers < 0) + throw GameEndingException.DataEntryValidation() + + do { + var retry = false + print("HOW MANY SQUARE MILES OF LAND? ") + landArea = numberInput() + if (landArea<0) + throw GameEndingException.DataEntryValidation() + if (landArea > 2000 || landArea <= 1000) { + println(" COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND") + println(" AND 10,000 SQ. MILES OF FOREST LAND.") + retry = true + } + } while (retry) + +} + + +/** + * All exceptions which indicate the premature ending of the game, due + * to mismanagement, starvation, revolution, or mis-entry of a game state. + */ +sealed class GameEndingException : Throwable() { + abstract fun displayConsequences() + + fun finalFate() { + if (rnd < .5) { + println("YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW") + println("RESIDING IN PRISON.") + } else { + println("YOU HAVE BEEN ASSASSINATED.") + } + println() + println() + } + + class ExtremeMismanagement(private val death: Int) : GameEndingException() { + override fun displayConsequences() { + println() + println("$death COUNTRYMEN DIED IN ONE YEAR!!!!!") + println("DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY") + println("BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU") + println( + when ((rnd * 10.0).toInt()) { + in 0..3 -> "ALSO HAD YOUR LEFT EYE GOUGED OUT!" + in 4..6 -> "HAVE ALSO GAINED A VERY BAD REPUTATION." + else -> "HAVE ALSO BEEN DECLARED NATIONAL FINK." + } + ) + } + } + + class TooManyPeopleDead : GameEndingException() { + // The mistyping of "population" is in the original game. + override fun displayConsequences() { + println(""" + + + OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU + WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING) + HATE YOUR GUTS. + """.trimIndent()) + finalFate() + } + } + + class AntiImmigrationRevolution : GameEndingException() { + override fun displayConsequences() { + println(""" + THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER + OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND + TAKEN OVER THE COUNTRY. + """.trimIndent()) + finalFate() + } + } + + class StarvationWithFullTreasury : GameEndingException() { + override fun displayConsequences() { + println(""" + 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. + """.trimIndent()) + } + } + + class DataEntryValidation : GameEndingException() { + override fun displayConsequences() { + // no action + } + } + + +} + +fun win(yearsRequired: Int) { + // The misspelling of "successfully" is in the original code. + println(""" + + CONGRATULATIONS!!!!!!!!!!!!!!!!!! + YOU HAVE SUCCESFULLY COMPLETED YOUR $yearsRequired 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. + + + """.trimIndent()) +} + +/** + * Record data, allow data input, and process the simulation for the game. + */ +class GameState(val yearsRequired: Int = 8) { + + /** + * The current year. Years start with zero, but we never + * output the current year. + */ + var currentYear = 0 + + /** + * Number of countrymen who have died of either pollution + * or starvation this year. + * It costs 9 rallods to bury a body. + * If you lose 200 people in one year, you will throw an {@see ExtremeMismanagementException} + */ + private var death = 0 + + /** + * Last year's tourist numbers. Use this to check whether the number + * of tourists has gone up or down each year. + */ + private var tourists = 0 + + private var moneySpentOnPollutionControl = 0 + private var moneySpentOnPlanting = 0 + + /** + * Current stock of rallods. + * Player starts with between 59000 and 61000 rallods, but + * mostly distributed close to 60000. 75% of the time it's + * between 59500 and 60500. + */ + var rallods = (60000.0 + (1000.0 * rnd) - (1000.0 * rnd)).toInt() + + /** + * Population. + * Initial population is about to 500. + * 75% of the time it's between 495 and 505. + */ + private var countrymen = (500 + (10 * rnd) - (10 * rnd)).toInt() + + /** + * Land sale price is evenly between 95 and 104 rallods per + * square mile. + * Price doesn't change over the course of the game. + */ + private var landPrice = (10 * rnd + 95).toInt() + + private var plantingArea = 0 + private var welfareThisYear = 0 + + /** + * Land area in square miles. Arable land is 1000 square miles less. + * Almost all calculations use landArea-1000 because only arable + * land is of any use. + */ + var landArea = 2000 + + /** + * Number of foreigners brought in by companies to whom you + * have sold land. If this gets higher than your population, there will + * be a revolution. + */ + var foreignWorkers = 0 + + /** + * Planting cost is recalculated every year. + */ + private var costToPlant: Int = 1 + + /** + * There is a brief explanation of land selling only + * on the first turn. + */ + private var explanationOfSellingGiven = false + + private var sellThisYear: Int = 0 + + /** + * Planting cost is recalculated every year + * at between 10 and 14 rallods. + */ + fun recalculateLandCost() { + costToPlant = ((rnd / 2.0) * 10.0 + 10.0).toInt() + } + + /** + * Show the current status of the world. + */ + fun displayStatus() { + println() + println("YOU NOW HAVE $rallods RALLODS IN THE TREASURY.") + print("$countrymen COUNTRYMEN, ") + if (foreignWorkers != 0) { + println("$foreignWorkers FOREIGN WORKERS, ") + } + println("AND $landArea SQ. MILES OF LAND.") + println("THIS YEAR INDUSTRY WILL BUY LAND FOR $landPrice") + println("RALLODS PER SQUARE MILE.") + println("LAND CURRENTLY COSTS $costToPlant RALLODS PER SQUARE MILE TO PLANT.") + } + + fun displayExitMessage() { + println() + println("GOODBYE.") + println("(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER") + println("'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START") + println("OF THE GAME).") + } + + fun performLandSale() { + landArea -= sellThisYear + rallods += sellThisYear * landPrice + } + + fun performPlanting() { + rallods -= moneySpentOnPlanting + } + + fun performWelfare() { + rallods -= welfareThisYear + } + + + /** + * Ask how much land we want to sell. Immediately get the money. + * The player has to do the calculations to work out how much + * money that makes. + */ + fun inputLandSale() { + do { + print("HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY? ") + sellThisYear = numberInput() + if (sellThisYear > landArea - 1000) { + println("*** THINK AGAIN. YOU ONLY HAVE ${landArea - 1000} SQUARE MILES OF FARM LAND.") + if (!explanationOfSellingGiven) { + println() + println("(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE") + println("FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,") + println("THICKER TOP SOIL, ETC.)") + explanationOfSellingGiven = true + } + } + } while (sellThisYear <= 0 || sellThisYear > landArea - 1000) + } + + /** + * Input the value of `welfareThisYear` + */ + fun inputWelfare() { + do { + var retry = false + print("HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN? ") + welfareThisYear = numberInput() + + if (welfareThisYear > rallods) { + println(" THINK AGAIN. YOU'VE ONLY $rallods RALLODS IN THE TREASURY") + retry = true + } + + if (welfareThisYear <= 0) { + retry = true + } + } while (retry) + } + + /** + * Get the number of square miles to plant this year. + * Validate the response: + * Each countryman can only plant 2 square miles. + * You can only plant on arable land. + * You may not spend more on planting than your treasury. + */ + fun inputPlantingArea() { + if (welfareThisYear == rallods) { + plantingArea = 0 + } else { + do { + var retry = false + print("HOW MANY SQUARE MILES DO YOU WISH TO PLANT? ") + plantingArea = numberInput() + val moneySpentOnPlanting = plantingArea * costToPlant + + if (plantingArea < 0) { + retry = true + } else if (plantingArea >= 0 && plantingArea > countrymen * 2) { + println(" SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.") + retry = true + } else if (plantingArea > landArea - 1000) { + println(" SORRY, BUT YOU'VE ONLY ${landArea - 1000} SQ. MILES OF FARM LAND.") + retry = true + } else if (moneySpentOnPlanting > rallods) { + println(" THINK AGAIN. YOU'VE ONLY $rallods RALLODS LEFT IN THE TREASURY.") + retry = true + } + } while (retry) + } + + } + + /** + * Enter amount for pollution control. + * Validate that this does not exceed treasury. + */ + fun inputPollutionControl() { + do { + var retry = false + print("HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL? ") + moneySpentOnPollutionControl = numberInput() + + if (rallods < 0) { + retry = true + } else if (moneySpentOnPollutionControl > rallods) { + println(" THINK AGAIN. YOU ONLY HAVE $rallods RALLODS REMAINING.") + retry = true + } + + } while (retry) + } + + /** + * @return true if all data entered so far has been zero. + */ + fun zeroInput() = sellThisYear == 0 && + welfareThisYear == 0 && + plantingArea == 0 && + moneySpentOnPollutionControl == 0 + + fun simulateOneYear() { + rallods -= moneySpentOnPollutionControl + val rallodsAfterPollutionControl = rallods + + var starvationDeaths = 0 + if (welfareThisYear / 100.0 - countrymen < 0) { + + /* + Wait, WHAT? + If you spend less than 5000 rallods on welfare, no matter the current size of the + population, then you will end the game, with the game claiming that too many + people have died, without showing exactly how many have died? + + https://github.com/coding-horror/basic-computer-games/blob/main/53_King/king.bas#:~:text=1105%20IF%20I/100%3C50%20THEN%201700 + */ + if (welfareThisYear / 100.0 < 50) + throw GameEndingException.TooManyPeopleDead() + + starvationDeaths = (countrymen - (welfareThisYear / 100.0)).toInt() + println("$starvationDeaths COUNTRYMEN DIED OF STARVATION") + } + + var pollutionDeaths = (rnd * (2000 - landArea)).toInt() + if (moneySpentOnPollutionControl >= 25) { + pollutionDeaths = (pollutionDeaths / (moneySpentOnPollutionControl / 25.0)).toInt() + } + + if (pollutionDeaths > 0) { + println("$pollutionDeaths COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION") + } + + death = pollutionDeaths + starvationDeaths + if (death > 0) { + println(" YOU WERE FORCED TO SPEND ${death * 9}") + println("RALLODS ON FUNERAL EXPENSES") + rallods -= death * 9 + } + + if (rallods < 0) { + println(" INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD") + landArea += rallods / landPrice + rallods = 1 + } + + countrymen -= death + + val newForeigners = + if (sellThisYear > 0) { + (sellThisYear + rnd * 10.0 + rnd * 20.0).toInt() + (if (foreignWorkers <= 0) 20 else 0) + } else 0 + + val immigration = ( + (welfareThisYear / 100.0 - countrymen) / 10.0 + + moneySpentOnPollutionControl / 25.0 - + (2000 - landArea) / 50.0 - + pollutionDeaths / 2.0 + ).toInt() + println( + "$newForeigners WORKERS CAME TO THE COUNTRY AND" + + " ${abs(immigration)} COUNTRYMEN ${if (immigration < 0) "LEFT" else "CAME TO"}" + + " THE ISLAND." + ) + + countrymen += immigration + foreignWorkers += newForeigners + + var cropLoss = ((2000 - landArea) * (rnd + 1.5) / 2.0).toInt() + val cropLossWorse = false + if (foreignWorkers > 0) + print("OF $plantingArea SQ. MILES PLANTED,") + if (plantingArea <= cropLoss) + cropLoss = plantingArea + println(" YOU HARVESTED ${plantingArea - cropLoss} SQ. MILES OF CROPS.") + + if (cropLoss > 0) { + println(" (DUE TO ${if (cropLossWorse) "INCREASED " else ""}AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY)") + } + + val agriculturalIncome = ((plantingArea - cropLoss) * landPrice / 2.0).toInt() + println("MAKING $agriculturalIncome RALLODS.") + rallods += agriculturalIncome + + val v1 = (((countrymen - immigration) * 22.0) + rnd * 500).toInt() + val v2 = ((2000.0 - landArea) * 15.0).toInt() + println(" YOU MADE ${abs(v1 - v2)} RALLODS FROM TOURIST TRADE.") + if (v2 != 0 && v1 - v2 < tourists) { + print(" DECREASE BECAUSE ") + println( + when ((10 * rnd).toInt()) { + in 0..2 -> "FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION." + in 3..4 -> "AIR POLLUTION IS KILLING GAME BIRD POPULATION." + in 5..6 -> "MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION." + in 7..8 -> "UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS." + else -> "HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT." + } + ) + } + + /* + The original code was incorrect. + If v3 starts at 0, for example, our money doubles, when we + have already been told that "YOU MADE ${abs(v1 - v2)} RALLODS + FROM TOURIST TRADE" + + See the original code + 1450 V3=INT(A+V3) + 1451 A=INT(A+V3) + + https://github.com/coding-horror/basic-computer-games/blob/main/53_King/king.bas#:~:text=1450%20V3%3DINT,INT(A%2BV3) + */ + if (INCLUDE_BUGS_FROM_ORIGINAL) { + tourists += rallods + } else { + tourists = abs(v1 - v2) + } + rallods += tourists + + if (death > 200) + throw GameEndingException.ExtremeMismanagement(death) + if (countrymen < 343) + throw GameEndingException.TooManyPeopleDead() + if (rallodsAfterPollutionControl / 100 > 5 && death - pollutionDeaths >= 2) + throw GameEndingException.StarvationWithFullTreasury() + if (foreignWorkers > countrymen) + throw GameEndingException.AntiImmigrationRevolution() + + } +} + + +private fun numberInput() = try { + readLine()?.toInt() ?: throw EndOfInputException() +} catch (r: NumberFormatException) { + 0 +} + + + + + From 2d994033c52c3ce42820d8d517863450fb9c0b5c Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Tue, 4 Jan 2022 10:14:09 +1100 Subject: [PATCH 032/331] update docs --- 53_King/kotlin/King.kt | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/53_King/kotlin/King.kt b/53_King/kotlin/King.kt index 2200a9be..01558c99 100644 --- a/53_King/kotlin/King.kt +++ b/53_King/kotlin/King.kt @@ -359,7 +359,7 @@ class GameState(val yearsRequired: Int = 8) { explanationOfSellingGiven = true } } - } while (sellThisYear <= 0 || sellThisYear > landArea - 1000) + } while (sellThisYear < 0 || sellThisYear > landArea - 1000) } /** @@ -376,7 +376,7 @@ class GameState(val yearsRequired: Int = 8) { retry = true } - if (welfareThisYear <= 0) { + if (welfareThisYear < 0) { retry = true } } while (retry) @@ -495,6 +495,14 @@ class GameState(val yearsRequired: Int = 8) { (sellThisYear + rnd * 10.0 + rnd * 20.0).toInt() + (if (foreignWorkers <= 0) 20 else 0) } else 0 + /* + Immigration is calculated as + One for every thousand rallods more welfare than strictly required + minus one for every 10 starvation deaths + plus One for every 25 rallods spent on pollution control + plus one for every 50 square miles of arable land + minus one for every 2 pollution deaths + */ val immigration = ( (welfareThisYear / 100.0 - countrymen) / 10.0 + moneySpentOnPollutionControl / 25.0 - @@ -510,6 +518,12 @@ class GameState(val yearsRequired: Int = 8) { countrymen += immigration foreignWorkers += newForeigners + /* + Crop loss is between 75% and 125% of the land sold to industry, + due to the pollution that industry causes. + Money spent on pollution control reduces pollution deaths among + the population, but does not affect crop losses. + */ var cropLoss = ((2000 - landArea) * (rnd + 1.5) / 2.0).toInt() val cropLossWorse = false if (foreignWorkers > 0) From 4a2217f4be3b586a5cf23098b0ef0de0024d9e38 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Tue, 4 Jan 2022 10:41:42 +1100 Subject: [PATCH 033/331] Update README.md --- 53_King/README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/53_King/README.md b/53_King/README.md index eb0ba8ab..206202f0 100644 --- a/53_King/README.md +++ b/53_King/README.md @@ -8,6 +8,28 @@ The money system is Rollods; each person needs 100 Rallods per year to survive. The author of this program is James A. Storer who wrote it while a student at Lexington High School. +## Bugs + +Implementers should be aware that this game contains at least one bug. + +On basic line 1450 + + 1450 V3=INT(A+V3) + 1451 A=INT(A+V3) + +...where A is the current treasury, and V3 is initially zero. +This would mean that the treasury doubles at the end of the first year, and all calculations for an increase in the treasury due to tourism are discarded. +Possibly, this made the game more playable, although impossible for the player to understand why the treasury was increasing? + +A quick fix for this bug in the original code would be + + 1450 V3=ABS(INT(V1-V2)) + 1451 A=INT(A+V3) + +...judging from the description of tourist income on basic line 1410 + + 1410 PRINT " YOU MADE";ABS(INT(V1-V2));"RALLODS FROM TOURIST TRADE." + --- As published in Basic Computer Games (1978): From 1e9c8008d162d294515ab4b454b29ee008f0c7a8 Mon Sep 17 00:00:00 2001 From: John Long Date: Mon, 3 Jan 2022 16:37:04 -0800 Subject: [PATCH 034/331] Add Kotlin for Synonym This is so much cleaner than the Java :). --- 85_Synonym/kotlin/README.md | 3 ++ 85_Synonym/kotlin/Synonym.kt | 71 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 85_Synonym/kotlin/README.md create mode 100644 85_Synonym/kotlin/Synonym.kt diff --git a/85_Synonym/kotlin/README.md b/85_Synonym/kotlin/README.md new file mode 100644 index 00000000..f43a5b70 --- /dev/null +++ b/85_Synonym/kotlin/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Kotlin](https://kotlinlang.org/) diff --git a/85_Synonym/kotlin/Synonym.kt b/85_Synonym/kotlin/Synonym.kt new file mode 100644 index 00000000..94066d03 --- /dev/null +++ b/85_Synonym/kotlin/Synonym.kt @@ -0,0 +1,71 @@ +/** + * Game of Synonym + * + * + * Based on the Basic game of Synonym here + * https://github.com/coding-horror/basic-computer-games/blob/main/85%20Synonym/synonym.bas + * + * + * Note: The idea was to create a version of the 1970's Basic game in Java, without introducing + * new features - no additional text, error checking, etc has been added. + */ + +fun main() { + println(introText) + synonyms.forEach { + // Inside with, "this" is the current synonym + with(it) { + do { + val answer = ask(" WHAT IS A SYNONYM OF $word ? ") + when { + answer == "HELP" -> + println("""**** A SYNONYM OF $word IS ${synonyms.random()}.""") + synonyms.contains(answer) -> + println(RANDOM_ANSWERS.random()) + else -> + println("TRY AGAIN.") + } + } while (!synonyms.contains(answer)) + } + } + println("SYNONYM DRILL COMPLETED.") +} + +val introText = """ +${tab(33)}SYNONYM +${tab(15)}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY +A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH +LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME + MEANING. +I CHOOSE A WORD -- YOU TYPE A SYNONYM. +IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP' +AND I WILL TELL YOU A SYNONYM. + + """ + +// prints a question and reads a string (and converts to uppercase) +private fun ask(text: String): String { + print(text) + return readln().uppercase() +} + +// Just like TAB in BASIC +private fun tab(spaces: Int): String = " ".repeat(spaces) + +val RANDOM_ANSWERS = arrayOf("RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK") + +// List of words and synonyms +private val synonyms = listOf( + SynonymList("FIRST", listOf("START", "BEGINNING", "ONSET", "INITIAL")), + SynonymList("SIMILAR", listOf("SAME", "LIKE", "RESEMBLING")), + SynonymList("MODEL", listOf("PATTERN", "PROTOTYPE", "STANDARD", "CRITERION")), + SynonymList("SMALL", listOf("INSIGNIFICANT", "LITTLE", "TINY", "MINUTE")), + SynonymList("STOP", listOf("HALT", "STAY", "ARREST", "CHECK", "STANDSTILL")), + SynonymList("HOUSE", listOf("DWELLING", "RESIDENCE", "DOMICILE", "LODGING", "HABITATION")), + SynonymList("PIT", listOf("HOLE", "HOLLOW", "WELL", "GULF", "CHASM", "ABYSS")), + SynonymList("PUSH", listOf("SHOVE", "THRUST", "PROD", "POKE", "BUTT", "PRESS")), + SynonymList("RED", listOf("ROUGE", "SCARLET", "CRIMSON", "FLAME", "RUBY")), + SynonymList("PAIN", listOf("SUFFERING", "HURT", "MISERY", "DISTRESS", "ACHE", "DISCOMFORT")) +) + +class SynonymList(val word: String, val synonyms: List) \ No newline at end of file From 8be28cd39a3ee3a642a047a8e303f70a24b1e5a4 Mon Sep 17 00:00:00 2001 From: John Long Date: Mon, 3 Jan 2022 16:45:26 -0800 Subject: [PATCH 035/331] A little cleaner implementation --- 85_Synonym/kotlin/Synonym.kt | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/85_Synonym/kotlin/Synonym.kt b/85_Synonym/kotlin/Synonym.kt index 94066d03..d2e68dc4 100644 --- a/85_Synonym/kotlin/Synonym.kt +++ b/85_Synonym/kotlin/Synonym.kt @@ -13,23 +13,25 @@ fun main() { println(introText) synonyms.forEach { - // Inside with, "this" is the current synonym - with(it) { - do { - val answer = ask(" WHAT IS A SYNONYM OF $word ? ") - when { - answer == "HELP" -> - println("""**** A SYNONYM OF $word IS ${synonyms.random()}.""") - synonyms.contains(answer) -> - println(RANDOM_ANSWERS.random()) - else -> - println("TRY AGAIN.") - } - } while (!synonyms.contains(answer)) - } + it.testUser() } println("SYNONYM DRILL COMPLETED.") } +// We could put this inside of SynonymList, but this keeps the core implementation +// right here at the top +private fun SynonymList.testUser() { + do { + val answer = ask(" WHAT IS A SYNONYM OF $word ? ") + when { + answer == "HELP" -> + println("""**** A SYNONYM OF $word IS ${synonyms.random()}.""") + synonyms.contains(answer) -> + println(RANDOM_ANSWERS.random()) + else -> + println("TRY AGAIN.") + } + } while (!synonyms.contains(answer)) +} val introText = """ ${tab(33)}SYNONYM From 1520a8f225ec55582cb4ff9070389fab56c9e1f5 Mon Sep 17 00:00:00 2001 From: John Long Date: Mon, 3 Jan 2022 16:47:47 -0800 Subject: [PATCH 036/331] Affirmation more accurate than Answer --- 85_Synonym/kotlin/Synonym.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/85_Synonym/kotlin/Synonym.kt b/85_Synonym/kotlin/Synonym.kt index d2e68dc4..dda96a82 100644 --- a/85_Synonym/kotlin/Synonym.kt +++ b/85_Synonym/kotlin/Synonym.kt @@ -26,7 +26,7 @@ private fun SynonymList.testUser() { answer == "HELP" -> println("""**** A SYNONYM OF $word IS ${synonyms.random()}.""") synonyms.contains(answer) -> - println(RANDOM_ANSWERS.random()) + println(RANDOM_AFFIRMATION.random()) else -> println("TRY AGAIN.") } @@ -54,7 +54,7 @@ private fun ask(text: String): String { // Just like TAB in BASIC private fun tab(spaces: Int): String = " ".repeat(spaces) -val RANDOM_ANSWERS = arrayOf("RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK") +val RANDOM_AFFIRMATION = arrayOf("RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK") // List of words and synonyms private val synonyms = listOf( From 916fa6f252188b1fa8a9bb605eda1d29569defb0 Mon Sep 17 00:00:00 2001 From: John Long Date: Mon, 3 Jan 2022 16:48:49 -0800 Subject: [PATCH 037/331] And now RANDOM is redundant --- 85_Synonym/kotlin/Synonym.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/85_Synonym/kotlin/Synonym.kt b/85_Synonym/kotlin/Synonym.kt index dda96a82..386a2525 100644 --- a/85_Synonym/kotlin/Synonym.kt +++ b/85_Synonym/kotlin/Synonym.kt @@ -26,7 +26,7 @@ private fun SynonymList.testUser() { answer == "HELP" -> println("""**** A SYNONYM OF $word IS ${synonyms.random()}.""") synonyms.contains(answer) -> - println(RANDOM_AFFIRMATION.random()) + println(AFFIRMATIONS.random()) else -> println("TRY AGAIN.") } @@ -54,7 +54,7 @@ private fun ask(text: String): String { // Just like TAB in BASIC private fun tab(spaces: Int): String = " ".repeat(spaces) -val RANDOM_AFFIRMATION = arrayOf("RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK") +val AFFIRMATIONS = arrayOf("RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK") // List of words and synonyms private val synonyms = listOf( From 2c1dea4de7cef0c0e8f6b0a3843b55396af0658f Mon Sep 17 00:00:00 2001 From: a2wd Date: Tue, 4 Jan 2022 01:57:36 +0100 Subject: [PATCH 038/331] Added bombardment in c# --- 11_Bombardment/csharp/Bombardment.cs | 183 +++++++++++++++++++++++ 11_Bombardment/csharp/Bombardment.csproj | 8 + 11_Bombardment/csharp/Program.cs | 13 ++ 3 files changed, 204 insertions(+) create mode 100644 11_Bombardment/csharp/Bombardment.cs create mode 100644 11_Bombardment/csharp/Bombardment.csproj create mode 100644 11_Bombardment/csharp/Program.cs diff --git a/11_Bombardment/csharp/Bombardment.cs b/11_Bombardment/csharp/Bombardment.cs new file mode 100644 index 00000000..bcbdcc26 --- /dev/null +++ b/11_Bombardment/csharp/Bombardment.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Generic; + +namespace Bombardment +{ + // + // Game of Bombardment + // Based on the Basic game of Bombardment here + // https://github.com/coding-horror/basic-computer-games/blob/main/11%20Bombardment/bombardment.bas + // Note: The idea was to create a version of the 1970's Basic game in C#, without introducing + // new features - no additional text, error checking, etc has been added. + // + internal class Bombardment + { + private static int MAX_GRID_SIZE = 25; + private static int MAX_PLATOONS = 4; + private static Random random = new Random(); + private List computerPositions = new List(); + private List playerPositions = new List(); + private List computerGuesses = new List(); + + private void PrintStartingMessage() + { + Console.WriteLine("{0}BOMBARDMENT", new string(' ', 33)); + Console.WriteLine("{0}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY", new string(' ', 15)); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); + + Console.WriteLine("YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU"); + Console.WriteLine("HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED."); + Console.WriteLine("YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST."); + Console.WriteLine("THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS."); + Console.WriteLine(); + Console.WriteLine("THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE"); + Console.WriteLine("OUTPOSTS OF THE COMPUTER. IT WILL DO THE SAME TO YOU."); + Console.WriteLine("THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS"); + Console.WriteLine("FIRST IS THE WINNER."); + Console.WriteLine(); + Console.WriteLine("GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!"); + Console.WriteLine(); + Console.WriteLine("TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS."); + + // As an alternative to repeating the call to WriteLine(), + // we can print the new line character five times. + Console.Write(new string('\n', 5)); + + // Print a sample board (presumably the game was originally designed to be + // physically printed on paper while played). + for (var i = 1; i <= 25; i += 5) + { + // The token replacement can be padded by using the format {tokenPosition, padding} + // Negative values for the padding cause the output to be left-aligned. + Console.WriteLine("{0,-3}{1,-3}{2,-3}{3,-3}{4,-3}", i, i + 1, i + 2, i + 3, i + 4); + } + + Console.WriteLine("\n"); + } + + // Generate 5 random positions for the computer's platoons. + private void PlaceComputerPlatoons() + { + do + { + var nextPosition = random.Next(1, MAX_GRID_SIZE); + if (!computerPositions.Contains(nextPosition)) + { + computerPositions.Add(nextPosition); + } + + } while (computerPositions.Count < MAX_PLATOONS); + } + + private void StoreHumanPositions() + { + Console.WriteLine("WHAT ARE YOUR FOUR POSITIONS"); + + // The original game assumed that the input would be five comma-separated values, all on one line. + // For example: 12,22,1,4,17 + var input = Console.ReadLine(); + var playerPositionsAsStrings = input.Split(","); + foreach (var playerPosition in playerPositionsAsStrings) { + playerPositions.Add(int.Parse(playerPosition)); + } + } + + private void HumanTurn() + { + Console.WriteLine("WHERE DO YOU WISH TO FIRE YOUR MISSLE"); + var input = Console.ReadLine(); + var humanGuess = int.Parse(input); + + if(computerPositions.Contains(humanGuess)) + { + Console.WriteLine("YOU GOT ONE OF MY OUTPOSTS!"); + computerPositions.Remove(humanGuess); + + switch(computerPositions.Count) + { + case 3: + Console.WriteLine("ONE DOWN, THREE TO GO."); + break; + case 2: + Console.WriteLine("TWO DOWN, TWO TO GO."); + break; + case 1: + Console.WriteLine("THREE DOWN, ONE TO GO."); + break; + case 0: + Console.WriteLine("YOU GOT ME, I'M GOING FAST."); + Console.WriteLine("BUT I'LL GET YOU WHEN MY TRANSISTO&S RECUP%RA*E!"); + break; + } + } + else + { + Console.WriteLine("HA, HA YOU MISSED. MY TURN NOW:"); + } + } + + private int GenerateComputerGuess() + { + int computerGuess; + do + { + computerGuess = random.Next(1, 25); + } + while(computerGuesses.Contains(computerGuess)); + computerGuesses.Add(computerGuess); + + return computerGuess; + } + + private void ComputerTurn() + { + var computerGuess = GenerateComputerGuess(); + + if (playerPositions.Contains(computerGuess)) + { + Console.WriteLine("I GOT YOU. IT WON'T BE LONG NOW. POST {0} WAS HIT.", computerGuess); + playerPositions.Remove(computerGuess); + + switch(playerPositions.Count) + { + case 3: + Console.WriteLine("YOU HAVE ONLY THREE OUTPOSTS LEFT."); + break; + case 2: + Console.WriteLine("YOU HAVE ONLY TWO OUTPOSTS LEFT."); + break; + case 1: + Console.WriteLine("YOU HAVE ONLY ONE OUTPOST LEFT."); + break; + case 0: + Console.WriteLine("YOU'RE DEAD. YOUR LAST OUTPOST WAS AT {0}. HA, HA, HA.", computerGuess); + Console.WriteLine("BETTER LUCK NEXT TIME."); + break; + } + } + else + { + Console.WriteLine("I MISSED YOU, YOU DIRTY RAT. I PICKED {0}. YOUR TURN:", computerGuess); + } + } + + public void Play() + { + PrintStartingMessage(); + PlaceComputerPlatoons(); + StoreHumanPositions(); + + while (playerPositions.Count > 0 && computerPositions.Count > 0) + { + HumanTurn(); + + if (computerPositions.Count > 0) + { + ComputerTurn(); + } + } + } + } +} diff --git a/11_Bombardment/csharp/Bombardment.csproj b/11_Bombardment/csharp/Bombardment.csproj new file mode 100644 index 00000000..e5e0e164 --- /dev/null +++ b/11_Bombardment/csharp/Bombardment.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp2.1 + + + diff --git a/11_Bombardment/csharp/Program.cs b/11_Bombardment/csharp/Program.cs new file mode 100644 index 00000000..acc438ba --- /dev/null +++ b/11_Bombardment/csharp/Program.cs @@ -0,0 +1,13 @@ +using System; + +namespace Bombardment +{ + class Program + { + static void Main(string[] args) + { + var bombardment = new Bombardment(); + bombardment.Play(); + } + } +} From e8849566baf01424909f797d9db7db36e432b0c2 Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 4 Jan 2022 12:35:51 +1100 Subject: [PATCH 039/331] fix(amazing): guarantee exit on bottom row of maze This issue only tends to show up on very small mazes (e.g. 2x2, 3x3). It is possible for the algorithm to never generate an exit to the maze. While the algorithm guarantees with the `Z` variable that only one exit will be generated, it does not test for the situation where we just happen to never get the right random value to open an exit on the bottom row. The simplest resolution is just to check for this before rendering the final result (i.e. `IF Z=0`), and add an exit to a random cell on the bottom row. --- 02_Amazing/amazing.bas | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/02_Amazing/amazing.bas b/02_Amazing/amazing.bas index 63255319..3b39c93a 100644 --- a/02_Amazing/amazing.bas +++ b/02_Amazing/amazing.bas @@ -117,10 +117,15 @@ 975 V(R,S)=3:Q=0:GOTO 1000 980 V(R,S)=1:Q=0:R=1:S=1:GOTO 250 1000 GOTO 210 -1010 FOR J=1 TO V -1011 PRINT "I"; -1012 FOR I=1 TO H -1013 IF V(I,J)<2 THEN 1030 +1010 IF Z=1 THEN 1015 +1011 X=INT(RND(1)*H+1) +1012 IF V(X,V)=0 THEN 1014 +1013 V(X,V)=3: GOTO 1015 +1014 V(X,V)=1 +1015 FOR J=1 TO V +1016 PRINT "I"; +1017 FOR I=1 TO H +1018 IF V(I,J)<2 THEN 1030 1020 PRINT " "; 1021 GOTO 1040 1030 PRINT " I"; From 321205cc7769f75671028fc3190b1aa45b338b78 Mon Sep 17 00:00:00 2001 From: Alaa Sarhan Date: Tue, 4 Jan 2022 02:49:50 +0100 Subject: [PATCH 040/331] minor changes --- 13_Bounce/ruby/bounce.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/13_Bounce/ruby/bounce.rb b/13_Bounce/ruby/bounce.rb index 339c7851..e215a897 100644 --- a/13_Bounce/ruby/bounce.rb +++ b/13_Bounce/ruby/bounce.rb @@ -110,8 +110,8 @@ def plot_bouncing_ball(strobbing_time, v0, c) } if heighest_position_in_next_bounce(time_in_bounce, v0, i, c) < plotted_height then - # If we got no more ball positions at or above current height, we can skip - # the rest of the bounces and move down to the next height to plot + # If we got no more ball positions at or above current height in the next bounce, + # we can skip the rest of the bounces and move down to the next height to plot puts break end @@ -170,11 +170,11 @@ def game_loop end -## Game entry point +## Entry point begin intro - while true + loop do game_loop end rescue SystemExit, Interrupt From f98c8af9f82a3cfe36c5ca2c18f3b70af6b94149 Mon Sep 17 00:00:00 2001 From: RibTips <36372030+ribtips@users.noreply.github.com> Date: Tue, 4 Jan 2022 00:21:38 -0500 Subject: [PATCH 041/331] Perl version of 35_evenwins --- 35_Even_Wins/perl/evenwins.pl | 168 ++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 35_Even_Wins/perl/evenwins.pl diff --git a/35_Even_Wins/perl/evenwins.pl b/35_Even_Wins/perl/evenwins.pl new file mode 100644 index 00000000..20065c23 --- /dev/null +++ b/35_Even_Wins/perl/evenwins.pl @@ -0,0 +1,168 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +&main; + +sub main { + &print_intro; + &game_play; +} + +sub game_play { + my $marbles = 27; + my $turn = 0; + my $player_total = 0; + my $computer_total = 0; + print "TYPE A '1' IF YOU WANT TO GO FIRST AND TYPE A '0' IF YOU WANT ME TO GO FIRST\n"; + my $choice = ; + chomp($choice); + if ($choice == 0) { + until ($marbles == 0) { + + my $computer_choice = &computer_select($marbles,$turn); + $marbles = $marbles - $computer_choice; + $computer_total = $computer_total + $computer_choice; + print "MY TOTAL IS $computer_total\n"; + + print "TOTAL= $marbles\n"; + + if ($marbles == 0) {&determine_winner($computer_total,$player_total)}; + + my $player_choice = &player_select($marbles,$turn); + $marbles = $marbles - $player_choice; + $player_total = $player_total + $player_choice; + print "YOUR TOTAL IS $player_total\n"; + $turn++; + print "TOTAL= $marbles\n"; + if ($marbles == 0) {&determine_winner($computer_total,$player_total)}; + } + } + elsif ($choice == 1) { + until ($marbles == 0) { + + my $player_choice = &player_select($marbles,$turn); + $marbles = $marbles - $player_choice; + $player_total = $player_total + $player_choice; + $turn++; + print "YOUR TOTAL IS $player_total\n"; + + print "TOTAL= $marbles\n"; + + if ($marbles == 0) {&determine_winner($computer_total,$player_total)}; + + my $computer_choice = &computer_select($marbles,$turn); + $marbles = $marbles - $computer_choice; + $computer_total = $computer_total + $computer_choice; + print "MY TOTAL IS $computer_total\n"; + + print "TOTAL= $marbles\n"; + + if ($marbles == 0) {&determine_winner($computer_total,$player_total)}; + + } + } +} + +sub determine_winner { + my $computer = shift; + my $player = shift; + print "THAT IS ALL OF THE MARBLES.\n\n"; + print "MY TOTAL IS $computer, YOUR TOTAL IS $player\n"; + if ($player % 2 == 0) { + print " YOU WON.\n"; + } + if ($computer % 2 == 0) { + print " I WON.\n"; + } + my $answer = -1; + until ($answer == 1 || $answer == 0) { + print "DO YOU WANT TO PLAY AGAIN? TYPE 1 FOR YES AND 0 FOR NO.\n"; + $answer=; + chomp($answer); + } + if ($answer == 1) { + &game_play; + } + else { + print "OK. SEE YOU LATER.\n"; + exit; + } +} + +sub player_select { + my $marbles = shift; + my $turn = shift; + my $validity="invalid"; + if ($turn == 0) { + print "WHAT IS YOUR FIRST MOVE\n"; + } + else { + print "WHAT IS YOUR NEXT MOVE\n"; + } + until ($validity eq "valid") { + my $num = ; + chomp($num); + my $validity=&validity_check($marbles,$num); + if ($validity eq "valid") { + return $num; + } + } +} + +sub computer_select { + my $marbles = shift; + my $turn = shift; + my $num = 2; + my $validity = "invalid"; + if ($turn == 0) { + print "I PICK UP $num MARBLES.\n\n"; + } + else { + until ($validity eq "valid") { + my $R=$marbles-6*int(($marbles/6)); + if ($marbles < 4.2) { + $num = $marbles; + } + if ($R > 3.4) { + if ($R < 4.7 || $R > 3.5) { + $num = 4; + } + else { + $num = 1; + } + } + $validity=&validity_check($marbles,$num); + } + print "\nI PICK UP $num MARBLES.\n\n"; + } + return $num; +} + +sub validity_check { + my $marbles = shift; + my $num = shift; + if ($num > $marbles) { + print "YOU HAVE TRIED TO TAKE MORE MARBLES THAN THERE ARE LEFT. TRY AGAIN. THERE ARE $marbles MARBLES LEFT\n"; + return "invalid"; + } + if ($num > 0 && $num <= 4) { + return "valid"; + } + if ($num < 1 || $num > 4) { + print "THE NUMBER OF MARBLES YOU TAKE MUST BE A POSITIVE INTEGER BETWEEN 1 AND 4\nWHAT IS YOUR NEXT MOVE?\n"; + return "invalid"; + } + else { + return "invalid"; + } +} + +sub print_intro { + print ' ' x 31 . "EVEN WINS\n"; + print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; + print "THIS IS A 2 PERSON GAME CALLED 'EVEN WINS'. TO PLAY THE GAME, THE PLAYERS NEED 27 MARBLES OR OTHER OBJECTS ON THE TABLE\n\n"; + print "THE 2 PLAYERS ALTERNATE TURNS, WITH EACH PLAYER REMOVING FROM 1 TO 4 MARBLES ON EACH MOVE. THE GAME ENDS WHEN THERE ARE NO MARBLES LEFT, AND THE WINNER IS THE ONE WITH AN EVEN NUMBER OF MARBLES\n"; + print "THE ONLY RULES ARE THAT (1) YOU MUST ALTERNATE TURNS, (2) YOU MUST TAKE BETWEEN 1 AND 4 MARBLES EACH TURN, AND (3) YOU CANNOT SKIP A TURN.\n\n"; +} From d82a637152968ff3dd6e035965b6bf65f1a228de Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 4 Jan 2022 16:47:32 +1100 Subject: [PATCH 042/331] chore(amazing): add note to README.md for #400 --- 02_Amazing/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/02_Amazing/README.md b/02_Amazing/README.md index 8f7b271b..e94949bd 100644 --- a/02_Amazing/README.md +++ b/02_Amazing/README.md @@ -12,3 +12,7 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html + +--- + +**2022-01-04:** patched original source in [#400](https://github.com/coding-horror/basic-computer-games/pull/400) to fix a minor bug where a generated maze may be missing an exit, particularly at small maze sizes. From 55b3c0d4e76142312e9abf2276b51b097aa5631d Mon Sep 17 00:00:00 2001 From: RibTips <36372030+ribtips@users.noreply.github.com> Date: Tue, 4 Jan 2022 01:33:11 -0500 Subject: [PATCH 043/331] Add files via upload --- 35_Even_Wins/perl/evenwins.pl | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/35_Even_Wins/perl/evenwins.pl b/35_Even_Wins/perl/evenwins.pl index 20065c23..c2fdc2d8 100644 --- a/35_Even_Wins/perl/evenwins.pl +++ b/35_Even_Wins/perl/evenwins.pl @@ -21,7 +21,7 @@ sub game_play { if ($choice == 0) { until ($marbles == 0) { - my $computer_choice = &computer_select($marbles,$turn); + my $computer_choice = &computer_select($marbles,$turn,$player_total); $marbles = $marbles - $computer_choice; $computer_total = $computer_total + $computer_choice; print "MY TOTAL IS $computer_total\n"; @@ -52,7 +52,7 @@ sub game_play { if ($marbles == 0) {&determine_winner($computer_total,$player_total)}; - my $computer_choice = &computer_select($marbles,$turn); + my $computer_choice = &computer_select($marbles,$turn,$player_total); $marbles = $marbles - $computer_choice; $computer_total = $computer_total + $computer_choice; print "MY TOTAL IS $computer_total\n"; @@ -114,6 +114,7 @@ sub player_select { sub computer_select { my $marbles = shift; my $turn = shift; + my $player_total = shift; my $num = 2; my $validity = "invalid"; if ($turn == 0) { @@ -122,14 +123,24 @@ sub computer_select { else { until ($validity eq "valid") { my $R=$marbles-6*int(($marbles/6)); - if ($marbles < 4.2) { + + if (int($player_total/2) == $player_total/2) { + if ($R < 1.5 || $R > 5.3) { + $num = 1; + } + else { + $num = $R - 1; + } + } + + elsif ($marbles < 4.2) { $num = $marbles; } - if ($R > 3.4) { + elsif ($R > 3.4) { if ($R < 4.7 || $R > 3.5) { $num = 4; } - else { + else { $num = 1; } } From 41183198a8d9e57135b079c48923ef7207d87404 Mon Sep 17 00:00:00 2001 From: RibTips <36372030+ribtips@users.noreply.github.com> Date: Tue, 4 Jan 2022 01:37:57 -0500 Subject: [PATCH 044/331] added logic/intelligence into the AI modified the logic from how the computer was making its selections. Original code had a simple random number, this incorporates the original logic from the BASIC game. --- 35_Even_Wins/python/evenwins.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/35_Even_Wins/python/evenwins.py b/35_Even_Wins/python/evenwins.py index fba20024..3fb9d4af 100644 --- a/35_Even_Wins/python/evenwins.py +++ b/35_Even_Wins/python/evenwins.py @@ -142,17 +142,32 @@ def game_over(): print('') def computer_turn(): - global marbles_in_middle - global computer_marbles + global marbles_in_middle + global computer_marbles + global human_marbles - print("It's the computer's turn ...") - max_choice = min(4, marbles_in_middle) + marbles_to_take=0 - # choose at random - n = random.randint(1, max_choice) - print(f'Computer takes {marbles_str(n)} ...') - marbles_in_middle -= n - computer_marbles += n + print("It's the computer's turn ...") + r = marbles_in_middle - 6 * int((marbles_in_middle/6)) #line 500 + + 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_in_middle -= marbles_to_take + computer_marbles += marbles_to_take def play_game(): global marbles_in_middle From 3b4b14427c6da19f03fd557afd380e20b65bd638 Mon Sep 17 00:00:00 2001 From: Alex Kapranoff Date: Tue, 4 Jan 2022 00:38:57 -0800 Subject: [PATCH 045/331] 02_Amazing in Perl --- 02_Amazing/perl/amazing.pl | 155 +++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 02_Amazing/perl/amazing.pl diff --git a/02_Amazing/perl/amazing.pl b/02_Amazing/perl/amazing.pl new file mode 100644 index 00000000..a474ba59 --- /dev/null +++ b/02_Amazing/perl/amazing.pl @@ -0,0 +1,155 @@ +#! /usr/bin/perl +use strict; +use warnings; + +# Translated from BASIC by Alex Kapranoff + +use feature qw/say/; + +# width and height of the maze +my ($width, $height) = input_dimensions(); + +# wall masks for all cells +my @walls; + +# flags of previous visitation for all cells +my %is_visited; + +# was the path out of the maze found? +my $path_found = 0; + +# column of entry to the maze in the top line +my $entry_col = int(rand($width)); + +# cell coordinates for traversal +my $col = $entry_col; +my $row = 0; + +$is_visited{$row, $col} = 1; + +# looping until we visit every cell +while (keys %is_visited < $width * $height) { + if (my @dirs = get_possible_directions()) { + my $dir = $dirs[rand @dirs]; + + # modify current cell wall if needed + $walls[$row]->[$col] |= $dir->[2]; + + # move the position + $row += $dir->[0]; + $col += $dir->[1]; + + # we found the exit! + if ($row == $height) { + $path_found = 1; + --$row; + + if ($walls[$row]->[$col] == 1) { + ($row, $col) = get_next_branch(0, 0); + } + } + else { + # modify the new cell wall if needed + $walls[$row]->[$col] |= $dir->[3]; + + $is_visited{$row, $col} = 1; + } + } + else { + ($row, $col) = get_next_branch($row, $col); + } +} + +print_maze(); + +sub input_dimensions { + # Print the banner and returns the dimensions as two integers > 1. + # The integers are parsed from the first line of standard input. + say ' ' x 28, 'AMAZING PROGRAM'; + say ' ' x 15, 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'; + print "\n" x 4; + + my ($w, $h) = (0, 0); + + while ($w <= 1 || $h <= 1) { + print 'WHAT ARE YOUR WIDTH AND LENGTH? '; + + ($w, $h) = =~ / \d+ /xg; + + if ($w < 1 || $h < 1) { + say "MEANINGLESS DIMENSIONS. TRY AGAIN." + } + } + + print "\n" x 4; + + return ($w, $h); +} + +sub get_possible_directions { + # Returns a list of all directions that are available to go to + # from the current coordinates. "Down" is available on the last line + # until we go there once and mark it as the path through the maze. + # + # Each returned direction element contains changes to the coordindates and to + # the wall masks of the previous and next cell after the move. + + my @rv; + # up + if ($row > 0 && !$is_visited{$row - 1, $col}) { + push @rv, [-1, 0, 0, 1]; + } + # left + if ($col > 0 && !$is_visited{$row, $col - 1}) { + push @rv, [0, -1, 0, 2]; + } + # right + if ($col < $width - 1 && !$is_visited{$row, $col + 1}) { + push @rv, [0, 1, 2, 0]; + } + # down + if ($row < $height - 1 && !$is_visited{$row + 1, $col} + || $row == $height - 1 && !$path_found + ) { + push @rv, [1, 0, 1, 0]; + } + + return @rv; +} + +sub get_next_branch { + # Returns the cell coordinates to start a new maze branch from. + # It looks for a visited cell starting from passed position and + # going down in the natural traversal order incrementing column and + # rows with a rollover to start at the bottom right corner. + my ($y, $x) = @_; + do { + if ($x < $width - 1) { + ++$x; + } elsif ($y < $height - 1) { + ($y, $x) = ($y + 1, 0); + } else { + ($y, $x) = (0, 0); + } + } while (!$is_visited{$y, $x}); + + return ($y, $x); +} + +sub print_maze { + # Print the full maze based on wall masks. + # For each cell, we mark the absense of the wall to the right with + # bit 2 and the absense of the wall down with bit 1. Full table: + # 0 -> both walls are present + # 1 -> wall down is absent + # 2 -> wall to the right is absent + # 3 -> both walls are absent + say join('.', '', map { $_ == $entry_col ? ' ' : '--' } 0 .. $width - 1), '.'; + + for my $row (@walls) { + say join(' ', map { $_ & 2 ? ' ' : 'I' } 0, @$row); + say join(':', '', map { $_ & 1 ? ' ' : '--' } @$row), '.'; + } + + return; +} From 6f599f12f64a51cfd2bc039a5ad48d5f9d8ef9d9 Mon Sep 17 00:00:00 2001 From: Alex Kapranoff Date: Tue, 4 Jan 2022 00:47:34 -0800 Subject: [PATCH 046/331] Fix the bug identified in #400 --- 02_Amazing/perl/amazing.pl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/02_Amazing/perl/amazing.pl b/02_Amazing/perl/amazing.pl index a474ba59..c7cb5f44 100644 --- a/02_Amazing/perl/amazing.pl +++ b/02_Amazing/perl/amazing.pl @@ -60,6 +60,10 @@ while (keys %is_visited < $width * $height) { } } +unless ($path_found) { + $walls[-1]->[rand $width] |= 1; +} + print_maze(); sub input_dimensions { From 5409fa3daf6d935d74543d8009d722d72cb0f6ba Mon Sep 17 00:00:00 2001 From: Alex Kapranoff Date: Tue, 4 Jan 2022 00:51:54 -0800 Subject: [PATCH 047/331] chmod +x on the Perl script, as is done in #307 --- 02_Amazing/perl/amazing.pl | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 02_Amazing/perl/amazing.pl diff --git a/02_Amazing/perl/amazing.pl b/02_Amazing/perl/amazing.pl old mode 100644 new mode 100755 From ec43a4fc9490c220e76b434c045b3c84198eeefd Mon Sep 17 00:00:00 2001 From: Bastiaan Veelo Date: Mon, 3 Jan 2022 00:19:19 +0100 Subject: [PATCH 048/331] D version of Acey-Ducey. --- 01_Acey_Ducey/d/.gitignore | 2 + 01_Acey_Ducey/d/README.md | 29 ++++++ 01_Acey_Ducey/d/aceyducey.d | 131 ++++++++++++++++++++++++++++ 01_Acey_Ducey/d/aceyducey_literal.d | 104 ++++++++++++++++++++++ 4 files changed, 266 insertions(+) create mode 100644 01_Acey_Ducey/d/.gitignore create mode 100644 01_Acey_Ducey/d/README.md create mode 100644 01_Acey_Ducey/d/aceyducey.d create mode 100644 01_Acey_Ducey/d/aceyducey_literal.d diff --git a/01_Acey_Ducey/d/.gitignore b/01_Acey_Ducey/d/.gitignore new file mode 100644 index 00000000..d969f6b2 --- /dev/null +++ b/01_Acey_Ducey/d/.gitignore @@ -0,0 +1,2 @@ +*.exe +*.obj diff --git a/01_Acey_Ducey/d/README.md b/01_Acey_Ducey/d/README.md new file mode 100644 index 00000000..a45fcb2c --- /dev/null +++ b/01_Acey_Ducey/d/README.md @@ -0,0 +1,29 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html) + +Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo). + +Two versions are supplied that are functionally equivalent, but differ in source layout: + +
+
aceyducey_literal.d
+
A largely literal transcription of the original Basic source. All unnecessary uglyness is preserved.
+
aceyducey.d
+
An idiomatic D refactoring of the original, with a focus on increasing the readability and robustness. + Memory-safety is ensured by the language, thanks to the + @safe annotation.
+
+ +## Running the code + +Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler: +```shell +dmd -run aceyducey.d +``` + +[Other compilers](https://dlang.org/download.html) also exist. + +Note that there are compiler switches related to memory-safety (`-preview=dip25` and `-preview=dip1000`) that are not +used here because they are unnecessary in this case. What these do is to make the analysis more thorough, so that with +them some code that needed to be `@system` can then be inferred to be in fact `@safe`. [Code that compiles without +these switches is just as safe as when compiled with them] +(https://forum.dlang.org/post/dftgjalswvwfjpyushgn@forum.dlang.org). diff --git a/01_Acey_Ducey/d/aceyducey.d b/01_Acey_Ducey/d/aceyducey.d new file mode 100644 index 00000000..036786c5 --- /dev/null +++ b/01_Acey_Ducey/d/aceyducey.d @@ -0,0 +1,131 @@ +@safe: // Make @safe the default for this file, enforcing memory-safety. + +void main() +{ + import std.stdio : write, writeln; + import std.string : center, toUpper, wrap; + import std.exception : ifThrown; + + enum width = 80; + writeln(center("Acey Ducey Card Game", width)); + writeln(center("(After Creative Computing Morristown, New Jersey)\n", width)); + writeln(wrap("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 third card will " ~ + "have a value between the first two. If you do not want to bet, input a 0.", width)); + + enum Hand {low, middle, high} + Card[Hand.max + 1] cards; // Three cards. + bool play = true; + + while (play) + { + int cash = 100; + while (cash > 0) + { + writeln("\nYou now have ", cash, " dollars."); + int bet = 0; + while (bet <= 0) + { + do // Draw new cards, until the first card has a smaller value than the last card. + { + foreach (ref card; cards) + card.drawNew; + } while (cards[Hand.low] >= cards[Hand.high]); + writeln("Here are your next two cards:\n", cards[Hand.low], "\n", cards[Hand.high]); + + int askBet() // A nested function. + { + import std.conv : to; + + write("\nWhat is your bet? "); + int answer = readString.to!int. + ifThrown!Exception(askBet); // Try again when answer does not convert to int. + if (answer <= cash) + return answer; + writeln("Sorry, my friend, but you bet too much.\nYou have only ", cash, " dollars to bet."); + return askBet; // Recurse: Ask again. + } + bet = askBet; + if (bet <= 0) // Negative bets are interpreted as 0. + writeln("CHICKEN!!"); + } // bet is now > 0. + + writeln(cards[Hand.middle]); + if (cards[Hand.low] < cards[Hand.middle] && cards[Hand.middle] < cards[Hand.high]) + { + writeln("YOU WIN!!!"); + cash += bet; + } + else + { + writeln("Sorry, you lose."); + cash -= bet; + if (cash <= 0) + { + writeln("\n\nSorry, friend, but you blew your wad."); + write("\n\nTry again (Yes or No)? "); + play = readString.toUpper == "YES"; + } + } + } + } + writeln("O.K., hope you had fun!"); +} + +struct Card +{ + int value = 2; + alias value this; // Enables Card to stand in as an int, so that cards can be compared as ints. + + invariant + { + assert(2 <= value && value <= 14); // Ensure cards always have a valid value. + } + + /// Adopt a new value. + void drawNew() + { + import std.random : uniform; + + value = uniform!("[]", int, int)(2, 14); // A random int between inclusive bounds. + } + + /// Called for implicit conversion to string. + string toString() const pure + { + import std.conv : text; + + switch (value) + { + case 11: return "Jack"; + case 12: return "Queen"; + case 13: return "King"; + case 14: return "Ace"; + default: return text(" ", value); // Basic prepends a space. + } + } +} + +/// Read a string from standard input, stripping newline and other enclosing whitespace. +string readString() nothrow +{ + import std.string : strip; + + try + return trustedReadln.strip; + catch (Exception) // readln throws on I/O and Unicode errors, which we handle here. + return ""; +} + +/** An @trusted wrapper around readln. + * + * This is the only function that formally requires manual review for memory-safety. + * [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com) + * which would remove the need to have any @trusted code in this program. + */ +string trustedReadln() @trusted +{ + import std.stdio : readln; + + return readln; +} diff --git a/01_Acey_Ducey/d/aceyducey_literal.d b/01_Acey_Ducey/d/aceyducey_literal.d new file mode 100644 index 00000000..a51028de --- /dev/null +++ b/01_Acey_Ducey/d/aceyducey_literal.d @@ -0,0 +1,104 @@ +void main() +{ + import std; + + L10: writef("%26s", ' '); writeln("ACEY DUCEY CARD GAME"); + L20: writef("%15s", ' '); writeln("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + L21: writeln; + L22: writeln; + L30: writeln("ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER "); + L40: writeln("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP"); + L50: writeln("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING"); + L60: writeln("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE"); + L70: writeln("A VALUE BETWEEN THE FIRST TWO."); + L80: writeln("IF YOU DO NOT WANT TO BET, INPUT A 0"); + L100: int N=100; + L110: int Q=100, M; + L120: writeln("YOU NOW HAVE ",Q," DOLLARS."); + L130: writeln; + L140: goto L260; + L210: Q=Q+M; + L220: goto L120; + L240: Q=Q-M; + L250: goto L120; + L260: writeln("HERE ARE YOUR NEXT TWO CARDS: "); + L270: auto A=to!int(14*uniform01)+2; + L280: if (A<2) goto L270; + L290: if (A>14) goto L270; + L300: auto B=to!int(14*uniform01)+2; + L310: if (B<2) goto L300; + L320: if (B>14) goto L300; + L330: if (A>=B) goto L270; + L350: if (A<11) goto L400; + L360: if (A==11) goto L420; + L370: if (A==12) goto L440; + L380: if (A==13) goto L460; + L390: if (A==14) goto L480; + L400: writefln("%2d", A); + L410: goto L500; + L420: writeln("JACK"); + L430: goto L500; + L440: writeln("QUEEN"); + L450: goto L500; + L460: writeln("KING"); + L470: goto L500; + L480: writeln("ACE"); + L500: if (B<11) goto L550; + L510: if (B==11) goto L570; + L520: if (B==12) goto L590; + L530: if (B==13) goto L610; + L540: if (B==14) goto L630; + L550: writefln("%2d", B); + L560: goto L650; + L570: writeln("JACK"); + L580: goto L650; + L590: writeln("QUEEN"); + L600: goto L650; + L610: writeln("KING"); + L620: goto L650; + L630: writeln("ACE"); + L640: writeln; + L650: writeln; + L660: write("WHAT IS YOUR BET? "); M = stdin.readln.strip.to!int; + L670: if (M!=0) goto L680; + L675: writeln("CHICKEN!!"); + L676: writeln; + L677: goto L260; + L680: if (M<=Q) goto L730; + L690: writeln("SORRY, MY FRIEND, BUT YOU BET TOO MUCH."); + L700: writeln("YOU HAVE ONLY ",Q," DOLLARS TO BET."); + L710: goto L650; + L730: auto C=to!int(14*uniform01)+2; + L740: if (C<2) goto L730; + L750: if (C>14) goto L730; + L760: if (C<11) goto L810; + L770: if (C==11) goto L830; + L780: if (C==12) goto L850; + L790: if (C==13) goto L870; + L800: if (C==14) goto L890; + L810: writeln(C); + L820: goto L910; + L830: writeln("JACK"); + L840: goto L910; + L850: writeln("QUEEN"); + L860: goto L910; + L870: writeln("KING"); + L880: goto L910; + L890: writeln( "ACE"); + L900: writeln; + L910: if (C>A) goto L930; + L920: goto L970; + L930: if (C>=B) goto L970; + L950: writeln("YOU WIN!!!"); + L960: goto L210; + L970: writeln("SORRY, YOU LOSE"); + L980: if (M Date: Wed, 5 Jan 2022 00:13:52 +1100 Subject: [PATCH 049/331] Remove exceptions used for standard flow-control - this is an antipattern. --- 53_King/kotlin/King.kt | 158 ++++++++++++++++++++++------------------- 1 file changed, 85 insertions(+), 73 deletions(-) diff --git a/53_King/kotlin/King.kt b/53_King/kotlin/King.kt index 01558c99..8f660357 100644 --- a/53_King/kotlin/King.kt +++ b/53_King/kotlin/King.kt @@ -19,29 +19,25 @@ fun main() { } ?: throw EndOfInputException() - try { - with(gameState) { - while(currentYear < yearsRequired) { - recalculateLandCost() - displayStatus() - inputLandSale() - performLandSale() - inputWelfare() - performWelfare() - inputPlantingArea() - performPlanting() - inputPollutionControl() - if (zeroInput()) { - displayExitMessage() - exitProcess(0) - } - simulateOneYear() - currentYear ++ + with(gameState) { + do { + recalculateLandCost() + displayStatus() + inputLandSale() + performLandSale() + inputWelfare() + performWelfare() + inputPlantingArea() + performPlanting() + inputPollutionControl() + if (zeroInput()) { + displayExitMessage() + exitProcess(0) } - } - win(gameState.yearsRequired) - } catch (e: GameEndingException) { - e.displayConsequences() + val yearResult = simulateOneYear().also { + it.displayConsequences() + } + } while (yearResult == YearOutcome.ContinueNextYear) } } @@ -54,7 +50,8 @@ private fun header() { } fun instructions(yearsRequired: Int) { - println(""" + println( + """ CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS @@ -83,7 +80,7 @@ fun loadOldGame(): GameState = GameState().apply { currentYear = numberInput() if (currentYear <= 0) - throw GameEndingException.DataEntryValidation() + throw DataEntryValidation() if (currentYear >= yearsRequired) { println(" COME ON, YOUR TERM IN OFFICE IS ONLY $yearsRequired YEARS.") @@ -94,19 +91,19 @@ fun loadOldGame(): GameState = GameState().apply { print("HOW MUCH DID YOU HAVE IN THE TREASURY? ") rallods = numberInput() if (rallods < 0) - throw GameEndingException.DataEntryValidation() + throw DataEntryValidation() print("HOW MANY WORKERS? ") foreignWorkers = numberInput() if (foreignWorkers < 0) - throw GameEndingException.DataEntryValidation() + throw DataEntryValidation() do { var retry = false print("HOW MANY SQUARE MILES OF LAND? ") landArea = numberInput() - if (landArea<0) - throw GameEndingException.DataEntryValidation() + if (landArea < 0) + throw DataEntryValidation() if (landArea > 2000 || landArea <= 1000) { println(" COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND") println(" AND 10,000 SQ. MILES OF FOREST LAND.") @@ -118,11 +115,13 @@ fun loadOldGame(): GameState = GameState().apply { /** - * All exceptions which indicate the premature ending of the game, due - * to mismanagement, starvation, revolution, or mis-entry of a game state. + * Possible outcomes for a year. */ -sealed class GameEndingException : Throwable() { - abstract fun displayConsequences() +sealed class YearOutcome { + + open fun displayConsequences() { + // Default display nothing + } fun finalFate() { if (rnd < .5) { @@ -135,7 +134,28 @@ sealed class GameEndingException : Throwable() { println() } - class ExtremeMismanagement(private val death: Int) : GameEndingException() { + object ContinueNextYear : YearOutcome() + + class Win(val yearsRequired: Int) : YearOutcome() { + override fun displayConsequences() { + // The misspelling of "successfully" is in the original code. + println( + """ + + CONGRATULATIONS!!!!!!!!!!!!!!!!!! + YOU HAVE SUCCESFULLY COMPLETED YOUR $yearsRequired 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. + + + """.trimIndent() + ) + } + } + + class ExtremeMismanagement(private val death: Int) : YearOutcome() { override fun displayConsequences() { println() println("$death COUNTRYMEN DIED IN ONE YEAR!!!!!") @@ -151,34 +171,39 @@ sealed class GameEndingException : Throwable() { } } - class TooManyPeopleDead : GameEndingException() { + object TooManyPeopleDead : YearOutcome() { // The mistyping of "population" is in the original game. override fun displayConsequences() { - println(""" + println( + """ OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING) HATE YOUR GUTS. - """.trimIndent()) + """.trimIndent() + ) finalFate() } } - class AntiImmigrationRevolution : GameEndingException() { + object AntiImmigrationRevolution : YearOutcome() { override fun displayConsequences() { - println(""" + println( + """ THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND TAKEN OVER THE COUNTRY. - """.trimIndent()) + """.trimIndent() + ) finalFate() } } - class StarvationWithFullTreasury : GameEndingException() { + object StarvationWithFullTreasury : YearOutcome() { override fun displayConsequences() { - println(""" + println( + """ 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 @@ -186,33 +211,14 @@ sealed class GameEndingException : Throwable() { THE CHOICE IS YOURS. IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER BEFORE PROCEEDING. - """.trimIndent()) + """.trimIndent() + ) } } - class DataEntryValidation : GameEndingException() { - override fun displayConsequences() { - // no action - } - } - - } -fun win(yearsRequired: Int) { - // The misspelling of "successfully" is in the original code. - println(""" - - CONGRATULATIONS!!!!!!!!!!!!!!!!!! - YOU HAVE SUCCESFULLY COMPLETED YOUR $yearsRequired 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. - - - """.trimIndent()) -} +class DataEntryValidation : Throwable() /** * Record data, allow data input, and process the simulation for the game. @@ -444,7 +450,7 @@ class GameState(val yearsRequired: Int = 8) { plantingArea == 0 && moneySpentOnPollutionControl == 0 - fun simulateOneYear() { + fun simulateOneYear(): YearOutcome { rallods -= moneySpentOnPollutionControl val rallodsAfterPollutionControl = rallods @@ -460,7 +466,7 @@ class GameState(val yearsRequired: Int = 8) { https://github.com/coding-horror/basic-computer-games/blob/main/53_King/king.bas#:~:text=1105%20IF%20I/100%3C50%20THEN%201700 */ if (welfareThisYear / 100.0 < 50) - throw GameEndingException.TooManyPeopleDead() + return YearOutcome.TooManyPeopleDead starvationDeaths = (countrymen - (welfareThisYear / 100.0)).toInt() println("$starvationDeaths COUNTRYMEN DIED OF STARVATION") @@ -575,14 +581,20 @@ class GameState(val yearsRequired: Int = 8) { } rallods += tourists - if (death > 200) - throw GameEndingException.ExtremeMismanagement(death) - if (countrymen < 343) - throw GameEndingException.TooManyPeopleDead() - if (rallodsAfterPollutionControl / 100 > 5 && death - pollutionDeaths >= 2) - throw GameEndingException.StarvationWithFullTreasury() - if (foreignWorkers > countrymen) - throw GameEndingException.AntiImmigrationRevolution() + return if (death > 200) + YearOutcome.ExtremeMismanagement(death) + else if (countrymen < 343) + YearOutcome.TooManyPeopleDead + else if (rallodsAfterPollutionControl / 100 > 5 && death - pollutionDeaths >= 2) + YearOutcome.StarvationWithFullTreasury + else if (foreignWorkers > countrymen) + YearOutcome.AntiImmigrationRevolution + else { + if (currentYear++ > yearsRequired) + YearOutcome.Win(yearsRequired) + else + YearOutcome.ContinueNextYear + } } } From 581a3f1441a9a7eed06709560ca1f3be1c00f9e4 Mon Sep 17 00:00:00 2001 From: Martin VanWinkle III Date: Tue, 4 Jan 2022 08:36:37 -0500 Subject: [PATCH 050/331] cleanup --- 31_Depth_Charge/ruby/.gitignore | 57 +++++++++++++++++++++++++++++ 31_Depth_Charge/ruby/depthcharge.rb | 48 ++++-------------------- 2 files changed, 65 insertions(+), 40 deletions(-) create mode 100644 31_Depth_Charge/ruby/.gitignore diff --git a/31_Depth_Charge/ruby/.gitignore b/31_Depth_Charge/ruby/.gitignore new file mode 100644 index 00000000..d25ad7bc --- /dev/null +++ b/31_Depth_Charge/ruby/.gitignore @@ -0,0 +1,57 @@ +# Package Shell Specific Things + +## Build Process + +/build + +## Transient files + +/src/input +/src/output +/src/log +/drop + +# Programming Languages + +## Java +/src/java/**/*.class + +## Rakudo / Perl6 +/src/**/.precomp + +## PHP +/vendor/ + +## Python +*.swp +__pycache__/ +*.pyc +*.egg-info +/dist + +## Ruby +*.gem +.bundle + +# Editors + +## Dia +*.dia.autosave + +## Emacs +\#*\# +.\#* + + +## Vi / Vim +*.swp + +# Filesystem Artifacts + +## Mac + +.DS_Store + +## NFS + +.nfs* diff --git a/31_Depth_Charge/ruby/depthcharge.rb b/31_Depth_Charge/ruby/depthcharge.rb index 5ba36ba6..ba2a5d83 100755 --- a/31_Depth_Charge/ruby/depthcharge.rb +++ b/31_Depth_Charge/ruby/depthcharge.rb @@ -13,7 +13,6 @@ class DepthCharge break if ! get_input_another_game() end - # 420 PRINT "OK. HOPE YOU ENJOYED YOURSELF." : GOTO 600 printf("OK. HOPE YOU ENJOYED YOURSELF.\n") end @@ -51,7 +50,7 @@ class DepthCharge the_input = Integer(value) rescue nil - if the_input == nil || the_input < 0 + if the_input == nil || the_input < 1 printf("PLEASE ENTER A POSITIVE NUMBER\n\n") next @@ -61,25 +60,7 @@ class DepthCharge end end - def get_search_area_dimension - # 20 INPUT "DIMENSION OF SEARCH AREA";G: PRINT - @search_area_dimension = get_input_positive_integer("DIMENSION OF SEARCH AREA: ") - # 30 N=INT(LOG(G)/LOG(2))+1 - - @num_tries = Integer( - Math.log(@search_area_dimension)/Math.log(2) - ) - - end - def print_instructions - # 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 printf( <<~INSTRUCTIONS YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR @@ -110,19 +91,21 @@ GOOD LUCK ! end def setup_game - get_search_area_dimension() + @search_area_dimension = get_input_positive_integer("DIMENSION OF SEARCH AREA: ") + + @num_tries = Integer( + Math.log(@search_area_dimension)/Math.log(2) + 1 + ) setup_enemy() end def setup_enemy - # 110 A=INT(G*RND(1)) : B=INT(G*RND(1)) : C=INT(G*RND(1)) @enemy_x = rand(1..@search_area_dimension) @enemy_y = rand(1..@search_area_dimension) @enemy_z = rand(1..@search_area_dimension) - end + end def game_loop - # 120 FOR D=1 TO N : PRINT : PRINT "TRIAL #";D; : INPUT X,Y,Z for @trial in 1..@num_tries do output_game_status() @@ -130,7 +113,6 @@ GOOD LUCK ! @shot_y = get_input_positive_integer("Y: ") @shot_z = get_input_positive_integer("Z: ") - # 130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300 if ( (@enemy_x - @shot_x).abs \ + (@enemy_y - @shot_y).abs \ @@ -140,7 +122,6 @@ GOOD LUCK ! you_win() return else - # 140 GOSUB 500 : PRINT : NEXT D missed_shot() end end @@ -156,54 +137,41 @@ GOOD LUCK ! printf("TRIAL \#%d\n", @trial) end def you_win - printf("B O O M ! ! YOU FOUND IT IN %d TRIES!\n\n", @trial ) + printf("\nB O O M ! ! YOU FOUND IT IN %d TRIES!\n\n", @trial ) end def missed_shot missed_directions = [] - # 530 IF X>A THEN PRINT "EAST"; - # 540 IF X @enemy_x missed_directions.push('TOO FAR EAST') elsif @shot_x < @enemy_x missed_directions.push('TOO FAR WEST') end - # 510 IF Y>B THEN PRINT "NORTH"; - # 520 IF Y @enemy_y missed_directions.push('TOO FAR NORTH') elsif @shot_y < @enemy_y missed_directions.push('TOO FAR SOUTH') end - # 560 IF Z>C THEN PRINT " TOO LOW." - # 570 IF Z @enemy_z missed_directions.push('TOO DEEP') elsif @shot_z < @enemy_z missed_directions.push('TOO SHALLOW') end - # 500 PRINT "SONAR REPORTS SHOT WAS "; printf("SONAR REPORTS SHOT WAS: \n") printf("%s\n", "\t" + missed_directions.join("\n\t")) - # 550 IF Y<>B OR X<>A THEN PRINT " AND"; - # 590 RETURN end def you_lose - # You took too long! printf("YOU HAVE BEEN TORPEDOED! ABANDON SHIP!\n") printf("THE SUBMARINE WAS AT %d %d %d\n", @enemy_x, @enemy_y, @enemy_z) end def get_input_another_game - # 400 PRINT : PRINT: INPUT "ANOTHER GAME (Y OR N)";A$ return get_input_y_or_n("ANOTHER GAME (Y OR N): ") - # 410 IF A$="Y" THEN 100 end end From ec6dfd4bc3a1dca54553905a268828ac69751724 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Wed, 5 Jan 2022 01:24:08 +1100 Subject: [PATCH 051/331] Bug fix - restoring game did not enter countrymen Refactor - Added validatedInput function --- 53_King/kotlin/King.kt | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/53_King/kotlin/King.kt b/53_King/kotlin/King.kt index 8f660357..f16f24e5 100644 --- a/53_King/kotlin/King.kt +++ b/53_King/kotlin/King.kt @@ -77,10 +77,7 @@ fun loadOldGame(): GameState = GameState().apply { do { var retry = false print("HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED? ") - currentYear = numberInput() - - if (currentYear <= 0) - throw DataEntryValidation() + currentYear = validatedInput { it > 0 } if (currentYear >= yearsRequired) { println(" COME ON, YOUR TERM IN OFFICE IS ONLY $yearsRequired YEARS.") @@ -89,21 +86,19 @@ fun loadOldGame(): GameState = GameState().apply { } while (retry) print("HOW MUCH DID YOU HAVE IN THE TREASURY? ") - rallods = numberInput() - if (rallods < 0) - throw DataEntryValidation() + rallods = validatedInput { it >= 0 } + + print("HOW MANY COUNTRYMEN? ") + countrymen = validatedInput { it >= 0 } print("HOW MANY WORKERS? ") - foreignWorkers = numberInput() - if (foreignWorkers < 0) - throw DataEntryValidation() + foreignWorkers = validatedInput { it >= 0 } do { var retry = false print("HOW MANY SQUARE MILES OF LAND? ") - landArea = numberInput() - if (landArea < 0) - throw DataEntryValidation() + landArea = validatedInput { it >= 0 } + if (landArea > 2000 || landArea <= 1000) { println(" COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND") println(" AND 10,000 SQ. MILES OF FOREST LAND.") @@ -218,13 +213,10 @@ sealed class YearOutcome { } -class DataEntryValidation : Throwable() - /** * Record data, allow data input, and process the simulation for the game. */ class GameState(val yearsRequired: Int = 8) { - /** * The current year. Years start with zero, but we never * output the current year. @@ -246,8 +238,8 @@ class GameState(val yearsRequired: Int = 8) { private var tourists = 0 private var moneySpentOnPollutionControl = 0 - private var moneySpentOnPlanting = 0 + private var moneySpentOnPlanting = 0 /** * Current stock of rallods. * Player starts with between 59000 and 61000 rallods, but @@ -258,10 +250,10 @@ class GameState(val yearsRequired: Int = 8) { /** * Population. - * Initial population is about to 500. + * Initial population is about 500. * 75% of the time it's between 495 and 505. */ - private var countrymen = (500 + (10 * rnd) - (10 * rnd)).toInt() + var countrymen = (500 + (10 * rnd) - (10 * rnd)).toInt() /** * Land sale price is evenly between 95 and 104 rallods per @@ -271,8 +263,8 @@ class GameState(val yearsRequired: Int = 8) { private var landPrice = (10 * rnd + 95).toInt() private var plantingArea = 0 - private var welfareThisYear = 0 + private var welfareThisYear = 0 /** * Land area in square miles. Arable land is 1000 square miles less. * Almost all calculations use landArea-1000 because only arable @@ -345,7 +337,6 @@ class GameState(val yearsRequired: Int = 8) { rallods -= welfareThisYear } - /** * Ask how much land we want to sell. Immediately get the money. * The player has to do the calculations to work out how much @@ -368,6 +359,7 @@ class GameState(val yearsRequired: Int = 8) { } while (sellThisYear < 0 || sellThisYear > landArea - 1000) } + /** * Input the value of `welfareThisYear` */ @@ -599,14 +591,12 @@ class GameState(val yearsRequired: Int = 8) { } } - private fun numberInput() = try { readLine()?.toInt() ?: throw EndOfInputException() } catch (r: NumberFormatException) { 0 } - - - - +class DataEntryValidationException : Throwable() +private fun validatedInput(predicate : (Int)->Boolean) = + numberInput().apply { if (!predicate(this)) throw DataEntryValidationException() } From bd0e7049149efb70999efe670a9926e91579cedd Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Wed, 5 Jan 2022 01:30:39 +1100 Subject: [PATCH 052/331] Update README.md --- 53_King/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/53_King/README.md b/53_King/README.md index 206202f0..4542f90c 100644 --- a/53_King/README.md +++ b/53_King/README.md @@ -8,6 +8,8 @@ The money system is Rollods; each person needs 100 Rallods per year to survive. The author of this program is James A. Storer who wrote it while a student at Lexington High School. +⚠️ This game includes references to suicide or self-harm. + ## Bugs Implementers should be aware that this game contains at least one bug. From 46baddd24c2bc487c970344e88981c048dce09d2 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Wed, 5 Jan 2022 01:33:41 +1100 Subject: [PATCH 053/331] change headings --- 53_King/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/53_King/README.md b/53_King/README.md index 206202f0..f97e7b33 100644 --- a/53_King/README.md +++ b/53_King/README.md @@ -1,4 +1,4 @@ -### King +## King This is one of the most comprehensive, difficult, and interesting games. (If you’ve never played one of these games, start with HAMMURABI.) @@ -8,7 +8,7 @@ The money system is Rollods; each person needs 100 Rallods per year to survive. The author of this program is James A. Storer who wrote it while a student at Lexington High School. -## Bugs +### Bugs Implementers should be aware that this game contains at least one bug. From 703b410f2e8a80e294a0ab2d11ea06c559e322bc Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 4 Jan 2022 10:03:48 -0500 Subject: [PATCH 054/331] Create High_IQ.py --- 48_High_IQ/python/High_IQ.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 48_High_IQ/python/High_IQ.py diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/48_High_IQ/python/High_IQ.py @@ -0,0 +1 @@ + From c744cd928247fd0059dad04645667fe6dc74446c Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Wed, 5 Jan 2022 02:09:38 +1100 Subject: [PATCH 055/331] Remove suicide reference by default --- 53_King/kotlin/King.kt | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/53_King/kotlin/King.kt b/53_King/kotlin/King.kt index f16f24e5..71e6d505 100644 --- a/53_King/kotlin/King.kt +++ b/53_King/kotlin/King.kt @@ -3,7 +3,8 @@ import kotlin.random.Random import kotlin.system.exitProcess lateinit var gameState: GameState -const val INCLUDE_BUGS_FROM_ORIGINAL = false +const val KEEP_ORIGINAL_BUGS = false +const val KEEP_ORIGINAL_SUICIDE_REFERENCE = false val rnd: Double get() = Random.nextDouble() fun tab(i: Int) = " ".repeat(i) @@ -198,15 +199,26 @@ sealed class YearOutcome { object StarvationWithFullTreasury : YearOutcome() { override fun displayConsequences() { println( - """ - 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. - """.trimIndent() + if (KEEP_ORIGINAL_SUICIDE_REFERENCE) { + """ + 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. + """.trimIndent() + } else { + """ + 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. + PLEASE TURN OFF YOUR COMPUTER AND SURRENDER IT TO + THE NEAREST POLICE STATION. + """.trimIndent() + } ) } } @@ -566,7 +578,7 @@ class GameState(val yearsRequired: Int = 8) { https://github.com/coding-horror/basic-computer-games/blob/main/53_King/king.bas#:~:text=1450%20V3%3DINT,INT(A%2BV3) */ - if (INCLUDE_BUGS_FROM_ORIGINAL) { + if (KEEP_ORIGINAL_BUGS) { tourists += rallods } else { tourists = abs(v1 - v2) From d16cc8d6d9f21053a37ae4a89555b5a8ed6448aa Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Wed, 5 Jan 2022 02:17:22 +1100 Subject: [PATCH 056/331] Warning for suicide references --- 76_Russian_Roulette/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/76_Russian_Roulette/README.md b/76_Russian_Roulette/README.md index cf1b64fc..5ec8148e 100644 --- a/76_Russian_Roulette/README.md +++ b/76_Russian_Roulette/README.md @@ -4,6 +4,8 @@ In this game, you are given by the computer a revolver loaded with one bullet an Tom Adametx wrote this program while a student at Curtis Jr. High School in Sudbury, Massachusetts. +⚠️ This game includes EXPLICT references to suicide, and should not be included in most distributions, especially considering the extreme simplicity of the program. + --- As published in Basic Computer Games (1978): From a05a1fedf37285e5e087138f3a529a2879d7f888 Mon Sep 17 00:00:00 2001 From: "christopher.millward" Date: Tue, 4 Jan 2022 10:40:59 -0500 Subject: [PATCH 057/331] War refactor and cleanup --- 94_War/javascript/war.js | 228 ++++++++++++++++++++++----------------- 1 file changed, 128 insertions(+), 100 deletions(-) diff --git a/94_War/javascript/war.js b/94_War/javascript/war.js index eb74fb0c..bdc935bc 100644 --- a/94_War/javascript/war.js +++ b/94_War/javascript/war.js @@ -1,60 +1,95 @@ // WAR // -// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess) +// Original conversion from BASIC to Javascript by Oscar Toledo G. (nanochess) // -function print(str) -{ +function print(str) { document.getElementById("output").appendChild(document.createTextNode(str)); } -function input() -{ - var input_element; - var input_str; - - return new Promise(function (resolve) { - 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_str = undefined; - input_element.addEventListener("keydown", function (event) { - if (event.keyCode == 13) { - input_str = input_element.value; - document.getElementById("output").removeChild(input_element); - print(input_str); - print("\n"); - resolve(input_str); - } - }); - }); -} - -function tab(space) -{ - var str = ""; - while (space-- > 0) +function tab(space) { + let str = ""; + while (space-- > 0) { str += " "; + } return str; } -var a = [, "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"]; +function input() { + return new Promise(function (resolve) { + const input_element = document.createElement("INPUT"); -var l = []; + 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); + } + }); + }); +} -// Main control section -async function main() -{ +async function askYesOrNo(question) { + while (1) { + print(question); + const str = await input(); + if (str == "YES") { + return true; + } + else if (str == "NO") { + return false; + } + else { + print("YES OR NO, PLEASE. "); + } + } +} + +async function askAboutInstructions() { + const playerWantsInstructions = await askYesOrNo("DO YOU WANT DIRECTIONS"); + if (playerWantsInstructions) { + print("THE COMPUTER GIVES YOU AND IT A 'CARD'. THE HIGHER CARD\n"); + print("(NUMERICALLY) WINS. THE GAME ENDS WHEN YOU CHOOSE NOT TO\n"); + print("CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\n"); + } + print("\n"); + print("\n"); +} + +function createGameDeck(cards, gameSize) { + const deck = []; + const deckSize = cards.length; + for (let j = 0; j < gameSize; j++) { + let card; + + // Compute a new card index until we find one that isn't already in the new deck + do { + card = Math.floor(deckSize * Math.random()); + } while (deck.includes(card)); + deck[j] = card + } + return deck; +} + +function computeCardValue(cardIndex) { + return Math.floor(cardIndex / 4); +} + +function printGameOver(playerScore, computerScore) { + print("\n"); + print("\n"); + print(`WE HAVE RUN OUT OF CARDS. FINAL SCORE: YOU: ${playerScore} THE COMPUTER: ${computerScore}\n`); + print("\n"); +} + +function printTitle() { print(tab(33) + "WAR\n"); print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"); print("\n"); @@ -62,72 +97,65 @@ async function main() print("\n"); print("THIS IS THE CARD GAME OF WAR. EACH CARD IS GIVEN BY SUIT-#\n"); print("AS S-7 FOR SPADE 7. "); - while (1) { - print("DO YOU WANT DIRECTIONS"); - str = await input(); - if (str == "YES") { - print("THE COMPUTER GIVES YOU AND IT A 'CARD'. THE HIGHER CARD\n"); - print("(NUMERICALLY) WINS. THE GAME ENDS WHEN YOU CHOOSE NOT TO\n"); - print("CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\n"); - break; - } - if (str == "NO") - break; - print("YES OR NO, PLEASE. "); - } - print("\n"); +} + +function printCards(playerCard, computerCard) { print("\n"); + print(`YOU: ${playerCard}\tCOMPUTER: ${computerCard}\n`); +} + +const 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" +]; + +// Main control section +async function main() { + printTitle(); + await askAboutInstructions(); - a1 = 0; - b1 = 0; - p = 0; + let computerScore = 0; + let playerScore = 0; // Generate a random deck - for (j = 1; j <= 52; j++) { - do { - l[j] = Math.floor(52 * Math.random()) + 1; - for (k = 1; k < j; k++) { - if (l[k] == l[j]) // Already in deck? - break; - } - } while (j != 1 && k < j) ; - } - l[j] = 0; // Mark the end of the deck + const gameSize = 4; + const deck = createGameDeck(cards, gameSize); + let shouldContinuePlaying = true; - while (1) { - m1 = l[++p]; // Take a card - m2 = l[++p]; // Take a card - print("\n"); - print("YOU: " + a[m1] + "\tCOMPUTER: " + a[m2] + "\n"); - n1 = Math.floor((m1 - 0.5) / 4); - n2 = Math.floor((m2 - 0.5) / 4); - if (n1 < n2) { - a1++; - print("THE COMPUTER WINS!!! YOU HAVE " + b1 + " AND THE COMPUTER HAS " + a1 + "\n"); - } else if (n1 > n2) { - b1++; - print("YOU WIN. YOU HAVE " + b1 + " AND THE COMPUTER HAS " + a1 + "\n"); + while (deck.length > 0 && shouldContinuePlaying) { + const m1 = deck.shift(); // Take a card + const m2 = deck.shift(); // Take a card + printCards(cards[m1], cards[m2]); + + const playerCardValue = computeCardValue(m1); + const computerCardValue = computeCardValue(m2); + if (playerCardValue < computerCardValue) { + computerScore++; + print("THE COMPUTER WINS!!! YOU HAVE " + playerScore + " AND THE COMPUTER HAS " + computerScore + "\n"); + } else if (playerCardValue > computerCardValue) { + playerScore++; + print("YOU WIN. YOU HAVE " + playerScore + " AND THE COMPUTER HAS " + computerScore + "\n"); } else { print("TIE. NO SCORE CHANGE.\n"); } - if (l[p + 1] == 0) { - print("\n"); - print("\n"); - print("WE HAVE RUN OUT OF CARDS. FINAL SCORE: YOU: " + b1 + " THE COMPUTER: " + a1 + "\n"); - print("\n"); - break; + + if (deck.length === 0) { + printGameOver(playerScore, computerScore); } - while (1) { - print("DO YOU WANT TO CONTINUE"); - str = await input(); - if (str == "YES") - break; - if (str == "NO") - break; - print("YES OR NO, PLEASE. "); + else { + shouldContinuePlaying = await askYesOrNo("DO YOU WANT TO CONTINUE"); } - if (str == "NO") - break; } print("THANKS FOR PLAYING. IT WAS FUN.\n"); print("\n"); From fe6ff50d2f5d18c32dc71548b2b969de67e3ada8 Mon Sep 17 00:00:00 2001 From: "christopher.millward" Date: Tue, 4 Jan 2022 10:44:48 -0500 Subject: [PATCH 058/331] Updated documentation and used push() --- 94_War/javascript/war.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/94_War/javascript/war.js b/94_War/javascript/war.js index bdc935bc..965294a6 100644 --- a/94_War/javascript/war.js +++ b/94_War/javascript/war.js @@ -73,7 +73,7 @@ function createGameDeck(cards, gameSize) { do { card = Math.floor(deckSize * Math.random()); } while (deck.includes(card)); - deck[j] = card + deck.push(card); } return deck; } @@ -129,7 +129,7 @@ async function main() { let playerScore = 0; // Generate a random deck - const gameSize = 4; + const gameSize = cards.length; // Number of cards to shuffle into the game deck. Can be <= cards.length. const deck = createGameDeck(cards, gameSize); let shouldContinuePlaying = true; From a6957caed0aba39c52d4d2e520aa7abf9926fdea Mon Sep 17 00:00:00 2001 From: "christopher.millward" Date: Tue, 4 Jan 2022 10:46:44 -0500 Subject: [PATCH 059/331] Removed last of the single-letter variables --- 94_War/javascript/war.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/94_War/javascript/war.js b/94_War/javascript/war.js index 965294a6..ededa1ed 100644 --- a/94_War/javascript/war.js +++ b/94_War/javascript/war.js @@ -134,12 +134,12 @@ async function main() { let shouldContinuePlaying = true; while (deck.length > 0 && shouldContinuePlaying) { - const m1 = deck.shift(); // Take a card - const m2 = deck.shift(); // Take a card - printCards(cards[m1], cards[m2]); + const playerCard = deck.shift(); // Take a card + const computerCard = deck.shift(); // Take a card + printCards(cards[playerCard], cards[computerCard]); - const playerCardValue = computeCardValue(m1); - const computerCardValue = computeCardValue(m2); + const playerCardValue = computeCardValue(playerCard); + const computerCardValue = computeCardValue(computerCard); if (playerCardValue < computerCardValue) { computerScore++; print("THE COMPUTER WINS!!! YOU HAVE " + playerScore + " AND THE COMPUTER HAS " + computerScore + "\n"); From 24313121ca9d0d61b038776f8ee94e74f9497f62 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 4 Jan 2022 12:00:29 -0500 Subject: [PATCH 060/331] Started python function layout Totally not doing this through github.com --- 48_High_IQ/python/High_IQ.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 8b137891..237454b3 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -1 +1,13 @@ +def print_instructions(): + print("This is where you will find instructions") + +def play_game(): + print("Lets play a game") + +def main(): + if input("Do you want instrunctions?").lower().startswith("y"): + print_instructions() + +if __name__ == "__main__": + main() From 05f597b12c1518da66b104fca8875aaf6ad00bd9 Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Tue, 4 Jan 2022 14:37:22 -0300 Subject: [PATCH 061/331] Added Calendar first implementation it has some formatting problems --- 21_Calendar/python/calendar.py | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 21_Calendar/python/calendar.py diff --git a/21_Calendar/python/calendar.py b/21_Calendar/python/calendar.py new file mode 100644 index 00000000..6f3cb191 --- /dev/null +++ b/21_Calendar/python/calendar.py @@ -0,0 +1,69 @@ + +def calendar(weekday, leap_year): + """ + function to print a year's calendar. + + input: + _weekday_: int - the initial day of the week (0=SUN, -1=MON, -2=TUES...) + _leap_year_: bool - indicates if the year is a leap year + """ + months_days = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] + days = ' S M T W T F S' + sep = "*" * 59 + years_day = 365 + d = weekday + + if leap_year: + months_days[2] = 29 + years_day = 366 + + months_names = [" JANUARY ", + " FEBRUARY", + " MARCH ", + " APRIL ", + " MAY ", + " JUNE ", + " JULY ", + " AUGUST ", + "SEPTEMBER", + " OCTOBER ", + " NOVEMBER", + " DECEMBER"] + + print(" "*32 + "CALENDAR") + print(" "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + + days_count = 0 # S in the original program + + # main loop + for n in range(1, 13): + days_count += months_days[n-1] + print("** {} ****************** {} ****************** {} **".format(days_count, + months_names[n-1], years_day-days_count)) + print(days) + print(sep) + print("\n") + + for w in range(1, 7): + print("\n") + for g in range(1, 8): + d += 1 + d2 = d - days_count + + if d2 > months_days[n]: + break + + if d2 > 0: + print("{}".format(d2),end=' ') + else: + print("{}".format(''),end=' ') + if d2 >= months_days[n]: + break + + if d2 > months_days[n]: + d -= g + + print("\n") + +if __name__ == "__main__": + calendar(-1, False) \ No newline at end of file From 1b81994c4a00ffc2b60e5d70813482bbd557fa47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Tue, 4 Jan 2022 17:59:28 +0000 Subject: [PATCH 062/331] Add Perl version of 25_Chief --- 25_Chief/perl/chief.pl | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 25_Chief/perl/chief.pl diff --git a/25_Chief/perl/chief.pl b/25_Chief/perl/chief.pl new file mode 100644 index 00000000..d3462514 --- /dev/null +++ b/25_Chief/perl/chief.pl @@ -0,0 +1,69 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +print ' ' x 30 . "CHIEF\n"; +print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n\n\n"; + +print "I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD.\n"; +print "ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR?\n"; + +chomp( my $A = uc ); +print "SHUT UP, PALE FACE WITH WISE TONGUE.\n" unless ( $A eq 'YES' ); + +print " TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND\n"; +print "MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1.\n"; +print " WHAT DO YOU HAVE?\n"; + +chomp( my $B = ); +my $C = ( $B + 1 - 5 ) * 5 / 8 * 5 - 3; + +print "I BET YOUR NUMBER WAS $C. AM I RIGHT?\n"; + +chomp( my $D = uc ); +if ( $D eq 'YES' ) { + print "BYE!!!\n"; + exit; +} + +print "WHAT WAS YOUR ORIGINAL NUMBER?\n"; + +chomp( my $K = ); +my $F = $K + 3; +my $G = $F / 5; +my $H = $G * 8; +my $I = $H / 5 + 5; +my $J = $I - 1; + +print "SO YOU THINK YOU'RE SO SMART, EH?\n"; +print "NOW WATCH.\n"; +print "$K PLUS 3 EQUALS $F. THIS DIVIDED BY 5 EQUALS $G;\n"; +print "THIS TIMES 8 EQUALS $H. IF WE DIVIDE BY 5 AND ADD 5,\n"; +print "WE GET $I , WHICH, MINUS 1, EQUALS $J.\n"; +print "NOW DO YOU BELIEVE ME?\n"; + +chomp( my $Z = uc ); +if ( $Z eq 'YES' ) { + print "BYE!!!\n"; + exit; +} + +print "YOU HAVE MADE ME MAD!!!\n"; +print "THERE MUST BE A GREAT LIGHTNING BOLT!\n\n\n"; + +for my $i ( reverse 22 .. 30 ) { + print ' ' x $i . "X X\n"; +} +print ' ' x 21 . "X XXX\n"; +print ' ' x 20 . "X X\n"; +print ' ' x 19 . "XX X\n"; +for my $i ( reverse 13 .. 20 ) { + print ' ' x $i . "X X\n"; +} +print ' ' x 12 . "XX\n"; +print ' ' x 11 . "X\n"; +print ' ' x 10 . "*\n"; +print "\n#########################\n\n"; +print "I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!\n"; From a8f0bb10c6fe8acfcfb5c5cb59fd35370292d566 Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Tue, 4 Jan 2022 15:10:08 -0300 Subject: [PATCH 063/331] formatting text updated --- 21_Calendar/python/calendar.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/21_Calendar/python/calendar.py b/21_Calendar/python/calendar.py index 6f3cb191..6c803771 100644 --- a/21_Calendar/python/calendar.py +++ b/21_Calendar/python/calendar.py @@ -8,7 +8,7 @@ def calendar(weekday, leap_year): _leap_year_: bool - indicates if the year is a leap year """ months_days = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] - days = ' S M T W T F S' + days = 'S M T W T F S\n' sep = "*" * 59 years_day = 365 d = weekday @@ -32,17 +32,16 @@ def calendar(weekday, leap_year): print(" "*32 + "CALENDAR") print(" "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - + print("\n"*11) days_count = 0 # S in the original program # main loop for n in range(1, 13): days_count += months_days[n-1] - print("** {} ****************** {} ****************** {} **".format(days_count, + print("** {} ****************** {} ****************** {} **\n".format(days_count, months_names[n-1], years_day-days_count)) print(days) print(sep) - print("\n") for w in range(1, 7): print("\n") @@ -54,9 +53,13 @@ def calendar(weekday, leap_year): break if d2 > 0: - print("{}".format(d2),end=' ') + if d2 < 10: + print(" {}".format(d2), end=' ') + else: + print("{}".format(d2), end=' ') else: - print("{}".format(''),end=' ') + print("{}".format(' '), end=' ') + if d2 >= months_days[n]: break @@ -65,5 +68,6 @@ def calendar(weekday, leap_year): print("\n") + if __name__ == "__main__": - calendar(-1, False) \ No newline at end of file + calendar(-6, False) From 873ca419e1846ab5e49e350f181a408875eb51fb Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Tue, 4 Jan 2022 15:12:41 -0300 Subject: [PATCH 064/331] formatting logic updated --- 21_Calendar/python/calendar.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/21_Calendar/python/calendar.py b/21_Calendar/python/calendar.py index 6c803771..c90b1b62 100644 --- a/21_Calendar/python/calendar.py +++ b/21_Calendar/python/calendar.py @@ -39,7 +39,7 @@ def calendar(weekday, leap_year): for n in range(1, 13): days_count += months_days[n-1] print("** {} ****************** {} ****************** {} **\n".format(days_count, - months_names[n-1], years_day-days_count)) + months_names[n-1], years_day-days_count)) print(days) print(sep) @@ -52,13 +52,12 @@ def calendar(weekday, leap_year): if d2 > months_days[n]: break - if d2 > 0: - if d2 < 10: - print(" {}".format(d2), end=' ') - else: - print("{}".format(d2), end=' ') - else: + if d2 <= 0: print("{}".format(' '), end=' ') + elif d2 < 10: + print(" {}".format(d2), end=' ') + else: + print("{}".format(d2), end=' ') if d2 >= months_days[n]: break From 6517975e250a0fa4f3d84936498877a5dd6a0f24 Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Tue, 4 Jan 2022 15:15:02 -0300 Subject: [PATCH 065/331] Updated formatting to look like the original program --- 21_Calendar/python/calendar.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/21_Calendar/python/calendar.py b/21_Calendar/python/calendar.py index c90b1b62..b59d09f4 100644 --- a/21_Calendar/python/calendar.py +++ b/21_Calendar/python/calendar.py @@ -58,6 +58,7 @@ def calendar(weekday, leap_year): print(" {}".format(d2), end=' ') else: print("{}".format(d2), end=' ') + print() if d2 >= months_days[n]: break @@ -67,6 +68,8 @@ def calendar(weekday, leap_year): print("\n") + print("\n") + if __name__ == "__main__": calendar(-6, False) From 9b44692b8ccaa3fca3dee78781b006ce67b660ec Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Tue, 4 Jan 2022 15:31:16 -0300 Subject: [PATCH 066/331] Added parse function for starting day of the week of the year and boolean to check if it's a leap year structured code --- 21_Calendar/python/calendar.py | 56 +++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/21_Calendar/python/calendar.py b/21_Calendar/python/calendar.py index b59d09f4..63c2741f 100644 --- a/21_Calendar/python/calendar.py +++ b/21_Calendar/python/calendar.py @@ -1,4 +1,46 @@ +def parse_input(): + """ + function to parse input for weekday and leap year boolean + """ + + days_mapping = { + "sunday": 0, + "monday": -1, + "tuesday": -2, + "wednesday": -3, + "thursday": -4, + "friday": -5, + "saturday": -6 + } + + day = 0 + leap_day = False + + correct_day_input = False + while not correct_day_input: + weekday = input("INSERT THE STARTING DAY OF THE WEEK OF THE YEAR:") + + for day_k in days_mapping.keys(): + if weekday.lower() in day_k: + day = days_mapping[day_k] + correct_day_input = True + break + + while True: + leap = input("IS IT A LEAP YEAR?:") + + if 'y' in leap.lower(): + leap_day = True + break + + if 'n' in leap.lower(): + leap_day = False + break + + return day, leap_day + + def calendar(weekday, leap_year): """ function to print a year's calendar. @@ -30,9 +72,6 @@ def calendar(weekday, leap_year): " NOVEMBER", " DECEMBER"] - print(" "*32 + "CALENDAR") - print(" "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") - print("\n"*11) days_count = 0 # S in the original program # main loop @@ -71,5 +110,14 @@ def calendar(weekday, leap_year): print("\n") +def main(): + print(" "*32 + "CALENDAR") + print(" "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print("\n"*11) + + day, leap_year = parse_input() + calendar(day, leap_year) + + if __name__ == "__main__": - calendar(-6, False) + main() From f673a3740f0bac5552e9359f8a7072e759558c69 Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Tue, 4 Jan 2022 15:45:12 -0300 Subject: [PATCH 067/331] Added porting notes and original program commentary --- 21_Calendar/python/calendar.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/21_Calendar/python/calendar.py b/21_Calendar/python/calendar.py index 63c2741f..6f3f572b 100644 --- a/21_Calendar/python/calendar.py +++ b/21_Calendar/python/calendar.py @@ -1,3 +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. +# +######################################################## def parse_input(): """ @@ -121,3 +142,15 @@ def main(): if __name__ == "__main__": main() + +######################################################## +# +######################################################## +# +# Porting notes: +# +# It has been added an input at the beginning of the +# program so the user can specify the first day of the +# week of the year and if the year is leap or not. +# +######################################################## From 89ffbe6c6d0070f91523618aecc9f5f128c69001 Mon Sep 17 00:00:00 2001 From: a2wd Date: Tue, 4 Jan 2022 19:51:10 +0100 Subject: [PATCH 068/331] Added instruction on how to run the games --- HOW_TO_RUN_THE_GAMES.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 HOW_TO_RUN_THE_GAMES.md diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md new file mode 100644 index 00000000..e69de29b From 40935505006bea529956b5e17e8708b7f48c3e6e Mon Sep 17 00:00:00 2001 From: Alito Date: Tue, 4 Jan 2022 19:57:29 +0100 Subject: [PATCH 069/331] Updated HOW_TO_RUN_THE_GAMES.md Added a new line to improve formatting around the note on the python environments. --- HOW_TO_RUN_THE_GAMES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md index 6de43c98..96533226 100644 --- a/HOW_TO_RUN_THE_GAMES.md +++ b/HOW_TO_RUN_THE_GAMES.md @@ -67,6 +67,7 @@ The python translations can be run from the command line by using the `py` inter * eg. `python aceyducey.py` **Note** + 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/). @@ -81,4 +82,4 @@ 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`. \ No newline at end of file +Follow the same steps as for the [csharp](#csharp) translations. This can be run with `dotnet` or `Visual Studio`. From 990eb9915cc2a09e2880b7c4a51138c537b6bc58 Mon Sep 17 00:00:00 2001 From: Alito Date: Tue, 4 Jan 2022 19:58:48 +0100 Subject: [PATCH 070/331] Updated HOW_TO_RUN_THE_GAMES.md Fixed a typo (missing 'c' in the ruby project link text). --- HOW_TO_RUN_THE_GAMES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md index 96533226..44d82e98 100644 --- a/HOW_TO_RUN_THE_GAMES.md +++ b/HOW_TO_RUN_THE_GAMES.md @@ -74,7 +74,7 @@ You can manage and use different versions of python with [pip](https://pypi.org/ ## ruby -If you don't already have a ruby interpreter, you can download it from the [ruby projet site](https://www.ruby-lang.org/en/). +If you don't already have a ruby interpreter, you can download it from the [ruby project site](https://www.ruby-lang.org/en/). 1. From the command-line, navigate to the corresponding directory. 1. Invoke with the `ruby` tool. From 651ae5fa8e8600d0679a303f5e549150fc4de077 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 4 Jan 2022 13:59:37 -0500 Subject: [PATCH 071/331] Added Instructions --- 48_High_IQ/python/High_IQ.py | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 237454b3..90dd756a 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -1,12 +1,39 @@ def print_instructions(): - print("This is where you will find instructions") - + print("\n" * 3) + print("HERE IS THE BOARD:\n") + print("\n") + print(" ! ! !\n") + print(" 13 14 15\n") + print("\n") + print(" ! ! !\n") + print(" 22 23 24\n") + print("\n") + print("! ! ! ! ! ! !\n") + print("29 30 31 32 33 34 35\n") + print("\n") + print("! ! ! ! ! ! !\n") + print("38 39 40 41 42 43 44\n") + print("\n") + print("! ! ! ! ! ! !\n") + print("47 48 49 50 51 52 53\n") + print("\n") + print(" ! ! !\n") + print(" 58 59 60\n") + print("\n") + print(" ! ! !\n") + print(" 67 68 69\n") + print("\n") + print("TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\n") + print("WILL BE USED DURING PLAY. REFER TO THE ABOVE ONE FOR PEG\n") + print("NUMBERS. OK, LET'S BEGIN.\n") + + def play_game(): print("Lets play a game") def main(): - if input("Do you want instrunctions?").lower().startswith("y"): + if input("Do you want instrunctions?\n").lower().startswith("y"): print_instructions() if __name__ == "__main__": From 497801d6ea3ef32b6534ca294c08e8d0c2ad7dc5 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 4 Jan 2022 14:05:39 -0500 Subject: [PATCH 072/331] no change --- 48_High_IQ/python/High_IQ.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 90dd756a..f7bc9669 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -31,10 +31,10 @@ def print_instructions(): def play_game(): print("Lets play a game") - + def main(): if input("Do you want instrunctions?\n").lower().startswith("y"): print_instructions() - + if __name__ == "__main__": main() From 639a33bdf1de7b7bfc6ec733b53dcc2cf5760e4e Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 4 Jan 2022 14:30:50 -0500 Subject: [PATCH 073/331] So the board was wrong... --- 48_High_IQ/python/High_IQ.py | 97 +++++++++++++++++++++--------------- 1 file changed, 57 insertions(+), 40 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index f7bc9669..18d48456 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -1,40 +1,57 @@ - -def print_instructions(): - print("\n" * 3) - print("HERE IS THE BOARD:\n") - print("\n") - print(" ! ! !\n") - print(" 13 14 15\n") - print("\n") - print(" ! ! !\n") - print(" 22 23 24\n") - print("\n") - print("! ! ! ! ! ! !\n") - print("29 30 31 32 33 34 35\n") - print("\n") - print("! ! ! ! ! ! !\n") - print("38 39 40 41 42 43 44\n") - print("\n") - print("! ! ! ! ! ! !\n") - print("47 48 49 50 51 52 53\n") - print("\n") - print(" ! ! !\n") - print(" 58 59 60\n") - print("\n") - print(" ! ! !\n") - print(" 67 68 69\n") - print("\n") - print("TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\n") - print("WILL BE USED DURING PLAY. REFER TO THE ABOVE ONE FOR PEG\n") - print("NUMBERS. OK, LET'S BEGIN.\n") - - -def play_game(): - print("Lets play a game") - -def main(): - if input("Do you want instrunctions?\n").lower().startswith("y"): - print_instructions() - -if __name__ == "__main__": - main() + +def new_board(): + 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]: + board[i] = "X" + board[41] = "_" + return board + + +def print_instructions(): + print("\n" * 3) + print("HERE IS THE BOARD:\n") + # print("\n") + # print(" ! ! !\n") + # print(" 13 14 15\n") + # print("\n") + # print(" ! ! !\n") + # print(" 22 23 24\n") + # print("\n") + # print("! ! ! ! ! ! ! ! !\n") + # print("29 30 31 32 33 34 35 36 37\n") + # print("\n") + # print("! ! ! ! ! ! !\n") + # print("38 39 40 41 42 43 44\n") + # print("\n") + # print("! ! ! ! ! ! !\n") + # print("47 48 49 50 51 52 53\n") + # print("\n") + # print(" ! ! !\n") + # print(" 58 59 60\n") + # print("\n") + # print(" ! ! !\n") + # print(" 67 68 69\n") + # print("\n") + print("TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\n") + print("WILL BE USED DURING PLAY. REFER TO THE ABOVE ONE FOR PEG\n") + print("NUMBERS. OK, LET'S BEGIN.\n") + +def print_board(board): + print(" " * 3 + board[13] + board[14] + board[15] + " " * 3) + print(" " * 3 + board[22] + board[23] + board[24] + " " * 3) + print(board[29] + board[30] + board[31] + board[32] + board[33] + board[34] + board[35]) + print(board[38] + board[39] + board[40] + board[41] + board[42] + board[43] + board[44]) + print(board[47] + board[48] + board[49] + board[50] + board[51] + board[52] + board[53]) + +def play_game(): + print("Lets play a game") + board = new_board() + print_board(board) + +def main(): + if input("Do you want instrunctions?\n").lower().startswith("y"): + print_instructions() + play_game() + +if __name__ == "__main__": + main() From 75cf4767f020f16c054ac680ccbc83db3be5b3e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuz=20Ersen?= Date: Tue, 4 Jan 2022 20:20:00 +0000 Subject: [PATCH 074/331] Update aceyducey.pl --- 01_Acey_Ducey/perl/aceyducey.pl | 123 ++++++++++++++------------------ 1 file changed, 53 insertions(+), 70 deletions(-) diff --git a/01_Acey_Ducey/perl/aceyducey.pl b/01_Acey_Ducey/perl/aceyducey.pl index e2de13df..d4dfb2c2 100755 --- a/01_Acey_Ducey/perl/aceyducey.pl +++ b/01_Acey_Ducey/perl/aceyducey.pl @@ -28,17 +28,15 @@ If you do not want to bet, input a 0. If you want to quit, input a -1. END_INSTRUCTIONS -my @cards = (1 .. 13); # That is, Ace through King. +my @cards = ( 1 .. 13 ); # That is, Ace through King. my $keepPlaying = 1; GAME: -while ($keepPlaying) -{ - my $playerBalance = 100; # The player starts with $100 +while ($keepPlaying) { + my $playerBalance = 100; # The player starts with $100 - HAND: - while (1) - { + HAND: + while (1) { print "\nYou now have $playerBalance dollars.\n\n"; # We'll create a new array that is a shuffled version of the deck. @@ -48,19 +46,17 @@ while ($keepPlaying) # that those will be unique. This way we don't have to keep drawing # if we get, say, two queens. We sort them as we pull them to make # sure that the first card is lower than the second one. - my ($firstCard, $secondCard) = sort { $a <=> $b } @shuffledDeck[ 0 .. 1 ]; + my ( $firstCard, $secondCard ) = sort { $a <=> $b } @shuffledDeck[ 0 .. 1 ]; print "I drew ", nameOfCard($firstCard), " and ", nameOfCard($secondCard), ".\n"; my $bet = getValidBet($playerBalance); - if ($bet == 0) - { + if ( $bet == 0 ) { print "Chicken!\n\n"; next HAND; } - if ($bet < 0) - { + if ( $bet < 0 ) { last GAME; } @@ -72,19 +68,16 @@ while ($keepPlaying) print "I drew ", nameOfCard($thirdCard), "!\n"; - if (($firstCard < $thirdCard) && ($thirdCard < $secondCard)) - { + if ( ( $firstCard < $thirdCard ) && ( $thirdCard < $secondCard ) ) { print "You win!\n\n"; $playerBalance += $bet; } - else - { + else { print "You lose!\n\n"; $playerBalance -= $bet; } - if ($playerBalance <= 0) - { + if ( $playerBalance <= 0 ) { print "Sorry, buddy, you blew your wad!\n\n"; last HAND; } @@ -96,49 +89,43 @@ while ($keepPlaying) print "Thanks for playing!\n"; ############### -sub getValidBet -{ +sub getValidBet { my $maxBet = shift; - print "\nWhat's your bet? "; - - my $input = ; - chomp $input; - - # This regular expression will validate that the player entered an integer. - # The !~ match operate *negates* the match, so if the player did NOT enter - # an integer, they'll be given an error and prompted again. - if ($input !~ /^ # Match the beginning of the string - [+-]? # Optional plus or minus... - \d+ # followed by one more more digits... - $ # and then the end of the string - /x # The x modifier ignores whitespace in this regex... - ) + INPUT: { - print "Sorry, numbers only!\n"; - $input = getValidBet($maxBet); - } + print "\nWhat's your bet? "; - if ($input > $maxBet) - { - print "Sorry, my friend, you can't bet more money than you have.\n"; - print "You only have $maxBet dollars to spend!\n"; - $input = getValidBet($maxBet); - } + chomp( my $input = ); - if ($input != int($input)) - { - print "Sorry, you must bet in whole dollars. No change!\n"; - $input = getValidBet($maxBet); - } + # This regular expression will validate that the player entered an integer. + # The !~ match operate *negates* the match, so if the player did NOT enter + # an integer, they'll be given an error and prompted again. + if ( + $input !~ /^ # Match the beginning of the string + [+-]? # Optional plus or minus... + \d+ # followed by one more more digits... + $ # and then the end of the string + /x # The x modifier ignores whitespace in this regex... + ) + { + print "Sorry, numbers only!\n"; + redo INPUT; + } - return $input; + if ( $input > $maxBet ) { + print "Sorry, my friend, you can't bet more money than you have.\n"; + print "You only have $maxBet dollars to spend!\n"; + redo INPUT; + } + + return $input; + } } # Since arrays in Perl are 0-based, we need to convert the value that we drew from # the array to its proper position in the deck. -sub nameOfCard -{ +sub nameOfCard { my $value = shift; # Note that the Joker isn't used in this game, but since arrays in Perl are @@ -150,25 +137,21 @@ sub nameOfCard return $cardlist[$value]; } -sub promptUserToKeepPlaying -{ - print "Try again (Y/N)? "; - my $input = ; - chomp $input; +sub promptUserToKeepPlaying { + YESNO: + { + print "Try again (Y/N)? "; - my $keepGoing; - if (uc($input) eq 'Y') - { - $keepGoing = 1; - } - elsif (uc($input) eq 'N') - { - $keepGoing = 0; - } - else - { - $keepGoing = promptUserToKeepPlaying(); - } + chomp( my $input = uc ); - return $keepGoing; + if ( $input eq 'Y' ) { + return 1; + } + elsif ( $input eq 'N' ) { + return 0; + } + else { + redo YESNO; + } + } } From cf9c2328b3ca8b7b1ae05282f3a9ef1d7279e503 Mon Sep 17 00:00:00 2001 From: Eric S Weilnau Date: Tue, 4 Jan 2022 18:38:07 -0500 Subject: [PATCH 075/331] Format external links --- 01_Acey_Ducey/README.md | 3 ++- 24_Chemist/README.md | 3 ++- 43_Hammurabi/README.md | 6 +++--- 84_Super_Star_Trek/README.md | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/01_Acey_Ducey/README.md b/01_Acey_Ducey/README.md index 3434eb8e..77ff8621 100644 --- a/01_Acey_Ducey/README.md +++ b/01_Acey_Ducey/README.md @@ -15,4 +15,5 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html -A Common Lisp port is [here](https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp). +#### External Links + - Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp diff --git a/24_Chemist/README.md b/24_Chemist/README.md index 95db3f66..b93c1431 100644 --- a/24_Chemist/README.md +++ b/24_Chemist/README.md @@ -13,4 +13,5 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html -[Conversion to C](https://github.com/ericfischer/basic-computer-games/blob/main/24%20Chemist/c/chemist.c) +#### External Links + - C: https://github.com/ericfischer/basic-computer-games/blob/main/24%20Chemist/c/chemist.c diff --git a/43_Hammurabi/README.md b/43_Hammurabi/README.md index c92b7ee3..c02219b1 100644 --- a/43_Hammurabi/README.md +++ b/43_Hammurabi/README.md @@ -21,6 +21,6 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html -[Port to C language](https://github.com/beyonddream/hamurabi) - -[Port to Rust language](https://github.com/beyonddream/hamurabi.rs) +#### External Links + - C: https://github.com/beyonddream/hamurabi + - Rust: https://github.com/beyonddream/hamurabi.rs diff --git a/84_Super_Star_Trek/README.md b/84_Super_Star_Trek/README.md index 4a96f528..77fae3d8 100644 --- a/84_Super_Star_Trek/README.md +++ b/84_Super_Star_Trek/README.md @@ -101,4 +101,4 @@ Instructions in this directory at instructions.txt #### External Links - - Super Star Trek in C++ : https://www.codeproject.com/Articles/28399/The-Object-Oriented-Text-Star-Trek-Game-in-C + - C++: https://www.codeproject.com/Articles/28399/The-Object-Oriented-Text-Star-Trek-Game-in-C From f7b4b999dddf1066d91844b1855e0b228213aefb Mon Sep 17 00:00:00 2001 From: Bastiaan Veelo Date: Wed, 5 Jan 2022 01:51:34 +0100 Subject: [PATCH 076/331] D version of the word game. --- 96_Word/d/.gitignore | 2 ++ 96_Word/d/README.md | 15 ++++++++ 96_Word/d/word.d | 85 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) create mode 100644 96_Word/d/.gitignore create mode 100644 96_Word/d/README.md create mode 100644 96_Word/d/word.d diff --git a/96_Word/d/.gitignore b/96_Word/d/.gitignore new file mode 100644 index 00000000..d969f6b2 --- /dev/null +++ b/96_Word/d/.gitignore @@ -0,0 +1,2 @@ +*.exe +*.obj diff --git a/96_Word/d/README.md b/96_Word/d/README.md new file mode 100644 index 00000000..764cb141 --- /dev/null +++ b/96_Word/d/README.md @@ -0,0 +1,15 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html) + +Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo). + +The Basic original required words to be exactly five letters in length for the program to behave correctly. +This version does not replicate that limitation, and the test for that requirement is commented out. + +## Running the code + +Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler: +```shell +dmd -dip1000 -run word.d +``` + +[Other compilers](https://dlang.org/download.html) also exist. diff --git a/96_Word/d/word.d b/96_Word/d/word.d new file mode 100644 index 00000000..6f4d46d6 --- /dev/null +++ b/96_Word/d/word.d @@ -0,0 +1,85 @@ +@safe: // Make @safe the default for this file, enforcing memory-safety. +import std; + +void main() +{ + enum width = 80; + writeln(center("Word", width)); + writeln(center("(After Creative Computing Morristown, New Jersey)\n\n\n", width)); + writeln(wrap("I am thinking of a word -- you guess it. I will give you " ~ + "clues to help you get it. Good luck!!\n\n", width)); + + string[] words = ["dinky", "smoke", "water", "grass", "train", "might", "first", + "candy", "champ", "would", "clump", "dopey"]; + + playLoop: while (true) + { + writeln("\n\nYou are starting a new game..."); + + string word = words[uniform(0, $-1)]; // $ is a short-hand for words.length. + int guesses = 0; + string knownLetters = '-'.repeat(word.length).array; + + while (true) + { + writeln("Guess a ", word.length, " letter word"); + string guess = readString.toLower; + if (guess == "?") + { + writeln("The secret word is ", word, "\n"); + continue playLoop; // Start a new game. + } + /* Uncomment this for equivalence with Basic. + if (guess.length != 5) + { + writeln("You must guess a 5 letter word. Start again."); + continue; // Ask for new guess. + } + */ + guesses++; + if (guess == word) + break; // Done guessing + string commonLetters; + foreach (i, wordLetter; word) + foreach (j, guessLetter; guess) + if (guessLetter == wordLetter) + { + commonLetters ~= guessLetter; + if (i == j) + knownLetters.replaceInPlace(i, i + 1, [guessLetter]); + } + writeln("There were ", commonLetters.length, " matches and the common letters were... ", commonLetters); + writeln("From the exact letter matches, you know................ ", knownLetters); + if (knownLetters == word) + break; // Done guessing + if (commonLetters.length < 2) + writeln("If you give up, type '?' for your next guess."); + writeln; + } + + writeln("You have guessed the word. It took ", guesses, " guesses!"); + write("\n\nWant to play again? "); + if (readString.toLower != "yes") + break; // Terminate playLoop + } +} + +/// Read a string from standard input, stripping newline and other enclosing whitespace. +string readString() nothrow +{ + try + return trustedReadln.strip; + catch (Exception) // readln throws on I/O and Unicode errors, which we handle here. + return ""; +} + +/** An @trusted wrapper around readln. + * + * This is the only function that formally requires manual review for memory-safety. + * [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com) + * which would remove the need to have any @trusted code in this program. + */ +string trustedReadln() @trusted +{ + return readln; +} From 5263ee6ba9eed38009724014098f9b9fe4baadc7 Mon Sep 17 00:00:00 2001 From: James Allenspach Date: Tue, 4 Jan 2022 22:12:28 -0600 Subject: [PATCH 077/331] Initial commit --- 44_Hangman/perl/hangman.pl | 223 +++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100755 44_Hangman/perl/hangman.pl diff --git a/44_Hangman/perl/hangman.pl b/44_Hangman/perl/hangman.pl new file mode 100755 index 00000000..e2aca815 --- /dev/null +++ b/44_Hangman/perl/hangman.pl @@ -0,0 +1,223 @@ +#!/usr/bin/perl + +use strict; +use warnings; + + +# global variables defined here + +my(@WORDS) = qw( + 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 +); +my(@PIC,@L,$board,@guessedLetters,$guesses,$hangCount); +my($guess,%GUESSED); + +# Subroutines defined here. + +# init_variables: initialize all of the variables needed +# (this covers lines 50-90 in the original BASIC program) + +sub init_variables { + @guessedLetters = (); + @PIC = ( + 'XXXXXXX ', + 'X X ', + 'X ', + 'X ', + 'X ', + 'X ', + 'X ', + 'X ', + 'X ', + 'X ', + 'X ', + 'X ', + ); + $guesses = 0; %GUESSED = (); + $hangCount = 0; +} + +# addchar: given a row & column, put the specified char in that place in @PIC +sub addchar { + my($row,$col, $c) = @_; + + substr($PIC[$row],$col,1) = $c; +} + + +# main code starts here + +print ' 'x31; print "Hangman\n"; +print ' 'x14; print "Creative Computing Morristown, New Jersey\n\n\n\n"; + +# an iteration of the PLAY block is one complete game. +# There is a continue block that will ask if the user +# wants to play another game. + +PLAY: while (1) { + + init_variables(); + # Any words left? + if (@WORDS == 0) { + print "You did all the words!\n"; + last PLAY; + } + # splice a random word out of the @WORDS array + my($thisWord) = splice(@WORDS, int(rand(scalar @WORDS)),1); + # $board is the "game board" of the filled-out word + # that the user is working on + $board = '.'x(length $thisWord); + + # GUESS loop is run for every time the user guesses a letter + GUESS: while(1) { + print "Here are the letters you used:\n"; + printf("%s\n", join(',',@guessedLetters)); + printf("\n\n%s\n", $board); + + print "What is your guess for a letter ? "; + chomp($guess = ); + # The %GUESSED hash allows us to quickly identify + # letters that have already been guessed + if ($GUESSED{lc $guess}) { + print "You guessed that letter before!\n\n"; + redo GUESS; + } + + # save the guessed letter + push @guessedLetters, $guess; + $GUESSED{lc $guess} = 1; + ++$guesses; + + # now look for the letter in the $thisWord var + # and put it into the $board var wherever it + # shows up. $foundLetter is a flag that indicates + # whether or not the letter is found. + my $foundLetter = 0; + for (my $i = 0; $i < length $thisWord; ++$i) { + if (lc substr($thisWord,$i,1) eq lc $guess) { + $foundLetter = 1; + substr($board, $i, 1) = substr($thisWord, $i, 1); + } + } + + # The user found a letter in the solution! + if ($foundLetter) { + + # Are there any '.' chars left in the board? + if (index($board, '.') < 0) { + print "You found the word!\n\n"; + } else { + printf("%s\n\n", $board); + print "What is your guess for the word ? "; + chomp(my $guessword = ); + if (lc $thisWord ne lc $guessword) { + print "Wrong. Try another letter.\n"; + # Go to the next iteration of the GUESS loop + next GUESS; + } + printf("Right! It took you %d %s!\n", $guesses, ($guesses == 1 ? 'guess' : 'guesses')); + } + # At this point the user has discovered the word and won. + # This "next" statement takes execution down to the + # continue block for the PLAY loop; + next PLAY; + + } else { # didn't find a letter + + ++$hangCount; + print "\n\n\nSorry, that letter isn't in the word.\n"; + + # The addchar() calls in the block below piece together the + # hangman graphic, depending on how many wrong letters + # the user has. + if ($hangCount == 1) { + print "First, we draw a head\n"; + addchar(2,5,"-");addchar(2,6,"-");addchar(2,7,"-"); + addchar(3,4,"("); addchar(3,5,"."); addchar(3,7,"."); addchar(3,8,")"); + addchar(4,5,"-");addchar(4,6,"-");addchar(4,7,"-"); + } + if ($hangCount == 2) { + print "Now we draw a body.\n"; + for (5 .. 8) { + addchar($_, 6, "X"); + } + } + if ($hangCount == 3) { + print "Next we draw an arm.\n"; + for (3 .. 6) { + addchar($_, $_-1, "\\"); + } + } + if ($hangCount == 4) { + print "This time it's the other arm.\n"; + addchar(3,10, "/"); + addchar(4, 9, "/"); + addchar(5, 8, "/"); + addchar(6, 7, "/"); + } + if ($hangCount == 5) { + print "Now, let's draw the right leg.\n"; + addchar( 9,5, "/"); + addchar(10,4, "/"); + } + if ($hangCount == 6) { + print "This time we draw the left leg.\n"; + addchar(9,7,"\\"); + addchar(10,8,"\\"); + } + if ($hangCount == 7) { + print "Now we put up a hand.\n"; + addchar(2,10,"\\"); + } + if ($hangCount == 8) { + print "Next the other hand.\n"; + addchar(2,2,"/"); + } + if ($hangCount == 9) { + print "Now we draw one foot\n"; + addchar(11,9,"\\"); + addchar(11,10, "-"); + } + if ($hangCount == 10) { + print "Here's the other foot -- you're hung!!\n"; + addchar(11,2,"-"); + addchar(11,3, "/"); + } + + printf("$_\n") for @PIC; + print "\n\n"; + + # Next guess if the user has not lost + if ($hangCount < 10) { + next GUESS; + } + + printf("Sorry, you lose. The word was %s\n", $thisWord); + next PLAY; + + } # didn't find a letter block + } # GUESS block +} # PLAY block + +# This block is reached either by the player winning (see the "next PLAY") +# statement) or by the user losing (as the PLAY block is complete and +# execution naturally comes to this continue block). +continue { + print "Want another word ? "; + chomp(my $in = ); + if ($in !~ m/^y/i) { + # Exit the PLAY loop + print "\nIt's been fun! Bye for now.\n\n"; + last PLAY; + } + # At this point execution goes to the start of the PLAY block, + # meaning a new game +} From 6e3da5b1a1c79b24bac5619ee9f3cd74edd7c6cc Mon Sep 17 00:00:00 2001 From: James Allenspach Date: Tue, 4 Jan 2022 22:14:49 -0600 Subject: [PATCH 078/331] Removal of unused var --- 44_Hangman/perl/hangman.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/44_Hangman/perl/hangman.pl b/44_Hangman/perl/hangman.pl index e2aca815..aadf631b 100755 --- a/44_Hangman/perl/hangman.pl +++ b/44_Hangman/perl/hangman.pl @@ -17,7 +17,7 @@ my(@WORDS) = qw( MAGISTRATE ERRONEOUSLY LOUDSPEAKER PHYTOTOXIC MATRIMONIAL PARASYMPATHOMIMETIC THIGMOTROPISM ); -my(@PIC,@L,$board,@guessedLetters,$guesses,$hangCount); +my(@PIC,$board,@guessedLetters,$guesses,$hangCount); my($guess,%GUESSED); # Subroutines defined here. From daab84dbd55d623c07059bc3f85fccc011174aad Mon Sep 17 00:00:00 2001 From: James Allenspach Date: Tue, 4 Jan 2022 22:18:09 -0600 Subject: [PATCH 079/331] Rename some vars to be more helpful --- 44_Hangman/perl/hangman.pl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/44_Hangman/perl/hangman.pl b/44_Hangman/perl/hangman.pl index aadf631b..45a6da9b 100755 --- a/44_Hangman/perl/hangman.pl +++ b/44_Hangman/perl/hangman.pl @@ -17,8 +17,8 @@ my(@WORDS) = qw( MAGISTRATE ERRONEOUSLY LOUDSPEAKER PHYTOTOXIC MATRIMONIAL PARASYMPATHOMIMETIC THIGMOTROPISM ); -my(@PIC,$board,@guessedLetters,$guesses,$hangCount); -my($guess,%GUESSED); +my(@PIC,$board,@guessedLetters,$guessCount,$hangCount); +my(%GUESSED); # Subroutines defined here. @@ -41,7 +41,7 @@ sub init_variables { 'X ', 'X ', ); - $guesses = 0; %GUESSED = (); + $guessCount = 0; %GUESSED = (); $hangCount = 0; } @@ -83,7 +83,7 @@ PLAY: while (1) { printf("\n\n%s\n", $board); print "What is your guess for a letter ? "; - chomp($guess = ); + chomp(my $guess = ); # The %GUESSED hash allows us to quickly identify # letters that have already been guessed if ($GUESSED{lc $guess}) { @@ -94,7 +94,7 @@ PLAY: while (1) { # save the guessed letter push @guessedLetters, $guess; $GUESSED{lc $guess} = 1; - ++$guesses; + ++$guessCount; # now look for the letter in the $thisWord var # and put it into the $board var wherever it @@ -123,7 +123,7 @@ PLAY: while (1) { # Go to the next iteration of the GUESS loop next GUESS; } - printf("Right! It took you %d %s!\n", $guesses, ($guesses == 1 ? 'guess' : 'guesses')); + printf("Right! It took you %d %s!\n", $guessCount, ($guessCount == 1 ? 'guess' : 'guesses')); } # At this point the user has discovered the word and won. # This "next" statement takes execution down to the From f2e7381878c198b467093eef1deac7c3bc3b6e88 Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 20:44:47 -0800 Subject: [PATCH 080/331] first very ugly port. --- 81_Splat/java/src/Splat.java | 277 +++++++++++++++++++++++++++++++++++ 1 file changed, 277 insertions(+) create mode 100644 81_Splat/java/src/Splat.java diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java new file mode 100644 index 00000000..0930dcc2 --- /dev/null +++ b/81_Splat/java/src/Splat.java @@ -0,0 +1,277 @@ +import java.util.Arrays; +import java.util.Random; +import java.util.Scanner; + +public class Splat { + private final Random random = new Random(); + private final Scanner scanner = new Scanner(System.in); + + public static void main(String[] args) { + new Splat().run(); + } + + public void run() { + System.out.printf("%33s%s\n", " ", "SPLAT"); + System.out.printf("%15s%s\n", " ", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.print("\n\n\n"); + System.out.println("WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE"); + System.out.println("JUMP. TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE"); + System.out.println("MOMENT WITHOUT GOING SPLAT."); + + float[] Arr = new float[42]; + Arrays.fill(Arr, 0.0f); + int K = 0; + int K1 = 0; + while (true) { + + System.out.print("\n\n"); + float V = 0.0f; + float A = 0.0f; + int N = 0; + int M = 0; + int D1 = (int) (9001.0f * random.nextFloat() + 1000); + D1 = 2937; //debug fixme + + System.out.print("SELECT YOUR OWN TERMINAL VELOCITY (YES OR NO) "); + float V1; + while (true) { + String A1 = scanner.next(); + if (A1.equals("NO")) { + V1 = (int) (1000 * random.nextFloat()); + System.out.printf("OK. TERMINAL VELOCITY = %d MI/HR\n", (int) V1); + break; + } + if (!A1.equals("YES")) { + System.out.print("YES OR NO "); + continue; + } + System.out.print("WHAT TERMINAL VELOCITY (MI/HR) "); + V1 = scanner.nextInt(); + break; + } + V1 = V1 * (5280.0f / 3600.0f); + V = V1 + ((V1 * random.nextFloat()) / 20.0f) - ((V1 * random.nextFloat()) / 20.0f); + System.out.print("WANT TO SELECT ACCELERATION DUE TO GRAVITY (YES OR NO) "); + float A2; + while (true) { + String B1 = scanner.next(); + if (B1.equals("NO")) { + switch (random.nextInt(10)) { + case 0: + System.out.println("FINE. YOU'RE ON MERCURY. ACCELERATION=12.2 FT/SEC/SEC."); + A2 = 12.2f; + break; + case 1: + System.out.println("ALL RIGHT. YOU'RE ON VENUS. ACCELERATION=28.3 FT/SEC/SEC."); + A2 = 28.3f; + break; + case 2: + System.out.println("THEN YOU'RE ON EARTH. ACCELERATION=32.16 FT/SEC/SEC."); + A2 = 32.16f; + break; + case 3: + System.out.println("FINE. YOU'RE ON THE MOON. ACCELERATION=5.15 FT/SEC/SEC."); + A2 = 5.15f; + break; + case 4: + System.out.println("ALL RIGHT. YOU'RE ON MARS. ACCELERATION=12.5 FT/SEC/SEC."); + A2 = 12.5f; + break; + case 5: + System.out.println("THEN YOU'RE ON JUPITER. ACCELERATION=85.2 FT/SEC/SEC."); + A2 = 85.2f; + break; + case 6: + System.out.println("FINE. YOU'RE ON SATURN. ACCELERATION=37.6 FT/SEC/SEC."); + A2 = 37.6f; + break; + case 7: + System.out.println("ALL RIGHT. YOU'RE ON URANUS. ACCELERATION=33.8 FT/SEC/SEC."); + A2 = 33.8f; + break; + case 8: + System.out.println("THEN YOU'RE ON NEPTUNE. ACCELERATION=39.6 FT/SEC/SEC."); + A2 = 39.6f; + break; + case 9: + System.out.println("FINE. YOU'RE ON THE SUN. ACCELERATION=896 FT/SEC/SEC."); + A2 = 896.0f; + break; + default: + throw new RuntimeException("Impossible. Will fix stupid switch statement later."); + } + break; + } + if (!B1.equals("YES")) { + System.out.print("YES OR NO "); + continue; + } + System.out.print("WHAT ACCELERATION (FT/SEC/SEC) "); + A2 = scanner.nextFloat(); + break; + } + A = A2 + ((A2 * random.nextFloat()) / 20.0f) - ((A2 * random.nextFloat()) / 20.0f); + System.out.println(); + System.out.printf(" ALTITUDE = %d FT\n", D1); + System.out.printf(" TERM. VELOCITY = %.2f FT/SEC +/-5%%\n", V1); + System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", A2); + System.out.println("SET THE TIMER FOR YOUR FREEFALL."); + System.out.print("HOW MANY SECONDS "); + float T = scanner.nextFloat(); + System.out.println("HERE WE GO.\n"); + System.out.println("TIME (SEC) DIST TO FALL (FT)"); + System.out.println("========== ================="); + boolean splat = false; + boolean terminalReached = false; + float D = 0.0f; + for (float i = 0.0f; !splat && (i < T); i += T / 8) { + if (i > (V / A)) { + terminalReached = true; + System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", (V / A)); + for (i = i; i < T; i += T / 8) { + D = D1 - ((V * V / (2 * A)) + (V * (i - (V / A)))); +// System.out.printf(" ......................................tv %f\n", D); + if (D <= 0) { + splat = true; + break; + } + System.out.printf("%10.2f %f\n", i, D); + } + break; + } + D = D1 - ((A / 2) * i * i); +// System.out.printf(" ......................................debug %f\n", D); + if (D <= 0) { + splat = true; + break; + } + System.out.printf("%10.2f %f\n", i, D); + } + + if (!splat) { + + System.out.println("CHUTE OPEN"); + int J = 0; + for (J = 0; J < 42; J++) { + if (Arr[J] == 0) { + Arr[J] = D; + break; + } + K = K + 1; + if (D > Arr[J]) { + continue; + } + K1 = K1 + 1; + } + + if (J > 2) { + if (K - K1 <= 0.1 * K) { + System.out.printf("WOW! THAT'S SOME JUMPING. OF THE %d SUCCESSFUL JUMPS\n", K); + System.out.printf("BEFORE YOURS, ONLY %d OPENED THEIR CHUTES LOWER THAN\n", K - K1); + System.out.println("YOU DID."); + } else if (K - K1 <= 0.25 * K) { + System.out.printf("PRETTY GOOD! %d SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\n", K); + System.out.printf("%d OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\n", K - K1); + System.out.println("OPENED."); + } else if (K - K1 <= 0.5 * K) { + System.out.printf("NOT BAD. THERE HAVE BEEN %d SUCCESSFUL JUMPS BEFORE YOURS.\n", K); + System.out.printf("YOU WERE BEATEN OUT BY %d OF THEM.\n", K - K1); + } else if (K - K1 <= 0.75 * K) { + System.out.printf("CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY %d IN THE\n", K - K1); + System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS.", K); + } else if (K - K1 <= -0.9 * K) { + System.out.println("HUMPH! DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE"); + System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN %d JUMPS\n", K, K1); + System.out.println("BETTER THAN THE WORST. SHAPE UP!!!\n"); + } else { + System.out.printf("HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. %f SUCCESSFUL\n", K); + System.out.printf("JUMPS BEFORE YOURS AND YOU CAME IN NUMBER %d! GET WITH IT!\n", K - K1); + } + } else { + System.out.println("AMAZING!!! NOT BAD FOR YOUR "); + switch (J) { + case 0: + System.out.print("1ST "); + break; + case 1: + System.out.print("2ND "); + break; + case 2: + System.out.print("3RD "); + break; + } + System.out.println("SUCCESSFUL JUMP!!!"); + } + + + } else { + if (terminalReached) { + System.out.printf("%.2f SPLAT\n", (V / A) + ((D1 - (V * V / (2 * A))) / V)); + } else { + System.out.printf("%.2f SPLAT\n", Math.sqrt(2 * D1 / A)); + + } + switch (random.nextInt(10)) { + case 0: + System.out.println("REQUIESCAT IN PACE."); + break; + case 1: + System.out.println("MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE."); + break; + case 2: + System.out.println("REST IN PEACE."); + break; + case 3: + System.out.println("SON-OF-A-GUN."); + break; + case 4: + System.out.println("#$%&&%!$"); + break; + case 5: + System.out.println("A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT."); + break; + case 6: + System.out.println("HMMM. SHOULD HAVE PICKED A SHORTER TIME."); + break; + case 7: + System.out.println("MUTTER. MUTTER. MUTTER."); + break; + case 8: + System.out.println("PUSHING UP DAISIES."); + break; + default: + System.out.println("EASY COME, EASY GO."); + + } + } + boolean chosen = false; + while (!chosen) { + System.out.print("DO YOU WANT TO PLAY AGAIN "); + String Z = scanner.next(); + if (Z.equals("YES")) { + break; + } + if (Z.equals("NO")) { + System.out.print("PLEASE "); + while (true) { + Z = scanner.next(); + if (Z.equals("YES")) { + chosen = true; + break; + } + if (Z.equals("NO")) { + System.out.println("SSSSSSSSSS."); + return; + } + System.out.print("YES OR NO "); + } + continue; + } else { + System.out.print("YES OR NO "); + } + } + + } + + } +} \ No newline at end of file From b899d6d5c508bfe9a746c64b9dbaad2496ac33dd Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 21:14:36 -0800 Subject: [PATCH 081/331] factor out planet enum --- 81_Splat/java/src/Splat.java | 86 +++++++++++++++++------------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index 0930dcc2..c5c94a5d 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -30,7 +30,6 @@ public class Splat { int N = 0; int M = 0; int D1 = (int) (9001.0f * random.nextFloat() + 1000); - D1 = 2937; //debug fixme System.out.print("SELECT YOUR OWN TERMINAL VELOCITY (YES OR NO) "); float V1; @@ -56,50 +55,7 @@ public class Splat { while (true) { String B1 = scanner.next(); if (B1.equals("NO")) { - switch (random.nextInt(10)) { - case 0: - System.out.println("FINE. YOU'RE ON MERCURY. ACCELERATION=12.2 FT/SEC/SEC."); - A2 = 12.2f; - break; - case 1: - System.out.println("ALL RIGHT. YOU'RE ON VENUS. ACCELERATION=28.3 FT/SEC/SEC."); - A2 = 28.3f; - break; - case 2: - System.out.println("THEN YOU'RE ON EARTH. ACCELERATION=32.16 FT/SEC/SEC."); - A2 = 32.16f; - break; - case 3: - System.out.println("FINE. YOU'RE ON THE MOON. ACCELERATION=5.15 FT/SEC/SEC."); - A2 = 5.15f; - break; - case 4: - System.out.println("ALL RIGHT. YOU'RE ON MARS. ACCELERATION=12.5 FT/SEC/SEC."); - A2 = 12.5f; - break; - case 5: - System.out.println("THEN YOU'RE ON JUPITER. ACCELERATION=85.2 FT/SEC/SEC."); - A2 = 85.2f; - break; - case 6: - System.out.println("FINE. YOU'RE ON SATURN. ACCELERATION=37.6 FT/SEC/SEC."); - A2 = 37.6f; - break; - case 7: - System.out.println("ALL RIGHT. YOU'RE ON URANUS. ACCELERATION=33.8 FT/SEC/SEC."); - A2 = 33.8f; - break; - case 8: - System.out.println("THEN YOU'RE ON NEPTUNE. ACCELERATION=39.6 FT/SEC/SEC."); - A2 = 39.6f; - break; - case 9: - System.out.println("FINE. YOU'RE ON THE SUN. ACCELERATION=896 FT/SEC/SEC."); - A2 = 896.0f; - break; - default: - throw new RuntimeException("Impossible. Will fix stupid switch statement later."); - } + A2 = chooseRandomAcceleration(); break; } if (!B1.equals("YES")) { @@ -274,4 +230,44 @@ public class Splat { } } + + private float chooseRandomAcceleration() { + Planet planet = Planet.pickRandom(); + System.out.printf("%s. ACCELERATION=%.2f FT/SEC/SEC.\n", planet.getMessage(), planet.getAcceleration()); + return planet.getAcceleration(); + } + + enum Planet { + MERCURY("FINE. YOU'RE ON MERCURY", 12.2f), + VENUS("ALL RIGHT. YOU'RE ON VENUS", 28.3f), + EARTH("THEN YOU'RE ON EARTH", 32.16f), + MOON("FINE. YOU'RE ON THE MOON", 5.15f), + MARS("ALL RIGHT. YOU'RE ON MARS", 12.5f), + JUPITER("THEN YOU'RE ON JUPITER", 85.2f), + SATURN("FINE. YOU'RE ON SATURN", 37.6f), + URANUS("ALL RIGHT. YOU'RE ON URANUS", 33.8f), + NEPTUNE("THEN YOU'RE ON NEPTUNE", 39.6f), + SUN("FINE. YOU'RE ON THE SUN", 896.0f); + + static final Random random = new Random(); + private final String message; + private final float acceleration; + + Planet(String message, float acceleration) { + this.message = message; + this.acceleration = acceleration; + } + + static Planet pickRandom(){ + return values()[random.nextInt(Planet.values().length)]; + } + + public String getMessage() { + return message; + } + + public float getAcceleration() { + return acceleration; + } + } } \ No newline at end of file From 22213547fc81233c2645c7014e60a2537a9a50ef Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 21:22:11 -0800 Subject: [PATCH 082/331] factor out askYesNo --- 81_Splat/java/src/Splat.java | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index c5c94a5d..3f44af2f 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -27,27 +27,18 @@ public class Splat { System.out.print("\n\n"); float V = 0.0f; float A = 0.0f; - int N = 0; - int M = 0; int D1 = (int) (9001.0f * random.nextFloat() + 1000); - System.out.print("SELECT YOUR OWN TERMINAL VELOCITY (YES OR NO) "); float V1; - while (true) { - String A1 = scanner.next(); - if (A1.equals("NO")) { - V1 = (int) (1000 * random.nextFloat()); - System.out.printf("OK. TERMINAL VELOCITY = %d MI/HR\n", (int) V1); - break; - } - if (!A1.equals("YES")) { - System.out.print("YES OR NO "); - continue; - } + if(askYesNo("SELECT YOUR OWN TERMINAL VELOCITY")){ System.out.print("WHAT TERMINAL VELOCITY (MI/HR) "); V1 = scanner.nextInt(); - break; } + else { + V1 = (int) (1000 * random.nextFloat()); + System.out.printf("OK. TERMINAL VELOCITY = %d MI/HR\n", (int) V1); + } + V1 = V1 * (5280.0f / 3600.0f); V = V1 + ((V1 * random.nextFloat()) / 20.0f) - ((V1 * random.nextFloat()) / 20.0f); System.out.print("WANT TO SELECT ACCELERATION DUE TO GRAVITY (YES OR NO) "); @@ -231,6 +222,18 @@ public class Splat { } + private boolean askYesNo(String prompt){ + System.out.printf("%s (YES OR NO) ", prompt); + while (true) { + String answer = scanner.next(); + switch(answer){ + case "YES": return true; + case "NO": return false; + default: System.out.print("YES OR NO "); + } + } + } + private float chooseRandomAcceleration() { Planet planet = Planet.pickRandom(); System.out.printf("%s. ACCELERATION=%.2f FT/SEC/SEC.\n", planet.getMessage(), planet.getAcceleration()); From 9fba41771c254890d30b14cf343d4f6babc4b645 Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 21:24:01 -0800 Subject: [PATCH 083/331] plug in yesno prompt for acceleration --- 81_Splat/java/src/Splat.java | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index 3f44af2f..ba1496ca 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -41,22 +41,16 @@ public class Splat { V1 = V1 * (5280.0f / 3600.0f); V = V1 + ((V1 * random.nextFloat()) / 20.0f) - ((V1 * random.nextFloat()) / 20.0f); - System.out.print("WANT TO SELECT ACCELERATION DUE TO GRAVITY (YES OR NO) "); + float A2; - while (true) { - String B1 = scanner.next(); - if (B1.equals("NO")) { - A2 = chooseRandomAcceleration(); - break; - } - if (!B1.equals("YES")) { - System.out.print("YES OR NO "); - continue; - } + if(askYesNo("WANT TO SELECT ACCELERATION DUE TO GRAVITY")){ System.out.print("WHAT ACCELERATION (FT/SEC/SEC) "); A2 = scanner.nextFloat(); - break; } + else { + A2 = chooseRandomAcceleration(); + } + A = A2 + ((A2 * random.nextFloat()) / 20.0f) - ((A2 * random.nextFloat()) / 20.0f); System.out.println(); System.out.printf(" ALTITUDE = %d FT\n", D1); From c3a1b621b917aaa71966c18cbe64004924d36dfd Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 21:32:56 -0800 Subject: [PATCH 084/331] factor out intro and prompt messages --- 81_Splat/java/src/Splat.java | 69 ++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index ba1496ca..e4614fa8 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -11,12 +11,7 @@ public class Splat { } public void run() { - System.out.printf("%33s%s\n", " ", "SPLAT"); - System.out.printf("%15s%s\n", " ", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); - System.out.print("\n\n\n"); - System.out.println("WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE"); - System.out.println("JUMP. TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE"); - System.out.println("MOMENT WITHOUT GOING SPLAT."); + showIntroduction(); float[] Arr = new float[42]; Arrays.fill(Arr, 0.0f); @@ -25,37 +20,18 @@ public class Splat { while (true) { System.out.print("\n\n"); - float V = 0.0f; - float A = 0.0f; int D1 = (int) (9001.0f * random.nextFloat() + 1000); - float V1; - if(askYesNo("SELECT YOUR OWN TERMINAL VELOCITY")){ - System.out.print("WHAT TERMINAL VELOCITY (MI/HR) "); - V1 = scanner.nextInt(); - } - else { - V1 = (int) (1000 * random.nextFloat()); - System.out.printf("OK. TERMINAL VELOCITY = %d MI/HR\n", (int) V1); - } + float terminalVelocity = promptTerminalVelocity(); + float V = terminalVelocity + ((terminalVelocity * random.nextFloat()) / 20.0f) - ((terminalVelocity * random.nextFloat()) / 20.0f); - V1 = V1 * (5280.0f / 3600.0f); - V = V1 + ((V1 * random.nextFloat()) / 20.0f) - ((V1 * random.nextFloat()) / 20.0f); + float gravitationalAcceleration = promptGravitationalAcceleration(); + float A = gravitationalAcceleration + ((gravitationalAcceleration * random.nextFloat()) / 20.0f) - ((gravitationalAcceleration * random.nextFloat()) / 20.0f); - float A2; - if(askYesNo("WANT TO SELECT ACCELERATION DUE TO GRAVITY")){ - System.out.print("WHAT ACCELERATION (FT/SEC/SEC) "); - A2 = scanner.nextFloat(); - } - else { - A2 = chooseRandomAcceleration(); - } - - A = A2 + ((A2 * random.nextFloat()) / 20.0f) - ((A2 * random.nextFloat()) / 20.0f); System.out.println(); System.out.printf(" ALTITUDE = %d FT\n", D1); - System.out.printf(" TERM. VELOCITY = %.2f FT/SEC +/-5%%\n", V1); - System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", A2); + System.out.printf(" TERM. VELOCITY = %.2f FT/SEC +/-5%%\n", terminalVelocity); + System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", gravitationalAcceleration); System.out.println("SET THE TIMER FOR YOUR FREEFALL."); System.out.print("HOW MANY SECONDS "); float T = scanner.nextFloat(); @@ -216,6 +192,37 @@ public class Splat { } + private void showIntroduction() { + System.out.printf("%33s%s\n", " ", "SPLAT"); + System.out.printf("%15s%s\n", " ", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.print("\n\n\n"); + System.out.println("WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE"); + System.out.println("JUMP. TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE"); + System.out.println("MOMENT WITHOUT GOING SPLAT."); + } + + private float promptTerminalVelocity() { + if(askYesNo("SELECT YOUR OWN TERMINAL VELOCITY")){ + System.out.print("WHAT TERMINAL VELOCITY (MI/HR) "); + return mphToFeetPerSec(scanner.nextFloat()); + } + float terminalVelocity = (int) (1000 * random.nextFloat()); + System.out.printf("OK. TERMINAL VELOCITY = %.2f MI/HR\n", terminalVelocity); + return mphToFeetPerSec(terminalVelocity); + } + + private float promptGravitationalAcceleration() { + if(askYesNo("WANT TO SELECT ACCELERATION DUE TO GRAVITY")){ + System.out.print("WHAT ACCELERATION (FT/SEC/SEC) "); + return scanner.nextFloat(); + } + return chooseRandomAcceleration(); + } + + private float mphToFeetPerSec(float speed){ + return speed * (5280.0f / 3600.0f); + } + private boolean askYesNo(String prompt){ System.out.printf("%s (YES OR NO) ", prompt); while (true) { From eba6c07fd03cd2f08ec0b711a3289397ba3b4cf9 Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 22:05:24 -0800 Subject: [PATCH 085/331] factor out initial jump conditions --- 81_Splat/java/src/Splat.java | 94 ++++++++++++++++++++++++++++-------- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index e4614fa8..67e278f8 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -3,7 +3,7 @@ import java.util.Random; import java.util.Scanner; public class Splat { - private final Random random = new Random(); + private static final Random random = new Random(); private final Scanner scanner = new Scanner(System.in); public static void main(String[] args) { @@ -19,19 +19,15 @@ public class Splat { int K1 = 0; while (true) { - System.out.print("\n\n"); - int D1 = (int) (9001.0f * random.nextFloat() + 1000); - - float terminalVelocity = promptTerminalVelocity(); - float V = terminalVelocity + ((terminalVelocity * random.nextFloat()) / 20.0f) - ((terminalVelocity * random.nextFloat()) / 20.0f); - - float gravitationalAcceleration = promptGravitationalAcceleration(); - float A = gravitationalAcceleration + ((gravitationalAcceleration * random.nextFloat()) / 20.0f) - ((gravitationalAcceleration * random.nextFloat()) / 20.0f); + InitialJumpConditions jump = buildInitialConditions(); + final float V = jump.getTerminalVelocity(); + final float A = jump.getGravitationalAcceleration(); System.out.println(); - System.out.printf(" ALTITUDE = %d FT\n", D1); - System.out.printf(" TERM. VELOCITY = %.2f FT/SEC +/-5%%\n", terminalVelocity); - System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", gravitationalAcceleration); + System.out.printf(" ALTITUDE = %d FT\n", jump.getAltitude()); + System.out.printf(" TERM. VELOCITY = %.2f FT/SEC +/-5%%\n", jump.getOriginalTerminalVelocity()); + System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", jump.getOriginalGravitationalAcceleration()); + System.out.println("SET THE TIMER FOR YOUR FREEFALL."); System.out.print("HOW MANY SECONDS "); float T = scanner.nextFloat(); @@ -42,12 +38,11 @@ public class Splat { boolean terminalReached = false; float D = 0.0f; for (float i = 0.0f; !splat && (i < T); i += T / 8) { - if (i > (V / A)) { + if (i > jump.getTimeOfTerminalAccelerationReached()) { terminalReached = true; - System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", (V / A)); + System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", jump.getTimeOfTerminalAccelerationReached()); for (i = i; i < T; i += T / 8) { - D = D1 - ((V * V / (2 * A)) + (V * (i - (V / A)))); -// System.out.printf(" ......................................tv %f\n", D); + D = jump.getAltitude() - ((V * V / (2 * A)) + (V * (i - (V / A)))); if (D <= 0) { splat = true; break; @@ -56,8 +51,7 @@ public class Splat { } break; } - D = D1 - ((A / 2) * i * i); -// System.out.printf(" ......................................debug %f\n", D); + D = jump.getAltitude() - ((A / 2) * i * i); if (D <= 0) { splat = true; break; @@ -123,9 +117,9 @@ public class Splat { } else { if (terminalReached) { - System.out.printf("%.2f SPLAT\n", (V / A) + ((D1 - (V * V / (2 * A))) / V)); + System.out.printf("%.2f SPLAT\n", (V / A) + ((jump.getAltitude() - (V * V / (2 * A))) / V)); } else { - System.out.printf("%.2f SPLAT\n", Math.sqrt(2 * D1 / A)); + System.out.printf("%.2f SPLAT\n", Math.sqrt(2 * jump.getAltitude() / A)); } switch (random.nextInt(10)) { @@ -192,6 +186,13 @@ public class Splat { } + private InitialJumpConditions buildInitialConditions() { + System.out.print("\n\n"); + float terminalVelocity = promptTerminalVelocity(); + float gravitationalAcceleration = promptGravitationalAcceleration(); + return InitialJumpConditions.create(terminalVelocity, gravitationalAcceleration); + } + private void showIntroduction() { System.out.printf("%33s%s\n", " ", "SPLAT"); System.out.printf("%15s%s\n", " ", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); @@ -241,6 +242,59 @@ public class Splat { return planet.getAcceleration(); } + + static class InitialJumpConditions { + private final float originalTerminalVelocity; + private final float originalGravitationalAcceleration; + private final float terminalVelocity; + private final float gravitationalAcceleration; + private final int altitude; + + private InitialJumpConditions(float originalTerminalVelocity, float originalGravitationalAcceleration, + float terminalVelocity, float gravitationalAcceleration, int altitude) { + this.originalTerminalVelocity = originalTerminalVelocity; + this.originalGravitationalAcceleration = originalGravitationalAcceleration; + this.terminalVelocity = terminalVelocity; + this.gravitationalAcceleration = gravitationalAcceleration; + this.altitude = altitude; + } + + // Create initial jump conditions with adjusted velocity/acceleration and a random initial altitude + private static InitialJumpConditions create(float terminalVelocity, float gravitationalAcceleration) { + final int altitude = (int) (9001.0f * random.nextFloat() + 1000); + return new InitialJumpConditions(terminalVelocity, gravitationalAcceleration, + plusMinus5Percent(terminalVelocity), plusMinus5Percent(gravitationalAcceleration), altitude); + } + + private static float plusMinus5Percent(float value) { + return value + ((value * random.nextFloat()) / 20.0f) - ((value * random.nextFloat()) / 20.0f); + } + + public float getOriginalTerminalVelocity() { + return originalTerminalVelocity; + } + + public float getOriginalGravitationalAcceleration() { + return originalGravitationalAcceleration; + } + + public float getTerminalVelocity() { + return terminalVelocity; + } + + public float getGravitationalAcceleration() { + return gravitationalAcceleration; + } + + public int getAltitude() { + return altitude; + } + + public float getTimeOfTerminalAccelerationReached(){ + return terminalVelocity / gravitationalAcceleration; + } + } + enum Planet { MERCURY("FINE. YOU'RE ON MERCURY", 12.2f), VENUS("ALL RIGHT. YOU'RE ON VENUS", 28.3f), From 8a992b6ba44b38beb827a66d6e5f551dbbbec786 Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 22:07:32 -0800 Subject: [PATCH 086/331] invert if and factor out splat message --- 81_Splat/java/src/Splat.java | 85 +++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index 67e278f8..65be1d77 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -59,7 +59,15 @@ public class Splat { System.out.printf("%10.2f %f\n", i, D); } - if (!splat) { + if (splat) { + if (terminalReached) { + System.out.printf("%.2f SPLAT\n", (V / A) + ((jump.getAltitude() - (V * V / (2 * A))) / V)); + } else { + System.out.printf("%.2f SPLAT\n", Math.sqrt(2 * jump.getAltitude() / A)); + + } + showRandomSplatMessage(); + } else { System.out.println("CHUTE OPEN"); int J = 0; @@ -115,45 +123,6 @@ public class Splat { } - } else { - if (terminalReached) { - System.out.printf("%.2f SPLAT\n", (V / A) + ((jump.getAltitude() - (V * V / (2 * A))) / V)); - } else { - System.out.printf("%.2f SPLAT\n", Math.sqrt(2 * jump.getAltitude() / A)); - - } - switch (random.nextInt(10)) { - case 0: - System.out.println("REQUIESCAT IN PACE."); - break; - case 1: - System.out.println("MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE."); - break; - case 2: - System.out.println("REST IN PEACE."); - break; - case 3: - System.out.println("SON-OF-A-GUN."); - break; - case 4: - System.out.println("#$%&&%!$"); - break; - case 5: - System.out.println("A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT."); - break; - case 6: - System.out.println("HMMM. SHOULD HAVE PICKED A SHORTER TIME."); - break; - case 7: - System.out.println("MUTTER. MUTTER. MUTTER."); - break; - case 8: - System.out.println("PUSHING UP DAISIES."); - break; - default: - System.out.println("EASY COME, EASY GO."); - - } } boolean chosen = false; while (!chosen) { @@ -186,6 +155,41 @@ public class Splat { } + private void showRandomSplatMessage() { + switch (random.nextInt(10)) { + case 0: + System.out.println("REQUIESCAT IN PACE."); + break; + case 1: + System.out.println("MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE."); + break; + case 2: + System.out.println("REST IN PEACE."); + break; + case 3: + System.out.println("SON-OF-A-GUN."); + break; + case 4: + System.out.println("#$%&&%!$"); + break; + case 5: + System.out.println("A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT."); + break; + case 6: + System.out.println("HMMM. SHOULD HAVE PICKED A SHORTER TIME."); + break; + case 7: + System.out.println("MUTTER. MUTTER. MUTTER."); + break; + case 8: + System.out.println("PUSHING UP DAISIES."); + break; + default: + System.out.println("EASY COME, EASY GO."); + + } + } + private InitialJumpConditions buildInitialConditions() { System.out.print("\n\n"); float terminalVelocity = promptTerminalVelocity(); @@ -243,6 +247,7 @@ public class Splat { } + // Immutable static class InitialJumpConditions { private final float originalTerminalVelocity; private final float originalGravitationalAcceleration; From dd0dbf648037ba072c4df2bba66b9ed2d62bccc7 Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 22:10:44 -0800 Subject: [PATCH 087/331] simplify splat message --- 81_Splat/java/src/Splat.java | 48 +++++++++++------------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index 65be1d77..3e2f2f83 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -1,4 +1,5 @@ import java.util.Arrays; +import java.util.List; import java.util.Random; import java.util.Scanner; @@ -121,8 +122,6 @@ public class Splat { } System.out.println("SUCCESSFUL JUMP!!!"); } - - } boolean chosen = false; while (!chosen) { @@ -156,38 +155,19 @@ public class Splat { } private void showRandomSplatMessage() { - switch (random.nextInt(10)) { - case 0: - System.out.println("REQUIESCAT IN PACE."); - break; - case 1: - System.out.println("MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE."); - break; - case 2: - System.out.println("REST IN PEACE."); - break; - case 3: - System.out.println("SON-OF-A-GUN."); - break; - case 4: - System.out.println("#$%&&%!$"); - break; - case 5: - System.out.println("A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT."); - break; - case 6: - System.out.println("HMMM. SHOULD HAVE PICKED A SHORTER TIME."); - break; - case 7: - System.out.println("MUTTER. MUTTER. MUTTER."); - break; - case 8: - System.out.println("PUSHING UP DAISIES."); - break; - default: - System.out.println("EASY COME, EASY GO."); - - } + List messages = Arrays.asList( + "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." + ); + System.out.println(messages.get(random.nextInt(10))); } private InitialJumpConditions buildInitialConditions() { From 42f57024fe971b10c0399eb81decc776e04ce04d Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 22:31:51 -0800 Subject: [PATCH 088/331] factor out silly play again prompt --- 81_Splat/java/src/Splat.java | 72 +++++++++++++++--------------------- 1 file changed, 29 insertions(+), 43 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index 3e2f2f83..73d91021 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -21,13 +21,11 @@ public class Splat { while (true) { InitialJumpConditions jump = buildInitialConditions(); - final float V = jump.getTerminalVelocity(); - final float A = jump.getGravitationalAcceleration(); System.out.println(); System.out.printf(" ALTITUDE = %d FT\n", jump.getAltitude()); System.out.printf(" TERM. VELOCITY = %.2f FT/SEC +/-5%%\n", jump.getOriginalTerminalVelocity()); - System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", jump.getOriginalGravitationalAcceleration()); + System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", jump.getOriginalAcceleration()); System.out.println("SET THE TIMER FOR YOUR FREEFALL."); System.out.print("HOW MANY SECONDS "); @@ -35,6 +33,8 @@ public class Splat { System.out.println("HERE WE GO.\n"); System.out.println("TIME (SEC) DIST TO FALL (FT)"); System.out.println("========== ================="); + final float V = jump.getTerminalVelocity(); + final float A = jump.getAcceleration(); boolean splat = false; boolean terminalReached = false; float D = 0.0f; @@ -123,37 +123,24 @@ public class Splat { System.out.println("SUCCESSFUL JUMP!!!"); } } - boolean chosen = false; - while (!chosen) { - System.out.print("DO YOU WANT TO PLAY AGAIN "); - String Z = scanner.next(); - if (Z.equals("YES")) { - break; - } - if (Z.equals("NO")) { - System.out.print("PLEASE "); - while (true) { - Z = scanner.next(); - if (Z.equals("YES")) { - chosen = true; - break; - } - if (Z.equals("NO")) { - System.out.println("SSSSSSSSSS."); - return; - } - System.out.print("YES OR NO "); - } - continue; - } else { - System.out.print("YES OR NO "); - } + if(!playAgain()){ + return; } - } } + private boolean playAgain() { + if (askYesNo("DO YOU WANT TO PLAY AGAIN ")) { + return true; + } + if (askYesNo("PLEASE")) { + return true; + } + System.out.println("SSSSSSSSSS."); + return false; + } + private void showRandomSplatMessage() { List messages = Arrays.asList( "REQUIESCAT IN PACE.", @@ -173,8 +160,8 @@ public class Splat { private InitialJumpConditions buildInitialConditions() { System.out.print("\n\n"); float terminalVelocity = promptTerminalVelocity(); - float gravitationalAcceleration = promptGravitationalAcceleration(); - return InitialJumpConditions.create(terminalVelocity, gravitationalAcceleration); + float acceleration = promptGravitationalAcceleration(); + return InitialJumpConditions.create(terminalVelocity, acceleration); } private void showIntroduction() { @@ -226,21 +213,20 @@ public class Splat { return planet.getAcceleration(); } - // Immutable static class InitialJumpConditions { private final float originalTerminalVelocity; - private final float originalGravitationalAcceleration; + private final float originalAcceleration; private final float terminalVelocity; - private final float gravitationalAcceleration; + private final float acceleration; private final int altitude; - private InitialJumpConditions(float originalTerminalVelocity, float originalGravitationalAcceleration, - float terminalVelocity, float gravitationalAcceleration, int altitude) { + private InitialJumpConditions(float originalTerminalVelocity, float originalAcceleration, + float terminalVelocity, float acceleration, int altitude) { this.originalTerminalVelocity = originalTerminalVelocity; - this.originalGravitationalAcceleration = originalGravitationalAcceleration; + this.originalAcceleration = originalAcceleration; this.terminalVelocity = terminalVelocity; - this.gravitationalAcceleration = gravitationalAcceleration; + this.acceleration = acceleration; this.altitude = altitude; } @@ -259,16 +245,16 @@ public class Splat { return originalTerminalVelocity; } - public float getOriginalGravitationalAcceleration() { - return originalGravitationalAcceleration; + public float getOriginalAcceleration() { + return originalAcceleration; } public float getTerminalVelocity() { return terminalVelocity; } - public float getGravitationalAcceleration() { - return gravitationalAcceleration; + public float getAcceleration() { + return acceleration; } public int getAltitude() { @@ -276,7 +262,7 @@ public class Splat { } public float getTimeOfTerminalAccelerationReached(){ - return terminalVelocity / gravitationalAcceleration; + return terminalVelocity / acceleration; } } From 347558b966a041a6bf221cfeb8d655aeedd28441 Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 22:53:32 -0800 Subject: [PATCH 089/331] factor out JumpResult and executeJump() --- 81_Splat/java/src/Splat.java | 111 +++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 39 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index 73d91021..ad15d84e 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -20,65 +20,41 @@ public class Splat { int K1 = 0; while (true) { - InitialJumpConditions jump = buildInitialConditions(); + InitialJumpConditions initial = buildInitialConditions(); System.out.println(); - System.out.printf(" ALTITUDE = %d FT\n", jump.getAltitude()); - System.out.printf(" TERM. VELOCITY = %.2f FT/SEC +/-5%%\n", jump.getOriginalTerminalVelocity()); - System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", jump.getOriginalAcceleration()); + System.out.printf(" ALTITUDE = %d FT\n", initial.getAltitude()); + System.out.printf(" TERM. VELOCITY = %.2f FT/SEC +/-5%%\n", initial.getOriginalTerminalVelocity()); + System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", initial.getOriginalAcceleration()); System.out.println("SET THE TIMER FOR YOUR FREEFALL."); System.out.print("HOW MANY SECONDS "); - float T = scanner.nextFloat(); + float freefallTime = scanner.nextFloat(); System.out.println("HERE WE GO.\n"); System.out.println("TIME (SEC) DIST TO FALL (FT)"); System.out.println("========== ================="); - final float V = jump.getTerminalVelocity(); - final float A = jump.getAcceleration(); - boolean splat = false; - boolean terminalReached = false; - float D = 0.0f; - for (float i = 0.0f; !splat && (i < T); i += T / 8) { - if (i > jump.getTimeOfTerminalAccelerationReached()) { - terminalReached = true; - System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", jump.getTimeOfTerminalAccelerationReached()); - for (i = i; i < T; i += T / 8) { - D = jump.getAltitude() - ((V * V / (2 * A)) + (V * (i - (V / A)))); - if (D <= 0) { - splat = true; - break; - } - System.out.printf("%10.2f %f\n", i, D); - } - break; - } - D = jump.getAltitude() - ((A / 2) * i * i); - if (D <= 0) { - splat = true; - break; - } - System.out.printf("%10.2f %f\n", i, D); - } + final float V = initial.getTerminalVelocity(); + final float A = initial.getAcceleration(); + JumpResult jump = executeJump(initial, freefallTime); - if (splat) { - if (terminalReached) { - System.out.printf("%.2f SPLAT\n", (V / A) + ((jump.getAltitude() - (V * V / (2 * A))) / V)); + if (jump.isSplat()) { + if (jump.hasReachedTerminalVelocity()) { + System.out.printf("%.2f SPLAT\n", (V / A) + ((initial.getAltitude() - (V * V / (2 * A))) / V)); } else { - System.out.printf("%.2f SPLAT\n", Math.sqrt(2 * jump.getAltitude() / A)); + System.out.printf("%.2f SPLAT\n", Math.sqrt(2 * initial.getAltitude() / A)); } showRandomSplatMessage(); } else { - System.out.println("CHUTE OPEN"); int J = 0; for (J = 0; J < 42; J++) { if (Arr[J] == 0) { - Arr[J] = D; + Arr[J] = jump.getDistance(); break; } K = K + 1; - if (D > Arr[J]) { + if (jump.getDistance() > Arr[J]) { continue; } K1 = K1 + 1; @@ -98,7 +74,7 @@ public class Splat { System.out.printf("YOU WERE BEATEN OUT BY %d OF THEM.\n", K - K1); } else if (K - K1 <= 0.75 * K) { System.out.printf("CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY %d IN THE\n", K - K1); - System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS.", K); + System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS.\n", K); } else if (K - K1 <= -0.9 * K) { System.out.println("HUMPH! DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE"); System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN %d JUMPS\n", K, K1); @@ -130,6 +106,33 @@ public class Splat { } + private JumpResult executeJump(InitialJumpConditions initial, float T) { + final float V = initial.getTerminalVelocity(); + final float A = initial.getAcceleration(); + + JumpResult jump = new JumpResult(initial.getAltitude()); + for (float i = 0.0f; !jump.isSplat() && (i < T); i += T / 8) { + if (i > initial.getTimeOfTerminalAccelerationReached()) { + jump.setReachedTerminalVelocity(); + System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", initial.getTimeOfTerminalAccelerationReached()); + for (i = i; i < T; i += T / 8) { + jump.setDistance(initial.getAltitude() - ((V * V / (2 * A)) + (V * (i - (V / A))))); + if (jump.isSplat()) { + break; + } + System.out.printf("%10.2f %f\n", i, jump.getDistance()); + } + break; + } + jump.setDistance( initial.getAltitude() - ((A / 2) * i * i)); + if (jump.isSplat()) { + break; + } + System.out.printf("%10.2f %f\n", i, jump.getDistance()); + } + return jump; + } + private boolean playAgain() { if (askYesNo("DO YOU WANT TO PLAY AGAIN ")) { return true; @@ -213,6 +216,36 @@ public class Splat { return planet.getAcceleration(); } + // Mutable + static class JumpResult { + private boolean reachedTerminalVelocity = false; + private float distance; // from the ground + + public JumpResult(float distance) { + this.distance = distance; + } + + public boolean isSplat() { + return distance <= 0; + } + + public boolean hasReachedTerminalVelocity() { + return reachedTerminalVelocity; + } + + public float getDistance() { + return distance; + } + + public void setDistance(float distance){ + this.distance = distance; + } + + public void setReachedTerminalVelocity(){ + reachedTerminalVelocity = true; + } + } + // Immutable static class InitialJumpConditions { private final float originalTerminalVelocity; From 98b4e94719d08fbcc05cf6fba07eca8df7aaa66f Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 23:14:58 -0800 Subject: [PATCH 090/331] factor out result message display and clean up ordinal switch --- 81_Splat/java/src/Splat.java | 159 +++++++++++++++++------------------ 1 file changed, 76 insertions(+), 83 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index ad15d84e..a0193507 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -6,6 +6,9 @@ import java.util.Scanner; public class Splat { private static final Random random = new Random(); private final Scanner scanner = new Scanner(System.in); + private final float[] Arr = new float[42]; + private int K = 0; + private int K1 = 0; public static void main(String[] args) { new Splat().run(); @@ -14,10 +17,7 @@ public class Splat { public void run() { showIntroduction(); - float[] Arr = new float[42]; Arrays.fill(Arr, 0.0f); - int K = 0; - int K1 = 0; while (true) { InitialJumpConditions initial = buildInitialConditions(); @@ -33,106 +33,100 @@ public class Splat { System.out.println("HERE WE GO.\n"); System.out.println("TIME (SEC) DIST TO FALL (FT)"); System.out.println("========== ================="); - final float V = initial.getTerminalVelocity(); - final float A = initial.getAcceleration(); + JumpResult jump = executeJump(initial, freefallTime); + showJumpResults(initial, jump); - if (jump.isSplat()) { - if (jump.hasReachedTerminalVelocity()) { - System.out.printf("%.2f SPLAT\n", (V / A) + ((initial.getAltitude() - (V * V / (2 * A))) / V)); - } else { - System.out.printf("%.2f SPLAT\n", Math.sqrt(2 * initial.getAltitude() / A)); - - } - showRandomSplatMessage(); - } else { - System.out.println("CHUTE OPEN"); - int J = 0; - for (J = 0; J < 42; J++) { - if (Arr[J] == 0) { - Arr[J] = jump.getDistance(); - break; - } - K = K + 1; - if (jump.getDistance() > Arr[J]) { - continue; - } - K1 = K1 + 1; - } - - if (J > 2) { - if (K - K1 <= 0.1 * K) { - System.out.printf("WOW! THAT'S SOME JUMPING. OF THE %d SUCCESSFUL JUMPS\n", K); - System.out.printf("BEFORE YOURS, ONLY %d OPENED THEIR CHUTES LOWER THAN\n", K - K1); - System.out.println("YOU DID."); - } else if (K - K1 <= 0.25 * K) { - System.out.printf("PRETTY GOOD! %d SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\n", K); - System.out.printf("%d OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\n", K - K1); - System.out.println("OPENED."); - } else if (K - K1 <= 0.5 * K) { - System.out.printf("NOT BAD. THERE HAVE BEEN %d SUCCESSFUL JUMPS BEFORE YOURS.\n", K); - System.out.printf("YOU WERE BEATEN OUT BY %d OF THEM.\n", K - K1); - } else if (K - K1 <= 0.75 * K) { - System.out.printf("CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY %d IN THE\n", K - K1); - System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS.\n", K); - } else if (K - K1 <= -0.9 * K) { - System.out.println("HUMPH! DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE"); - System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN %d JUMPS\n", K, K1); - System.out.println("BETTER THAN THE WORST. SHAPE UP!!!\n"); - } else { - System.out.printf("HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. %f SUCCESSFUL\n", K); - System.out.printf("JUMPS BEFORE YOURS AND YOU CAME IN NUMBER %d! GET WITH IT!\n", K - K1); - } - } else { - System.out.println("AMAZING!!! NOT BAD FOR YOUR "); - switch (J) { - case 0: - System.out.print("1ST "); - break; - case 1: - System.out.print("2ND "); - break; - case 2: - System.out.print("3RD "); - break; - } - System.out.println("SUCCESSFUL JUMP!!!"); - } - } if(!playAgain()){ + System.out.println("SSSSSSSSSS."); return; } } - } - private JumpResult executeJump(InitialJumpConditions initial, float T) { + private void showJumpResults(InitialJumpConditions initial, JumpResult jump) { final float V = initial.getTerminalVelocity(); final float A = initial.getAcceleration(); + if (jump.isSplat()) { + if (jump.hasReachedTerminalVelocity()) { + System.out.printf("%.2f SPLAT\n", (V / A) + ((initial.getAltitude() - (V * V / (2 * A))) / V)); + } else { + System.out.printf("%.2f SPLAT\n", Math.sqrt(2 * initial.getAltitude() / A)); + } + showRandomSplatMessage(); + } else { + System.out.println("CHUTE OPEN"); + int J = 0; + for (J = 0; J < 42; J++) { + if (Arr[J] == 0) { + Arr[J] = jump.getDistance(); + break; + } + K = K + 1; + if (jump.getDistance() > Arr[J]) { + continue; + } + K1 = K1 + 1; + } + + if (J > 2) { + if (K - K1 <= 0.1 * K) { + System.out.printf("WOW! THAT'S SOME JUMPING. OF THE %d SUCCESSFUL JUMPS\n", K); + System.out.printf("BEFORE YOURS, ONLY %d OPENED THEIR CHUTES LOWER THAN\n", K - K1); + System.out.println("YOU DID."); + } else if (K - K1 <= 0.25 * K) { + System.out.printf("PRETTY GOOD! %d SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\n", K); + System.out.printf("%d OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\n", K - K1); + System.out.println("OPENED."); + } else if (K - K1 <= 0.5 * K) { + System.out.printf("NOT BAD. THERE HAVE BEEN %d SUCCESSFUL JUMPS BEFORE YOURS.\n", K); + System.out.printf("YOU WERE BEATEN OUT BY %d OF THEM.\n", K - K1); + } else if (K - K1 <= 0.75 * K) { + System.out.printf("CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY %d IN THE\n", K - K1); + System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS.\n", K); + } else if (K - K1 <= -0.9 * K) { + System.out.println("HUMPH! DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE"); + System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN %d JUMPS\n", K, K1); + System.out.println("BETTER THAN THE WORST. SHAPE UP!!!\n"); + } else { + System.out.printf("HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. %f SUCCESSFUL\n", K); + System.out.printf("JUMPS BEFORE YOURS AND YOU CAME IN NUMBER %d! GET WITH IT!\n", K - K1); + } + } else { + String[] nums = new String[]{ "1ST", "2ND", "3RD"}; + System.out.printf("AMAZING!!! NOT BAD FOR YOUR %s SUCCESSFUL JUMP!!!\n", nums[J]); + } + } + } + + private JumpResult executeJump(InitialJumpConditions initial, float chuteOpenTime) { JumpResult jump = new JumpResult(initial.getAltitude()); - for (float i = 0.0f; !jump.isSplat() && (i < T); i += T / 8) { - if (i > initial.getTimeOfTerminalAccelerationReached()) { + for (float time = 0.0f; !jump.isSplat() && (time < chuteOpenTime); time += chuteOpenTime / 8) { + if (!jump.hasReachedTerminalVelocity() && time > initial.getTimeOfTerminalAccelerationReached()) { jump.setReachedTerminalVelocity(); System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", initial.getTimeOfTerminalAccelerationReached()); - for (i = i; i < T; i += T / 8) { - jump.setDistance(initial.getAltitude() - ((V * V / (2 * A)) + (V * (i - (V / A))))); - if (jump.isSplat()) { - break; - } - System.out.printf("%10.2f %f\n", i, jump.getDistance()); - } - break; } - jump.setDistance( initial.getAltitude() - ((A / 2) * i * i)); + float newDistance = computeDistance(initial, time, jump.hasReachedTerminalVelocity()); + jump.setDistance(newDistance); + if (jump.isSplat()) { - break; + return jump; } - System.out.printf("%10.2f %f\n", i, jump.getDistance()); + System.out.printf("%10.2f %f\n", time, jump.getDistance()); } return jump; } + private float computeDistance(InitialJumpConditions initial, float i, boolean hasReachedTerminalVelocity) { + final float V = initial.getTerminalVelocity(); + final float A = initial.getAcceleration(); + if(hasReachedTerminalVelocity) { + return initial.getAltitude() - ((V * V / (2 * A)) + (V * (i - (V / A)))); + } + return initial.getAltitude() - ((A / 2) * i * i); + } + private boolean playAgain() { if (askYesNo("DO YOU WANT TO PLAY AGAIN ")) { return true; @@ -140,7 +134,6 @@ public class Splat { if (askYesNo("PLEASE")) { return true; } - System.out.println("SSSSSSSSSS."); return false; } From 8e98439f35e93e95379ef652fd283a10d919baeb Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 23:49:31 -0800 Subject: [PATCH 091/331] simplify handling of past successes --- 81_Splat/java/src/Splat.java | 146 +++++++++++++++++------------------ 1 file changed, 72 insertions(+), 74 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index a0193507..2586ecab 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -1,14 +1,9 @@ -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import java.util.Scanner; +import java.util.*; public class Splat { private static final Random random = new Random(); private final Scanner scanner = new Scanner(System.in); - private final float[] Arr = new float[42]; - private int K = 0; - private int K1 = 0; + private final List pastSuccessfulJumpDistances = new ArrayList<>(); public static void main(String[] args) { new Splat().run(); @@ -17,7 +12,6 @@ public class Splat { public void run() { showIntroduction(); - Arrays.fill(Arr, 0.0f); while (true) { InitialJumpConditions initial = buildInitialConditions(); @@ -45,59 +39,66 @@ public class Splat { } private void showJumpResults(InitialJumpConditions initial, JumpResult jump) { + if (jump.isSplat()) { + showSplatMessage(initial, jump); + showCleverSplatMessage(); + return; + } + System.out.println("CHUTE OPEN"); + int worseJumpCount = countWorseHistoricalJumps(jump); + pastSuccessfulJumpDistances.add(jump.getDistance()); + int successfulJumpCt = pastSuccessfulJumpDistances.size(); + + if (pastSuccessfulJumpDistances.size() <= 2) { + List ordinals = Arrays.asList("1ST", "2ND", "3RD"); + System.out.printf("AMAZING!!! NOT BAD FOR YOUR %s SUCCESSFUL JUMP!!!\n", ordinals.get(successfulJumpCt)); + return; + } + + int betterThanCount = successfulJumpCt - worseJumpCount; + if (betterThanCount <= 0.1 * successfulJumpCt) { + System.out.printf("WOW! THAT'S SOME JUMPING. OF THE %d SUCCESSFUL JUMPS\n", successfulJumpCt); + System.out.printf("BEFORE YOURS, ONLY %d OPENED THEIR CHUTES LOWER THAN\n", betterThanCount); + System.out.println("YOU DID."); + } else if (betterThanCount <= 0.25 * successfulJumpCt) { + System.out.printf("PRETTY GOOD! %d SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\n", successfulJumpCt); + System.out.printf("%d OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\n", betterThanCount); + System.out.println("OPENED."); + } else if (betterThanCount <= 0.5 * successfulJumpCt) { + System.out.printf("NOT BAD. THERE HAVE BEEN %d SUCCESSFUL JUMPS BEFORE YOURS.\n", successfulJumpCt); + System.out.printf("YOU WERE BEATEN OUT BY %d OF THEM.\n", betterThanCount); + } else if (betterThanCount <= 0.75 * successfulJumpCt) { + System.out.printf("CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY %d IN THE\n", betterThanCount); + System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS.\n", successfulJumpCt); + } else if (betterThanCount <= -0.9 * successfulJumpCt) { + System.out.println("HUMPH! DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE"); + System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN %d JUMPS\n", successfulJumpCt, worseJumpCount); + System.out.println("BETTER THAN THE WORST. SHAPE UP!!!\n"); + } else { + System.out.printf("HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. %d SUCCESSFUL\n", successfulJumpCt); + System.out.printf("JUMPS BEFORE YOURS AND YOU CAME IN NUMBER %d! GET WITH IT!\n", betterThanCount); + } + } + + private void showSplatMessage(InitialJumpConditions initial, JumpResult jump) { + double timeOfSplat = computeTimeOfSplat(initial, jump); + System.out.printf("%10.2f SPLAT\n", timeOfSplat); + } + + private double computeTimeOfSplat(InitialJumpConditions initial, JumpResult jump) { final float V = initial.getTerminalVelocity(); final float A = initial.getAcceleration(); - - if (jump.isSplat()) { - if (jump.hasReachedTerminalVelocity()) { - System.out.printf("%.2f SPLAT\n", (V / A) + ((initial.getAltitude() - (V * V / (2 * A))) / V)); - } else { - System.out.printf("%.2f SPLAT\n", Math.sqrt(2 * initial.getAltitude() / A)); - } - showRandomSplatMessage(); - } else { - System.out.println("CHUTE OPEN"); - int J = 0; - for (J = 0; J < 42; J++) { - if (Arr[J] == 0) { - Arr[J] = jump.getDistance(); - break; - } - K = K + 1; - if (jump.getDistance() > Arr[J]) { - continue; - } - K1 = K1 + 1; - } - - if (J > 2) { - if (K - K1 <= 0.1 * K) { - System.out.printf("WOW! THAT'S SOME JUMPING. OF THE %d SUCCESSFUL JUMPS\n", K); - System.out.printf("BEFORE YOURS, ONLY %d OPENED THEIR CHUTES LOWER THAN\n", K - K1); - System.out.println("YOU DID."); - } else if (K - K1 <= 0.25 * K) { - System.out.printf("PRETTY GOOD! %d SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\n", K); - System.out.printf("%d OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\n", K - K1); - System.out.println("OPENED."); - } else if (K - K1 <= 0.5 * K) { - System.out.printf("NOT BAD. THERE HAVE BEEN %d SUCCESSFUL JUMPS BEFORE YOURS.\n", K); - System.out.printf("YOU WERE BEATEN OUT BY %d OF THEM.\n", K - K1); - } else if (K - K1 <= 0.75 * K) { - System.out.printf("CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY %d IN THE\n", K - K1); - System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS.\n", K); - } else if (K - K1 <= -0.9 * K) { - System.out.println("HUMPH! DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE"); - System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN %d JUMPS\n", K, K1); - System.out.println("BETTER THAN THE WORST. SHAPE UP!!!\n"); - } else { - System.out.printf("HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. %f SUCCESSFUL\n", K); - System.out.printf("JUMPS BEFORE YOURS AND YOU CAME IN NUMBER %d! GET WITH IT!\n", K - K1); - } - } else { - String[] nums = new String[]{ "1ST", "2ND", "3RD"}; - System.out.printf("AMAZING!!! NOT BAD FOR YOUR %s SUCCESSFUL JUMP!!!\n", nums[J]); - } + if (jump.hasReachedTerminalVelocity()) { + return (V / A) + ((initial.getAltitude() - (V * V / (2 * A))) / V); } + return Math.sqrt(2 * initial.getAltitude() / A); + } + + // Returns the number of jumps that this jump was better than + private int countWorseHistoricalJumps(JumpResult jump) { + return (int) pastSuccessfulJumpDistances.stream() + .filter(distance -> jump.getDistance() < distance) + .count(); } private JumpResult executeJump(InitialJumpConditions initial, float chuteOpenTime) { @@ -131,13 +132,10 @@ public class Splat { if (askYesNo("DO YOU WANT TO PLAY AGAIN ")) { return true; } - if (askYesNo("PLEASE")) { - return true; - } - return false; + return askYesNo("PLEASE"); } - private void showRandomSplatMessage() { + private void showCleverSplatMessage() { List messages = Arrays.asList( "REQUIESCAT IN PACE.", "MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.", @@ -205,7 +203,7 @@ public class Splat { private float chooseRandomAcceleration() { Planet planet = Planet.pickRandom(); - System.out.printf("%s. ACCELERATION=%.2f FT/SEC/SEC.\n", planet.getMessage(), planet.getAcceleration()); + System.out.printf("%s %s. ACCELERATION=%.2f FT/SEC/SEC.\n", planet.getMessage(), planet.name(), planet.getAcceleration()); return planet.getAcceleration(); } @@ -293,16 +291,16 @@ public class Splat { } enum Planet { - MERCURY("FINE. YOU'RE ON MERCURY", 12.2f), - VENUS("ALL RIGHT. YOU'RE ON VENUS", 28.3f), - EARTH("THEN YOU'RE ON EARTH", 32.16f), - MOON("FINE. YOU'RE ON THE MOON", 5.15f), - MARS("ALL RIGHT. YOU'RE ON MARS", 12.5f), - JUPITER("THEN YOU'RE ON JUPITER", 85.2f), - SATURN("FINE. YOU'RE ON SATURN", 37.6f), - URANUS("ALL RIGHT. YOU'RE ON URANUS", 33.8f), - NEPTUNE("THEN YOU'RE ON NEPTUNE", 39.6f), - SUN("FINE. YOU'RE ON THE SUN", 896.0f); + MERCURY("FINE. YOU'RE ON", 12.2f), + VENUS("ALL RIGHT. YOU'RE ON", 28.3f), + EARTH("THEN YOU'RE ON", 32.16f), + MOON("FINE. YOU'RE ON THE", 5.15f), + MARS("ALL RIGHT. YOU'RE ON", 12.5f), + JUPITER("THEN YOU'RE ON", 85.2f), + SATURN("FINE. YOU'RE ON", 37.6f), + URANUS("ALL RIGHT. YOU'RE ON", 33.8f), + NEPTUNE("THEN YOU'RE ON", 39.6f), + SUN("FINE. YOU'RE ON THE", 896.0f); static final Random random = new Random(); private final String message; From 522975485110ed58784438945e21e575e14bc5ef Mon Sep 17 00:00:00 2001 From: jason Date: Tue, 4 Jan 2022 23:59:26 -0800 Subject: [PATCH 092/331] fix problem with holding count after add and fix up some visiblity for simplicity --- 81_Splat/java/src/Splat.java | 92 ++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index 2586ecab..6b89dde2 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -46,8 +46,8 @@ public class Splat { } System.out.println("CHUTE OPEN"); int worseJumpCount = countWorseHistoricalJumps(jump); - pastSuccessfulJumpDistances.add(jump.getDistance()); int successfulJumpCt = pastSuccessfulJumpDistances.size(); + pastSuccessfulJumpDistances.add(jump.getDistance()); if (pastSuccessfulJumpDistances.size() <= 2) { List ordinals = Arrays.asList("1ST", "2ND", "3RD"); @@ -207,6 +207,40 @@ public class Splat { return planet.getAcceleration(); } + enum Planet { + MERCURY("FINE. YOU'RE ON", 12.2f), + VENUS("ALL RIGHT. YOU'RE ON", 28.3f), + EARTH("THEN YOU'RE ON", 32.16f), + MOON("FINE. YOU'RE ON THE", 5.15f), + MARS("ALL RIGHT. YOU'RE ON", 12.5f), + JUPITER("THEN YOU'RE ON", 85.2f), + SATURN("FINE. YOU'RE ON", 37.6f), + URANUS("ALL RIGHT. YOU'RE ON", 33.8f), + NEPTUNE("THEN YOU'RE ON", 39.6f), + SUN("FINE. YOU'RE ON THE", 896.0f); + + private static final Random random = new Random(); + private final String message; + private final float acceleration; + + Planet(String message, float acceleration) { + this.message = message; + this.acceleration = acceleration; + } + + static Planet pickRandom(){ + return values()[random.nextInt(Planet.values().length)]; + } + + String getMessage() { + return message; + } + + float getAcceleration() { + return acceleration; + } + } + // Mutable static class JumpResult { private boolean reachedTerminalVelocity = false; @@ -216,23 +250,23 @@ public class Splat { this.distance = distance; } - public boolean isSplat() { + boolean isSplat() { return distance <= 0; } - public boolean hasReachedTerminalVelocity() { + boolean hasReachedTerminalVelocity() { return reachedTerminalVelocity; } - public float getDistance() { + float getDistance() { return distance; } - public void setDistance(float distance){ + void setDistance(float distance){ this.distance = distance; } - public void setReachedTerminalVelocity(){ + void setReachedTerminalVelocity(){ reachedTerminalVelocity = true; } } @@ -265,62 +299,28 @@ public class Splat { return value + ((value * random.nextFloat()) / 20.0f) - ((value * random.nextFloat()) / 20.0f); } - public float getOriginalTerminalVelocity() { + float getOriginalTerminalVelocity() { return originalTerminalVelocity; } - public float getOriginalAcceleration() { + float getOriginalAcceleration() { return originalAcceleration; } - public float getTerminalVelocity() { + float getTerminalVelocity() { return terminalVelocity; } - public float getAcceleration() { + float getAcceleration() { return acceleration; } - public int getAltitude() { + int getAltitude() { return altitude; } - public float getTimeOfTerminalAccelerationReached(){ + float getTimeOfTerminalAccelerationReached(){ return terminalVelocity / acceleration; } } - - enum Planet { - MERCURY("FINE. YOU'RE ON", 12.2f), - VENUS("ALL RIGHT. YOU'RE ON", 28.3f), - EARTH("THEN YOU'RE ON", 32.16f), - MOON("FINE. YOU'RE ON THE", 5.15f), - MARS("ALL RIGHT. YOU'RE ON", 12.5f), - JUPITER("THEN YOU'RE ON", 85.2f), - SATURN("FINE. YOU'RE ON", 37.6f), - URANUS("ALL RIGHT. YOU'RE ON", 33.8f), - NEPTUNE("THEN YOU'RE ON", 39.6f), - SUN("FINE. YOU'RE ON THE", 896.0f); - - static final Random random = new Random(); - private final String message; - private final float acceleration; - - Planet(String message, float acceleration) { - this.message = message; - this.acceleration = acceleration; - } - - static Planet pickRandom(){ - return values()[random.nextInt(Planet.values().length)]; - } - - public String getMessage() { - return message; - } - - public float getAcceleration() { - return acceleration; - } - } } \ No newline at end of file From 9cc332f568189fa7bc028e662de6a5e08e3a88a7 Mon Sep 17 00:00:00 2001 From: jason Date: Wed, 5 Jan 2022 00:00:03 -0800 Subject: [PATCH 093/331] grammar nit --- 81_Splat/java/src/Splat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index 6b89dde2..4c0e2fdf 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -94,7 +94,7 @@ public class Splat { return Math.sqrt(2 * initial.getAltitude() / A); } - // Returns the number of jumps that this jump was better than + // Returns the number of jumps for which this jump was better private int countWorseHistoricalJumps(JumpResult jump) { return (int) pastSuccessfulJumpDistances.stream() .filter(distance -> jump.getDistance() < distance) From 11dba9dd92cef1a0d26c2300129be460072a6fd7 Mon Sep 17 00:00:00 2001 From: jason Date: Wed, 5 Jan 2022 00:04:24 -0800 Subject: [PATCH 094/331] debrand --- 81_Splat/java/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/81_Splat/java/README.md b/81_Splat/java/README.md index 51edd8d4..b8998fa6 100644 --- a/81_Splat/java/README.md +++ b/81_Splat/java/README.md @@ -1,3 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Oracle Java](https://openjdk.java.net/) +Conversion to [Java](https://openjdk.java.net/) From 18b37bda81c1504cc6c062de84787a6403953630 Mon Sep 17 00:00:00 2001 From: jason Date: Wed, 5 Jan 2022 00:12:43 -0800 Subject: [PATCH 095/331] add top comment copied from readme (includes attribution) and reorganize methods for readability. --- 81_Splat/java/src/Splat.java | 196 +++++++++++++++++++---------------- 1 file changed, 109 insertions(+), 87 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index 4c0e2fdf..3c4cd817 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -1,5 +1,22 @@ import java.util.*; +/** + * SPLAT simulates a parachute jump in which you try to open your parachute at the last possible moment without going + * splat! You may select your own terminal velocity or let the computer do it for you. You many also select the + * acceleration due to gravity or, again, let the computer do it in which case you might wind up on any of eight + * planets (out to Neptune), the moon, or the sun. + *

+ * The computer then tells you the height you’re jumping from and asks for the seconds of free fall. It then divides + * your free fall time into eight intervals and gives you progress reports on your way down. The computer also keeps + * track of all prior jumps in the array A and lets you know how you compared with previous successful jumps. If you + * want to recall information from previous runs, then you should store array A in a disk or take file and read it + * before each run. + *

+ * John Yegge created this program while at the Oak Ridge Associated Universities. + *

+ * Ported from BASIC by jason plumb (@breedx2) + *

+ */ public class Splat { private static final Random random = new Random(); private final Scanner scanner = new Scanner(System.in); @@ -31,13 +48,74 @@ public class Splat { JumpResult jump = executeJump(initial, freefallTime); showJumpResults(initial, jump); - if(!playAgain()){ + if (!playAgain()) { System.out.println("SSSSSSSSSS."); return; } } } + private void showIntroduction() { + System.out.printf("%33s%s\n", " ", "SPLAT"); + System.out.printf("%15s%s\n", " ", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.print("\n\n\n"); + System.out.println("WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE"); + System.out.println("JUMP. TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE"); + System.out.println("MOMENT WITHOUT GOING SPLAT."); + } + + private InitialJumpConditions buildInitialConditions() { + System.out.print("\n\n"); + float terminalVelocity = promptTerminalVelocity(); + float acceleration = promptGravitationalAcceleration(); + return InitialJumpConditions.create(terminalVelocity, acceleration); + } + + private float promptTerminalVelocity() { + if (askYesNo("SELECT YOUR OWN TERMINAL VELOCITY")) { + System.out.print("WHAT TERMINAL VELOCITY (MI/HR) "); + return mphToFeetPerSec(scanner.nextFloat()); + } + float terminalVelocity = (int) (1000 * random.nextFloat()); + System.out.printf("OK. TERMINAL VELOCITY = %.2f MI/HR\n", terminalVelocity); + return mphToFeetPerSec(terminalVelocity); + } + + private float promptGravitationalAcceleration() { + if (askYesNo("WANT TO SELECT ACCELERATION DUE TO GRAVITY")) { + System.out.print("WHAT ACCELERATION (FT/SEC/SEC) "); + return scanner.nextFloat(); + } + return chooseRandomAcceleration(); + } + + private JumpResult executeJump(InitialJumpConditions initial, float chuteOpenTime) { + JumpResult jump = new JumpResult(initial.getAltitude()); + for (float time = 0.0f; !jump.isSplat() && (time < chuteOpenTime); time += chuteOpenTime / 8) { + if (!jump.hasReachedTerminalVelocity() && time > initial.getTimeOfTerminalAccelerationReached()) { + jump.setReachedTerminalVelocity(); + System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", initial.getTimeOfTerminalAccelerationReached()); + } + float newDistance = computeDistance(initial, time, jump.hasReachedTerminalVelocity()); + jump.setDistance(newDistance); + + if (jump.isSplat()) { + return jump; + } + System.out.printf("%10.2f %f\n", time, jump.getDistance()); + } + return jump; + } + + private float computeDistance(InitialJumpConditions initial, float i, boolean hasReachedTerminalVelocity) { + final float V = initial.getTerminalVelocity(); + final float A = initial.getAcceleration(); + if (hasReachedTerminalVelocity) { + return initial.getAltitude() - ((V * V / (2 * A)) + (V * (i - (V / A)))); + } + return initial.getAltitude() - ((A / 2) * i * i); + } + private void showJumpResults(InitialJumpConditions initial, JumpResult jump) { if (jump.isSplat()) { showSplatMessage(initial, jump); @@ -85,6 +163,9 @@ public class Splat { System.out.printf("%10.2f SPLAT\n", timeOfSplat); } + /** + * Returns the number of jumps for which this jump was better + */ private double computeTimeOfSplat(InitialJumpConditions initial, JumpResult jump) { final float V = initial.getTerminalVelocity(); final float A = initial.getAcceleration(); @@ -94,38 +175,26 @@ public class Splat { return Math.sqrt(2 * initial.getAltitude() / A); } - // Returns the number of jumps for which this jump was better private int countWorseHistoricalJumps(JumpResult jump) { return (int) pastSuccessfulJumpDistances.stream() .filter(distance -> jump.getDistance() < distance) .count(); } - private JumpResult executeJump(InitialJumpConditions initial, float chuteOpenTime) { - JumpResult jump = new JumpResult(initial.getAltitude()); - for (float time = 0.0f; !jump.isSplat() && (time < chuteOpenTime); time += chuteOpenTime / 8) { - if (!jump.hasReachedTerminalVelocity() && time > initial.getTimeOfTerminalAccelerationReached()) { - jump.setReachedTerminalVelocity(); - System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", initial.getTimeOfTerminalAccelerationReached()); - } - float newDistance = computeDistance(initial, time, jump.hasReachedTerminalVelocity()); - jump.setDistance(newDistance); - - if (jump.isSplat()) { - return jump; - } - System.out.printf("%10.2f %f\n", time, jump.getDistance()); - } - return jump; - } - - private float computeDistance(InitialJumpConditions initial, float i, boolean hasReachedTerminalVelocity) { - final float V = initial.getTerminalVelocity(); - final float A = initial.getAcceleration(); - if(hasReachedTerminalVelocity) { - return initial.getAltitude() - ((V * V / (2 * A)) + (V * (i - (V / A)))); - } - return initial.getAltitude() - ((A / 2) * i * i); + private void showCleverSplatMessage() { + List messages = Arrays.asList( + "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." + ); + System.out.println(messages.get(random.nextInt(10))); } private boolean playAgain() { @@ -135,68 +204,21 @@ public class Splat { return askYesNo("PLEASE"); } - private void showCleverSplatMessage() { - List messages = Arrays.asList( - "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." - ); - System.out.println(messages.get(random.nextInt(10))); - } - - private InitialJumpConditions buildInitialConditions() { - System.out.print("\n\n"); - float terminalVelocity = promptTerminalVelocity(); - float acceleration = promptGravitationalAcceleration(); - return InitialJumpConditions.create(terminalVelocity, acceleration); - } - - private void showIntroduction() { - System.out.printf("%33s%s\n", " ", "SPLAT"); - System.out.printf("%15s%s\n", " ", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); - System.out.print("\n\n\n"); - System.out.println("WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE"); - System.out.println("JUMP. TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE"); - System.out.println("MOMENT WITHOUT GOING SPLAT."); - } - - private float promptTerminalVelocity() { - if(askYesNo("SELECT YOUR OWN TERMINAL VELOCITY")){ - System.out.print("WHAT TERMINAL VELOCITY (MI/HR) "); - return mphToFeetPerSec(scanner.nextFloat()); - } - float terminalVelocity = (int) (1000 * random.nextFloat()); - System.out.printf("OK. TERMINAL VELOCITY = %.2f MI/HR\n", terminalVelocity); - return mphToFeetPerSec(terminalVelocity); - } - - private float promptGravitationalAcceleration() { - if(askYesNo("WANT TO SELECT ACCELERATION DUE TO GRAVITY")){ - System.out.print("WHAT ACCELERATION (FT/SEC/SEC) "); - return scanner.nextFloat(); - } - return chooseRandomAcceleration(); - } - - private float mphToFeetPerSec(float speed){ + private float mphToFeetPerSec(float speed) { return speed * (5280.0f / 3600.0f); } - private boolean askYesNo(String prompt){ + private boolean askYesNo(String prompt) { System.out.printf("%s (YES OR NO) ", prompt); while (true) { String answer = scanner.next(); - switch(answer){ - case "YES": return true; - case "NO": return false; - default: System.out.print("YES OR NO "); + switch (answer) { + case "YES": + return true; + case "NO": + return false; + default: + System.out.print("YES OR NO "); } } } @@ -228,7 +250,7 @@ public class Splat { this.acceleration = acceleration; } - static Planet pickRandom(){ + static Planet pickRandom() { return values()[random.nextInt(Planet.values().length)]; } @@ -262,11 +284,11 @@ public class Splat { return distance; } - void setDistance(float distance){ + void setDistance(float distance) { this.distance = distance; } - void setReachedTerminalVelocity(){ + void setReachedTerminalVelocity() { reachedTerminalVelocity = true; } } @@ -319,7 +341,7 @@ public class Splat { return altitude; } - float getTimeOfTerminalAccelerationReached(){ + float getTimeOfTerminalAccelerationReached() { return terminalVelocity / acceleration; } } From 3c185d1c8c2c3c7eed2995b04aed9861699294dc Mon Sep 17 00:00:00 2001 From: jason Date: Wed, 5 Jan 2022 00:15:05 -0800 Subject: [PATCH 096/331] remove unnecessary leftover check --- 81_Splat/java/src/Splat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index 3c4cd817..b76c82ff 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -91,7 +91,7 @@ public class Splat { private JumpResult executeJump(InitialJumpConditions initial, float chuteOpenTime) { JumpResult jump = new JumpResult(initial.getAltitude()); - for (float time = 0.0f; !jump.isSplat() && (time < chuteOpenTime); time += chuteOpenTime / 8) { + for (float time = 0.0f; time < chuteOpenTime; time += chuteOpenTime / 8) { if (!jump.hasReachedTerminalVelocity() && time > initial.getTimeOfTerminalAccelerationReached()) { jump.setReachedTerminalVelocity(); System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", initial.getTimeOfTerminalAccelerationReached()); From 3bdb7be6d171f0f7dd461af0a72e1e8f0f3c27ab Mon Sep 17 00:00:00 2001 From: Minas Date: Wed, 5 Jan 2022 14:08:37 +0000 Subject: [PATCH 097/331] Fixed the A to be : to make more sense in the first game in java --- 01_Acey_Ducey/java/src/AceyDucey.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01_Acey_Ducey/java/src/AceyDucey.java b/01_Acey_Ducey/java/src/AceyDucey.java index 43fc9950..d53c0d05 100644 --- a/01_Acey_Ducey/java/src/AceyDucey.java +++ b/01_Acey_Ducey/java/src/AceyDucey.java @@ -167,6 +167,6 @@ public class AceyDucey { System.out.println("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING"); System.out.println("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE"); System.out.println("A VALUE BETWEEN THE FIRST TWO."); - System.out.println("IF YOU DO NOT WANT TO BET, INPUT A 0"); + System.out.println("IF YOU DO NOT WANT TO BET, INPUT: 0"); } } \ No newline at end of file From e1871a1df90591863aa46e5dd66e598ea485e019 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Thu, 6 Jan 2022 01:59:09 +1100 Subject: [PATCH 098/331] initial jvm gradle build scripts. --- .../build/kotlin/build53Kingkotlinjar-classes.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 buildJvm/build_53_King_kotlin/build/kotlin/build53Kingkotlinjar-classes.txt diff --git a/buildJvm/build_53_King_kotlin/build/kotlin/build53Kingkotlinjar-classes.txt b/buildJvm/build_53_King_kotlin/build/kotlin/build53Kingkotlinjar-classes.txt new file mode 100644 index 00000000..1bd92f25 --- /dev/null +++ b/buildJvm/build_53_King_kotlin/build/kotlin/build53Kingkotlinjar-classes.txt @@ -0,0 +1 @@ +/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/DataEntryValidationException.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/EndOfInputException.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/GameState.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt$loadOldGame$1$1.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt$loadOldGame$1$2.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt$loadOldGame$1$3.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt$loadOldGame$1$4.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt$loadOldGame$1$5.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$AntiImmigrationRevolution.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$ContinueNextYear.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$ExtremeMismanagement.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$StarvationWithFullTreasury.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$TooManyPeopleDead.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$Win.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome.class \ No newline at end of file From d9cac10ed59c3161943b5d7eb9b5d0fad0c5a7e0 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Thu, 6 Jan 2022 02:01:18 +1100 Subject: [PATCH 099/331] change King package --- 53_King/kotlin/King.kt | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/53_King/kotlin/King.kt b/53_King/kotlin/King.kt index 71e6d505..169cd6a0 100644 --- a/53_King/kotlin/King.kt +++ b/53_King/kotlin/King.kt @@ -1,3 +1,5 @@ +package king53 + import kotlin.math.abs import kotlin.random.Random import kotlin.system.exitProcess @@ -22,6 +24,7 @@ fun main() { with(gameState) { do { + recalculateLandCost() displayStatus() inputLandSale() @@ -84,6 +87,7 @@ fun loadOldGame(): GameState = GameState().apply { println(" COME ON, YOUR TERM IN OFFICE IS ONLY $yearsRequired YEARS.") retry = true } + } while (retry) print("HOW MUCH DID YOU HAVE IN THE TREASURY? ") @@ -115,6 +119,10 @@ fun loadOldGame(): GameState = GameState().apply { */ sealed class YearOutcome { + /** + * Display output for the end of the year, for each different possible + * year outcome. + */ open fun displayConsequences() { // Default display nothing } @@ -132,7 +140,7 @@ sealed class YearOutcome { object ContinueNextYear : YearOutcome() - class Win(val yearsRequired: Int) : YearOutcome() { + class Win(private val yearsRequired: Int) : YearOutcome() { override fun displayConsequences() { // The misspelling of "successfully" is in the original code. println( @@ -229,12 +237,18 @@ sealed class YearOutcome { * Record data, allow data input, and process the simulation for the game. */ class GameState(val yearsRequired: Int = 8) { + /** * The current year. Years start with zero, but we never * output the current year. */ var currentYear = 0 + /** + * Keep track of each year's crop loss, so we can report increases. + */ + private var lastYearsCropLoss: Int = 0 + /** * Number of countrymen who have died of either pollution * or starvation this year. @@ -535,11 +549,12 @@ class GameState(val yearsRequired: Int = 8) { the population, but does not affect crop losses. */ var cropLoss = ((2000 - landArea) * (rnd + 1.5) / 2.0).toInt() - val cropLossWorse = false if (foreignWorkers > 0) print("OF $plantingArea SQ. MILES PLANTED,") if (plantingArea <= cropLoss) cropLoss = plantingArea + val cropLossWorse = cropLoss > lastYearsCropLoss + lastYearsCropLoss = cropLoss println(" YOU HARVESTED ${plantingArea - cropLoss} SQ. MILES OF CROPS.") if (cropLoss > 0) { From f4a71b965b5f0e661d00aade832aa86963a8cd5a Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Thu, 6 Jan 2022 02:02:29 +1100 Subject: [PATCH 100/331] remove build artifacts accidentally added --- .../build/kotlin/build53Kingkotlinjar-classes.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 buildJvm/build_53_King_kotlin/build/kotlin/build53Kingkotlinjar-classes.txt diff --git a/buildJvm/build_53_King_kotlin/build/kotlin/build53Kingkotlinjar-classes.txt b/buildJvm/build_53_King_kotlin/build/kotlin/build53Kingkotlinjar-classes.txt deleted file mode 100644 index 1bd92f25..00000000 --- a/buildJvm/build_53_King_kotlin/build/kotlin/build53Kingkotlinjar-classes.txt +++ /dev/null @@ -1 +0,0 @@ -/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/DataEntryValidationException.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/EndOfInputException.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/GameState.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt$loadOldGame$1$1.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt$loadOldGame$1$2.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt$loadOldGame$1$3.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt$loadOldGame$1$4.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt$loadOldGame$1$5.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/KingKt.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$AntiImmigrationRevolution.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$ContinueNextYear.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$ExtremeMismanagement.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$StarvationWithFullTreasury.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$TooManyPeopleDead.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome$Win.class:/home/paul/Projects/basic-computer-games/buildJvm/build_53_King_kotlin/build/classes/kotlin/main/king53/YearOutcome.class \ No newline at end of file From a98662a4f0521d3fd7537b79849f26140d171e9f Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 5 Jan 2022 11:35:09 -0500 Subject: [PATCH 101/331] Create HighIQ.java --- 48_High_IQ/java/HighIQ.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 48_High_IQ/java/HighIQ.java diff --git a/48_High_IQ/java/HighIQ.java b/48_High_IQ/java/HighIQ.java new file mode 100644 index 00000000..58f3203a --- /dev/null +++ b/48_High_IQ/java/HighIQ.java @@ -0,0 +1,4 @@ +public class HighIQ { + + +} From c9d26373b597ea8e2983f02dbca7d6426dc3ce10 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 5 Jan 2022 11:36:38 -0500 Subject: [PATCH 102/331] Move java to src folder --- 48_High_IQ/java/{ => src}/HighIQ.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename 48_High_IQ/java/{ => src}/HighIQ.java (100%) diff --git a/48_High_IQ/java/HighIQ.java b/48_High_IQ/java/src/HighIQ.java similarity index 100% rename from 48_High_IQ/java/HighIQ.java rename to 48_High_IQ/java/src/HighIQ.java From 9b47c69be55bb6b24ff8bdf4a71c735a7d14aae0 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 5 Jan 2022 11:37:24 -0500 Subject: [PATCH 103/331] Create HighIQGame.java --- 48_High_IQ/java/src/HighIQGame.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 48_High_IQ/java/src/HighIQGame.java diff --git a/48_High_IQ/java/src/HighIQGame.java b/48_High_IQ/java/src/HighIQGame.java new file mode 100644 index 00000000..c7d4df9b --- /dev/null +++ b/48_High_IQ/java/src/HighIQGame.java @@ -0,0 +1,5 @@ +public class HighIQGame { + public static void main(String[] args) { + + } +} From 917915048e22d329c521ff8a214c132beae651a2 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 5 Jan 2022 11:41:21 -0500 Subject: [PATCH 104/331] Create Board.java --- 48_High_IQ/java/src/Board.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 48_High_IQ/java/src/Board.java diff --git a/48_High_IQ/java/src/Board.java b/48_High_IQ/java/src/Board.java new file mode 100644 index 00000000..18b17cf5 --- /dev/null +++ b/48_High_IQ/java/src/Board.java @@ -0,0 +1,10 @@ +public class Board { + + public Board() { + + } + + public String toString() { + return ""; + } +} From 4ea34f845644d89cdc009c7c33a6937201b3fb1e Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 5 Jan 2022 11:49:07 -0500 Subject: [PATCH 105/331] Add method signatures to HighIQ.java --- 48_High_IQ/java/src/HighIQ.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index 58f3203a..2516bb1b 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -1,4 +1,10 @@ public class HighIQ { + public HighIQ() { + + } + public void play() { + + } } From fb8a87bade402b7ddd225f8554bfe5a3af4d2682 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 5 Jan 2022 11:59:12 -0500 Subject: [PATCH 106/331] Added the board matrix --- 48_High_IQ/java/src/Board.java | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/48_High_IQ/java/src/Board.java b/48_High_IQ/java/src/Board.java index 18b17cf5..6a320bd1 100644 --- a/48_High_IQ/java/src/Board.java +++ b/48_High_IQ/java/src/Board.java @@ -1,10 +1,28 @@ public class Board { - public Board() { - - } + private int[][] board; - public String toString() { - return ""; - } + public Board() { + board = new int[7][7]; + + //Set all of the corners to -1, and place pegs in proper spaces + for(int i = 0; i < 7; i++) { + for(int j = 0; j < 7; j++) { + if((i < 3 || i > 5) && (j < 3 || j > 5)) { + //If both i and j are either less than 3 or greater than 5, then the index is a corner + board[i][j] = -1; + } else if(i == 4 && j == 4) { + //Do not place a peg in the center + board[i][j] = 0; + } else { + //Place a peg everywhere else + board[i][j] = 1; + } + } + } + } + + public String toString() { + return ""; + } } From 64f854171814659ed7968b8fb24445737ad5dbfd Mon Sep 17 00:00:00 2001 From: Bastiaan Veelo Date: Wed, 5 Jan 2022 15:02:47 +0100 Subject: [PATCH 107/331] D version of 3D-plot. With bonus. --- 87_3-D_Plot/d/.gitignore | 2 + 87_3-D_Plot/d/README.md | 182 ++++++++++++++++++++++++++++ 87_3-D_Plot/d/threedeeplot.d | 35 ++++++ 87_3-D_Plot/d/threedeeplot_random.d | 50 ++++++++ 4 files changed, 269 insertions(+) create mode 100644 87_3-D_Plot/d/.gitignore create mode 100644 87_3-D_Plot/d/README.md create mode 100644 87_3-D_Plot/d/threedeeplot.d create mode 100644 87_3-D_Plot/d/threedeeplot_random.d diff --git a/87_3-D_Plot/d/.gitignore b/87_3-D_Plot/d/.gitignore new file mode 100644 index 00000000..d969f6b2 --- /dev/null +++ b/87_3-D_Plot/d/.gitignore @@ -0,0 +1,2 @@ +*.exe +*.obj diff --git a/87_3-D_Plot/d/README.md b/87_3-D_Plot/d/README.md new file mode 100644 index 00000000..8a01faf3 --- /dev/null +++ b/87_3-D_Plot/d/README.md @@ -0,0 +1,182 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html) + +Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo). + +## Running the code + +Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler: +```shell +dmd -dip1000 -run threedeeplot.d +``` + +[Other compilers](https://dlang.org/download.html) also exist. + +## On rounding floating point values to integer values + +The D equivalent of Basic `INT` is [`floor`](https://dlang.org/phobos/std_math_rounding.html#.floor), +which rounds towards negative infinity. If you change occurrences of `floor` to +[`lrint`](https://dlang.org/phobos/std_math_rounding.html#.lrint), you'll see that the plots show a bit more detail, +as is done in the bonus below. + +## Bonus: Self-writing programs + +With a small modification to the source, the program can be extended to **plot a random function**, and **print its formula**. + +```shell +rdmd -dip1000 threedeeplot_random.d +``` +(`rdmd` caches the executable, which results in speedy execution when the source does not change.) + +### Example output +``` + 3D Plot + (After Creative Computing Morristown, New Jersey) + + + f(z) = 30 * sin(z / 10.0) + + * + * * * * + * * * * * + * * * * * + * * * * * * + * * * * * * + * * * * * ** + * * * * * * * + * * * * * * ** + * * * * * * * * + * * * * * * * * + * * * * * * * ** + * * * * * * * * * + * * * * ** * * * * + * * * * ** * * * + * * * * * * * * + * * * * * * * * + * * * ** * * ** + * * * ** * ** + * * * * * ** + * * * * * ** + * * * * * ** + * * * ** * ** + * * * ** * * ** + * * * * * * * * + * * * * * * * * + * * * * ** * * * + * * * * ** * * * * + * * * * * * * * * + * * * * * * * ** + * * * * * * * * + * * * * * * * * + * * * * * * ** + * * * * * * * + * * * * * ** + * * * * * * + * * * * * * + * * * * * + * * * * * + * * * * + * +``` + +### Breakdown of differences + +Have a look at the relevant differences between `threedeeplot.d` and `threedeeplot_random.d`. +This is the original function with the single expression that is evaluated for the plot: +```d + static float fna(float z) + { + return 30.0 * exp(-z * z / 100.0); + } +``` +Here `static` means that the nested function does not need acces to its enclosing scope. + +Now, by inserting the following: +```d + enum functions = ["30.0 * exp(-z * z / 100.0)", + "sqrt(900.01 - z * z) * .9 - 2", + "30 * (cos(z / 16.0) + .5)", + "30 - 30 * sin(z / 18.0)", + "30 * exp(-cos(z / 16.0)) - 30", + "30 * sin(z / 10.0)"]; + + size_t index = uniform(0, functions.length); + writeln(center("f(z) = " ~ functions[index], width), "\n"); +``` +and changing the implementation of `fna` to +```d + float fna(float z) + { + final switch (index) + { + static foreach (i, f; functions) + case i: + mixin("return " ~ f ~ ";"); + } + } +``` +we unlock some very special abilities of D. Let's break it down: + +```d + enum functions = ["30.0 * exp(-z * z / 100.0)", /*...*/]; +``` +This defines an array of strings, each containing a mathematical expression. Due to the `enum` keyword, this is an +array that really only exists at compile-time. + +```d + size_t index = uniform(0, functions.length); +``` +This defines a random index into the array. `functions.length` is evaluated at compile-time, due to D's compile-time +function evaluation (CTFE). + +```d + writeln(center("f(z) = " ~ functions[index], width), "\n"); +``` +Unmistakenly, this prints the formula centered on a line. What happens behind the scenes is that `functions` (which +only existed at compile-time before now) is pasted in, so that an instance of that array actually exists at run-time +at this spot, and is instantly indexed. + +```d + float fna(float z) + { + final switch (index) + { + // ... + } + } +``` +`static` has been dropped from the nested function because we want to evaluate `index` inside it. The function contains +an ordinary `switch`, with `final` providing some extra robustness. It disallows a `default` case and produces an error +when the switch doesn't handle all cases. The `switch` body is where the magic happens and consists of these three +lines: +```d + static foreach (i, f; functions) + case i: + mixin("return " ~ f ~ ";"); +``` +The `static foreach` iterates over `functions` at compile-time, producing one `case` for every element in `functions`. +`mixin` takes a string, which is constructed at compile-time, and pastes it right into the source. + +In effect, the implementation of `float fna(float z)` unrolls itself into +```d + float fna(float z) + { + final switch (index) + { + case 0: + return 30.0 * exp(-z * z / 100.0); + case 1: + return sqrt(900.01 - z * z) * .9 - 2; + case 2: + return 30 * (cos(z / 16.0) + .5); + case 3: + return 30 - 30 * sin(z / 18.0); + case 4: + return 30 * exp(-cos(z / 16.0)) - 30; + case 5: + return 30 * sin(z / 10.0)"; + } + } +``` + +So if you feel like adding another function, all you need to do is append it to the `functions` array, and the rest of +the program *rewrites itself...* diff --git a/87_3-D_Plot/d/threedeeplot.d b/87_3-D_Plot/d/threedeeplot.d new file mode 100644 index 00000000..a3660321 --- /dev/null +++ b/87_3-D_Plot/d/threedeeplot.d @@ -0,0 +1,35 @@ +@safe: // Make @safe the default for this file, enforcing memory-safety. +import std.stdio, std.string, std.math, std.range, std.conv, std.algorithm; + +void main() +{ + enum width = 80; + writeln(center("3D Plot", width)); + writeln(center("(After Creative Computing Morristown, New Jersey)\n\n\n", width)); + + static float fna(float z) + { + return 30.0 * exp(-z * z / 100.0); + } + + char[] row; + + for (float x = -30.0; x <= 30.0; x += 1.5) + { + size_t max_z = 0L; + auto y1 = 5 * floor((sqrt(900 - x * x)) / 5.0); + for (float y = y1; y >= -y1; y -= 5) + { + auto z = to!size_t(max(0, floor(25 + fna(sqrt(x * x + y * y)) - .7 * y))); + if (z > max_z) // Visible + { + max_z = z; + if (z + 1 > row.length) // row needs to grow + row ~= ' '.repeat(z + 1 - row.length).array; + row[z] = '*'; + } + } + writeln(row); + row = null; + } +} diff --git a/87_3-D_Plot/d/threedeeplot_random.d b/87_3-D_Plot/d/threedeeplot_random.d new file mode 100644 index 00000000..3db1a2cd --- /dev/null +++ b/87_3-D_Plot/d/threedeeplot_random.d @@ -0,0 +1,50 @@ +@safe: // Make @safe the default for this file, enforcing memory-safety. +import std.stdio, std.string, std.math, std.range, std.conv, std.random, std.algorithm; + +void main() +{ + enum width = 80; + writeln(center("3D Plot", width)); + writeln(center("(After Creative Computing Morristown, New Jersey)\n\n", width)); + + enum functions = ["30.0 * exp(-z * z / 100.0)", + "sqrt(900.01 - z * z) * .9 - 2", + "30 * (cos(z / 16.0) + .5)", + "30 - 30 * sin(z / 18.0)", + "30 * exp(-cos(z / 16.0)) - 30", + "30 * sin(z / 10.0)"]; + + size_t index = uniform(0, functions.length); + writeln(center("f(z) = " ~ functions[index], width), "\n"); + + float fna(float z) + { + final switch (index) + { + static foreach (i, f; functions) + case i: + mixin("return " ~ f ~ ";"); + } + } + + char[] row; + + for (float x = -30.0; x <= 30.0; x += 1.5) + { + size_t max_z = 0L; + auto y1 = 5 * lrint((sqrt(900 - x * x)) / 5.0); + for (float y = y1; y >= -y1; y -= 5) + { + auto z = to!size_t(max(0, lrint(25 + fna(sqrt(x * x + y * y)) - .7 * y))); + if (z > max_z) // Visible + { + max_z = z; + if (z + 1 > row.length) // row needs to grow + row ~= ' '.repeat(z + 1 - row.length).array; + row[z] = '*'; + } + } + writeln(row); + row = null; + } +} From b250689f378aff08202fa72e735f233c2f45f109 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 5 Jan 2022 12:20:07 -0500 Subject: [PATCH 108/331] Use Map instead of 2d array --- 48_High_IQ/java/src/Board.java | 36 ++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/48_High_IQ/java/src/Board.java b/48_High_IQ/java/src/Board.java index 6a320bd1..8d183675 100644 --- a/48_High_IQ/java/src/Board.java +++ b/48_High_IQ/java/src/Board.java @@ -1,25 +1,27 @@ +import java.util.Map; +import java.util.HashMap; + public class Board { - private int[][] board; + private final Map board; public Board() { - board = new int[7][7]; - - //Set all of the corners to -1, and place pegs in proper spaces - for(int i = 0; i < 7; i++) { - for(int j = 0; j < 7; j++) { - if((i < 3 || i > 5) && (j < 3 || j > 5)) { - //If both i and j are either less than 3 or greater than 5, then the index is a corner - board[i][j] = -1; - } else if(i == 4 && j == 4) { - //Do not place a peg in the center - board[i][j] = 0; - } else { - //Place a peg everywhere else - board[i][j] = 1; - } - } + board = new HashMap<>(); + + int[] locations = new int[] {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}; + + for(int i : locations) { + //put board(i) in } + + //set the center position as 0 + } public String toString() { From 4a44f5097a1b97dde887f2b1348a84b5db41869a Mon Sep 17 00:00:00 2001 From: Yash Chauhan <68198489+ITrustNumbers@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:19:34 +0530 Subject: [PATCH 109/331] Ported the Traditional NIM Game into python 3 I just completed the NIM(Traditional Version) game in python. Hope it works as expected --- 65_Nim/python/Traditional_NIM.py | 126 +++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 65_Nim/python/Traditional_NIM.py diff --git a/65_Nim/python/Traditional_NIM.py b/65_Nim/python/Traditional_NIM.py new file mode 100644 index 00000000..5c01ee2e --- /dev/null +++ b/65_Nim/python/Traditional_NIM.py @@ -0,0 +1,126 @@ +import random + +#Class of the Game +class NIM: + + def __init__(self): + + self.Piles = { + 1 : 7, + 2 : 5, + 3 : 3, + 4 : 1 + } + + def Remove_pegs(self, command): + + try: + + pile, num = command.split(',') + num = int(num) + pile = int(pile) + + except Exception as e: + + if 'not enough values' in str(e): + print('\nNot a valid command. Your command should be in the form of "1,3", Try Again\n') + + else: + print('\nError, Try again\n') + return None + + if self._command_integrity(num, pile) == True: + self.Piles[pile] -= num + else: + print('\nInvalid value of either Peg or Pile\n') + + 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): + + if pile <= 4 and pile >= 1: + if num <= self.Piles[pile]: + return True + + return False + + def print_pegs(self): + + for pile, peg in self.Piles.items(): + print('Pile {} : {}'.format(pile, 'O '*peg)) + + 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') + self.print_pegs() + print('\nAny Number of of Objects are removed one pile by "YOU" and the machine alternatively') + print('\nOn your turn, you may take all the objects that remain in any pile') + print('but you must take ATLEAST one object') + print('\nAnd you may take objects from only one pile on a single turn.') + print('\nThe winner is defined as the one that picks the last remaning object') + print('-'*10) + + def Checkforwin(self): + + sum = 0 + for k,v in self.Piles.items(): + sum += v + + if sum == 0: + return True + + else: + return False + +#main program +if __name__ == "__main__": + + #Game initialization + game = NIM() + + print('Hello, This is a game of NIM') + help = input('Do You Need Instruction (YES or NO): ') + + if help == 'yes' or help == 'YES' or help == 'Yes': + + #Printing Game Instruction + game.Help() + + #Start game loop + input('\nPress Enter to start the Game:\n') + End = False + while True: + + game.print_pegs() + + #Players Move + command = input('\nYOUR MOVE - Number of PILE, Number of Object? ') + game.Remove_pegs(command) + End = game.Checkforwin() + if End == True: + print('Player Wins the Game, Congratulations!!') + input('Press any key to exit') + break + + #Computers Move + command = game.get_AI_move() + print('\nA.I MOVE - A.I Removed {} pegs from Pile {}'.format(command[1],command[0])) + game.Remove_pegs(str(command[0]) +',' + str(command[1])) + End = game.Checkforwin() + if End == True: + print('\nComputer Wins the Game, Better Luck Next Time\n') + input('Press any key to exit') + break From df70eca658dc62f31ac5897ae5ab206a16582875 Mon Sep 17 00:00:00 2001 From: Yash Chauhan <68198489+ITrustNumbers@users.noreply.github.com> Date: Thu, 6 Jan 2022 00:36:48 +0530 Subject: [PATCH 110/331] Minor Changes to the Traditional NIM --- 65_Nim/python/Traditional_NIM.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/65_Nim/python/Traditional_NIM.py b/65_Nim/python/Traditional_NIM.py index 5c01ee2e..3507ecc2 100644 --- a/65_Nim/python/Traditional_NIM.py +++ b/65_Nim/python/Traditional_NIM.py @@ -111,8 +111,8 @@ if __name__ == "__main__": game.Remove_pegs(command) End = game.Checkforwin() if End == True: - print('Player Wins the Game, Congratulations!!') - input('Press any key to exit') + print('\nPlayer Wins the Game, Congratulations!!') + input('\nPress any key to exit') break #Computers Move From f34bf73563db35671a930fad7d8d6a08f54e3703 Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Wed, 5 Jan 2022 16:07:54 -0300 Subject: [PATCH 111/331] Aded synonym ruby port --- 85_Synonym/ruby/synonim.rb | 59 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 85_Synonym/ruby/synonim.rb diff --git a/85_Synonym/ruby/synonim.rb b/85_Synonym/ruby/synonim.rb new file mode 100644 index 00000000..f4dcb558 --- /dev/null +++ b/85_Synonym/ruby/synonim.rb @@ -0,0 +1,59 @@ + + +puts <<~INSTRUCTIONS + SYNONYM + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + +A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH +LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME MEANING. +I CHOOSE A WORD -- YOU TYPE A SYNONYM. +IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP' +AND I WILL TELL YOU A SYNONYM. + + +INSTRUCTIONS + +right_words = ["RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK"] + +synonym_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"], +] + +synonym_words.shuffle.each {|words_ar| + +} + + +synonym_words.each {|words_ar| + answer = false + keyword = words_ar.shift + + while not answer and words_ar.length != 0 + puts " WHAT IS A SYNONYM OF #{keyword}? " + inp = gets.chomp.upcase + + if inp == "HELP" + clue = words_ar.sample + puts "**** A SYNONYM OF #{keyword} IS #{clue}." + words_ar.delete(clue) + elsif words_ar.include? inp + puts right_words.sample + answer = true + else + puts "TRY AGAIN." + end + + end + +} + +puts "SYNONYM DRILL COMPLETED" \ No newline at end of file From fd489bf3da56b950c1ca12f68af9eb5f94c357f2 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 5 Jan 2022 14:30:02 -0500 Subject: [PATCH 112/331] Using single class --- 48_High_IQ/java/src/Board.java | 30 ------------ 48_High_IQ/java/src/HighIQ.java | 82 +++++++++++++++++++++++++++++---- 2 files changed, 74 insertions(+), 38 deletions(-) delete mode 100644 48_High_IQ/java/src/Board.java diff --git a/48_High_IQ/java/src/Board.java b/48_High_IQ/java/src/Board.java deleted file mode 100644 index 8d183675..00000000 --- a/48_High_IQ/java/src/Board.java +++ /dev/null @@ -1,30 +0,0 @@ -import java.util.Map; -import java.util.HashMap; - -public class Board { - - private final Map board; - - public Board() { - board = new HashMap<>(); - - int[] locations = new int[] {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}; - - for(int i : locations) { - //put board(i) in - } - - //set the center position as 0 - - } - - public String toString() { - return ""; - } -} diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index 2516bb1b..cf0c05ab 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -1,10 +1,76 @@ +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; + public class HighIQ { - - public HighIQ() { - - } - - public void play() { - - } + + private Map board; + private PrintStream out; + private Scanner scanner; + + public HighIQ() { + out = System.out; + scanner = new Scanner(System.in); + board = new HashMap<>(); + + //Set of all locations to put initial pegs on + int[] locations = new int[]{ + 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 + }; + + for (int i : locations) { + board.put(i, true); + } + + board.put(41, false); + } + + public boolean move() { + System.out.println("MOVE WHICH PIECE"); + int from = scanner.nextInt(); + + //using the getOrDefault, which will make the statement false if it is an invalid position + if(!board.getOrDefault(from,false)) { + return false; + } + + System.out.println("TO WHERE"); + int to = scanner.nextInt(); + + if(board.getOrDefault(to,true)) { + return false; + } + + //Do nothing if they are the same + if(from == to) { + return true; + } + + //using the difference to check if the relative locations are valid + int difference = Math.abs(to - from); + if(difference != 2 && difference != 18) { + return false; + } + + //check if there is a peg between from and to + if(!board.getOrDefault((to + from) / 2,false)) { + return false; + } + + return true; + } + + public void play() { + while(true) { + while(!move()) { + System.out.println("ILLEGAL MOVE, TRY AGAIN..."); + + } + } + } + + public void printBoard() { + + } } From 6a43be82295eb141b729e282b3b07fd469155e40 Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Wed, 5 Jan 2022 16:42:43 -0300 Subject: [PATCH 113/331] Added history and porting comments --- 85_Synonym/ruby/synonim.rb | 39 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/85_Synonym/ruby/synonim.rb b/85_Synonym/ruby/synonim.rb index f4dcb558..6334104a 100644 --- a/85_Synonym/ruby/synonim.rb +++ b/85_Synonym/ruby/synonim.rb @@ -1,4 +1,25 @@ - +######################################################## +# +# Synonym +# +# From Basic Computer Games (1978) +# +#A synonym of a word is another word (in the English language) which has the same, +#or very nearly the same, meaning. This program tests your knowledge of synonyms +#of a few common words. +# +#The computer chooses a word and asks you for a synonym. The computer then tells +#you whether you’re right or wrong. If you can’t think of a synonym, type “HELP” +#which causes a synonym to be printed. +#You may put in words of your choice in the data statements. +#The number following DATA in Statement 500 is the total number of data statements. +#In each data statement, the first number is the number of words in that statement. +# +#Can you think of a way to make this into a more general kind of CAI program for any subject? +#Walt Koetke of Lexington High School, Massachusetts created this program. +# +# +######################################################## puts <<~INSTRUCTIONS SYNONYM @@ -56,4 +77,18 @@ synonym_words.each {|words_ar| } -puts "SYNONYM DRILL COMPLETED" \ No newline at end of file +puts "SYNONYM DRILL COMPLETED" + + +###################################################################### +# +# Porting notes +# +# There is a bug in the original program where if you keep asking for +# synoyms of a given word it ends up running out of synonyms +# in the array and the program crashes. +# The bug has been fixed in this version and now when +# it runs out of words it continues with the next +# array. +# +###################################################################### From f85645fceec41fd2f7786a2b9ecffa3c8c856711 Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Wed, 5 Jan 2022 16:45:12 -0300 Subject: [PATCH 114/331] Formatting comments --- 85_Synonym/ruby/synonim.rb | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/85_Synonym/ruby/synonim.rb b/85_Synonym/ruby/synonim.rb index 6334104a..92d2e8c7 100644 --- a/85_Synonym/ruby/synonim.rb +++ b/85_Synonym/ruby/synonim.rb @@ -4,19 +4,19 @@ # # From Basic Computer Games (1978) # -#A synonym of a word is another word (in the English language) which has the same, -#or very nearly the same, meaning. This program tests your knowledge of synonyms -#of a few common words. +# A synonym of a word is another word (in the English language) which has the same, +# or very nearly the same, meaning. This program tests your knowledge of synonyms +# of a few common words. # -#The computer chooses a word and asks you for a synonym. The computer then tells -#you whether you’re right or wrong. If you can’t think of a synonym, type “HELP” -#which causes a synonym to be printed. -#You may put in words of your choice in the data statements. -#The number following DATA in Statement 500 is the total number of data statements. -#In each data statement, the first number is the number of words in that statement. +# The computer chooses a word and asks you for a synonym. The computer then tells +# you whether you’re right or wrong. If you can’t think of a synonym, type “HELP” +# which causes a synonym to be printed. +# You may put in words of your choice in the data statements. +# The number following DATA in Statement 500 is the total number of data statements. +# In each data statement, the first number is the number of words in that statement. # -#Can you think of a way to make this into a more general kind of CAI program for any subject? -#Walt Koetke of Lexington High School, Massachusetts created this program. +# Can you think of a way to make this into a more general kind of CAI program for any subject? +# Walt Koetke of Lexington High School, Massachusetts created this program. # # ######################################################## From f74537329b88473a1061061f2d877857bf454cff Mon Sep 17 00:00:00 2001 From: Yash Chauhan <68198489+ITrustNumbers@users.noreply.github.com> Date: Thu, 6 Jan 2022 03:03:02 +0530 Subject: [PATCH 115/331] Ported Chief game to Python --- 25_Chief/python/Chief.py | 77 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 25_Chief/python/Chief.py diff --git a/25_Chief/python/Chief.py b/25_Chief/python/Chief.py new file mode 100644 index 00000000..67b4eab8 --- /dev/null +++ b/25_Chief/python/Chief.py @@ -0,0 +1,77 @@ +def print_lightning_bolt(): + + 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): + + print('\n{} plus 3 gives {}. This Divided by 5 equals {}'.format(n, n+3, (n+3)/5)) + print('This times 8 gives {}. If we divide 5 and add 5.'.format(( (n+3)/5 )*8 )) + print('We get {}, which, minus 1 equals {}'.format(( ((n+3)/5)*8)/5+5, ((((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('\nI bet your number was {} was i right(Yes or No)? '.format(comp_guess)) + + 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('') From 56ccff2d55d16b71f16956f893ec17bfee4cae6e Mon Sep 17 00:00:00 2001 From: jason Date: Wed, 5 Jan 2022 19:48:19 -0800 Subject: [PATCH 116/331] improve input handling of numeric values --- 81_Splat/java/src/Splat.java | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/81_Splat/java/src/Splat.java b/81_Splat/java/src/Splat.java index b76c82ff..e042c326 100644 --- a/81_Splat/java/src/Splat.java +++ b/81_Splat/java/src/Splat.java @@ -39,8 +39,7 @@ public class Splat { System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", initial.getOriginalAcceleration()); System.out.println("SET THE TIMER FOR YOUR FREEFALL."); - System.out.print("HOW MANY SECONDS "); - float freefallTime = scanner.nextFloat(); + float freefallTime = promptFloat("HOW MANY SECONDS "); System.out.println("HERE WE GO.\n"); System.out.println("TIME (SEC) DIST TO FALL (FT)"); System.out.println("========== ================="); @@ -73,18 +72,28 @@ public class Splat { private float promptTerminalVelocity() { if (askYesNo("SELECT YOUR OWN TERMINAL VELOCITY")) { - System.out.print("WHAT TERMINAL VELOCITY (MI/HR) "); - return mphToFeetPerSec(scanner.nextFloat()); + float terminalVelocity = promptFloat("WHAT TERMINAL VELOCITY (MI/HR) "); + return mphToFeetPerSec(terminalVelocity); } float terminalVelocity = (int) (1000 * random.nextFloat()); System.out.printf("OK. TERMINAL VELOCITY = %.2f MI/HR\n", terminalVelocity); return mphToFeetPerSec(terminalVelocity); } + private float promptFloat(String prompt){ + while(true){ + System.out.print(prompt); + try { + return scanner.nextFloat(); + } catch (Exception e) { + scanner.next(); // clear current input + } + } + } + private float promptGravitationalAcceleration() { if (askYesNo("WANT TO SELECT ACCELERATION DUE TO GRAVITY")) { - System.out.print("WHAT ACCELERATION (FT/SEC/SEC) "); - return scanner.nextFloat(); + return promptFloat("WHAT ACCELERATION (FT/SEC/SEC) "); } return chooseRandomAcceleration(); } From e6586027238a750768fd6cc75b226eec87086bd2 Mon Sep 17 00:00:00 2001 From: Adam Coffman Date: Wed, 5 Jan 2022 20:17:52 -0600 Subject: [PATCH 117/331] initial implementation of FlipFlop in Ruby --- 36_Flip_Flop/ruby/flipflop.rb | 162 ++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 36_Flip_Flop/ruby/flipflop.rb diff --git a/36_Flip_Flop/ruby/flipflop.rb b/36_Flip_Flop/ruby/flipflop.rb new file mode 100644 index 00000000..3a65a4c2 --- /dev/null +++ b/36_Flip_Flop/ruby/flipflop.rb @@ -0,0 +1,162 @@ +#A class representing the internal state of a single game of flip flop +# state represents the list of X's (A in the original code) +# guesses represents the number of guesses the user has made (C in the original code) +# seed represents the random seed for an instance of the game (Q in the original code) +Game = Struct.new(:state, :guesses, :seed) do + + #The original BASIC program used 1 indexed arrays while Ruby has 0-indexed arrays. + #We can't use 0 indexed arrays for the flip functions or we'll get divide by zero errors. + #These convenience functions allow us to modify and access internal game state in a 1-indexed fashion + def flip_letter(letter_number) + index = letter_number -1 + if self.state[index] == 'X' + self.state[index] = 'O' + else + self.state[index] = 'X' + end + end + + def letter_at(letter_number) + self.state[letter_number - 1] + end +end + +def print_welcome + puts 'FLIPFLOP'.center(72) + puts 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'.center(72) + puts <<~EOS + + THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS: + + X X X X X X X X X X + + TO THIS: + + O O O O O O O O O O + + BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE + LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON + OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0 + (ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE + 11 (ELEVEN). + EOS +end + +def print_starting_message + puts <<~EOS + + HERE IS THE STARTING LINE OF X'S. + + 1 2 3 4 5 6 7 8 9 10 + X X X X X X X X X X + + EOS +end + +#Create a new game with [X,X,X,X,X,X,X,X,X,X] as the state +#0 as the number of guesses and a random seed between 0 and 1 +def generate_new_game + Game.new(Array.new(10, 'X'), 0, rand()) +end + +#Given a game, an index, and a shuffle function, flip one or more letters +def shuffle_board(game, index, shuffle_function) + n = method(shuffle_function).call(game, index) + + if game.letter_at(n) == "O" + game.flip_letter(n) + if index == n + n = shuffle_board(game, index, shuffle_function) + end + else + game.flip_letter(n) + end + return n +end + +#Shuffle logic copied from original BASIC code +def shuffle_function1(game, index) + r = Math.tan(game.seed + index / game.seed - index) - Math.sin(game.seed / index) + 336 * Math.sin(8 * index) + n = r - r.floor + (10 * n).floor +end + +def shuffle_function2(game, index) + r = 0.592 * (1/ Math.tan(game.seed / index + game.seed)) / Math.sin(index * 2 + game.seed) - Math.cos(index) + n = r - r.floor + (10 * n) +end + +def play_game + print_starting_message + game = generate_new_game + working_index = nil + + loop do + puts "INPUT THE NUMBER" + input = gets.chomp.downcase + + #See if the user input a valid integer, fail otherwise + if numeric_input = Integer(input, exception: false) + + #If 11 is entered, we're done with this version of the game + if numeric_input == 11 + return :restart + end + + if numeric_input > 11 + puts 'ILLEGAL ENTRY--TRY AGAIN.' + next #illegal entries don't count towards your guesses + end + + if working_index == numeric_input + game.flip_letter(numeric_input) + working_index = shuffle_board(game, numeric_input, :shuffle_function2) + #If 0 is entered, we want to reset the state, but not the random seed or number of guesses and keep playing + elsif numeric_input == 0 + game.state = Array.new(10, 'X') + elsif game.letter_at(numeric_input) == "O" + game.flip_letter(numeric_input) + if numeric_input == working_index + working_index = shuffle_board(game, numeric_input, :shuffle_function1) + end + else + game.flip_letter(numeric_input) + working_index = shuffle_board(game, numeric_input, :shuffle_function1) + end + else + puts 'ILLEGAL ENTRY--TRY AGAIN.' + next #illegal entries don't count towards your guesses + end + + game.guesses += 1 + puts '1 2 3 4 5 6 7 8 9 10' + puts game.state.join(' ') + + if game.state.all? { |x| x == 'O' } + if game.guesses > 12 + puts "TRY HARDER NEXT TIME. IT TOOK YOU #{game.guesses} GUESSES." + else + puts "VERY GOOD. YOU GUESSED IT IN ONLY #{game.guesses} GUESSES." + end + #game is complete + return + end + end +end + + + +#Execution starts +print_welcome +loop do + result = play_game + if result == :restart + next + end + + puts 'DO YOU WANT TO TRY ANOTHER PUZZLE' + if gets.chomp.downcase[0] == 'n' + break + end +end From aed1f65c761348a046a39bfe8e3e097b8661972a Mon Sep 17 00:00:00 2001 From: RibTips <36372030+ribtips@users.noreply.github.com> Date: Thu, 6 Jan 2022 01:24:44 -0500 Subject: [PATCH 118/331] 11_Bombardment in Perl A version of bombardment written in perl --- 11_Bombardment/perl/bombardment.pl | 129 +++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 11_Bombardment/perl/bombardment.pl diff --git a/11_Bombardment/perl/bombardment.pl b/11_Bombardment/perl/bombardment.pl new file mode 100644 index 00000000..593bd9fa --- /dev/null +++ b/11_Bombardment/perl/bombardment.pl @@ -0,0 +1,129 @@ +#!/usr/bin/perl + +use strict; +use warnings; + + +#GLOBAL +my %player_bases; +my %computer_bases; +my %player_choices; +my %computer_choices; + +&main; + +sub main { + &print_intro; + &display_field; + &populate_computer_bases; + &populate_player_bases; + &game_play; +} + +sub game_play { + until (keys %computer_bases == 0 || keys %player_bases == 0) { + &player_turn; + if (keys %computer_bases == 0) { + exit; + } + &computer_turn; + } + exit; +} + +sub computer_turn { + # There is logic in here to ensure that the computer doesn't try to pick a target it has already picked + my $valid_choice = 0; + until ($valid_choice == 1) { + my $target = int(rand(25)+1); + if (exists $computer_choices{$target}) { + $valid_choice = 0; + } + else { + $valid_choice = 1; + $computer_choices{$target}=1; + if (exists $player_bases{$target}) { + delete($player_bases{$target}); + my $size = keys %player_bases; + if ($size > 0) { + print "I GOT YOU. IT WON'T BE LONG NOW. POST $target WAS HIT.\n"; + if ($size == 3) { print "YOU HAVE ONLY THREE OUTPOSTS LEFT.\n"}; + if ($size == 2) { print "YOU HAVE ONLY TWO OUTPOSTS LEFT.\n"}; + if ($size == 1) { print "YOU HAVE ONLY ONE OUTPOSTS LEFT.\n"}; + } + else { + print "YOU'RE DEAD. YOUR LAST OUTPOST WAS AT $target. HA, HA, HA.\nBETTER LUCK NEXT TIME\n"; + } + + } + else { + print "I MISSED YOU, YOU DIRTY RAT. I PICKED $target. YOUR TURN:\n"; + } + } + } +} + +sub player_turn { + print "WHERE DO YOU WISH TO FIRE YOUR MISSILE\n"; + chomp(my $target=); + if (exists $computer_bases{$target}) { + print "YOU GOT ONE OF MY OUTPOSTS!\n"; + delete($computer_bases{$target}); + my $size = keys %computer_bases; + if ($size == 3) { print "ONE DOWN, THREE TO GO.\n"}; + if ($size == 2) { print "TWO DOWN, TWO TO GO.\n"}; + if ($size == 1) { print "THREE DOWN, ONE TO GO.\n"}; + if ($size == 0) { print "YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\nMY TRANSISTO&S RECUP%RA*E!\n"}; + } + else { + print "HA, HA YOU MISSED. MY TURN NOW:\n"; + } +} + +sub populate_player_bases { + print "WHAT ARE YOUR FOUR POSITIONS\n"; + my $positions=; + chomp($positions); + my @positions = split/ /,$positions; + foreach my $base (@positions) { + $player_bases{$base}=0; + } +} + +sub display_field { + for my $num (1..25) { + if (length($num) < 2) { + $num = " $num"; + } + print "$num "; + if ($num % 5 == 0) { + print "\n"; + } + } +} + +sub populate_computer_bases { + my $size = 0; + until ($size == 4) { + my $base = int(rand(25)+1); + $computer_bases{$base}=0; + $size = keys %computer_bases; + } +} + +sub print_intro { + print "" * 33 + "BOMBARDMENT\n"; + print "" * 15 + " CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; + print "\n\n"; + print "YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\n"; + print "HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\n"; + print "YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\n"; + print "THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\n\n"; + print "THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\n"; + print "OUTPOSTS OF THE COMPUTER. IT WILL DO THE SAME TO YOU.\n"; + print "THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\n"; + print "FIRST IS THE WINNER.\n"; + print "GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\n"; + print "TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\n"; + print "\n\n\n\n"; +} From 71c754190550fbebb0ac8ae92d4bef3cd8b7c94b Mon Sep 17 00:00:00 2001 From: John Long Date: Wed, 5 Jan 2022 23:22:46 -0800 Subject: [PATCH 119/331] Switch to readln readln throws an exception when a file hits EOF, wheras readLine returns null. That puts us in an infinite loop if we hit EOF. --- 03_Animal/kotlin/Animal.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03_Animal/kotlin/Animal.kt b/03_Animal/kotlin/Animal.kt index bac9af08..90fc9f20 100644 --- a/03_Animal/kotlin/Animal.kt +++ b/03_Animal/kotlin/Animal.kt @@ -37,14 +37,14 @@ fun main() { // an answer or a blank string fun ask(question: String): String { print("$question? ") - return readLine()?.uppercase() ?: "" + return readln().uppercase() ?: "" } // Special case for a "yes or no" question, returns true of yes fun askYesOrNo(question: String): Boolean { return generateSequence { print("$question? ") - readLine() + readln() }.firstNotNullOf { yesOrNo(it) } } From 2811e23a4f23e69a52790067790103f96ab4fcbf Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 08:36:05 -0500 Subject: [PATCH 120/331] Finished print_board(board) method --- 48_High_IQ/python/High_IQ.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 18d48456..83443466 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -42,7 +42,9 @@ def print_board(board): print(board[29] + board[30] + board[31] + board[32] + board[33] + board[34] + board[35]) print(board[38] + board[39] + board[40] + board[41] + board[42] + board[43] + board[44]) print(board[47] + board[48] + board[49] + board[50] + board[51] + board[52] + board[53]) - + print(" " * 3 + board[58] + board[59] + board[60] + " " * 3) + print(" " * 3 + board[67] + board[68] + board[69] + " " * 3) + def play_game(): print("Lets play a game") board = new_board() From 27b81d48710b3d9cb975157695b8cba1c2c7c970 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 08:37:28 -0500 Subject: [PATCH 121/331] Uncommented board-positions guide --- 48_High_IQ/python/High_IQ.py | 44 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 83443466..3f19a4f5 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -10,28 +10,28 @@ def new_board(): def print_instructions(): print("\n" * 3) print("HERE IS THE BOARD:\n") - # print("\n") - # print(" ! ! !\n") - # print(" 13 14 15\n") - # print("\n") - # print(" ! ! !\n") - # print(" 22 23 24\n") - # print("\n") - # print("! ! ! ! ! ! ! ! !\n") - # print("29 30 31 32 33 34 35 36 37\n") - # print("\n") - # print("! ! ! ! ! ! !\n") - # print("38 39 40 41 42 43 44\n") - # print("\n") - # print("! ! ! ! ! ! !\n") - # print("47 48 49 50 51 52 53\n") - # print("\n") - # print(" ! ! !\n") - # print(" 58 59 60\n") - # print("\n") - # print(" ! ! !\n") - # print(" 67 68 69\n") - # print("\n") + print("\n") + print(" ! ! !\n") + print(" 13 14 15\n") + print("\n") + print(" ! ! !\n") + print(" 22 23 24\n") + print("\n") + print("! ! ! ! ! ! ! ! !\n") + print("29 30 31 32 33 34 35 36 37\n") + print("\n") + print("! ! ! ! ! ! !\n") + print("38 39 40 41 42 43 44\n") + print("\n") + print("! ! ! ! ! ! !\n") + print("47 48 49 50 51 52 53\n") + print("\n") + print(" ! ! !\n") + print(" 58 59 60\n") + print("\n") + print(" ! ! !\n") + print(" 67 68 69\n") + print("\n") print("TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\n") print("WILL BE USED DURING PLAY. REFER TO THE ABOVE ONE FOR PEG\n") print("NUMBERS. OK, LET'S BEGIN.\n") From 919bb2f682427a8226e2b20319bf8f9519bfc925 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 08:40:45 -0500 Subject: [PATCH 122/331] No longer asks before printing instructions --- 48_High_IQ/python/High_IQ.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 3f19a4f5..0f03dc04 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -51,8 +51,8 @@ def play_game(): print_board(board) def main(): - if input("Do you want instrunctions?\n").lower().startswith("y"): - print_instructions() +# if input("Do you want instrunctions?\n").lower().startswith("y"): + print_instructions() play_game() if __name__ == "__main__": From 92064c668a92e10f03aadb193108a53786d53bbb Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 08:43:12 -0500 Subject: [PATCH 123/331] Update High_IQ.py --- 48_High_IQ/python/High_IQ.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 0f03dc04..9561bbae 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -52,6 +52,8 @@ def play_game(): def main(): # if input("Do you want instrunctions?\n").lower().startswith("y"): + print("\t" * 33 + "H-I-Q") + print("\t" * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print_instructions() play_game() From c207acaa561f7e6c3129c2f71f8ab375d930d1cc Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 08:46:27 -0500 Subject: [PATCH 124/331] Removed trailing spaces --- 48_High_IQ/python/High_IQ.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 9561bbae..df1ffdbd 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -37,13 +37,13 @@ def print_instructions(): print("NUMBERS. OK, LET'S BEGIN.\n") def print_board(board): - print(" " * 3 + board[13] + board[14] + board[15] + " " * 3) - print(" " * 3 + board[22] + board[23] + board[24] + " " * 3) + print(" " * 3 + board[13] + board[14] + board[15]) + print(" " * 3 + board[22] + board[23] + board[24]) print(board[29] + board[30] + board[31] + board[32] + board[33] + board[34] + board[35]) print(board[38] + board[39] + board[40] + board[41] + board[42] + board[43] + board[44]) print(board[47] + board[48] + board[49] + board[50] + board[51] + board[52] + board[53]) - print(" " * 3 + board[58] + board[59] + board[60] + " " * 3) - print(" " * 3 + board[67] + board[68] + board[69] + " " * 3) + print(" " * 3 + board[58] + board[59] + board[60]) + print(" " * 3 + board[67] + board[68] + board[69]) def play_game(): print("Lets play a game") From f8cc93aaeab6f7a73ebc15e1a91957b75e794e5a Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 08:50:17 -0500 Subject: [PATCH 125/331] added getChar method --- 48_High_IQ/java/src/HighIQ.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index cf0c05ab..75426197 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -71,6 +71,17 @@ public class HighIQ { } public void printBoard() { - + + } + + private char getChar(int position) { + Boolean value = board.get(position); + if(value == null) { + return ' '; + } else if(value) { + return '!'; + } else { + return 'O'; + } } } From 918b42149e0f4abe2512eaf69343fb1cbe7baef5 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 08:52:12 -0500 Subject: [PATCH 126/331] Implemented Possible printBoard Doing this through web browser, so unsure if this will work or compile.. Will check later --- 48_High_IQ/java/src/HighIQ.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index 75426197..93340556 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -71,7 +71,12 @@ public class HighIQ { } public void printBoard() { - + for(int i = 0; i < 7; i++) { + for(int j = 11; j < 18; j++) { + out.print(getChar(j + 9 * i)); + } + out.println(); + } } private char getChar(int position) { From 056c8cd4d971174bd68aed81708a2de1b39e59a2 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 09:06:15 -0500 Subject: [PATCH 127/331] Update HighIQ.java --- 48_High_IQ/java/src/HighIQ.java | 36 ++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index 93340556..77e0e5ae 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -62,12 +62,38 @@ public class HighIQ { } public void play() { - while(true) { - while(!move()) { - System.out.println("ILLEGAL MOVE, TRY AGAIN..."); - + do { + do { + while(!move()) { + System.out.println("ILLEGAL MOVE, TRY AGAIN..."); + } + } while(!isGameFinished()); + + int pegCount = 0; + for(Integer key : board.getKeySet()) { + if(board.getOrDefault(key,false)) { + pegCount++; + } } - } + + out.println("YOU HAD " + pegCount + " PEGS REMAINING"); + + if(pegCount == 1) { + out.println("BRAVO! YOU MADE A PERFECT SCORE!"); + out.println("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!"); + } + + } while(playAgain()); + } + + private boolean playAgain() { + out.println("PLAY AGAIN (YES OR NO)"); + return scanner.nextLine().toLowerCase().equals("yes"); + } + + + public boolean isGameFinished() { + return false; } public void printBoard() { From aaa8d6186061983dc6af1f8b7b9ec09c0b926353 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 09:34:20 -0500 Subject: [PATCH 128/331] Implemented GameFinished does it work? Unsure... --- 48_High_IQ/java/src/HighIQ.java | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index 77e0e5ae..99d046fe 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -93,7 +93,26 @@ public class HighIQ { public boolean isGameFinished() { - return false; + for(Integer key : board.getKeySet()) { + if(board.get(key)) { + //Spacing is either 1 or 9 + for(int space = 1; space <= 9; space += 8) { + //Next val is the next spot, prev and next after are the two spots where the peg would go if a move was possible + Boolean nextVal = board.get(key + space); + Boolean prevAfter = board.get(key - space); + Boolean nextAfter = board.get(key + space * 2); + + if(nextVal != null && nextVal) { + if((prevAfter != null && !prevAfter) || (nextAfter != null && !nextAfter)) { + return false; + } + } + + } + } + + } + return true; } public void printBoard() { From 31dec710639d360536207692634a24b3e2bf108e Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 09:45:04 -0500 Subject: [PATCH 129/331] Simplified isGameFinished Unsure if I should simplify further --- 48_High_IQ/java/src/HighIQ.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index 99d046fe..83cff254 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -96,18 +96,13 @@ public class HighIQ { for(Integer key : board.getKeySet()) { if(board.get(key)) { //Spacing is either 1 or 9 - for(int space = 1; space <= 9; space += 8) { - //Next val is the next spot, prev and next after are the two spots where the peg would go if a move was possible - Boolean nextVal = board.get(key + space); - Boolean prevAfter = board.get(key - space); - Boolean nextAfter = board.get(key + space * 2); - - if(nextVal != null && nextVal) { - if((prevAfter != null && !prevAfter) || (nextAfter != null && !nextAfter)) { - return false; - } + //Looking to the right and down from every point, checking for both directions of movement + for(int space : new int[] {1,9}) { + Boolean nextToPeg = board.getOrDefault(key + space,false); + Boolean hasMovableSpace = !board.getOrDefault(key - space,true) || !board.getOrDefault(key + space * 2, true); + if(nextToPeg && hasMovableSpace) { + return false; } - } } From e19a4aef19457cdb6256899c062b88e2580679fd Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 09:46:58 -0500 Subject: [PATCH 130/331] Added leaving comment --- 48_High_IQ/java/src/HighIQ.java | 1 + 1 file changed, 1 insertion(+) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index 83cff254..b1a40831 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -84,6 +84,7 @@ public class HighIQ { } } while(playAgain()); + out.println("SO LONG FOR NOW."); } private boolean playAgain() { From 58f68bcd2fd8271b9f73cfac0ca8ff2bc6f0f45e Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 09:54:18 -0500 Subject: [PATCH 131/331] Added is_game_finished I have absolutely no idea if it works.. --- 48_High_IQ/python/High_IQ.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index df1ffdbd..d80b95a4 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -56,6 +56,18 @@ def main(): print("\t" * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print_instructions() play_game() + +def is_game_finished(board): + for pos in board.keys(): + if board[pos] == "X": + for space in [1,9]: + nextToPeg = ((pos + space) in board) and board[pos + space] + hasMovableSpace = (not ((pos - space) in board and board[pos - space])) or (not ((pos + space * 2) in board and board[pos + space * 2])) + if nextToPeg and hasMovableSpace: + return False + + return True + if __name__ == "__main__": main() From a0210ffe839fdd3b25f9003e1f51ae93a1564c7f Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 09:55:01 -0500 Subject: [PATCH 132/331] Forgot board isn't booleans Maybe I should make it booleans? --- 48_High_IQ/python/High_IQ.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index d80b95a4..52aff04c 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -61,8 +61,8 @@ def is_game_finished(board): for pos in board.keys(): if board[pos] == "X": for space in [1,9]: - nextToPeg = ((pos + space) in board) and board[pos + space] - hasMovableSpace = (not ((pos - space) in board and board[pos - space])) or (not ((pos + space * 2) in board and board[pos + space * 2])) + nextToPeg = ((pos + space) in board) and board[pos + space] == "X" + hasMovableSpace = (not ((pos - space) in board and board[pos - space] == "X")) or (not ((pos + space * 2) in board and board[pos + space * 2] == "X")) if nextToPeg and hasMovableSpace: return False From 821ae4befe7bb7845e7fcea6f1f28a0308bd778a Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 10:02:44 -0500 Subject: [PATCH 133/331] Moving re-playability to other script --- 48_High_IQ/java/src/HighIQ.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index b1a40831..37fd6aa2 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -9,9 +9,9 @@ public class HighIQ { private PrintStream out; private Scanner scanner; - public HighIQ() { + public HighIQ(Scanner sccanner) { out = System.out; - scanner = new Scanner(System.in); + this.scanner = scanner; board = new HashMap<>(); //Set of all locations to put initial pegs on @@ -25,6 +25,7 @@ public class HighIQ { board.put(41, false); } + public boolean move() { System.out.println("MOVE WHICH PIECE"); @@ -63,7 +64,6 @@ public class HighIQ { public void play() { do { - do { while(!move()) { System.out.println("ILLEGAL MOVE, TRY AGAIN..."); } @@ -83,14 +83,12 @@ public class HighIQ { out.println("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!"); } - } while(playAgain()); - out.println("SO LONG FOR NOW."); } - private boolean playAgain() { - out.println("PLAY AGAIN (YES OR NO)"); - return scanner.nextLine().toLowerCase().equals("yes"); - } +// private boolean playAgain() { +// out.println("PLAY AGAIN (YES OR NO)"); +// return scanner.nextLine().toLowerCase().equals("yes"); +// } public boolean isGameFinished() { From f5997021970a2ac6b278a5321430cf74553d0caf Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Thu, 6 Jan 2022 13:03:31 -0300 Subject: [PATCH 134/331] Added script to write a markdown TODO list of implementations for games --- 00_Utilities/markdown_todo.py | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 00_Utilities/markdown_todo.py diff --git a/00_Utilities/markdown_todo.py b/00_Utilities/markdown_todo.py new file mode 100644 index 00000000..accf1ac2 --- /dev/null +++ b/00_Utilities/markdown_todo.py @@ -0,0 +1,43 @@ +import os + + +lang_pos = { + "csharp": 1, "java": 2, "javascript": 3, + "pascal": 4, "perl": 5, "python": 6, "ruby": 7, "vbnet": 8 +} + +write_string = "# TODO list \n game | csharp | java | javascript | pascal | perl | python | ruby | vbnet \n --- | --- | --- | --- | --- | --- | --- | --- | --- \n" +# Set the directory you want to start from +rootDir = '..' + +checklist = ["game", "csharp", "java", "javascript", + "pascal", "perl", "python", "ruby", "vbnet"] + +prev_game = "" + +for dirName, subdirList, fileList in os.walk(rootDir): + split_dir = dirName.split("/") + + if len(split_dir) == 2 and not split_dir[1] in ['.git', '00_Utilities']: + if prev_game == "": + prev_game = split_dir[1] + checklist[0] = split_dir[1] + + if prev_game != split_dir[1]: + # it's a new dir + write_string += " | ".join(checklist) + "\n" + checklist = [split_dir[1], "csharp", "java", "javascript", + "pascal", "perl", "python", "ruby", "vbnet"] + prev_game = split_dir[1] + + elif len(split_dir) == 3 and split_dir[1] != '.git': + if split_dir[2] in lang_pos.keys(): + if len(fileList) > 1 or len(subdirList) > 0: + # there is more files than the readme + checklist[lang_pos[split_dir[2]]] = "✅" + else: + checklist[lang_pos[split_dir[2]]] = "⬜️" + + +with open("README.md", "w") as f: + f.write(write_string) From 08b299b3bb23a22f03dec849d460660a004ce946 Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Thu, 6 Jan 2022 13:13:04 -0300 Subject: [PATCH 135/331] Sorted table --- 00_Utilities/markdown_todo.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/00_Utilities/markdown_todo.py b/00_Utilities/markdown_todo.py index accf1ac2..74e358c0 100644 --- a/00_Utilities/markdown_todo.py +++ b/00_Utilities/markdown_todo.py @@ -10,6 +10,8 @@ write_string = "# TODO list \n game | csharp | java | javascript | pascal | perl # Set the directory you want to start from rootDir = '..' +strings_done = [] + checklist = ["game", "csharp", "java", "javascript", "pascal", "perl", "python", "ruby", "vbnet"] @@ -25,7 +27,7 @@ for dirName, subdirList, fileList in os.walk(rootDir): if prev_game != split_dir[1]: # it's a new dir - write_string += " | ".join(checklist) + "\n" + strings_done.append(checklist) checklist = [split_dir[1], "csharp", "java", "javascript", "pascal", "perl", "python", "ruby", "vbnet"] prev_game = split_dir[1] @@ -39,5 +41,10 @@ for dirName, subdirList, fileList in os.walk(rootDir): checklist[lang_pos[split_dir[2]]] = "⬜️" +sorted_strings = list(map(lambda l: " | ".join(l) + "\n", + sorted(strings_done, key=lambda x: x[0]))) +write_string += ''.join(sorted_strings) + + with open("README.md", "w") as f: f.write(write_string) From 048b9c31a283b6b40bafd3480cd7cc5667f1eab6 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 11:38:17 -0500 Subject: [PATCH 136/331] Added re-playability --- 48_High_IQ/java/src/HighIQGame.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/48_High_IQ/java/src/HighIQGame.java b/48_High_IQ/java/src/HighIQGame.java index c7d4df9b..efbd09ec 100644 --- a/48_High_IQ/java/src/HighIQGame.java +++ b/48_High_IQ/java/src/HighIQGame.java @@ -1,5 +1,11 @@ +import java.util.Scanner; + public class HighIQGame { public static void main(String[] args) { - + Scanner scanner = new Scanner(System.in); + do { + new HighIQ(scanner).play(); + System.out.println("PLAY AGAIN (YES OR NO)"); + } while(scanner.nextLine().toLowerCase().equals("yes")); } } From 18016b59ed7f647cef92213243cb20ba8b689983 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 13:15:48 -0500 Subject: [PATCH 137/331] Typo Fixes --- 48_High_IQ/java/src/HighIQ.java | 6 +++--- 48_High_IQ/java/src/HighIQGame.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index 37fd6aa2..37528748 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -9,7 +9,7 @@ public class HighIQ { private PrintStream out; private Scanner scanner; - public HighIQ(Scanner sccanner) { + public HighIQ(Scanner scanner) { out = System.out; this.scanner = scanner; board = new HashMap<>(); @@ -70,7 +70,7 @@ public class HighIQ { } while(!isGameFinished()); int pegCount = 0; - for(Integer key : board.getKeySet()) { + for(Integer key : board.keySet()) { if(board.getOrDefault(key,false)) { pegCount++; } @@ -92,7 +92,7 @@ public class HighIQ { public boolean isGameFinished() { - for(Integer key : board.getKeySet()) { + for(Integer key : board.keySet()) { if(board.get(key)) { //Spacing is either 1 or 9 //Looking to the right and down from every point, checking for both directions of movement diff --git a/48_High_IQ/java/src/HighIQGame.java b/48_High_IQ/java/src/HighIQGame.java index efbd09ec..4df22853 100644 --- a/48_High_IQ/java/src/HighIQGame.java +++ b/48_High_IQ/java/src/HighIQGame.java @@ -6,6 +6,6 @@ public class HighIQGame { do { new HighIQ(scanner).play(); System.out.println("PLAY AGAIN (YES OR NO)"); - } while(scanner.nextLine().toLowerCase().equals("yes")); + } while(scanner.nextLine().equalsIgnoreCase("yes")); } } From 45345d593d136668e36d63668eed61e124435f63 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 13:16:55 -0500 Subject: [PATCH 138/331] Reformatted Code --- 48_High_IQ/java/src/HighIQ.java | 84 ++++++++++++++++----------------- 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index 37528748..5c3f31aa 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -5,7 +5,7 @@ import java.util.Scanner; public class HighIQ { - private Map board; + private Map board; private PrintStream out; private Scanner scanner; @@ -25,104 +25,100 @@ public class HighIQ { board.put(41, false); } - + + public void play() { + do { + while (!move()) { + System.out.println("ILLEGAL MOVE, TRY AGAIN..."); + } + } while (!isGameFinished()); + + int pegCount = 0; + for (Integer key : board.keySet()) { + if (board.getOrDefault(key, false)) { + pegCount++; + } + } + + out.println("YOU HAD " + pegCount + " PEGS REMAINING"); + + if (pegCount == 1) { + out.println("BRAVO! YOU MADE A PERFECT SCORE!"); + out.println("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!"); + } + } public boolean move() { System.out.println("MOVE WHICH PIECE"); int from = scanner.nextInt(); //using the getOrDefault, which will make the statement false if it is an invalid position - if(!board.getOrDefault(from,false)) { + if (!board.getOrDefault(from, false)) { return false; } System.out.println("TO WHERE"); int to = scanner.nextInt(); - if(board.getOrDefault(to,true)) { + if (board.getOrDefault(to, true)) { return false; } //Do nothing if they are the same - if(from == to) { + if (from == to) { return true; } //using the difference to check if the relative locations are valid int difference = Math.abs(to - from); - if(difference != 2 && difference != 18) { + if (difference != 2 && difference != 18) { return false; } //check if there is a peg between from and to - if(!board.getOrDefault((to + from) / 2,false)) { + if (!board.getOrDefault((to + from) / 2, false)) { return false; } return true; } - public void play() { - do { - while(!move()) { - System.out.println("ILLEGAL MOVE, TRY AGAIN..."); - } - } while(!isGameFinished()); - - int pegCount = 0; - for(Integer key : board.keySet()) { - if(board.getOrDefault(key,false)) { - pegCount++; - } - } - - out.println("YOU HAD " + pegCount + " PEGS REMAINING"); - - if(pegCount == 1) { - out.println("BRAVO! YOU MADE A PERFECT SCORE!"); - out.println("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!"); - } - - } - // private boolean playAgain() { // out.println("PLAY AGAIN (YES OR NO)"); // return scanner.nextLine().toLowerCase().equals("yes"); // } - - + public boolean isGameFinished() { - for(Integer key : board.keySet()) { - if(board.get(key)) { + for (Integer key : board.keySet()) { + if (board.get(key)) { //Spacing is either 1 or 9 //Looking to the right and down from every point, checking for both directions of movement - for(int space : new int[] {1,9}) { - Boolean nextToPeg = board.getOrDefault(key + space,false); - Boolean hasMovableSpace = !board.getOrDefault(key - space,true) || !board.getOrDefault(key + space * 2, true); - if(nextToPeg && hasMovableSpace) { + for (int space : new int[]{1, 9}) { + Boolean nextToPeg = board.getOrDefault(key + space, false); + Boolean hasMovableSpace = !board.getOrDefault(key - space, true) || !board.getOrDefault(key + space * 2, true); + if (nextToPeg && hasMovableSpace) { return false; } } } - } return true; } public void printBoard() { - for(int i = 0; i < 7; i++) { - for(int j = 11; j < 18; j++) { + for (int i = 0; i < 7; i++) { + for (int j = 11; j < 18; j++) { out.print(getChar(j + 9 * i)); } out.println(); } } - + private char getChar(int position) { Boolean value = board.get(position); - if(value == null) { + if (value == null) { return ' '; - } else if(value) { + } else if (value) { return '!'; } else { return 'O'; From 3d4f5c685adbb4865e707490474cf039efacd9c7 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 13:22:56 -0500 Subject: [PATCH 139/331] Added Instructions --- 48_High_IQ/java/src/HighIQ.java | 3 +++ 48_High_IQ/java/src/HighIQGame.java | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index 5c3f31aa..a0278771 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -27,7 +27,10 @@ public class HighIQ { } public void play() { + + do { + printBoard(); while (!move()) { System.out.println("ILLEGAL MOVE, TRY AGAIN..."); } diff --git a/48_High_IQ/java/src/HighIQGame.java b/48_High_IQ/java/src/HighIQGame.java index 4df22853..e74e5783 100644 --- a/48_High_IQ/java/src/HighIQGame.java +++ b/48_High_IQ/java/src/HighIQGame.java @@ -2,10 +2,34 @@ import java.util.Scanner; public class HighIQGame { public static void main(String[] args) { + + printInstructions(); + Scanner scanner = new Scanner(System.in); do { new HighIQ(scanner).play(); System.out.println("PLAY AGAIN (YES OR NO)"); } while(scanner.nextLine().equalsIgnoreCase("yes")); } + + public static void printInstructions() { + System.out.println("HERE IS THE BOARD:"); + System.out.println(" ! ! !"); + System.out.println(" 13 14 15\n"); + System.out.println(" ! ! !"); + System.out.println(" 22 23 24\n"); + System.out.println("! ! ! ! ! ! !"); + System.out.println("29 30 31 32 33 34 35\n"); + System.out.println("! ! ! ! ! ! !"); + System.out.println("38 39 40 41 42 43 44\n"); + System.out.println("! ! ! ! ! ! !"); + System.out.println("47 48 49 50 51 52 53\n"); + System.out.println(" ! ! !"); + System.out.println(" 58 59 60\n"); + System.out.println(" ! ! !"); + System.out.println(" 67 68 69"); + System.out.println("TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD"); + System.out.println("WILL BE USED DURING PLAY. REFER TO THE ABOVE ONE FOR PEG"); + System.out.println("NUMBERS. OK, LET'S BEGIN."); + } } From 110b77fccd5d8cbc956abae1c1538964ab9a8e27 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 13:35:37 -0500 Subject: [PATCH 140/331] Cleanup --- 48_High_IQ/java/src/HighIQ.java | 49 ++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/48_High_IQ/java/src/HighIQ.java b/48_High_IQ/java/src/HighIQ.java index a0278771..d77a2ec2 100644 --- a/48_High_IQ/java/src/HighIQ.java +++ b/48_High_IQ/java/src/HighIQ.java @@ -3,11 +3,25 @@ import java.util.HashMap; import java.util.Map; import java.util.Scanner; +/** + * Game of HighIQ + *

+ * Based on the Basic Game of HighIQ Here: + * https://github.com/coding-horror/basic-computer-games/blob/main/48_High_IQ/highiq.bas + * + * No additional functionality has been added + */ public class HighIQ { - private Map board; - private PrintStream out; - private Scanner scanner; + //Game board, as a map of position numbers to their values + private final Map board; + + //Output stream + private final PrintStream out; + + //Input scanner to use + private final Scanner scanner; + public HighIQ(Scanner scanner) { out = System.out; @@ -26,13 +40,14 @@ public class HighIQ { board.put(41, false); } + /** + * Plays the actual game, from start to finish. + */ public void play() { - - do { printBoard(); while (!move()) { - System.out.println("ILLEGAL MOVE, TRY AGAIN..."); + out.println("ILLEGAL MOVE, TRY AGAIN..."); } } while (!isGameFinished()); @@ -51,8 +66,12 @@ public class HighIQ { } } + /** + * Makes an individual move + * @return True if the move was valid, false if the user made an error and the move is invalid + */ public boolean move() { - System.out.println("MOVE WHICH PIECE"); + out.println("MOVE WHICH PIECE"); int from = scanner.nextInt(); //using the getOrDefault, which will make the statement false if it is an invalid position @@ -60,7 +79,7 @@ public class HighIQ { return false; } - System.out.println("TO WHERE"); + out.println("TO WHERE"); int to = scanner.nextInt(); if (board.getOrDefault(to, true)) { @@ -83,14 +102,18 @@ public class HighIQ { return false; } + //Actually move + board.put(from,false); + board.put(to,true); + board.put((from + to) / 2, false); + return true; } -// private boolean playAgain() { -// out.println("PLAY AGAIN (YES OR NO)"); -// return scanner.nextLine().toLowerCase().equals("yes"); -// } - + /** + * Checks if the game is finished + * @return True if there are no more moves, False otherwise + */ public boolean isGameFinished() { for (Integer key : board.keySet()) { if (board.get(key)) { From 60b84070c99624f8fa5d7db18c9d26d854b90686 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 13:40:28 -0500 Subject: [PATCH 141/331] Added Header --- 48_High_IQ/java/src/HighIQGame.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/48_High_IQ/java/src/HighIQGame.java b/48_High_IQ/java/src/HighIQGame.java index e74e5783..43400fb3 100644 --- a/48_High_IQ/java/src/HighIQGame.java +++ b/48_High_IQ/java/src/HighIQGame.java @@ -13,6 +13,8 @@ public class HighIQGame { } public static void printInstructions() { + System.out.println("\t\t\t H-I-Q"); + System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); System.out.println("HERE IS THE BOARD:"); System.out.println(" ! ! !"); System.out.println(" 13 14 15\n"); From c41e7ce057acb8747e7ce159ed9f40214f31a95b Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 13:58:12 -0500 Subject: [PATCH 142/331] Formatted Board into single string --- 48_High_IQ/python/High_IQ.py | 82 +++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 52aff04c..1f32e300 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -1,54 +1,58 @@ def new_board(): 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]: - board[i] = "X" - board[41] = "_" + 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(): - print("\n" * 3) - print("HERE IS THE BOARD:\n") - print("\n") - print(" ! ! !\n") - print(" 13 14 15\n") - print("\n") - print(" ! ! !\n") - print(" 22 23 24\n") - print("\n") - print("! ! ! ! ! ! ! ! !\n") - print("29 30 31 32 33 34 35 36 37\n") - print("\n") - print("! ! ! ! ! ! !\n") - print("38 39 40 41 42 43 44\n") - print("\n") - print("! ! ! ! ! ! !\n") - print("47 48 49 50 51 52 53\n") - print("\n") - print(" ! ! !\n") - print(" 58 59 60\n") - print("\n") - print(" ! ! !\n") - print(" 67 68 69\n") - print("\n") - print("TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\n") - print("WILL BE USED DURING PLAY. REFER TO THE ABOVE ONE FOR PEG\n") - print("NUMBERS. OK, LET'S BEGIN.\n") + print(""" +HERE IS THE BOARD: + + ! ! ! + 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 + +TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD +WILL BE USED DURING PLAY. REFER TO THE ABOVE ONE FOR PEG +NUMBERS. OK, LET'S BEGIN. + """) def print_board(board): - print(" " * 3 + board[13] + board[14] + board[15]) - print(" " * 3 + board[22] + board[23] + board[24]) + print(" " * 2 + board[13] + board[14] + board[15]) + print(" " * 2 + board[22] + board[23] + board[24]) print(board[29] + board[30] + board[31] + board[32] + board[33] + board[34] + board[35]) print(board[38] + board[39] + board[40] + board[41] + board[42] + board[43] + board[44]) print(board[47] + board[48] + board[49] + board[50] + board[51] + board[52] + board[53]) - print(" " * 3 + board[58] + board[59] + board[60]) - print(" " * 3 + board[67] + board[68] + board[69]) - + print(" " * 2 + board[58] + board[59] + board[60]) + print(" " * 2 + board[67] + board[68] + board[69]) + def play_game(): print("Lets play a game") board = new_board() - print_board(board) + + while not is_game_finished(board): + print_board(board) + def main(): # if input("Do you want instrunctions?\n").lower().startswith("y"): @@ -56,7 +60,7 @@ def main(): print("\t" * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print_instructions() play_game() - + def is_game_finished(board): for pos in board.keys(): if board[pos] == "X": @@ -65,9 +69,9 @@ def is_game_finished(board): hasMovableSpace = (not ((pos - space) in board and board[pos - space] == "X")) or (not ((pos + space * 2) in board and board[pos + space * 2] == "X")) if nextToPeg and hasMovableSpace: return False - + return True - + if __name__ == "__main__": main() From 6ae9fbcd3676ad929d44c89b07d90dd415d83a4b Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 14:22:28 -0500 Subject: [PATCH 143/331] Initial Commit Added Instructions, Random mine placement, and the general layout --- 30_Cube/java/src/Cube.java | 80 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 30_Cube/java/src/Cube.java diff --git a/30_Cube/java/src/Cube.java b/30_Cube/java/src/Cube.java new file mode 100644 index 00000000..2e19a691 --- /dev/null +++ b/30_Cube/java/src/Cube.java @@ -0,0 +1,80 @@ +import java.io.PrintStream; +import java.util.Random; + +public class Cube { + + private Location playerLocation; + private Location[] mines; + private PrintStream out; + + + public static void main(String[] args) { + new Cube().play(); + } + + public Cube() { + out = System.out; + } + + private void placeMines() { + mines = new Location[5]; + Random random = new Random(); + for(int i = 0; i < mines.length; i++) { + int x = random.nextInt(1,4); + int y = random.nextInt(1,4); + int z = random.nextInt(1,4); + mines[i] = new Location(x,y,z); + } + } + + public void play() { + + } + + public void printInstructions() { + out.println("THIS IS A GAME IN WHICH YOU WILL BE PLAYING AGAINST THE"); + out.println("RANDOM DECISION OF THE COMPUTER. THE FIELD OF PLAY IS A"); + out.println("CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED"); + out.println("CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED"); + out.println("BY INPUTTING THREE NUMBERS SUCH AS 2,3,1. AT THE START"); + out.println("YOU ARE AUTOMATICALLY AT LOCATION 1,1,1. THE OBJECT OF"); + out.println("THE GAME IS TO GET TO LOCATION 3,3,3. ONE MINOR DETAIL:"); + out.println("THE COMPUTER WILL PICK, AT RANDOM, 5 LOCATIONS AT WHICH"); + out.println("IT WILL PLANT LAND MINES. IF YOU HIT ONE OF THESE LOCATIONS"); + out.println("YOU LOSE. ONE OTHER DETAIL: YOU MAY MOVE ONLY ONE SPACE"); + out.println("IN ONE DIRECTION EACH MOVE. FOR EXAMPLE: FROM 1,1,2 YOU"); + out.println("MAY MOVE TO 2,1,2 OR 1,1,3. YOU MAY NOT CHANGE"); + out.println("TWO OF THE NUMBERS ON THE SAME MOVE. IF YOU MAKE AN ILLEGAL"); + out.println("MOVE, YOU LOSE AND THE COMPUTER TAKES THE MONEY YOU MAY"); + } + + public class Location { + int x,y,z; + + public Location(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Location location = (Location) o; + + if (x != location.x) return false; + if (y != location.y) return false; + return z == location.z; + } + + @Override + public int hashCode() { + int result = x; + result = 31 * result + y; + result = 31 * result + z; + return result; + } + } +} From 4d88281a17750b7dd00735c41b52d2f361114e8e Mon Sep 17 00:00:00 2001 From: Flavio Poletti Date: Thu, 6 Jan 2022 20:09:19 +0100 Subject: [PATCH 144/331] Add Perl for 04_Awari --- 04_Awari/perl/awari.pl | 267 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 04_Awari/perl/awari.pl diff --git a/04_Awari/perl/awari.pl b/04_Awari/perl/awari.pl new file mode 100644 index 00000000..3d70452c --- /dev/null +++ b/04_Awari/perl/awari.pl @@ -0,0 +1,267 @@ +#!/usr/bin/env perl +use v5.24; +use warnings; +use experimental 'signatures'; +no warnings 'experimental::signatures'; +use List::Util 'none'; + +# our board will be represented with an array of 14 slots, from 0 to 13. +# Positions 6 and 13 represent the "home pit" for the human and the +# computer, respectively. +use constant PLAYER_HOME => 6; +use constant COMPUTER_HOME => 13; + +use constant FIRST => 0; +use constant AGAIN => 1; + +exit main(@ARGV); + +sub main { + $|++; # disable buffering on standard output, every print will be + # done immediately + + welcome(); # startup message + + # this array will keep track of computer-side failures, defined as + # "the computer did not win". Whenever the computer loses or draws, the + # specific sequence of moves will be saved and then used to drive + # the search for a (hopefully) optimal move. + my $failures = []; + while ('enjoying') { + + # a new game starts, let's reset the board to the initial condition + my $board = [ (3) x 6, 0, (3) x 6, 0 ]; + + # this string will keep track of all moves performed + my $moves = '/'; + + # the human player starts + my $turn = 'player'; + + say "\n"; + print_board($board); + + while (not is_game_over($board)) { + + my $move; # this will collect the move in this turn + + if ($turn eq 'player') { # "first" move for player + + # player_move(...) does the move selected by the player, + # returning both the selected move as well as the pit id + # where the last seed landed + ($move, my $landing) = player_move($board); + + # if we landed on the Player's Home Pit we get another move + $turn = $landing == PLAYER_HOME ? 'player-again' : 'computer'; + } + elsif ($turn eq 'player-again') { # "second" move for player + + # here we call player_move making it clear that it's the + # second move, to get the right prompt eventually. We only + # care for the $move as the result, so we ignore the other. + ($move) = player_move($board, AGAIN); + $turn = 'computer'; + } + else { + + # the computer_move(...) function analyzes the $board as well + # as adapting the strategy based on past "failures" (i.e. + # matches where the computer did not win). For this it's + # important to pass the log of these failures, as well as the + # full record of moves in this specific match. + ($move, my $landing) = computer_move($board, $failures, $moves); + print "\nMY MOVE IS ", $move - 6; + + # do the second move in the turn if conditions apply + if ($landing == COMPUTER_HOME && ! is_game_over($board)) { + + # save the first move before doing the second one! + $moves .= "$move/"; + + my ($move) = computer_move($board, $failures, $moves); + print ',', $move - 6; + } + $turn = 'player'; + } + + # append the last selected move by either party, to track this + # specific match (useful for computer's AI and ML) + $moves .= "$move/"; + print_board($board); + } + + # assess_victory() returns the difference between player's and + # computer's seeds, so a negative value is a win for the computer. + my $computer_won = assess_victory($board) < 0; + + # if this last match was a "failure" (read: not a win for the + # computer), then record it for future memory. + push $failures->@*, $moves unless $computer_won; + } + + return 0; +} + +# calculate the difference between the two home pits. Negative values mean +# that the computer won, 0 is a draw, positive values is a player's win. +# The difference is also returned back, in case of need. +sub assess_victory ($board) { + say "\nGAME OVER"; + my $difference = $board->[PLAYER_HOME] - $board->[COMPUTER_HOME]; + if ($difference < 0) { + say 'I WIN BY ', -$difference, ' POINTS'; + } + else { + say $difference ? "YOU WIN BY $difference POINTS" : 'DRAWN GAME'; + } + return $difference; +} + +# move the seeds from $pit and take into account possible bonuses +sub move_seeds ($board, $pit) { + + # get the seeds from the selected pit $pit + my $seeds = $board->[$pit]; + $board->[$pit] = 0; + + # $landing will be our "moving cursor" to place seeds around + my $landing = $pit; + while ($seeds > 0) { + $landing = ($landing + 1) % 14; # 12 --> 13 -[wrap]-> 0 --> 1 + --$seeds; + ++$board->[$landing]; + } + + # check for "stealing seeds" condition. This cannot happen in home pits + if ($landing != PLAYER_HOME && $landing != COMPUTER_HOME + && $board->[$landing] == 1 && $board->[12 - $landing] > 0) { + my $home = $pit < 7 ? PLAYER_HOME : COMPUTER_HOME; + $board->[$home] += 1 + $board->[12 - $landing]; + $board->@[$landing, 12 - $landing] = (0, 0); + } + + return ($pit, $landing); +} + +sub get_player_move ($board, $prompt) { + print "\n$prompt? "; + while (defined(my $move = )) { + chomp($move); # remove newline + return $move - 1 if $move =~ m{\A[1-6]\z}mxs && $board->[$move - 1]; + print 'ILLEGAL MOVE\nAGAIN? '; + } + die "goodbye\n"; +} + +sub player_move ($board, $stage = FIRST) { + my $prompt = $stage == FIRST ? 'YOUR MOVE' : 'AGAIN'; + my $selected_move = get_player_move($board, $prompt); + return move_seeds($board, $selected_move); +} + +sub computer_move ($board, $failures, $moves) { + + # we will go through all possible moves for the computer and all + # possible responses by the player, collecting the "best" move in terms + # of reasonable outcome (assuming that each side wants to maximize their + # outcome. $best_move will eventually contain the best move for the + # computer, and $best_difference the best difference in scoring (as + # seen from the computer). + my ($best_move, $best_difference); + for my $c_move (7 .. 12) { + next unless $board->[$c_move]; # only consider pits with seeds inside + + # we work on a copy of the board to do all our trial-and-errors + my $copy = [ $board->@* ]; + move_seeds($copy, $c_move); + + # it's time to "think like a player" and see what's the "best" move + # for the player in this situation. This heuristic is "not perfect" + # but it seems OK anyway. + my $best_player_score = 0; + for my $p_move (0 .. 5) { + next unless $copy->[$p_move]; # only pits with seeds inside + my $landing = $copy->[$p_move] + $p_move; + + # the player's score for this move, calculated as additional seeds + # placed in the player's pit. The original algorithm sets this to + # 1 only if the $landing position is greater than 13, which can + # be obtained by setting the ORIGINAL environment variable to a + # "true" value (in Perl terms). Otherwise it is calculated + # according to the real rules for the game. + my $p_score = $ENV{ORIGINAL} ? $landing > 13 : int(($landing - 5) / 14); + + # whatever, the landing position must be within the bounds + $landing %= 14; + + # if the conditions apply, the player's move might win additional + # seeds, which we have to to take into account. + $p_score += $copy->[12 - $landing] + if $copy->[$landing] == 0 + && $landing != PLAYER_HOME && $landing != COMPUTER_HOME; + + # let's compare this move's score against the best collected + # so far (as a response to a specific computer's move). + $best_player_score = $p_score if $p_score > $best_player_score; + } + + # the overall score for the player is the additional seeds we just + # calculated into $best_player_score plus the seeds that were already + # in the player's pit + $best_player_score += $copy->[PLAYER_HOME]; + + # the best difference we can aim for with this computer's move must + # assume that the player will try its best + my $difference = $copy->[COMPUTER_HOME] - $best_player_score; + + # now it's time to check this computer's move against the history + # of failed matches. $candidate_moves will be the "candidate" list + # of moves if we accept this one. + my $candidate_moves = $moves . $c_move . '/'; + for my $failure ($failures->@*) { + + # index(.) returns 0 if and only if $candidate_moves appears at + # the very beginning of $failure, i.e. it matches a previous + # behaviour. + next if index($failure, $candidate_moves) != 0; + + # same sequence of moves as before... assign a penalty + $difference -= 2; + } + + # update $best_move and $best_difference if they need to + ($best_move, $best_difference) = ($c_move, $difference) + if (! defined $best_move) || ($best_difference < $difference); + } + + # apply the selected move and return + return move_seeds($board, $best_move); +} + +sub welcome { + say ' ' x 34, 'AWARI'; + say ' ' x 15, 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'; +} + +sub print_board ($board) { + my $template = ' + %2d %2d %2d %2d %2d %2d + %2d %d + %2d %2d %2d %2d %2d %2d +'; + printf $template, $board->@[12, 11, 10, 9, 8 , 7, 13, 6, 0 .. 5]; + return; +} + +sub is_game_over ($board) { + + # game over if the player's side is empty + return 1 if none { $_ } $board->@[0 .. 5]; + + # game over if the computers' side is empty + return 1 if none { $_ } $board->@[7 .. 12]; + + # not game over + return 0; +} From 33dbe7e92d14980b17ddfb3afa56868c95013287 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 15:35:24 -0500 Subject: [PATCH 145/331] Started work on the play cycle --- 30_Cube/java/src/Cube.java | 90 +++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 5 deletions(-) diff --git a/30_Cube/java/src/Cube.java b/30_Cube/java/src/Cube.java index 2e19a691..7fbe39ee 100644 --- a/30_Cube/java/src/Cube.java +++ b/30_Cube/java/src/Cube.java @@ -1,11 +1,17 @@ import java.io.PrintStream; +import java.util.HashSet; import java.util.Random; +import java.util.Scanner; +import java.util.Set; public class Cube { private Location playerLocation; - private Location[] mines; + private Set mines; private PrintStream out; + private Scanner scanner; + + private int money; public static void main(String[] args) { @@ -14,28 +20,84 @@ public class Cube { public Cube() { out = System.out; + scanner = new Scanner(System.in); + money = 500; + mines = new HashSet<>(); } private void placeMines() { - mines = new Location[5]; + mines.clear(); Random random = new Random(); - for(int i = 0; i < mines.length; i++) { + for(int i = 0; i < 5; i++) { int x = random.nextInt(1,4); int y = random.nextInt(1,4); int z = random.nextInt(1,4); - mines[i] = new Location(x,y,z); + mines.add(new Location(x,y,z)); } } public void play() { + out.println("DO YOU WANT TO SEE INSTRUCTIONS? (YES--1,NO--0)"); + if(readParsedBoolean()) { + printInstructions(); + } + do { + placeMines(); + out.println("WANT TO MAKE A WAGER?"); + int wager = 0 ; + if(readParsedBoolean()) { + out.println("HOW MUCH?"); + do { + wager = scanner.nextInt(); + if(wager > money) { + out.println("TRIED TO FOOL ME; BET AGAIN"); + } + } while(wager > money); + } + + + while(playerLocation.x + playerLocation.y + playerLocation.z != 9) { + out.println("\nNEXT MOVE"); + String input = scanner.nextLine(); + + String[] stringValues = input.split(","); + + int x = Integer.parseInt(stringValues[0]); + int y = Integer.parseInt(stringValues[1]); + int z = Integer.parseInt(stringValues[2]); + + Location location = new Location(x,y,z); + + if(x < 1 || x > 3 || y < 1 || y > 3 || z < 1 || z > 3 || isMoveValid(playerLocation,location)) { + out.println("ILLEGAL MOVE, YOU LOSE."); + return; + } + + playerLocation = location; + + if(mines.contains(location)) { + out.println("******BANG******"); + out.println("YOU LOSE!\n\n"); + money -= wager; + } + } + } while(money > 0 && !doAnotherRound()); + } + + private boolean doAnotherRound() { + if(money > 0) { + out.println("DO YOU WANT TO TRY AGAIN?"); + return readParsedBoolean(); + } else { + return false; + } } public void printInstructions() { out.println("THIS IS A GAME IN WHICH YOU WILL BE PLAYING AGAINST THE"); out.println("RANDOM DECISION OF THE COMPUTER. THE FIELD OF PLAY IS A"); out.println("CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED"); - out.println("CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED"); out.println("BY INPUTTING THREE NUMBERS SUCH AS 2,3,1. AT THE START"); out.println("YOU ARE AUTOMATICALLY AT LOCATION 1,1,1. THE OBJECT OF"); out.println("THE GAME IS TO GET TO LOCATION 3,3,3. ONE MINOR DETAIL:"); @@ -46,6 +108,24 @@ public class Cube { out.println("MAY MOVE TO 2,1,2 OR 1,1,3. YOU MAY NOT CHANGE"); out.println("TWO OF THE NUMBERS ON THE SAME MOVE. IF YOU MAKE AN ILLEGAL"); out.println("MOVE, YOU LOSE AND THE COMPUTER TAKES THE MONEY YOU MAY"); + out.println("\n"); + out.println("ALL YES OR NO QUESTIONS WILL BE ANSWERED BY A 1 FOR YES"); + out.println("OR A 0 (ZERO) FOR NO."); + out.println(); + out.println("WHEN STATING THE AMOUNT OF A WAGER, PRINT ONLY THE NUMBER"); + out.println("OF DOLLARS (EXAMPLE: 250) YOU ARE AUTOMATICALLY STARTED WITH"); + out.println("500 DOLLARS IN YOUR ACCOUNT."); + out.println(); + out.println("GOOD LUCK!"); + } + + private boolean readParsedBoolean() { + String in = scanner.nextLine(); + return in.toLowerCase().charAt(0) == 'y' || Boolean.parseBoolean(in); + } + + private boolean isMoveValid(Location from, Location to) { + return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) + Math.abs(from.z - to.z) <= 1; } public class Location { From 28b94b55679a7b1472367b23684707e00f9b6fa6 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 16:04:03 -0500 Subject: [PATCH 146/331] Game now works --- 30_Cube/java/src/Cube.java | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/30_Cube/java/src/Cube.java b/30_Cube/java/src/Cube.java index 7fbe39ee..1b68a285 100644 --- a/30_Cube/java/src/Cube.java +++ b/30_Cube/java/src/Cube.java @@ -49,27 +49,32 @@ public class Cube { if(readParsedBoolean()) { out.println("HOW MUCH?"); do { - wager = scanner.nextInt(); + wager = Integer.parseInt(scanner.nextLine()); if(wager > money) { out.println("TRIED TO FOOL ME; BET AGAIN"); } } while(wager > money); } - + playerLocation = new Location(1,1,1); while(playerLocation.x + playerLocation.y + playerLocation.z != 9) { out.println("\nNEXT MOVE"); String input = scanner.nextLine(); String[] stringValues = input.split(","); + if(stringValues.length < 3) { + out.println("ILLEGAL MOVE, YOU LOSE."); + return; + } + int x = Integer.parseInt(stringValues[0]); int y = Integer.parseInt(stringValues[1]); int z = Integer.parseInt(stringValues[2]); Location location = new Location(x,y,z); - if(x < 1 || x > 3 || y < 1 || y > 3 || z < 1 || z > 3 || isMoveValid(playerLocation,location)) { + if(x < 1 || x > 3 || y < 1 || y > 3 || z < 1 || z > 3 || !isMoveValid(playerLocation,location)) { out.println("ILLEGAL MOVE, YOU LOSE."); return; } @@ -80,9 +85,18 @@ public class Cube { out.println("******BANG******"); out.println("YOU LOSE!\n\n"); money -= wager; + break; } } - } while(money > 0 && !doAnotherRound()); + + if(wager > 0) { + out.printf("YOU NOW HAVE %d DOLLARS\n",money); + } + + } while(money > 0 && doAnotherRound()); + + out.println("TOUGH LUCK!"); + out.println("\nGOODBYE."); } private boolean doAnotherRound() { @@ -121,7 +135,11 @@ public class Cube { private boolean readParsedBoolean() { String in = scanner.nextLine(); - return in.toLowerCase().charAt(0) == 'y' || Boolean.parseBoolean(in); + try { + return in.toLowerCase().charAt(0) == 'y' || Boolean.parseBoolean(in) || Integer.parseInt(in) == 1; + } catch(NumberFormatException exception) { + return false; + } } private boolean isMoveValid(Location from, Location to) { From fe6cb06d6f660916fe08a8d02d58f760685ac438 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 16:11:12 -0500 Subject: [PATCH 147/331] Added Comments --- 30_Cube/java/src/Cube.java | 46 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/30_Cube/java/src/Cube.java b/30_Cube/java/src/Cube.java index 1b68a285..1237a49d 100644 --- a/30_Cube/java/src/Cube.java +++ b/30_Cube/java/src/Cube.java @@ -4,16 +4,33 @@ import java.util.Random; import java.util.Scanner; import java.util.Set; +/** + * Game of Cube + *

+ /// 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 00000000..7b88d7b7 --- /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 index 4daabb5c..0f4d812a 100644 --- a/93_23_Matches/csharp/README.md +++ b/93_23_Matches/csharp/README.md @@ -1,3 +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. \ No newline at end of file From cc3b941bcb38b8c705d1ec5d949d3951008525fa Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Sun, 9 Jan 2022 11:21:48 -0500 Subject: [PATCH 207/331] Port 68_Orbit to Perl. Nothing fancy; just a straight port to idiomatic Perl. --- 68_Orbit/perl/README.md | 8 ++ 68_Orbit/perl/orbit.pl | 239 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 247 insertions(+) create mode 100755 68_Orbit/perl/orbit.pl diff --git a/68_Orbit/perl/README.md b/68_Orbit/perl/README.md index e69c8b81..e3bc2e31 100644 --- a/68_Orbit/perl/README.md +++ b/68_Orbit/perl/README.md @@ -1,3 +1,11 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +This Perl script is a port of orbit, which is the 68th entry in Basic +Computer Games. + +In this game you are a planetary defense gunner trying to shoot down a +cloaked Romulan ship before it can escape. + +This is pretty much a straight port of the BASIC into idiomatic Perl. diff --git a/68_Orbit/perl/orbit.pl b/68_Orbit/perl/orbit.pl new file mode 100755 index 00000000..f8e9fccf --- /dev/null +++ b/68_Orbit/perl/orbit.pl @@ -0,0 +1,239 @@ +#!/usr/bin/env perl + +use 5.010; # To get 'state' and 'say' + +use strict; # Require explicit declaration of variables +use warnings; # Enable optional compiler warnings + +use English; # Use more friendly names for Perl's magic variables +use Term::ReadLine; # Prompt and return user input + +our $VERSION = '0.000_01'; + +use constant PI => atan2( 0, -1 ); +use constant DEG_TO_RAD => atan2( 0, -1 ) / 180; + +print <<'EOD'; + 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. +EOD + +while ( 1 ) { # Iterate indefinitely + + my $romulan_angle = int( 360 * rand() ); + my $romulan_distance = int( 200 * rand() + 200 ); + my $romulan_velocity = int( 20 * rand() + 10 ); + + my $hour = 0; + while ( 1 ) { # Iterate indefinitely + $hour++; + + print <<"EOD"; + + +This is hour $hour, at what angle do you wish to send +EOD + my $bomb_angle = get_input( + 'do you wish to send your photon bomb? ', + sub { m/ \A [0-9]+ \z /smx }, + "Please enter an integer angle in degrees\n", + ); + say ''; + my $bomb_distance = get_input( + 'How far out do you wish to detonate it? ', + sub { m/ \A [0-9]+ \z /smx }, + "Please enter an integer distance in hundreds of miles\n", + ); + + $romulan_angle = ( $romulan_angle + $romulan_velocity ) % 360; + my $miss_angle = abs( $romulan_angle - $bomb_angle ); + $miss_angle = 360 - $miss_angle if $miss_angle >= 180; + my $miss_distance = int sqrt( + $romulan_distance * $romulan_distance + + $bomb_distance * $bomb_distance - + 2 * $romulan_distance * $bomb_distance * + cos( $miss_angle * DEG_TO_RAD ) ); + print <<"EOD"; + +Your photon bomb exploded $miss_distance*10^2 miles from the +Romulan ship. +EOD + if ( $miss_distance <= 50 ) { + say "\nYou have successfully completed your mission."; + last; + } elsif ( $hour > 6 ) { + say "\nYou have allowed the Romulans to escape."; + last; + } + } + + say "\nAnother Romulan ship has gone into orbit."; + last unless get_yes_no( 'Do you wish to try to destroy it' ); +} + +print <<'EOD'; + +Good bye. +EOD + +# Get input from the user. The arguments are: +# * The prompt +# * A reference to validation code. This code receives the response in +# $ARG and returns true for a valid response. +# * A warning to print if the response is not valid. This must end in a +# return. +# The first valid response is returned. An end-of-file terminates the +# script. +sub get_input { + my ( $prompt, $validate, $warning ) = @ARG; + + # If no validator is passed, default to one that always returns + # true. + $validate ||= sub { 1 }; + + # Create the readline object. The 'state' causes the variable to be + # initialized only once, no matter how many times this subroutine is + # called. The do { ... } is a compound statement used because we + # need to tweak the created object before we store it. + state $term = do { + my $obj = Term::ReadLine->new( 'reverse' ); + $obj->ornaments( 0 ); + $obj; + }; + + while ( 1 ) { # Iterate indefinitely + + # Read the input into the topic variable, localized to prevent + # Spooky Action at a Distance. We exit on undef, which signals + # end-of-file. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Return the input if it is valid. + return $ARG if $validate->(); + + # Issue the warning, and go around the merry-go-round again. + warn $warning; + } +} + +# Get a yes-or-no answer. The argument is the prompt, which will have +# '? [y/n]: ' appended. The donkey work is done by get_input(), which is +# requested to validate the response as beginning with 'y' or 'n', +# case-insensitive. The return is a true value for 'y' and a false value +# for 'n'. +sub get_yes_no { + my ( $prompt ) = @ARG; + state $map_answer = { + n => 0, + y => 1, + }; + my $resp = lc get_input( + "$prompt? [y/n]: ", + sub { m/ \A [yn] /smxi }, + "Please respond 'y' or 'n'\n", + ); + return $map_answer->{ substr $resp, 0, 1 }; +} + +__END__ + +=head1 TITLE + +orbit - Play the game 'Orbit' from Basic Computer Games + +=head1 SYNOPSIS + + orbit.pl + +=head1 DETAILS + +This Perl script is a port of orbit, which is the 68th entry in Basic +Computer Games. + +In this game you are a planetary defense gunner trying to shoot down a +cloaked Romulan ship before it can escape. + +This is pretty much a straight port of the BASIC into idiomatic Perl. + +=head1 PORTED BY + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set expandtab tabstop=4 textwidth=72 : From dedca6ac0d3662863fa3721fb0ad4f08b00355b5 Mon Sep 17 00:00:00 2001 From: Flow Date: Sun, 9 Jan 2022 18:51:34 +0100 Subject: [PATCH 208/331] Add pizza implementation in c# --- 69_Pizza/csharp/Pizza/CustomerMap.cs | 131 ++++++++ 69_Pizza/csharp/Pizza/Pizza.csproj | 10 + 69_Pizza/csharp/Pizza/Pizza.sln | 25 ++ 69_Pizza/csharp/Pizza/PizzaGame.cs | 296 ++++++++++++++++++ 69_Pizza/csharp/Pizza/Program.cs | 11 + .../csharp/Pizza/StringBuilderExtensions.cs | 21 ++ 6 files changed, 494 insertions(+) create mode 100644 69_Pizza/csharp/Pizza/CustomerMap.cs create mode 100644 69_Pizza/csharp/Pizza/Pizza.csproj create mode 100644 69_Pizza/csharp/Pizza/Pizza.sln create mode 100644 69_Pizza/csharp/Pizza/PizzaGame.cs create mode 100644 69_Pizza/csharp/Pizza/Program.cs create mode 100644 69_Pizza/csharp/Pizza/StringBuilderExtensions.cs diff --git a/69_Pizza/csharp/Pizza/CustomerMap.cs b/69_Pizza/csharp/Pizza/CustomerMap.cs new file mode 100644 index 00000000..ee991de3 --- /dev/null +++ b/69_Pizza/csharp/Pizza/CustomerMap.cs @@ -0,0 +1,131 @@ +using System.Text; + +namespace Pizza +{ + internal class CustomerMap + { + private readonly int _mapSize; + private readonly string[,] _customerMap; + + public CustomerMap(int mapSize) + { + _mapSize = mapSize; + _customerMap = GenerateCustomerMap(); + } + + /// + /// Gets customer on position X, Y. + /// + /// Represents X position. + /// Represents Y position. + /// If positions is valid then returns customer name otherwise returns empty string. + public string GetCustomerOnPosition(int x, int y) + { + if(IsPositionOutOfRange(x, y)) + { + return string.Empty; + } + + return _customerMap[y, x]; + } + + /// + /// Overridden ToString for getting text representation of customers map. + /// + /// Text representation of customers map. + public override string ToString() + { + int verticalSpace = 4; + int horizontalSpace = 5; + + var mapToDisplay = new StringBuilder(); + + AppendXLine(mapToDisplay, horizontalSpace); + + for (int i = _customerMap.GetLength(0) - 1; i >= 0; i--) + { + mapToDisplay.AppendLine("-", verticalSpace); + mapToDisplay.Append($"{i + 1}"); + mapToDisplay.Append(' ', horizontalSpace); + + for (var j = 0; j < _customerMap.GetLength(1); j++) + { + mapToDisplay.Append($"{_customerMap[i, j]}"); + mapToDisplay.Append(' ', horizontalSpace); + } + + mapToDisplay.Append($"{i + 1}"); + mapToDisplay.Append(' ', horizontalSpace); + mapToDisplay.Append(Environment.NewLine); + } + + mapToDisplay.AppendLine("-", verticalSpace); + + AppendXLine(mapToDisplay, horizontalSpace); + + return mapToDisplay.ToString(); + } + + /// + /// Checks if position is out of range or not. + /// + /// Represents X position. + /// Represents Y position. + /// True if position is out of range otherwise false. + private bool IsPositionOutOfRange(int x, int y) + { + return + x < 0 || x > _mapSize - 1 || + y < 0 || y > _mapSize - 1; + } + + /// + /// Generates array which represents customers map. + /// + /// Returns customers map. + private string[,] GenerateCustomerMap() + { + string[,] customerMap = new string[_mapSize, _mapSize]; + string[] customerNames = GetCustomerNames(_mapSize * _mapSize); + int currentCustomerNameIndex = 0; + + for (int i = 0; i < customerMap.GetLength(0); i++) + { + for (int j = 0; j < customerMap.GetLength(1); j++) + { + customerMap[i, j] = customerNames[currentCustomerNameIndex++].ToString(); + } + } + + return customerMap; + } + + /// + /// Generates customer names. Names are represented by alphanumerics from 'A'. Name of last customer depends on passed parameter. + /// + /// How many customers need to be generated. + /// List of customer names. + private static string[] GetCustomerNames(int numberOfCustomers) + { + // returns ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P"]; + return Enumerable.Range(65, numberOfCustomers).Select(c => ((Char)c).ToString()).ToArray(); + } + + /// + /// Appends line with X coordinates. + /// + /// Current map where a new line will be appended. + /// Number of horizontal delimiters which will be added between each coordination. + private void AppendXLine(StringBuilder mapToDisplay, int horizontalSpace) + { + mapToDisplay.Append(' '); + mapToDisplay.Append('-', horizontalSpace); + for (var i = 0; i < _customerMap.GetLength(0); i++) + { + mapToDisplay.Append($"{i + 1}"); + mapToDisplay.Append('-', horizontalSpace); + } + mapToDisplay.Append(Environment.NewLine); + } + } +} \ No newline at end of file diff --git a/69_Pizza/csharp/Pizza/Pizza.csproj b/69_Pizza/csharp/Pizza/Pizza.csproj new file mode 100644 index 00000000..74abf5c9 --- /dev/null +++ b/69_Pizza/csharp/Pizza/Pizza.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/69_Pizza/csharp/Pizza/Pizza.sln b/69_Pizza/csharp/Pizza/Pizza.sln new file mode 100644 index 00000000..91785a8c --- /dev/null +++ b/69_Pizza/csharp/Pizza/Pizza.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31912.275 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pizza", "Pizza.csproj", "{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8F7E9FAD-38C5-47A2-B5CA-2B6E5947B982} + EndGlobalSection +EndGlobal diff --git a/69_Pizza/csharp/Pizza/PizzaGame.cs b/69_Pizza/csharp/Pizza/PizzaGame.cs new file mode 100644 index 00000000..22c78e05 --- /dev/null +++ b/69_Pizza/csharp/Pizza/PizzaGame.cs @@ -0,0 +1,296 @@ +namespace Pizza +{ + internal class PizzaGame + { + private const int CustomerMapSize = 4; + private readonly CustomerMap _customerMap = new CustomerMap(CustomerMapSize); + + /// + /// Starts game. Main coordinator for pizza game. + /// It is responsible for showing information, getting data from user and starting to delivery pizza. + /// + public void Play() + { + ShowHeader(); + + string playerName = GetPlayerName(); + + ShowIntroduction(playerName); + ShowMap(); + + if (AskForMoreDirections()) + { + ShowMoreDirections(playerName); + + var playerUnderstands = AskIfPlayerUnderstand(); + if (!playerUnderstands) + { + return; + } + } + + StartDelivery(playerName); + EndDelivery(playerName); + } + + /// + /// Starts with pizza delivering to customers. + /// Every 5 deliveries it is asking user whether want to continue in delivering. + /// + /// Player name which was filled by user. + private void StartDelivery(string playerName) + { + var numberOfDeliveredPizzas = 0; + while (true) + { + numberOfDeliveredPizzas++; + string deliverPizzaToCustomer = GetRandomCustomer(); + + WriteEmptyLine(); + Console.WriteLine($"HELLO {playerName}'S PIZZA. THIS IS {deliverPizzaToCustomer}."); + Console.WriteLine("\tPLEASE SEND A PIZZA."); + + DeliverPizzaByPlayer(playerName, deliverPizzaToCustomer); + + if (numberOfDeliveredPizzas % 5 == 0) + { + bool playerWantToDeliveryMorePizzas = AskQuestionWithYesNoResponse("DO YOU WANT TO DELIVER MORE PIZZAS?"); + if (!playerWantToDeliveryMorePizzas) + { + WriteEmptyLine(); + break; + } + } + } + } + + /// + /// Gets random customer for which pizza should be delivered. + /// + /// Customer name. + private string GetRandomCustomer() + { + int randomPositionOnX = Random.Shared.Next(0, CustomerMapSize); + int randomPositionOnY = Random.Shared.Next(0, CustomerMapSize); + + return _customerMap.GetCustomerOnPosition(randomPositionOnX, randomPositionOnY); + } + + /// + /// Delivers pizza to customer by player. It verifies whether player was delivering pizza to correct customer. + /// + /// Player name which was filled by user. + /// Customer name which order pizza. + private void DeliverPizzaByPlayer(string playerName, string deliverPizzaToCustomer) + { + while (true) + { + string userInput = GetPlayerInput($"\tDRIVER TO {playerName}: WHERE DOES {deliverPizzaToCustomer} LIVE?"); + var deliveredToCustomer = GetCustomerFromPlayerInput(userInput); + if (string.IsNullOrEmpty(deliveredToCustomer)) + { + deliveredToCustomer = "UNKNOWN CUSTOMER"; + } + + if (deliveredToCustomer.Equals(deliverPizzaToCustomer)) + { + Console.WriteLine($"HELLO {playerName}. THIS IS {deliverPizzaToCustomer}, THANKS FOR THE PIZZA."); + break; + } + + Console.WriteLine($"THIS IS {deliveredToCustomer}. I DID NOT ORDER A PIZZA."); + Console.WriteLine($"I LIVE AT {userInput}"); + } + } + + /// + /// Gets customer name by user input with customer coordinations. + /// + /// Input from users - it should represent customer coordination separated by ','. + /// If coordinations are correct and customer exists then returns true otherwise false. + private string GetCustomerFromPlayerInput(string userInput) + { + var pizzaIsDeliveredToPosition = userInput? + .Split(',') + .Select(i => int.TryParse(i, out var customerPosition) ? (customerPosition - 1) : -1) + .Where(i => i != -1) + .ToArray() ?? Array.Empty(); + if (pizzaIsDeliveredToPosition.Length != 2) + { + return string.Empty; + } + + return _customerMap.GetCustomerOnPosition(pizzaIsDeliveredToPosition[0], pizzaIsDeliveredToPosition[1]); + } + + /// + /// Shows game header in console. + /// + private void ShowHeader() + { + Console.WriteLine("PIZZA".PadLeft(22)); + Console.WriteLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + WriteEmptyLine(3); + Console.WriteLine("PIZZA DELIVERY GAME"); + WriteEmptyLine(); + } + + /// + /// Asks user for name which will be used in game. + /// + /// Player name. + private string GetPlayerName() + { + return GetPlayerInput("WHAT IS YOUR FIRST NAME:"); + } + + /// + /// Shows game introduction in console + /// + /// Player name which was filled by user. + private void ShowIntroduction(string playerName) + { + Console.WriteLine($"HI, {playerName}. IN THIS GAME YOU ARE TO TAKE ORDERS"); + Console.WriteLine("FOR PIZZAS. THEN YOU ARE TO TELL A DELIVERY BOY"); + Console.WriteLine("WHERE TO DELIVER THE ORDERED PIZZAS."); + WriteEmptyLine(2); + } + + /// + /// Shows customers map in console. In this method is used overridden method 'ToString' for getting text representation of customers map. + /// + private void ShowMap() + { + Console.WriteLine("MAP OF THE CITY OF HYATTSVILLE"); + WriteEmptyLine(); + + Console.WriteLine(_customerMap.ToString()); + + Console.WriteLine("THE OUTPUT IS A MAP OF THE HOMES WHERE"); + Console.WriteLine("YOU ARE TO SEND PIZZAS."); + WriteEmptyLine(); + Console.WriteLine("YOUR JOB IS TO GIVE A TRUCK DRIVER"); + Console.WriteLine("THE LOCATION OR COORDINATES OF THE"); + Console.WriteLine("HOME ORDERING THE PIZZA."); + WriteEmptyLine(); + } + + /// + /// Asks user if needs more directions. + /// + /// True if user need more directions otherwise false. + private bool AskForMoreDirections() + { + var playerNeedsMoreDirections = AskQuestionWithYesNoResponse("DO YOU NEED MORE DIRECTIONS?"); + WriteEmptyLine(); + + return playerNeedsMoreDirections; + } + + /// + /// Shows more directions. + /// + /// Player name which was filled by user. + private void ShowMoreDirections(string playerName) + { + Console.WriteLine("SOMEBODY WILL ASK FOR A PIZZA TO BE"); + Console.WriteLine("DELIVERED. THEN A DELIVERY BOY WILL"); + Console.WriteLine("ASK YOU FOR THE LOCATION."); + Console.WriteLine("\tEXAMPLE:"); + Console.WriteLine("THIS IS J. PLEASE SEND A PIZZA."); + Console.WriteLine($"DRIVER TO {playerName}. WHERE DOES J LIVE?"); + Console.WriteLine("YOUR ANSWER WOULD BE 2,3"); + } + + /// + /// Asks user if understands to instructions. + /// + /// True if user understand otherwise false. + private bool AskIfPlayerUnderstand() + { + var playerUnderstands = AskQuestionWithYesNoResponse("UNDERSTAND?"); + if (!playerUnderstands) + { + Console.WriteLine("THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY"); + return false; + } + + WriteEmptyLine(); + Console.WriteLine("GOOD. YOU ARE NOW READY TO START TAKING ORDERS."); + WriteEmptyLine(); + Console.WriteLine("GOOD LUCK!!"); + WriteEmptyLine(); + + return true; + } + + /// + /// Shows message about ending delivery in console. + /// + /// Player name which was filled by user. + private void EndDelivery(string playerName) + { + Console.WriteLine($"O.K. {playerName}, SEE YOU LATER!"); + WriteEmptyLine(); + } + + /// + /// Gets input from user. + /// + /// Question which is displayed in console. + /// User input. + private string GetPlayerInput(string question) + { + Console.Write($"{question} "); + + while (true) + { + var userInput = Console.ReadLine(); + if (!string.IsNullOrWhiteSpace(userInput)) + { + return userInput; + } + } + } + + /// + /// Asks user with required resposne 'YES', 'Y, 'NO', 'N'. + /// + /// Question which is displayed in console. + /// True if user write 'YES', 'Y'. False if user write 'NO', 'N'. + private static bool AskQuestionWithYesNoResponse(string question) + { + var possitiveResponse = new string[] { "Y", "YES" }; + var negativeResponse = new string[] { "N", "NO" }; + var validUserInputs = possitiveResponse.Concat(negativeResponse); + + Console.Write($"{question} "); + + string? userInput; + while (true) + { + userInput = Console.ReadLine(); + if (!string.IsNullOrWhiteSpace(userInput) && validUserInputs.Contains(userInput.ToUpper())) + { + break; + } + + Console.Write($"'YES' OR 'NO' PLEASE, NOW THEN, {question} "); + } + + return possitiveResponse.Contains(userInput.ToUpper()); + } + + /// + /// Writes empty line in console. + /// + /// Number of empty lines which will be written in console. Parameter is optional and default value is 1. + private void WriteEmptyLine(int numberOfEmptyLines = 1) + { + for (int i = 0; i < numberOfEmptyLines; i++) + { + Console.WriteLine(); + } + } + } +} \ No newline at end of file diff --git a/69_Pizza/csharp/Pizza/Program.cs b/69_Pizza/csharp/Pizza/Program.cs new file mode 100644 index 00000000..6c21fad0 --- /dev/null +++ b/69_Pizza/csharp/Pizza/Program.cs @@ -0,0 +1,11 @@ +namespace Pizza +{ + internal class Program + { + static void Main(string[] args) + { + var pizzaGame = new PizzaGame(); + pizzaGame.Play(); + } + } +} \ No newline at end of file diff --git a/69_Pizza/csharp/Pizza/StringBuilderExtensions.cs b/69_Pizza/csharp/Pizza/StringBuilderExtensions.cs new file mode 100644 index 00000000..f7cb828d --- /dev/null +++ b/69_Pizza/csharp/Pizza/StringBuilderExtensions.cs @@ -0,0 +1,21 @@ +using System.Text; + +namespace Pizza +{ + internal static class StringBuilderExtensions + { + /// + /// Extensions for adding new lines of specific value. + /// + /// Extended class. + /// Value which will be repeated. + /// Number of lines that will be appended. + public static void AppendLine(this StringBuilder stringBuilder, string value, int numberOfLines) + { + for (int i = 0; i < numberOfLines; i++) + { + stringBuilder.AppendLine(value); + } + } + } +} \ No newline at end of file From fbbf0bf622bde3293b10f6cafd4743812142d931 Mon Sep 17 00:00:00 2001 From: jcoehoorn Date: Sun, 9 Jan 2022 12:37:32 -0600 Subject: [PATCH 209/331] Create program.vb --- 02_Amazing/vbnet/program.vb | 295 ++++++++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 02_Amazing/vbnet/program.vb diff --git a/02_Amazing/vbnet/program.vb b/02_Amazing/vbnet/program.vb new file mode 100644 index 00000000..d39eb450 --- /dev/null +++ b/02_Amazing/vbnet/program.vb @@ -0,0 +1,295 @@ +Imports System + +Module Program + + Enum Directions + SolveAndReset = 0 + Left = 1 + Up = 2 + Right = 3 + Down = 4 + End Enum + + 'Program State + Dim Width As Integer = 0, Height As Integer = 0, Q As Integer = 0, CellsVisited As Integer = 2, curCol As Integer, curRow As Integer = 1 + Dim SolutionCompleted As Boolean = False + Dim CellVisitHistory(,) As Integer + Dim CellState(,) As Integer + + Dim rnd As New Random() + + Public ReadOnly Property BlockedLeft As Boolean + Get + Return curCol - 1 = 0 OrElse CellVisitHistory(curCol - 1, curRow) <> 0 + End Get + End Property + Public ReadOnly Property BlockedAbove As Boolean + Get + Return curRow - 1 = 0 OrElse CellVisitHistory(curCol, curRow - 1) <> 0 + End Get + End Property + Public ReadOnly Property BlockedRight As Boolean + Get + Return curCol = Width OrElse CellVisitHistory(curCol + 1, curRow) <> 0 + End Get + End Property + 'Note: "BlockedBelow" does NOT include checking if we have a solution! + Public ReadOnly Property BlockedBelow As Boolean + Get + Return curRow = Height OrElse CellVisitHistory(curCol, curRow + 1) <> 0 + End Get + End Property + Public ReadOnly Property OnBottomRow As Boolean + Get + Return curRow.Equals(Height) + End Get + End Property + + Sub Main(args As String()) + Const header As String = +" AMAZING PROGRAM + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + +" + Console.WriteLine(header) + + While Width <= 1 OrElse Height <= 1 + Console.Write("WHAT ARE YOUR WIDTH AND LENGTH? ") + + 'We no longer have the old convenient INPUT command, so need to parse out the inputs + Dim parts = Console.ReadLine().Split(","c).Select(Function(s) Convert.ToInt32(s.Trim())).ToList() + Width = parts(0) + Height = parts(1) + + If Width <= 1 OrElse Height <= 1 Then Console.WriteLine($"MEANINGLESS DIMENSIONS. TRY AGAIN.{vbCrLf}") + End While + + ReDim CellVisitHistory(Width, Height), CellState(Width, Height) + + Console.WriteLine(" + +") + + curCol = rnd.Next(1, Width + 1) 'Starting X position + CellVisitHistory(curCol, 1) = 1 + Dim startXPos As Integer = curCol 'we need to know this at the end to print opening line + + Dim keepGoing As Boolean = True + While keepGoing + If BlockedLeft Then + keepGoing = ChoosePath_BlockedToTheLeft() + ElseIf BlockedAbove Then + keepGoing = ChoosePath_BlockedAbove() + ElseIf BlockedRight Then + keepGoing = ChoosePath_BlockedToTheRight() + Else + keepGoing = SelectRandomDirection(Directions.Left, Directions.Up, Directions.Right) 'Go anywhere but down + End If + End While + + PrintFinalResults(startXPos) + End Sub + + Public Sub ResetCurrentPosition() + Do + If curCol <> Width Then 'not at the right edge + curCol += 1 + ElseIf curRow <> Height Then 'not at the bottom + curCol = 1 + curRow += 1 + Else + curCol = 1 + curRow = 1 + End If + Loop While CellVisitHistory(curCol, curRow) = 0 + End Sub + + Dim methods() As Func(Of Boolean) = {AddressOf MarkSolvedAndResetPosition, AddressOf GoLeft, AddressOf GoUp, AddressOf GoRight, AddressOf GoDown} + Public Function SelectRandomDirection(ParamArray possibles() As Directions) As Boolean + Dim x As Integer = rnd.Next(0, possibles.Length) + Return methods(possibles(x))() + End Function + + Public Function ChoosePath_BlockedToTheLeft() As Boolean + If BlockedAbove Then + If BlockedRight Then + If curRow <> Height Then + If CellVisitHistory(curCol, curRow + 1) <> 0 Then ' Can't go down, but not at the edge...blocked. Reset and try again + ResetCurrentPosition() + Return True + Else + Return GoDown() + End If + ElseIf SolutionCompleted Then 'Can't go Down (there's already another solution) + ResetCurrentPosition() + Return True + Else 'Can't go LEFT, UP, RIGHT, or DOWN, but we're on the bottom and there's no solution yet + Return MarkSolvedAndResetPosition() + End If + ElseIf BlockedBelow Then + Return GoRight() + ElseIf Not OnBottomRow Then + Return SelectRandomDirection(Directions.Right, Directions.Down) + ElseIf SolutionCompleted Then 'Can only go right, and we're at the bottom + Return GoRight() + Else 'Can only go right, we're at the bottom, and there's not a solution yet + Return SelectRandomDirection(Directions.Right, Directions.SolveAndReset) + End If + '== Definitely can go Up == + ElseIf BlockedRight Then + If BlockedBelow Then + Return GoUp() + ElseIf Not OnBottomRow Then + Return SelectRandomDirection(Directions.Up, Directions.Down) + ElseIf SolutionCompleted Then 'We're on the bottom row, can only go up + Return GoUp() + Else 'We're on the bottom row, can only go up, but there's no solution + Return SelectRandomDirection(Directions.Up, Directions.SolveAndReset) + End If + '== Definitely can go Up and Right == + ElseIf BlockedBelow Then + Return SelectRandomDirection(Directions.Up, Directions.Right) + ElseIf Not OnBottomRow Then + Return SelectRandomDirection(Directions.Up, Directions.Right, Directions.Down) + ElseIf SolutionCompleted Then 'at the bottom, but already have a solution + Return SelectRandomDirection(Directions.Up, Directions.Right) + Else + Return SelectRandomDirection(Directions.Up, Directions.Right, Directions.SolveAndReset) + End If + End Function + + Public Function ChoosePath_BlockedAbove() As Boolean + 'No need to check the left side, only called from the "keepGoing" loop where LEFT is already cleared + If BlockedRight Then + If BlockedBelow Then + Return GoLeft() + ElseIf Not OnBottomRow Then + Return SelectRandomDirection(Directions.Left, Directions.Down) + ElseIf SolutionCompleted Then 'Can't go down because there's already a solution + Return GoLeft() + Else 'At the bottom, no solution yet... + Return SelectRandomDirection(Directions.Left, Directions.SolveAndReset) + End If + ElseIf BlockedBelow Then + Return SelectRandomDirection(Directions.Left, Directions.Right) + ElseIf Not OnBottomRow Then + Return SelectRandomDirection(Directions.Left, Directions.Right, Directions.Down) + ElseIf SolutionCompleted Then + Return SelectRandomDirection(Directions.Left, Directions.Right) + Else + Return SelectRandomDirection(Directions.Left, Directions.Right, Directions.SolveAndReset) + End If + End Function + + Public Function ChoosePath_BlockedToTheRight() As Boolean + 'No need to check Left or Up, only called from the "keepGoing" loop where LEFT and UP are already cleared + If BlockedRight Then 'Can't go Right -- why? we knew this when calling the function + If BlockedBelow Then + Return SelectRandomDirection(Directions.Left, Directions.Up) + ElseIf Not OnBottomRow Then + Return SelectRandomDirection(Directions.Left, Directions.Up, Directions.Down) + ElseIf SolutionCompleted Then + Return SelectRandomDirection(Directions.Left, Directions.Up) + Else + Return SelectRandomDirection(Directions.Left, Directions.Up, Directions.SolveAndReset) + End If + Else 'Should never get here + Return SelectRandomDirection(Directions.Left, Directions.Up, Directions.Right) 'Go Left, Up, or Right (but path is blocked?) + End If + End Function + + Public Sub PrintFinalResults(startPos As Integer) + For i As Integer = 0 To Width - 1 + If i = startPos Then Console.Write(". ") Else Console.Write(".--") + Next + Console.WriteLine(".") + + If Not SolutionCompleted Then 'Pick a random exit + Dim X As Integer = rnd.Next(1, Width + 1) + If CellState(X, Height) = 0 Then + CellState(X, Height) = 1 + Else + CellState(X, Height) = 3 + End If + End If + + For j As Integer = 1 To Height + Console.Write("I") + For i As Integer = 1 To Width + If CellState(i, j) < 2 Then + Console.Write(" I") + Else + Console.Write(" ") + End If + Next + Console.WriteLine() + + For i As Integer = 1 To Width + If CellState(i, j) = 0 OrElse CellState(i, j) = 2 Then + Console.Write(":--") + Else + Console.Write(": ") + End If + Next + Console.WriteLine(".") + Next + End Sub + + Public Function GoLeft() As Boolean + curCol -= 1 + CellVisitHistory(curCol, curRow) = CellsVisited + CellsVisited += 1 + CellState(curCol, curRow) = 2 + If CellsVisited > Width * Height Then Return False + Q = 0 + Return True + End Function + + Public Function GoUp() As Boolean + curRow -= 1 + CellVisitHistory(curCol, curRow) = CellsVisited + CellsVisited += 1 + CellState(curCol, curRow) = 1 + If CellsVisited > Width * Height Then Return False + Q = 0 + Return True + End Function + + Public Function GoRight() As Boolean + CellVisitHistory(curCol + 1, curRow) = CellsVisited + CellsVisited += 1 + If CellState(curCol, curRow) = 0 Then CellState(curCol, curRow) = 2 Else CellState(curCol, curRow) = 3 + curCol += 1 + If CellsVisited > Width * Height Then Return False + Return ChoosePath_BlockedToTheLeft() + End Function + + Public Function GoDown() As Boolean + If Q = 1 Then Return MarkSolvedAndResetPosition() + + CellVisitHistory(curCol, curRow + 1) = CellsVisited + CellsVisited += 1 + If CellState(curCol, curRow) = 0 Then CellState(curCol, curRow) = 1 Else CellState(curCol, curRow) = 3 + curRow += 1 + If CellsVisited > Width * Height Then Return False + Return True + End Function + + Public Function MarkSolvedAndResetPosition() As Boolean + ' AlWAYS returns true + SolutionCompleted = True + Q = 1 + If CellState(curCol, curRow) = 0 Then + CellState(curCol, curRow) = 1 + curCol = 1 + curRow = 1 + If CellVisitHistory(curCol, curRow) = 0 Then ResetCurrentPosition() + Else + CellState(curCol, curRow) = 3 + ResetCurrentPosition() + End If + Return True + End Function +End Module From e0b041dfd7fc75f1eb1e53f566b9f27581d52b6b Mon Sep 17 00:00:00 2001 From: Jackson Brouwer Date: Sun, 9 Jan 2022 15:05:24 -0600 Subject: [PATCH 210/331] Python version --- 07_Basketball/python/basketball.py | 343 +++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 07_Basketball/python/basketball.py diff --git a/07_Basketball/python/basketball.py b/07_Basketball/python/basketball.py new file mode 100644 index 00000000..5ba88188 --- /dev/null +++ b/07_Basketball/python/basketball.py @@ -0,0 +1,343 @@ +import random + +# The basketball class is a computer game that allows you to play as +# Dartmouth College's captain and playmaker +# The game uses set probabilites to simulate outcomes of each posession +# You are able to choose your shot types as well as defensive formations + + +class Basketball(): + def __init__(self): + self.time = 0 + self.score = [0, 0] # first value is opponents score, second is home + self.defense = None + self.defense_choices = [6, 6.5, 7, 7.5] + self.shot = None + self.shot_choices = [1, 2, 3, 4] + self.z1 = None + + # Explains the keyboard inputs + print("\t\t\t Basketball") + print("\t Creative Computing Morristown, New Jersey\n\n\n") + print("This is Dartmouth College basketball. ") + print("Υou will be Dartmouth captain and playmaker.") + print("Call shots as follows:") + print("1. Long (30ft.) Jump Shot; 2. Short (15 ft.) Jump Shot; " + + "3. Lay up; 4. Set Shot") + print("Both teams will use the same defense. Call Defense as follows:") + print("6. Press; 6.5 Man-to-Man; 7. Zone; 7.5 None.") + print("To change defense, just type 0 as your next shot.") + print("Your starting defense will be? ", end='') + + # takes input for a defense + try: + self.defense = float(input()) + + except ValueError: + self.defense = None + + # if the input wasn't a valid defense, takes input again + while self.defense not in self.defense_choices: + print("Your new defensive allignment is? ", end='') + try: + self.defense = float(input()) + + except ValueError: + continue + + # takes input for opponent's name + print("\nChoose your opponent? ", end='') + + self.opponent = input() + self.start_of_period() + + # adds points to the score + # team can take 0 or 1, for opponent or Dartmouth, respectively + def add_points(self, team, points): + self.score[team] += points + self.print_score() + + def ball_passed_back(self): + print("Ball passed back to you. ", end='') + self.dartmouth_ball() + + # change defense, called when the user enters 0 for their shot + def change_defense(self): + self.defense = None + + while self.defense not in self.defense_choices: + print("Your new defensive allignment is? ") + try: + self.defense = float(input()) + + except ValueError: + continue + self.dartmouth_ball() + + # simulates two foul shots for a player and adds the points + def foul_shots(self, team): + print("Shooter fouled. Two shots.") + if random.random() > .49: + if random.random() > .75: + print("Both shots missed.") + else: + print("Shooter makes one shot and misses one.") + self.score[team] += 1 + else: + print("Shooter makes both shots.") + self.score[team] += 2 + + self.print_score() + + # called when t = 50, starts a new period + def halftime(self): + print("\n ***** End of first half *****\n") + self.print_score() + self.start_of_period() + + # prints the current score + def print_score(self): + print("Score: " + str(self.score[1]) + + " to " + str(self.score[0]) + "\n") + + # simulates a center jump for posession at the beginning of a period + def start_of_period(self): + print("Center jump") + if random.random() > .6: + print("Dartmouth controls the tap.\n") + self.dartmouth_ball() + else: + print(self.opponent + " controls the tap.\n") + self.opponent_ball() + + # called when t = 92 + def two_minute_warning(self): + print(" *** Two minutes left in the game ***") + + # called when the user enters 1 or 2 for their shot + def dartmouth_jump_shot(self): + self.time += 1 + if self.time == 50: + self.halftime() + elif self.time == 92: + self.two_minute_warning() + print("Jump Shot.") + # simulates chances of different possible outcomes + if random.random() > .341 * self.defense / 8: + if random.random() > .682 * self.defense / 8: + if random.random() > .782 * self.defense / 8: + if random.random() > .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() + else: + if random.random() > .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() > .45: + print("Rebound to " + self.opponent + "\n") + self.opponent_ball() + else: + print("Dartmouth controls the rebound.") + if random.random() > .4: + if self.defense == 6 and random.random() > .6: + 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("") + self.dartmouth_non_jump_shot() + else: + print("Shot is good.") + self.add_points(1, 2) + self.opponent_ball() + + # called when the user enters 0, 3, or 4 + # lay up, set shot, or defense change + def dartmouth_non_jump_shot(self): + self.time += 1 + if self.time == 50: + self.halftime() + elif self.time == 92: + self.two_minute_warning() + + if self.shot == 4: + print("Set shot.") + elif self.shot == 3: + print("Lay up.") + elif self.shot == 0: + self.change_defense() + + # simulates different outcomes after a lay up or set shot + if 7/self.defense*random.random() > .4: + if 7/self.defense*random.random() > .7: + if 7/self.defense*random.random() > .875: + if 7/self.defense*random.random() > .925: + print("Charging foul. Dartmouth loses the ball.\n") + self.opponent_ball() + else: + print("Shot blocked. " + self.opponent + "'s ball.\n") + self.opponent_ball() + else: + self.foul_shots(1) + self.opponent_ball() + else: + print("Shot is off the rim.") + if random.random() > 2/3: + print("Dartmouth controls the rebound.") + if random.random() > .4: + print("Ball passed back to you.\n") + self.dartmouth_ball() + else: + self.dartmouth_non_jump_shot() + else: + print(self.opponent + " controls the rebound.\n") + self.opponent_ball() + else: + print("Shot is good. Two points.") + self.add_points(1, 2) + self.opponent_ball() + + # plays out a Dartmouth posession, starting with your choice of shot + def dartmouth_ball(self): + print("Your shot? ", end='') + self.shot = None + try: + self.shot = int(input()) + except ValueError: + self.shot = None + + while self.shot not in self.shot_choices: + print("Incorrect answer. Retype it. Your shot? ", end='') + try: + self.shot = int(input()) + except: + continue + + if self.time < 100 or random.random() < .5: + if self.shot == 1 or self.shot == 2: + self.dartmouth_jump_shot() + else: + self.dartmouth_non_jump_shot() + else: + if self.score[0] != self.score[1]: + print("\n ***** End Of Game *****") + print("Final Score: Dartmouth: " + str(self.score[1]) + " " + + self.opponent + ": " + str(self.score[0])) + else: + print("\n ***** End Of Second Half *****") + print("Score at end of regulation time:") + print(" Dartmouth: " + str(self.score[1]) + " " + + self.opponent + ": " + str(self.score[0])) + print("Begin two minute overtime period") + self.time = 93 + self.start_of_period() + + # simulates the opponents jumpshot + def opponent_jumpshot(self): + print("Jump Shot.") + if 8/self.defense*random.random() > .35: + if 8/self.defense*random.random() > .75: + if 8/self.defense*random.random() > .9: + print("Offensive foul. Dartmouth's ball.\n") + self.dartmouth_ball() + else: + self.foul_shots(0) + self.dartmouth_ball() + else: + print("Shot is off the rim.") + if self.defense/6*random.random() > .5: + print(self.opponent + " controls the rebound.") + if self.defense == 6: + if random.random() > .75: + print("Ball stolen. Easy lay up for Dartmouth.") + self.add_points(1, 2) + self.opponent_ball() + else: + if random.random() > .5: + print("") + self.opponent_non_jumpshot() + else: + print("Pass back to " + self.opponent + + " guard.\n") + self.opponent_ball() + else: + if random.random() > .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() + else: + print("Shot is good.") + self.add_points(0, 2) + self.dartmouth_ball() + + # simulates opponents lay up or set shot + def opponent_non_jumpshot(self): + if self.z1 > 3: + print("Set shot.") + else: + print("Lay up") + if 7/self.defense*random.random() > .413: + print("Shot is missed.") + if self.defense/6*random.random() > .5: + print(self.opponent + " controls the rebound.") + if self.defense == 6: + if random.random() > .75: + print("Ball stolen. Easy lay up for Dartmouth.") + self.add_points(1, 2) + self.opponent_ball() + else: + if random.random() > .5: + print("") + self.opponent_non_jumpshot() + else: + print("Pass back to " + self.opponent + + " guard.\n") + self.opponent_ball() + else: + if random.random() > .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() + else: + print("Shot is good.") + self.add_points(0, 2) + self.dartmouth_ball() + + # simulates an opponents possesion + # #randomly picks jump shot or lay up / set shot. + def opponent_ball(self): + self.time += 1 + if self.time == 50: + self.halftime() + self.z1 = 10/4*random.random()+1 + if self.z1 > 2: + self.opponent_non_jumpshot() + else: + self.opponent_jumpshot() + + +new_game = Basketball() From e22e1bed266fd9e6224a9bdd751645cf2d502926 Mon Sep 17 00:00:00 2001 From: Bastiaan Veelo Date: Sun, 9 Jan 2022 23:38:17 +0100 Subject: [PATCH 211/331] Add D version of High_IQ (48). --- 48_High_IQ/d/.gitignore | 2 + 48_High_IQ/d/README.md | 214 ++++++++++++++++++++++++++++++++++++ 48_High_IQ/d/highiq.d | 238 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 454 insertions(+) create mode 100644 48_High_IQ/d/.gitignore create mode 100644 48_High_IQ/d/README.md create mode 100644 48_High_IQ/d/highiq.d diff --git a/48_High_IQ/d/.gitignore b/48_High_IQ/d/.gitignore new file mode 100644 index 00000000..d969f6b2 --- /dev/null +++ b/48_High_IQ/d/.gitignore @@ -0,0 +1,2 @@ +*.exe +*.obj diff --git a/48_High_IQ/d/README.md b/48_High_IQ/d/README.md new file mode 100644 index 00000000..0eea7b00 --- /dev/null +++ b/48_High_IQ/d/README.md @@ -0,0 +1,214 @@ +Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html) + +Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo). + +## Running the code + +Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler: +```shell +dmd -dip1000 -run highiq.d +``` + +[Other compilers](https://dlang.org/download.html) also exist. + + +## Discussion + +The original BASIC game code made use of calculus and clever choises of field IDs to determine the validity of moves. +This is the original layout of IDs over the board: + +``` + 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 +``` + +This seems not very logical, because, wouldn't it make much more sense to let columns increase with 1 and rows increase +with 10, so you'd get a consistent coordinate system? It seems that the original author's first step in validating +moves was to check that moves jumped from one field over another one onto the next. He did this by making sure that +adjacent IDs alter between even and odd horizontally *and* vertically. So a valid move was always from an even ID to an +even ID *or* from an odd ID to an odd ID. So one of the checks that the BASIC code made was that the sum of both IDs +was even. This is of course not a sufficient test, because moves that jump over three fields are illegal. Therefore the +IDs seem to have been carefully laid oud so that the IDs increase with 1 horizontally, and 9 vertically, everywhere. So +the only valid difference between IDs for a horizontal move was always 2, and the only valid difference for a vertical +move was always 18. + +Fact of the matter is, however, that checking for difference is sufficient and the even sum rule is superfluous, so +there is no need for the peculiar distribution of field IDs. Therefore I have chosen the following more logical +distribution: + +``` + 13 14 15 + + 23 24 25 + +31 32 33 34 35 36 37 + +41 42 43 44 45 46 47 + +51 52 53 54 55 56 57 + + 63 64 65 + + 73 74 75 +``` + +As a consequence, the implementation of the game code has become much simpler; Not alone due to one less check, but due +to the fact that conversions between IDs and board coordinates have become unnecessary and thus we can work with a single +representation of the board state. + +This version makes a prettier print of the board than the BASIC original, with coordinates for every move, and explains +illegal moves. + + +## Demo + +``` + H-I-Q +(After Creative Computing Morristown, New Jersey) + + +Fields are identified by 2-digit numbers, each +between 1 and 7. Example: the middle field is 44, +the bottom middle is 74. + + _1 _2 _3 _4 _5 _6 _7 + ┌───┬───┬───┐ + 1_ │ ■ │ ■ │ ■ │ + ├───┼───┼───┤ + 2_ │ ■ │ ■ │ ■ │ + ┌───┬───┼───┼───┼───┼───┬───┐ + 3_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ + ├───┼───┼───┼───┼───┼───┼───┤ + 4_ │ ■ │ ■ │ ■ │ │ ■ │ ■ │ ■ │ + ├───┼───┼───┼───┼───┼───┼───┤ + 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ + └───┴───┼───┼───┼───┼───┴───┘ + 6_ │ ■ │ ■ │ ■ │ + ├───┼───┼───┤ + 7_ │ ■ │ ■ │ ■ │ + └───┴───┴───┘ + +Move which peg? 23 +The peg at 23 has nowhere to go. Try again. + +Move which peg? 24 +To where? 34 +Field 34 is occupied. Try again. +To where? 54 +Field 54 is occupied. Try again. +To where? 44 + + _1 _2 _3 _4 _5 _6 _7 + ┌───┬───┬───┐ + 1_ │ ■ │ ■ │ ■ │ + ├───┼───┼───┤ + 2_ │ ■ │ │ ■ │ + ┌───┬───┼───┼───┼───┼───┬───┐ + 3_ │ ■ │ ■ │ ■ │ │ ■ │ ■ │ ■ │ + ├───┼───┼───┼───┼───┼───┼───┤ + 4_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ + ├───┼───┼───┼───┼───┼───┼───┤ + 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ + └───┴───┼───┼───┼───┼───┴───┘ + 6_ │ ■ │ ■ │ ■ │ + ├───┼───┼───┤ + 7_ │ ■ │ ■ │ ■ │ + └───┴───┴───┘ + +Move which peg? 14 +The peg at 14 has nowhere to go. Try again. + +Move which peg? 24 +There is no peg at 24. Try again. + +Move which peg? 44 +The peg at 44 has nowhere to go. Try again. + +Move which peg? 32 +To where? 22 +Field 22 is ouside the board. Try again. +To where? 33 +Field 33 is occupied. Try again. +To where? 34 + + _1 _2 _3 _4 _5 _6 _7 + ┌───┬───┬───┐ + 1_ │ ■ │ ■ │ ■ │ + ├───┼───┼───┤ + 2_ │ ■ │ │ ■ │ + ┌───┬───┼───┼───┼───┼───┬───┐ + 3_ │ ■ │ │ │ ■ │ ■ │ ■ │ ■ │ + ├───┼───┼───┼───┼───┼───┼───┤ + 4_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ + ├───┼───┼───┼───┼───┼───┼───┤ + 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ + └───┴───┼───┼───┼───┼───┴───┘ + 6_ │ ■ │ ■ │ ■ │ + ├───┼───┼───┤ + 7_ │ ■ │ ■ │ ■ │ + └───┴───┴───┘ + +Move which peg? 44 +To where? 33 +You cannot move diagonally. Try again. +To where? 24 + + _1 _2 _3 _4 _5 _6 _7 + ┌───┬───┬───┐ + 1_ │ ■ │ ■ │ ■ │ + ├───┼───┼───┤ + 2_ │ ■ │ ■ │ ■ │ + ┌───┬───┼───┼───┼───┼───┬───┐ + 3_ │ ■ │ │ │ │ ■ │ ■ │ ■ │ + ├───┼───┼───┼───┼───┼───┼───┤ + 4_ │ ■ │ ■ │ ■ │ │ ■ │ ■ │ ■ │ + ├───┼───┼───┼───┼───┼───┼───┤ + 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ + └───┴───┼───┼───┼───┼───┴───┘ + 6_ │ ■ │ ■ │ ■ │ + ├───┼───┼───┤ + 7_ │ ■ │ ■ │ ■ │ + └───┴───┴───┘ + +Move which peg? 36 +To where? 33 +You can't jump that far. Try again. +To where? 35 +Field 35 is occupied. Try again. +To where? 34 + + _1 _2 _3 _4 _5 _6 _7 + ┌───┬───┬───┐ + 1_ │ ■ │ ■ │ ■ │ + ├───┼───┼───┤ + 2_ │ ■ │ ■ │ ■ │ + ┌───┬───┼───┼───┼───┼───┬───┐ + 3_ │ ■ │ │ │ ■ │ │ │ ■ │ + ├───┼───┼───┼───┼───┼───┼───┤ + 4_ │ ■ │ ■ │ ■ │ │ ■ │ ■ │ ■ │ + ├───┼───┼───┼───┼───┼───┼───┤ + 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ + └───┴───┼───┼───┼───┼───┴───┘ + 6_ │ ■ │ ■ │ ■ │ + ├───┼───┼───┤ + 7_ │ ■ │ ■ │ ■ │ + └───┴───┴───┘ + +Move which peg? 46 +To where? 36 +You need to jump over another peg. Try again. +To where? down +Field 00 is ouside the board. Try again. +To where? +``` diff --git a/48_High_IQ/d/highiq.d b/48_High_IQ/d/highiq.d new file mode 100644 index 00000000..78445545 --- /dev/null +++ b/48_High_IQ/d/highiq.d @@ -0,0 +1,238 @@ +@safe: // Make @safe the default for this file, enforcing memory-safety. +import std; + +void main() +{ + enum width = 50; + writeln(center("H-I-Q", width)); + writeln(center("(After Creative Computing Morristown, New Jersey)\n\n", width)); + writeln(wrap("Fields are identified by 2-digit numbers, each between 1 and 7. " ~ + "Example: the middle field is 44, the bottom middle is 74.", width)); + + Board board; + + while (true) + { + while (!board.isGameOver) + { + writeln(board); // Calls board.toString(). + board.makeMove; + } + writeln(board, "\nThe game is over.\nYou had ", board.numPegs, " pieces remaining."); + if (board.numPegs == 1) + writeln("Bravo! You made a perfect score!\n", + "Make a screen dump as a record of your accomplishment!\n"); + write("Play again? (Yes or No) "); + if (readString.toLower != "yes") + break; + writeln; writeln; + board = Board.init; + } + writeln("\nSo long for now.\n"); +} + +/// Representation of the game board with pegs. +struct Board +{ + enum {outside, taken, empty}; + int[8][8] state = [ + 1: [ 3: taken, 4: taken, 5: taken], + 2: [ 3: taken, 4: taken, 5: taken], + 3: [1: taken, 2: taken, 3: taken, 4: taken, 5: taken, 6: taken, 7: taken], + 4: [1: taken, 2: taken, 3: taken, 4: empty, 5: taken, 6: taken, 7: taken], + 5: [1: taken, 2: taken, 3: taken, 4: taken, 5: taken, 6: taken, 7: taken], + 6: [ 3: taken, 4: taken, 5: taken], + 7: [ 3: taken, 4: taken, 5: taken] + ]; // Row 0 and column 0 are unused. Default is 0 (outside). + + /// Returns a string representing the board and its current state. + string toString() const + { + dchar[][] lines = [(" _1 _2 _3 _4 _5 _6 _7 ").to!(dchar[]), + (" ┌───┬───┬───┐ ").to!(dchar[]), + (" 1_ │ │ │ │ ").to!(dchar[]), + (" ├───┼───┼───┤ ").to!(dchar[]), + (" 2_ │ │ │ │ ").to!(dchar[]), + (" ┌───┬───┼───┼───┼───┼───┬───┐").to!(dchar[]), + (" 3_ │ │ │ │ │ │ │ │").to!(dchar[]), + (" ├───┼───┼───┼───┼───┼───┼───┤").to!(dchar[]), + (" 4_ │ │ │ │ │ │ │ │").to!(dchar[]), + (" ├───┼───┼───┼───┼───┼───┼───┤").to!(dchar[]), + (" 5_ │ │ │ │ │ │ │ │").to!(dchar[]), + (" └───┴───┼───┼───┼───┼───┴───┘").to!(dchar[]), + (" 6_ │ │ │ │ ").to!(dchar[]), + (" ├───┼───┼───┤ ").to!(dchar[]), + (" 7_ │ │ │ │ ").to!(dchar[]), + (" └───┴───┴───┘ ").to!(dchar[])]; + foreach (y, row; state) + foreach (x, field; row) + if (field == taken) + lines[y * 2][x * 4 + 2] = '■'; + return lines.join("\n").to!string; + } + + /// Tests for possible moves. + bool isGameOver() const + { + foreach (r, row; state) + foreach (c, field; row) + if (field == taken && canMoveFrom(r, c)) + return false; + return true; + } + + bool canMoveFrom(int row, int col) const + { + if (row >= 3 && state[row - 2][col] == empty) // Up + return state[row - 1][col] == taken; + if (row <= 5 && state[row + 2][col] == empty) // Down + return state[row + 1][col] == taken; + if (col >= 3 && state[row][col - 2] == empty) // Left + return state[row][col - 1] == taken; + if (col <= 5 && state[row][col + 2] == empty) // Right + return state[row][col + 1] == taken; + return false; + } + + /// Asks for input, validates the move and updates the board. + void makeMove() + { + bool isOutside(int row, int col) + { + if (row < 1 || row > 7 || + col < 1 || col > 7 || + state[row][col] == outside) + { + writeln("Field ", row, col, " is ouside the board. Try again."); + return true; + } + return false; + } + + while (true) + { + auto from = (){ + while (true) + { + write("\nMove which peg? "); + int field = readInt; + int row = field / 10, col = field % 10; + if (isOutside(row, col)) + continue; + if (state[row][col] != taken) + { + writeln("There is no peg at ", field, ". Try again."); + continue; + } + if (!canMoveFrom(row, col)) + { + writeln("The peg at ", field, " has nowhere to go. Try again."); + continue; + } + return tuple!("row", "col")(row, col); + } + }(); + auto to = (){ + while (true) + { + write("To where? "); + int field = readInt; + int row = field / 10, col = field % 10; + if (isOutside(row, col)) + continue; + if (state[row][col] == taken) + { + writeln("Field ", field, " is occupied. Try again."); + continue; + } + if (row != from.row && col != from.col) + { + writeln("You cannot move diagonally. Try again."); + continue; + } + if (row == from.row && col == from.col) + { + writeln("You aren't going anywhere. Try again."); + continue; + } + if (abs(row - from.row) + abs(col - from.col) > 2) + { + writeln("You can't jump that far. Try again."); + continue; + } + if (abs(row - from.row) + abs(col - from.col) < 2 || + state[(row + from.row) / 2][(col + from.col) / 2] != taken) + { + writeln("You need to jump over another peg. Try again."); + continue; + } + return tuple!("row", "col")(row, col); + } + }(); + // The move is legal. Update the board state. + state[from.row][from.col] = empty; + state[ to.row][ to.col] = taken; + state[(from.row + to.row) / 2][(from.col + to.col) / 2] = empty; + writeln; + break; + } + } + + /// Returns the number of remaining pegs on the board. + int numPegs() const + { + int num = 0; + foreach (row; state) + foreach (field; row) + if (field == taken) + num++; + return num; + } +} + +/// Reads an integer from standard input. +int readInt() nothrow +{ + try + return readString.to!int; + catch (Exception) // Not an integer. + return 0; +} + +/// Reads a string from standard input. +string readString() nothrow +{ + try + return trustedReadln.strip; + catch (Exception) // readln throws on I/O and Unicode errors, which we handle here. + return ""; +} + +/** An @trusted wrapper around readln. + * + * This is the only function that formally requires manual review for memory-safety. + * [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com) + * which would remove the need to have any @trusted code in this program. + */ +string trustedReadln() @trusted +{ + return readln; +} + +version (Windows) +{ + // Make the Windows console do a better job at printing UTF-8 strings, + // and restore the default upon termination. + + import core.sys.windows.windows; + + shared static this() @trusted + { + SetConsoleOutputCP(CP_UTF8); + } + + shared static ~this() @trusted + { + SetConsoleOutputCP(GetACP); + } +} From 5d00a092af55935b604d4c7f00af71314420094c Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Tue, 11 Jan 2022 00:00:22 +1100 Subject: [PATCH 212/331] Building kotlin files. IntelliJ import instructions. --- HOW_TO_RUN_THE_GAMES.md | 28 ++++++++++++++++++++-------- buildJvm/README.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md index 6df23205..f067f872 100644 --- a/HOW_TO_RUN_THE_GAMES.md +++ b/HOW_TO_RUN_THE_GAMES.md @@ -23,16 +23,23 @@ Alternatively, for non-dotnet compatible translations, you will need [Visual Stu ## java +{% tip %} + +You can build all the java and kotlin games at once +using the instructions in the [buildJvm directory](buildJvm/README.md) + +{% endtip %} + 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. `javac AceyDuceyGame.java` + * eg. `javac AceyDuceyGame.java` 1. Run the compiled program with `java`: - * eg. `java AceyDuceyGame` - + * eg. `java AceyDuceyGame` + or if you are **using JDK11 or later** you can now execute a self contained java file that has a main method directly with `java .java`. ## javascript @@ -41,6 +48,11 @@ The javascript examples can be run from within your web browser: 1. Simply open the corresponding `.html` file from your web browser. +## kotlin + +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/). @@ -48,7 +60,7 @@ The pascal examples can be run using [Free Pascal](https://www.freepascal.org/). 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` + * eg. `fpc amazing.pas` 1. The output is an executable file that can be run directly. ## perl @@ -57,7 +69,7 @@ The perl translations can be run using a perl interpreter (a copy can be downloa 1. From the command-line, navigate to the corresponding directory. 1. Invoke with the `perl` command. - * eg. `perl aceyducey.pl` + * eg. `perl aceyducey.pl` ## python @@ -65,8 +77,8 @@ The python translations can be run from the command line by using the `py` inter 1. From the command-line, navigate to the corresponding directory. 1. Invoke with the `py` or `python` interpreter (depending on your python version). - * eg. `py acey_ducey_oo.py` - * eg. `python aceyducey.py` + * eg. `py acey_ducey_oo.py` + * eg. `python aceyducey.py` **Note** @@ -80,7 +92,7 @@ If you don't already have a ruby interpreter, you can download it from the [ruby 1. From the command-line, navigate to the corresponding directory. 1. Invoke with the `ruby` tool. - * eg. `ruby aceyducey.rb` + * eg. `ruby aceyducey.rb` ## vbnet diff --git a/buildJvm/README.md b/buildJvm/README.md index f0046ab3..c70bf573 100644 --- a/buildJvm/README.md +++ b/buildJvm/README.md @@ -20,6 +20,34 @@ Then, run a game 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. +--- +## 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 @@ -37,6 +65,7 @@ The `build.gradle` file will normally be identical to this: plugins { id 'application' + // id 'org.jetbrains.kotlin.jvm' // UNCOMMENT for kotlin projects } sourceSets { From 25c79621a0c42a3f755a962bb9a5913ef5ae5cf8 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Tue, 11 Jan 2022 00:09:09 +1100 Subject: [PATCH 213/331] Update HOW_TO_RUN_THE_GAMES.md remove bad formatting --- HOW_TO_RUN_THE_GAMES.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md index f067f872..fae0656f 100644 --- a/HOW_TO_RUN_THE_GAMES.md +++ b/HOW_TO_RUN_THE_GAMES.md @@ -23,13 +23,9 @@ Alternatively, for non-dotnet compatible translations, you will need [Visual Stu ## java -{% tip %} - -You can build all the java and kotlin games at once +**TIP:** You can build all the java and kotlin games at once using the instructions in the [buildJvm directory](buildJvm/README.md) -{% endtip %} - 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/)). From 8b2c72bc21fc93fcabdb108721fbadad8ec0e1d3 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Tue, 11 Jan 2022 00:12:21 +1100 Subject: [PATCH 214/331] update README.md --- buildJvm/README.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/buildJvm/README.md b/buildJvm/README.md index c70bf573..a5169abd 100644 --- a/buildJvm/README.md +++ b/buildJvm/README.md @@ -1,25 +1,28 @@ # 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: - - cd buildJvm - ./gradlew -q assemble installDist distributeBin distributeLib +```shell + cd buildJvm + ./gradlew -q assemble installDist distributeBin distributeLib +``` Then, run a game ### Mac or linux: - - build/distrib/bin/build_53_King_kotlin - +```shell +build/distrib/bin/build_53_King_kotlin +``` ### Windows [not tested yet] - build\distrib\bin\build_53_King_kotlin.bat +```shell +build\distrib\bin\build_53_King_kotlin.bat +``` -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. --- ## Using an IDE to work on JVM games @@ -62,7 +65,7 @@ there is some special requirement. directory for the java or kotlin file, and the class that contains the `main` method. The `build.gradle` file will normally be identical to this: - +```groovy plugins { id 'application' // id 'org.jetbrains.kotlin.jvm' // UNCOMMENT for kotlin projects @@ -83,6 +86,7 @@ The `build.gradle` file will normally be identical to this: application { mainClass = gameMain } +``` And the `gradle.properties` file should look like this: From eaf24739e3e8f0b8f4ff5b7e9d7c306a99620622 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 10 Jan 2022 10:05:28 -0500 Subject: [PATCH 215/331] Initial Commit, added instructions --- 75_Roulette/java/src/Roulette.java | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 75_Roulette/java/src/Roulette.java diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java new file mode 100644 index 00000000..a07d2afd --- /dev/null +++ b/75_Roulette/java/src/Roulette.java @@ -0,0 +1,69 @@ +import java.io.PrintStream; + +public class Roulette { + + private PrintStream out; + + public static void main(String[] args) { + new Roulette(System.out).play(); + } + + public Roulette(PrintStream out) { + this.out = out; + } + + public void play() { + printInstructions(); + } + + + public void printInstructions() { + System.out.println(); + System.out.println( "THIS IS THE BETTING LAYOUT"); + System.out.println( " (*=RED)"); + System.out.println(); + System.out.println( " 1* 2 3*"); + System.out.println( " 4 5* 6 "); + System.out.println( " 7* 8 9*"); + System.out.println( "10 11 12*"); + System.out.println( "---------------"); + System.out.println( "13 14* 15 "); + System.out.println( "16* 17 18*"); + System.out.println( "19* 20 21*"); + System.out.println( "22 23* 24 "); + System.out.println( "---------------"); + System.out.println( "25* 26 27*"); + System.out.println( "28 29 30*"); + System.out.println( "31 32* 33 "); + System.out.println( "34* 35 36*"); + System.out.println( "---------------"); + System.out.println( " 00 0 "); + System.out.println(); + System.out.println( "TYPES OF BETS"); + System.out.println(); + System.out.println( "THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET"); + System.out.println( "ON THAT NUMBER."); + System.out.println( "THESE PAY OFF 35:1"); + System.out.println(); + System.out.println( "THE 2:1 BETS ARE:"); + System.out.println( " 37) 1-12 40) FIRST COLUMN"); + System.out.println( " 38) 13-24 41) SECOND COLUMN"); + System.out.println( " 39) 25-36 42) THIRD COLUMN"); + System.out.println(); + System.out.println( "THE EVEN MONEY BETS ARE:"); + System.out.println( " 43) 1-18 46) ODD"); + System.out.println( " 44) 19-36 47) RED"); + System.out.println( " 45) EVEN 48) BLACK"); + System.out.println(); + System.out.println( " 49)0 AND 50)00 PAY OFF 35:1"); + System.out.println( " NOTE: 0 AND 00 DO NOT COUNT UNDER ANY"); + System.out.println( " BETS EXCEPT THEIR OWN."); + System.out.println(); + System.out.println( "WHEN I ASK FOR EACH BET, TYPE THE NUMBER"); + System.out.println( "AND THE AMOUNT, SEPARATED BY A COMMA."); + System.out.println( "FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500"); + System.out.println( "WHEN I ASK FOR A BET."); + System.out.println(); + System.out.println( "THE MINIMUM BET IS $5, THE MAXIMUM IS $500."); + } +} From b97f4f5e3e404970124e78bb55674cee8e38d4a1 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 10 Jan 2022 10:44:49 -0500 Subject: [PATCH 216/331] Added querying of bets and randomized roll --- 75_Roulette/java/src/Roulette.java | 198 +++++++++++++++++++++-------- 1 file changed, 147 insertions(+), 51 deletions(-) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java index a07d2afd..3522364d 100644 --- a/75_Roulette/java/src/Roulette.java +++ b/75_Roulette/java/src/Roulette.java @@ -1,69 +1,165 @@ +import java.io.InputStream; import java.io.PrintStream; +import java.util.*; public class Roulette { private PrintStream out; + private Scanner scanner; - public static void main(String[] args) { - new Roulette(System.out).play(); + private int houseBalance, playerBalance; + + private Random random; + + private static Set RED_NUMBERS; + + static { + RED_NUMBERS = Set.of(1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36); } - public Roulette(PrintStream out) { + public static void main(String[] args) { + new Roulette(System.out, System.in).play(); + } + + public Roulette(PrintStream out, InputStream in) { this.out = out; + this.scanner = new Scanner(in); + houseBalance = 100000; + playerBalance = 1000; + random = new Random(); } public void play() { - printInstructions(); + out.println(" ROULETTE"); + out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + out.println("WELCOME TO THE ROULETTE TABLE\n"); + out.println("DO YOU WANT INSTRUCTIONS"); + if(scanner.nextLine().toLowerCase().charAt(0) != 'n') { + printInstructions(); + } + + while(houseBalance > 0 && playerBalance > 0) { + + Bet[] bets = queryBets(); + + out.println("SPINNING...\n\n\n"); + int result = random.nextInt(1,39); + + /* + Equivalent to following line + if(RED_NUMBERS.contains(result)) { + out.println(result + " RED"); + } else { + out.println(result + " BLACK"); + } + */ + out.println(result + (RED_NUMBERS.contains(result) ? " RED\n" : " BLACK\n")); + + + } } + private Bet[] queryBets() { + int numBets = -1; + while(numBets < 1) { + out.println("HOW MANY BETS"); + try { + numBets = Integer.parseInt(scanner.nextLine()); + } catch(NumberFormatException exception) { + out.println("THAT IS NOT A NUMBER"); + } + } + + Bet[] bets = new Bet[numBets]; + + for(int i = 0; i < numBets; i++) { + try { + out.println("BET NUMBER " + (i + 1) + ":"); + String[] values = scanner.nextLine().split(","); + int betNumber = Integer.parseInt(values[0]); + int betValue = Integer.parseInt(values[1]); + + for(int j = 0; j < i; j++) { + if(bets[j].number == betNumber) { + out.println("YOU MADE THAT BET ONCE ALREADY,DUM-DUM"); + throw new Exception(); + } + } + + if(betNumber < 1 || betNumber > 50 || betValue < 5 || betValue > 500) { + out.println("INVALID VALUE, TRY AGAIN"); + i--; + continue; + } + + bets[i] = new Bet(betNumber,betValue); + + } catch(Exception exception) { + if(exception instanceof NumberFormatException) { + out.println("SYNTAX ERROR, TRY AGAIN"); + } + i--; + } + } + return bets; + } public void printInstructions() { - System.out.println(); - System.out.println( "THIS IS THE BETTING LAYOUT"); - System.out.println( " (*=RED)"); - System.out.println(); - System.out.println( " 1* 2 3*"); - System.out.println( " 4 5* 6 "); - System.out.println( " 7* 8 9*"); - System.out.println( "10 11 12*"); - System.out.println( "---------------"); - System.out.println( "13 14* 15 "); - System.out.println( "16* 17 18*"); - System.out.println( "19* 20 21*"); - System.out.println( "22 23* 24 "); - System.out.println( "---------------"); - System.out.println( "25* 26 27*"); - System.out.println( "28 29 30*"); - System.out.println( "31 32* 33 "); - System.out.println( "34* 35 36*"); - System.out.println( "---------------"); - System.out.println( " 00 0 "); - System.out.println(); - System.out.println( "TYPES OF BETS"); - System.out.println(); - System.out.println( "THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET"); - System.out.println( "ON THAT NUMBER."); - System.out.println( "THESE PAY OFF 35:1"); - System.out.println(); - System.out.println( "THE 2:1 BETS ARE:"); - System.out.println( " 37) 1-12 40) FIRST COLUMN"); - System.out.println( " 38) 13-24 41) SECOND COLUMN"); - System.out.println( " 39) 25-36 42) THIRD COLUMN"); - System.out.println(); - System.out.println( "THE EVEN MONEY BETS ARE:"); - System.out.println( " 43) 1-18 46) ODD"); - System.out.println( " 44) 19-36 47) RED"); - System.out.println( " 45) EVEN 48) BLACK"); - System.out.println(); - System.out.println( " 49)0 AND 50)00 PAY OFF 35:1"); - System.out.println( " NOTE: 0 AND 00 DO NOT COUNT UNDER ANY"); - System.out.println( " BETS EXCEPT THEIR OWN."); - System.out.println(); - System.out.println( "WHEN I ASK FOR EACH BET, TYPE THE NUMBER"); - System.out.println( "AND THE AMOUNT, SEPARATED BY A COMMA."); - System.out.println( "FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500"); - System.out.println( "WHEN I ASK FOR A BET."); - System.out.println(); - System.out.println( "THE MINIMUM BET IS $5, THE MAXIMUM IS $500."); + out.println(); + out.println( "THIS IS THE BETTING LAYOUT"); + out.println( " (*=RED)"); + out.println(); + out.println( " 1* 2 3*"); + out.println( " 4 5* 6 "); + out.println( " 7* 8 9*"); + out.println( "10 11 12*"); + out.println( "---------------"); + out.println( "13 14* 15 "); + out.println( "16* 17 18*"); + out.println( "19* 20 21*"); + out.println( "22 23* 24 "); + out.println( "---------------"); + out.println( "25* 26 27*"); + out.println( "28 29 30*"); + out.println( "31 32* 33 "); + out.println( "34* 35 36*"); + out.println( "---------------"); + out.println( " 00 0 "); + out.println(); + out.println( "TYPES OF BETS"); + out.println(); + out.println( "THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET"); + out.println( "ON THAT NUMBER."); + out.println( "THESE PAY OFF 35:1"); + out.println(); + out.println( "THE 2:1 BETS ARE:"); + out.println( " 37) 1-12 40) FIRST COLUMN"); + out.println( " 38) 13-24 41) SECOND COLUMN"); + out.println( " 39) 25-36 42) THIRD COLUMN"); + out.println(); + out.println( "THE EVEN MONEY BETS ARE:"); + out.println( " 43) 1-18 46) ODD"); + out.println( " 44) 19-36 47) RED"); + out.println( " 45) EVEN 48) BLACK"); + out.println(); + out.println( " 49)0 AND 50)00 PAY OFF 35:1"); + out.println( " NOTE: 0 AND 00 DO NOT COUNT UNDER ANY"); + out.println( " BETS EXCEPT THEIR OWN."); + out.println(); + out.println( "WHEN I ASK FOR EACH BET, TYPE THE NUMBER"); + out.println( "AND THE AMOUNT, SEPARATED BY A COMMA."); + out.println( "FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500"); + out.println( "WHEN I ASK FOR A BET."); + out.println(); + out.println( "THE MINIMUM BET IS $5, THE MAXIMUM IS $500."); + } + + public class Bet { + final int number, value; + + public Bet(int number, int value) { + this.number = number; + this.value = value; + } } } From c32798aa755eddc94a878faf09e8c72f9732dd45 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 10 Jan 2022 11:14:10 -0500 Subject: [PATCH 217/331] Added bet checking conditions --- 75_Roulette/java/src/Roulette.java | 45 ++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java index 3522364d..533afe4e 100644 --- a/75_Roulette/java/src/Roulette.java +++ b/75_Roulette/java/src/Roulette.java @@ -53,7 +53,11 @@ public class Roulette { out.println(result + " BLACK"); } */ - out.println(result + (RED_NUMBERS.contains(result) ? " RED\n" : " BLACK\n")); + switch(result) { + case 37 -> out.print("00"); + case 38 -> out.print("0"); + default -> out.println(result + (RED_NUMBERS.contains(result) ? " RED\n" : " BLACK\n")); + } } @@ -80,7 +84,7 @@ public class Roulette { int betValue = Integer.parseInt(values[1]); for(int j = 0; j < i; j++) { - if(bets[j].number == betNumber) { + if(bets[j].num == betNumber) { out.println("YOU MADE THAT BET ONCE ALREADY,DUM-DUM"); throw new Exception(); } @@ -104,6 +108,35 @@ public class Roulette { return bets; } + private void betResults(Bet[] bets, int num) { + for(int i = 0; i < bets.length; i++) { + Bet bet = bets[i]; + /* + Using a switch statement of ternary operators that check if a certain condition is met based on the bet value + Returns the coefficient that the bet amount should be multiplied by to get the resulting value + */ + int coefficient = switch(bet.num) { + case 37 -> (num <= 12) ? 2 : -1; + case 38 -> (num > 12 && num <= 24) ? 2 : -1; + case 39 -> (num > 24 && num < 37) ? 2 : -1; + case 40 -> (num < 37 && num % 3 == 1) ? 2 : -1; + case 41 -> (num < 37 && num % 3 == 2) ? 2 : -1; + case 42 -> (num < 37 && num % 3 == 0) ? 2 : -1; + case 43 -> (num <= 18) ? 1 : -1; + case 44 -> (num > 18 && num <= 36) ? 1 : -1; + case 45 -> (num % 2 == 0) ? 1 : -1; + case 46 -> (num % 2 == 1) ? 1 : -1; + case 47 -> RED_NUMBERS.contains(num) ? 1 : -1; + case 48 -> !RED_NUMBERS.contains(num) ? 1 : -1; + case 49 -> (num == 37) ? 35 : -1; + case 50 -> (num == 38) ? 35 : -1; + default -> (bet.num < 49 && bet.num == num) ? 35 : -1; + }; + + int betResult = bet.amount * coefficient; + } + } + public void printInstructions() { out.println(); out.println( "THIS IS THE BETTING LAYOUT"); @@ -155,11 +188,11 @@ public class Roulette { } public class Bet { - final int number, value; + final int num, amount; - public Bet(int number, int value) { - this.number = number; - this.value = value; + public Bet(int num, int amount) { + this.num = num; + this.amount = amount; } } } From a40c2fc5345b69bd4658e69d5657fc76e4836c42 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 10 Jan 2022 11:29:50 -0500 Subject: [PATCH 218/331] Added replay and ending I think... --- 75_Roulette/java/src/Roulette.java | 42 +++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java index 533afe4e..49d14275 100644 --- a/75_Roulette/java/src/Roulette.java +++ b/75_Roulette/java/src/Roulette.java @@ -1,5 +1,6 @@ import java.io.InputStream; import java.io.PrintStream; +import java.lang.management.PlatformLoggingMXBean; import java.util.*; public class Roulette { @@ -38,7 +39,7 @@ public class Roulette { printInstructions(); } - while(houseBalance > 0 && playerBalance > 0) { + do { Bet[] bets = queryBets(); @@ -53,13 +54,33 @@ public class Roulette { out.println(result + " BLACK"); } */ - switch(result) { - case 37 -> out.print("00"); - case 38 -> out.print("0"); - default -> out.println(result + (RED_NUMBERS.contains(result) ? " RED\n" : " BLACK\n")); - } + switch(result) { + case 37 -> out.print("00"); + case 38 -> out.print("0"); + default -> out.println(result + (RED_NUMBERS.contains(result) ? " RED\n" : " BLACK\n")); + } + betResults(bets,result); + out.println(); + out.println("TOTALS:"); + out.println("\tME: " + houseBalance); + out.println("\tYOU " + playerBalance); + + } while(playAgain()); + if(playerBalance <= 0) { + out.println("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!"); + } else if(houseBalance <= 0) { + out.println("YOU BROKE THE HOUSE!"); + } + } + + private boolean playAgain() { + if(playerBalance > 0 && houseBalance > 0) { + out.println("PLAY AGAIN?"); + return scanner.nextLine().toLowerCase().charAt(0) == 'y'; + } else { + return false; } } @@ -134,6 +155,15 @@ public class Roulette { }; int betResult = bet.amount * coefficient; + + if(betResult < 0) { + out.println("YOU LOSE " + -betResult + " DOLLARS ON BET " + (i + 1)); + } else { + out.println("YOU WIN " + betResult + " DOLLARS ON BET " + (i + 1)); + } + + playerBalance += betResult; + houseBalance -= betResult; } } From 0d7f407197e19fd76068691270945863d830e397 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 10 Jan 2022 11:31:04 -0500 Subject: [PATCH 219/331] Create roulette.py --- 75_Roulette/python/roulette.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 75_Roulette/python/roulette.py diff --git a/75_Roulette/python/roulette.py b/75_Roulette/python/roulette.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/75_Roulette/python/roulette.py @@ -0,0 +1 @@ + From 2dc63bb95a75326a78472a8698638c6e829ce258 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 10 Jan 2022 11:41:02 -0500 Subject: [PATCH 220/331] Still unsure about $$ Is the check for the difference? Is it only when the house cannot pay what it owes? --- 75_Roulette/java/src/Roulette.java | 47 ++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java index 49d14275..c6e46152 100644 --- a/75_Roulette/java/src/Roulette.java +++ b/75_Roulette/java/src/Roulette.java @@ -1,6 +1,7 @@ import java.io.InputStream; import java.io.PrintStream; import java.lang.management.PlatformLoggingMXBean; +import java.time.LocalDateTime; import java.util.*; public class Roulette { @@ -69,14 +70,54 @@ public class Roulette { } while(playAgain()); if(playerBalance <= 0) { - out.println("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!"); + out.println("THANKS FOR YOUR MONEY\nI'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL"); } else if(houseBalance <= 0) { - out.println("YOU BROKE THE HOUSE!"); + out.println("TO WHOM SHALL I MAKE THE CHECK"); + String name = scanner.nextLine(); + out.println(); + for(int i = 0; i < 72; i++) { + out.print("-"); + } + out.println(); + for(int i = 0; i < 50; i++) { + out.print(" "); + } + out.println("CHECK NO. " + random.nextInt(0,1000)); + out.println(); + for(int i = 0; i < 40; i++) { + out.print(" "); + } + out.println(LocalDateTime.now()); + out.println("\n"); + out.println("PAY TO THE ORDER OF----- " + name + "------$" + (playerBalance - 1000)); + out.println("\n"); + for(int i = 0; i < 10; i++) { + out.print(" "); + } + out.println("THE MEMORY BANK OF NEW YORK"); + for(int i = 0; i < 40; i++) { + out.print(" "); + } + out.println("THE COMPUTER"); + for(int i = 0; i < 40; i++) { + out.print(" "); + } + out.println("----------X-----"); + for(int i = 0; i < 72; i++) { + out.print("-"); + } + out.println("\n"); + out.println("COME BACK SOON"); } } private boolean playAgain() { - if(playerBalance > 0 && houseBalance > 0) { + if(playerBalance > 0) { + if(houseBalance <= 0) { + out.println("YOU BROKE THE HOUSE!"); + //using default values + playerBalance = 101000; + } out.println("PLAY AGAIN?"); return scanner.nextLine().toLowerCase().charAt(0) == 'y'; } else { From 82a126bce36b1c3aea47fbaa017953968cd968c7 Mon Sep 17 00:00:00 2001 From: Mark Wieder Date: Mon, 10 Jan 2022 10:18:24 -0800 Subject: [PATCH 221/331] initial attempt --- 65_Nim/ruby/nim.rb | 282 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 65_Nim/ruby/nim.rb diff --git a/65_Nim/ruby/nim.rb b/65_Nim/ruby/nim.rb new file mode 100644 index 00000000..a326695f --- /dev/null +++ b/65_Nim/ruby/nim.rb @@ -0,0 +1,282 @@ +puts "NIM".center(80) +puts"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".center(80) +puts "\n\n\n" + +#210 DIM A(100),B(100,10),D(2) +$pileArray = Array.new[100] +$bArray = Array.new +$dArray = Array.new[2] +$winOption = 0 # take-last option +$numberOfPiles = 1 +$c = 0 +$e = 0 +$f = 0 +$g = 0 +$h = 0 + +def displayTheRules +puts "THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS." +puts "ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND" +puts "THE MACHINE ALTERNATELY. ON YOUR TURN, YOU MAY TAKE" +puts "ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST" +puts "TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM" +puts "ONLY ONE PILE ON A SINGLE TURN. YOU MUST SPECIFY WHETHER" +puts "WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT," +puts "THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE" +puts "ORIGINALLY IN EACH PILE. EACH PILE MAY CONTAIN A" +puts "DIFFERENT NUMBER OF OBJECTS." +puts "THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE" +puts "NUMBER OF OBJECTS REMAINING IN THE PILES AFTER EACH OF ITS" +puts "MOVES." +end + +def sub1570 + $z=0 + for i in 1..$numberOfPiles do + if $pileArray[i] != 0 then + return + end + $z=1 + return + end +end + +def playAnother + put "do you want to play another game"; + return gets.strip.ucase == "YES" +end +puts "THIS IS THE GAME OF NIM." +print "DO YOU WANT INSTRUCTIONS?" +240 +wantInstructions = gets.strip.upcase +if wantInstructions == "YES" then + displayTheRules +end +#250 IF Z$="NO" THEN 440 +#260 IF Z$="no" THEN 440 +#270 IF Z$="YES" THEN displayTheRules +#280 IF Z$="yes" THEN displayTheRules +#290 PRINT "PLEASE ANSWER YES OR NO" +#300 GOTO 240 + +def sub490 # get number of piles + print "ENTER NUMBER OF PILES:" + while $numberOfPiles < 0 && $numberOfPiles <= 100 do + $numberOfPiles = gets.strip.to_i + end +end + +def getPileSizes + puts "ENTER PILE SIZES:" + for i in 1..$numberOfPiles do + print i + while true do + $pileArray[i] = gets.strip.to_i + if $pileArray[i] < 2000 && $pileArray[i] > 0 then + break + end + end + end +end + +def sub440 # get win option + puts "" + $winOption = 0 + while $winOption != 1 && q != 2 do + puts "ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST" + $winOption = gets.strip.to_i + end +end + +puts "DO YOU WANT TO MOVE FIRST?"; +#630 INPUT Q9$ +moveFirst = "" +while moveFirst != "YES" && moveFirst != "NO" do + moveFirst = gets.strip.upcase + case moveFirst + when "YES" + yourMove + when "NO" + machineMove + end +end + +#640 IF Q9$="YES" THEN 1450 +#650 IF Q9$="yes" THEN 1450 +#660 IF Q9$="NO" THEN 700 +#670 IF Q9$="no" THEN 700 +#680 PRINT "PLEASE ANSWER YES OR NO." +#690 GOTO 630 + +def machineMove + if $winOption == 1 then + sub940 # take last + end + $c=0 + for i in 1..$numberOfPiles do + if $pileArray[i] != 0 then 770 + $c=$c+1 + if $c == 3 then + sub840 + end + $dArray[$c-1]=i + end + end + + if $c == 2 then + sub920 + end + if $pileArray[$dArray[0]] > 1 then + machineWins + end + machineLoses +end + +def machineLoses + puts "MACHINE LOSES" +# 810 GOTO playAnother + if playAnother then + sub440 # loop for another + end +end + +def machineWins + puts "MACHINE WINS" +# 830 GOTO playAnother + if playAnother then + sub440 # loop for another + end +end + +def sub840 + $c=0 + for i in 1..$numberOfPiles do + if $pileArray[i] > 1 then + sub940 + end + if $pileArray[i] == 0 then 890 + $c=$c+1 + end + if $c/2 != ($c/2).to_i then + machineLoses + end + sub940 # goto + end +end + +def sub920 + if $pileArray[$dArray[0]] == 1 then + machineWins + end + if $pileArray[$dArray[1]] == 1 then + machineWins + end +end + +def sub940 + for i in 1..$numberOfPiles do + e=$pileArray[i] + for j in 0..10 do + $f = $e/2 + $bArray[i][j] = 2*($f-($f.to_i)) + $e = $f.to_i + end + end +end + +#for j in 10..0 STEP -1 do +10..0.step(-1).each do|index| + $c=0 + $h=0 + for i in 1..$numberOfPiles do + if $bArray[i][index] != 0 then + $c=$c+1 + if $pileArray[i] > $h then + $h = $pileArray[i] + $g = i + end + end + end +end + +if $c/2 != ($c/2).to_i then 1190 +end +$e = rand($numberOfPiles).to_i +#if $pileArray[$e] == 0 then 1140 + +$f = rand($pileArray[$e]).to_i +$pileArray[$e] = $pileArray[$e]-$f +sub1380 +$pileArray[$g]=0 +for j in 0..10 do +$bArray[$g][index]=0 +$c=0 +for i in 1..$numberOfPiles do + if $bArray[i][index] != 0 then + $c=$c+1 + end + end +$pileArray[$g]=$pileArray[$g]+2*($c/2-($c/2)).to_i*2^j +end +if $winOption == 1 then + sub1380 +end +$c=0 +for i in 1..$numberOfPiles do +if $pileArray[i]>1 then + sub1380 +end +if $pileArray[i] != 0 then + $c=$c+1 +end +if $c/2 == ($c/2).to_i then + sub1380 +end +$pileArray[$g] == 1 -$pileArray[$g] + +def sub1380 + puts "PILE SIZE" + for i in 1..$numberOfPiles do + put i + put $pileArray[i] + end + if $winOption == 2 then # avoid take-last option + yourMove + end + sub1570 + if $z == 1 then + machineWins + end +end + +def yourMove + put "YOUR MOVE - PILE, NUMBER TO BE REMOVED" +# 1460 INPUT x,y +x = gets.strip.to_i +y = gets.strip.to_i + if x > $numberOfPiles then yourMove + if x < 1 then yourMove + if x != INT(x) then yourMove + if y > $pileArray[x] then yourMove + if y < 1 then + yourMove + end + if y != INT(y) then + yourMove + end + + $pileArray[x] = $pileArray[x]-y + sub1570 # gosub + if $z == 1 then + machineLoses + end +# 1560 GOTO 700 +end + +end +end +end +end +end + + From 420597dbcf4ee0b1f7859b719ca2a46c53497326 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 10 Jan 2022 19:21:15 +0000 Subject: [PATCH 222/331] First cut java battleships --- 09_Battle/java/Battle.java | 372 +++++++++++++++++++++++++++++++++++++ 1 file changed, 372 insertions(+) create mode 100644 09_Battle/java/Battle.java diff --git a/09_Battle/java/Battle.java b/09_Battle/java/Battle.java new file mode 100644 index 00000000..aa53896c --- /dev/null +++ b/09_Battle/java/Battle.java @@ -0,0 +1,372 @@ +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Random; +import java.util.function.Predicate; +import java.text.NumberFormat; + +public class Battle { + private int seaSize; + private int[] sizes; + private int[] counts; + + private ArrayList ships; + private Sea sea; + + private int[] losses; + private int hits; + private int misses; + + private static String NAMES_BY_SIZE[] = { + "error", + "size1", + "destroyer", + "cruiser", + "aircraft carrier", + "size5" }; + + public static void main(String args[]) { + Battle game = new Battle(6, + new int[] { 2, 3, 4 }, + new int[] { 2, 2, 2 }); + game.play(); + } + + public Battle(int scale, int[] shipSizes, int[] shipCounts) { + seaSize = scale; + sizes = shipSizes; + counts = shipCounts; + + /* validate parameters */ + if (seaSize < 4) throw new RuntimeException("Sea Size " + seaSize + " invalid, must be at least 4"); + + for (int sz : sizes) { + if ((sz < 1) || (sz > seaSize)) + throw new RuntimeException("Ship has invalid size " + sz); + } + + if (counts.length != sizes.length) { + throw new RuntimeException("Ship counts must match"); + } + + sea = new Sea(seaSize); + ships = new ArrayList(); + losses = new int[counts.length]; + + int shipNumber = 1; + for (int type = 0; type < counts.length; ++type) { + for (int i = 0; i < counts[i]; ++i) { + ships.add(new Ship(shipNumber++, "Ship", sizes[type])); + } + } + + ArrayList largestFirst = new ArrayList<>(ships); + Collections.sort(largestFirst, Comparator.comparingInt((Ship ship) -> ship.size()).reversed()); + + for (Ship ship : largestFirst) { + ship.placeRandom(sea); + } + } + + public void play() { + System.out.println("The following code of the bad guys' fleet disposition\nhas been captured but not decoded:\n"); + System.out.println(sea.encodedDump()); + System.out.println("De-code it and use it if you can\nbut keep the de-coding method a secret.\n"); + + int lost = 0; + System.out.println("Start game"); + try { + BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); + NumberFormat parser = NumberFormat.getIntegerInstance(); + + while (lost < ships.size()) { + System.out.print("\nTarget x,y\n> "); + String inputLine = input.readLine(); + if (inputLine == null) { + System.out.println("Game quit\n"); + return; + } + String[] coords = inputLine.split(","); + if (coords.length != 2) { + System.out.println("Need two coordinates separated by ','"); + continue; + } + int[] xy = new int[2]; + boolean error = false; + try { + for (int c = 0 ; c < 2; ++c ) { + int val = Integer.parseInt(coords[c].strip()); + if ((val < 1) || (val > seaSize)) { + System.out.println("Coordinates must be from 1 to " + seaSize); + error = true; + } else { + xy[c] = val; + } + } + } + catch (NumberFormatException ne) { + System.out.println("Coordinates must be numbers"); + error = true; + } + if (error) continue; + + int row = seaSize - xy[1]; + int col = xy[0] - 1; + + if (sea.isEmpty(col, row)) { + ++misses; + System.out.println("Splash! Try again."); + } else { + Ship ship = ships.get(sea.get(col, row) - 1); + if (ship.isSunk()) { + ++misses; + System.out.println("There used to be a ship at that point, but you sunk it."); + System.out.println("Splash! Try again."); + } else if (ship.wasHit(col, row)) { + ++misses; + System.out.println("You already put a hole in ship number " + ship.id()); + System.out.println("Splash! Try again."); + } else { + ship.hit(col, row); + ++hits; + System.out.println("A direct hit on ship number " + ship.id()); + if (ship.isSunk()) { + ++lost; + System.out.println("And you sunk it. Hurrah for the good guys."); + System.out.print("So far, the bad guys have lost "); + ArrayList typeDescription = new ArrayList<>(); + for (int i = 0 ; i < sizes.length; ++i) { + if (sizes[i] == ship.size()) { + ++losses[i]; + } + StringBuilder sb = new StringBuilder(); + sb.append(losses[i]); + sb.append(" "); + sb.append(NAMES_BY_SIZE[sizes[i]]); + if (losses[i] != 1) + sb.append("s"); + typeDescription.add(sb.toString()); + } + System.out.println(String.join(", ", typeDescription)); + double ratioNum = ((double)misses)/hits; + String ratio = NumberFormat.getInstance().format(ratioNum); + System.out.println("Your current splash/hit ratio is " + ratio); + + if (lost == ships.size()) { + System.out.println("You have totally wiped out the bad guys' fleet"); + System.out.println("With a final splash/hit ratio of " + ratio); + + if (misses == 0) { + System.out.println("Congratulations - A direct hit every time."); + } + + System.out.println("\n****************************\n"); + } + } + } + } + } + } + catch (IOException e) { + } + } + + private static class Ship { + public static final int ORIENT_E=0; + public static final int ORIENT_SE=1; + public static final int ORIENT_S=2; + public static final int ORIENT_SW=3; + + private int id; + private int size; + private String type; + private boolean placed; + private boolean sunk; + private ArrayList hits; + + private int startX; + private int startY; + private int orientX; + private int orientY; + + public Ship(int i, String name, int sz) { + id = i; type = name; size = sz; + sunk = false; placed = false; + hits = new ArrayList<>(Collections.nCopies(size, false)); + } + + public int id() { return id; } + public int size() { return size; } + + public void hit(int x, int y) { + int offset; + if (orientX != 0) { + offset = (x - startX) / orientX; + } else { + offset = (y - startY) / orientY; + } + hits.set(offset, true); + + sunk = hits.stream().allMatch(Predicate.isEqual(true)); + } + + public boolean isSunk() { return sunk; } + + public boolean wasHit(int x, int y) { + int offset; + if (orientX != 0) { + offset = (x - startX) / orientX; + } else { + offset = (y - startY) / orientY; + } + return hits.get(offset); + }; + + public void placeRandom(Sea s) { + Random random = new Random(); + for (int tries = 0 ; tries < 1000 ; ++tries) { + int x = random.nextInt(s.size()); + int y = random.nextInt(s.size()); + int orient = random.nextInt(4); + + if (place(s, x, y, orient)) return; + } + + throw new RuntimeException("Could not place any more ships"); + } + + private boolean extendShip(Sea s, int fromX, int fromY, int toX, int toY) { + if (!s.isEmpty(toX, toY)) return false; // no space + if ((fromX == toX)||(fromY == toY)) return true; // horizontal or vertical + + // we can extend the ship without colliding, but we are going diagonally + // and it should not be possible for two ships to cross each other on + // opposite diagonals. + + // check the two tiles that would cross us here - if either is empty, we are OK + // if they both contain different ships, we are OK + // but if they both contain the same ship, we are crossing! + int corner1 = s.get(fromX, toY); + int corner2 = s.get(toX, fromY); + if ((corner1 == 0) || (corner1 != corner2)) return true; + return false; + } + + public boolean place(Sea s, int x, int y, int orient) { + if (placed) { + throw new RuntimeException("Program error - placed ship " + id + " twice"); + } + switch(orient) { + case ORIENT_E: + orientX = 1; orientY = 0; + break; + case ORIENT_SE: + orientX = 1; orientY = 1; + break; + case ORIENT_S: + orientX = 0; orientY = 1; + break; + case ORIENT_SW: + orientX = -1; orientY = 1; + break; + default: + throw new RuntimeException("Invalid orientation " + orient); + } + + if (!s.isEmpty(x, y)) return false; + startX = x; startY = y; + int tilesPlaced = 1; + int nextX = startX; + int nextY = startY; + while (tilesPlaced < size) { + if (extendShip(s, nextX, nextY, nextX + orientX, nextY + orientY)) { + tilesPlaced += 1; + nextX = nextX + orientX; + nextY = nextY + orientY; + } else { + int backX = startX - orientX; + int backY = startY - orientY; + + if (extendShip(s, startX, startY, backX, backY)) { + tilesPlaced +=1; + startX = backX; + startY = backY; + } else { + return false; + } + } + } + + for (int i = 0; i < size; ++i) { + int sx = startX + i * orientX; + int sy = startY + i * orientY; + s.set(sx, sy, id); + } + placed = true; + return true; + } + + } + + private static class Sea { + private int tiles[]; + private boolean hits[]; + + private int size; + public Sea(int make_size) { + size = make_size; + tiles = new int[size*size]; + } + + public int size() { return size; } + + public String encodedDump() { + StringBuilder out = new StringBuilder(); + for (int x = 0; x < size; ++x) { + for (int y = 0; y < size; ++y) + out.append(Integer.toString(get(x, y))); + out.append('\n'); + } + return out.toString(); + } + + /* return true if x,y is in the sea and empty + * return false if x,y is occupied or is out of range + */ + public boolean isEmpty(int x, int y) { + if ((x<0)||(x>=size)||(y<0)||(y>=size)) return false; + return (get(x,y) == 0); + } + + /* return the ship number, or zero if no ship */ + public int get(int x, int y) { + return tiles[index(x,y)]; + } + + public void set(int x, int y, int value) { + tiles[index(x, y)] = value; + } + + public int shipHit(int x, int y) { + if (hits[index(x,y)]) return get(x, y); + else return 0; + } + + public void recordHit(int x, int y) { + hits[index(x, y)] = true; + } + + private int index(int x, int y) { + if ((x < 0) || (x >= size)) + throw new ArrayIndexOutOfBoundsException("Program error: x cannot be " + x); + if ((y < 0) || (y >= size)) + throw new ArrayIndexOutOfBoundsException("Program error: y cannot be " + y); + + return y*size + x; + } + } +} From c074beaf42e0c0aeb91413c152a827ac48942417 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 10 Jan 2022 19:38:23 +0000 Subject: [PATCH 223/331] pull out input parsing --- 09_Battle/java/Battle.java | 38 ++++---------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/09_Battle/java/Battle.java b/09_Battle/java/Battle.java index aa53896c..b548292c 100644 --- a/09_Battle/java/Battle.java +++ b/09_Battle/java/Battle.java @@ -1,5 +1,3 @@ -import java.io.BufferedReader; -import java.io.InputStreamReader; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -79,43 +77,15 @@ public class Battle { int lost = 0; System.out.println("Start game"); + Input input = new Input(seaSize); try { - BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); - NumberFormat parser = NumberFormat.getIntegerInstance(); - while (lost < ships.size()) { - System.out.print("\nTarget x,y\n> "); - String inputLine = input.readLine(); - if (inputLine == null) { - System.out.println("Game quit\n"); + if (! input.readCoordinates()) { return; } - String[] coords = inputLine.split(","); - if (coords.length != 2) { - System.out.println("Need two coordinates separated by ','"); - continue; - } - int[] xy = new int[2]; - boolean error = false; - try { - for (int c = 0 ; c < 2; ++c ) { - int val = Integer.parseInt(coords[c].strip()); - if ((val < 1) || (val > seaSize)) { - System.out.println("Coordinates must be from 1 to " + seaSize); - error = true; - } else { - xy[c] = val; - } - } - } - catch (NumberFormatException ne) { - System.out.println("Coordinates must be numbers"); - error = true; - } - if (error) continue; - int row = seaSize - xy[1]; - int col = xy[0] - 1; + int row = seaSize - input.y(); + int col = input.x() - 1; if (sea.isEmpty(col, row)) { ++misses; From 8e88e25d6c3fbc9fd783aa39d834fb10105fc0ec Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 10 Jan 2022 19:46:37 +0000 Subject: [PATCH 224/331] Classes in own files --- 09_Battle/java/.gitignore | 1 + 09_Battle/java/Battle.java | 195 ------------------------------------- 09_Battle/java/Input.java | 58 +++++++++++ 09_Battle/java/Sea.java | 57 +++++++++++ 09_Battle/java/Ship.java | 142 +++++++++++++++++++++++++++ 5 files changed, 258 insertions(+), 195 deletions(-) create mode 100644 09_Battle/java/.gitignore create mode 100644 09_Battle/java/Input.java create mode 100644 09_Battle/java/Sea.java create mode 100644 09_Battle/java/Ship.java diff --git a/09_Battle/java/.gitignore b/09_Battle/java/.gitignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/09_Battle/java/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/09_Battle/java/Battle.java b/09_Battle/java/Battle.java index b548292c..627906d0 100644 --- a/09_Battle/java/Battle.java +++ b/09_Battle/java/Battle.java @@ -144,199 +144,4 @@ public class Battle { catch (IOException e) { } } - - private static class Ship { - public static final int ORIENT_E=0; - public static final int ORIENT_SE=1; - public static final int ORIENT_S=2; - public static final int ORIENT_SW=3; - - private int id; - private int size; - private String type; - private boolean placed; - private boolean sunk; - private ArrayList hits; - - private int startX; - private int startY; - private int orientX; - private int orientY; - - public Ship(int i, String name, int sz) { - id = i; type = name; size = sz; - sunk = false; placed = false; - hits = new ArrayList<>(Collections.nCopies(size, false)); - } - - public int id() { return id; } - public int size() { return size; } - - public void hit(int x, int y) { - int offset; - if (orientX != 0) { - offset = (x - startX) / orientX; - } else { - offset = (y - startY) / orientY; - } - hits.set(offset, true); - - sunk = hits.stream().allMatch(Predicate.isEqual(true)); - } - - public boolean isSunk() { return sunk; } - - public boolean wasHit(int x, int y) { - int offset; - if (orientX != 0) { - offset = (x - startX) / orientX; - } else { - offset = (y - startY) / orientY; - } - return hits.get(offset); - }; - - public void placeRandom(Sea s) { - Random random = new Random(); - for (int tries = 0 ; tries < 1000 ; ++tries) { - int x = random.nextInt(s.size()); - int y = random.nextInt(s.size()); - int orient = random.nextInt(4); - - if (place(s, x, y, orient)) return; - } - - throw new RuntimeException("Could not place any more ships"); - } - - private boolean extendShip(Sea s, int fromX, int fromY, int toX, int toY) { - if (!s.isEmpty(toX, toY)) return false; // no space - if ((fromX == toX)||(fromY == toY)) return true; // horizontal or vertical - - // we can extend the ship without colliding, but we are going diagonally - // and it should not be possible for two ships to cross each other on - // opposite diagonals. - - // check the two tiles that would cross us here - if either is empty, we are OK - // if they both contain different ships, we are OK - // but if they both contain the same ship, we are crossing! - int corner1 = s.get(fromX, toY); - int corner2 = s.get(toX, fromY); - if ((corner1 == 0) || (corner1 != corner2)) return true; - return false; - } - - public boolean place(Sea s, int x, int y, int orient) { - if (placed) { - throw new RuntimeException("Program error - placed ship " + id + " twice"); - } - switch(orient) { - case ORIENT_E: - orientX = 1; orientY = 0; - break; - case ORIENT_SE: - orientX = 1; orientY = 1; - break; - case ORIENT_S: - orientX = 0; orientY = 1; - break; - case ORIENT_SW: - orientX = -1; orientY = 1; - break; - default: - throw new RuntimeException("Invalid orientation " + orient); - } - - if (!s.isEmpty(x, y)) return false; - startX = x; startY = y; - int tilesPlaced = 1; - int nextX = startX; - int nextY = startY; - while (tilesPlaced < size) { - if (extendShip(s, nextX, nextY, nextX + orientX, nextY + orientY)) { - tilesPlaced += 1; - nextX = nextX + orientX; - nextY = nextY + orientY; - } else { - int backX = startX - orientX; - int backY = startY - orientY; - - if (extendShip(s, startX, startY, backX, backY)) { - tilesPlaced +=1; - startX = backX; - startY = backY; - } else { - return false; - } - } - } - - for (int i = 0; i < size; ++i) { - int sx = startX + i * orientX; - int sy = startY + i * orientY; - s.set(sx, sy, id); - } - placed = true; - return true; - } - - } - - private static class Sea { - private int tiles[]; - private boolean hits[]; - - private int size; - public Sea(int make_size) { - size = make_size; - tiles = new int[size*size]; - } - - public int size() { return size; } - - public String encodedDump() { - StringBuilder out = new StringBuilder(); - for (int x = 0; x < size; ++x) { - for (int y = 0; y < size; ++y) - out.append(Integer.toString(get(x, y))); - out.append('\n'); - } - return out.toString(); - } - - /* return true if x,y is in the sea and empty - * return false if x,y is occupied or is out of range - */ - public boolean isEmpty(int x, int y) { - if ((x<0)||(x>=size)||(y<0)||(y>=size)) return false; - return (get(x,y) == 0); - } - - /* return the ship number, or zero if no ship */ - public int get(int x, int y) { - return tiles[index(x,y)]; - } - - public void set(int x, int y, int value) { - tiles[index(x, y)] = value; - } - - public int shipHit(int x, int y) { - if (hits[index(x,y)]) return get(x, y); - else return 0; - } - - public void recordHit(int x, int y) { - hits[index(x, y)] = true; - } - - private int index(int x, int y) { - if ((x < 0) || (x >= size)) - throw new ArrayIndexOutOfBoundsException("Program error: x cannot be " + x); - if ((y < 0) || (y >= size)) - throw new ArrayIndexOutOfBoundsException("Program error: y cannot be " + y); - - return y*size + x; - } - } } diff --git a/09_Battle/java/Input.java b/09_Battle/java/Input.java new file mode 100644 index 00000000..8a782dba --- /dev/null +++ b/09_Battle/java/Input.java @@ -0,0 +1,58 @@ +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; +import java.text.NumberFormat; + +public class Input { + private BufferedReader reader; + private NumberFormat parser; + private int scale; + private boolean isQuit; + private int[] coords; + + public Input(int seaSize) { + scale = seaSize; + reader = new BufferedReader(new InputStreamReader(System.in)); + parser = NumberFormat.getIntegerInstance(); + } + + public boolean readCoordinates() throws IOException { + while (true) { + System.out.print("\nTarget x,y\n> "); + String inputLine = reader.readLine(); + if (inputLine == null) { + System.out.println("Game quit\n"); + isQuit = true; + return false; + } + + String[] fields = inputLine.split(","); + if (fields.length != 2) { + System.out.println("Need two coordinates separated by ','"); + continue; + } + + coords = new int[2]; + boolean error = false; + try { + for (int c = 0 ; c < 2; ++c ) { + int val = Integer.parseInt(fields[c].strip()); + if ((val < 1) || (val > scale)) { + System.out.println("Coordinates must be from 1 to " + scale); + error = true; + } else { + coords[c] = val; + } + } + } + catch (NumberFormatException ne) { + System.out.println("Coordinates must be numbers"); + error = true; + } + if (!error) return true; + } + } + + public int x() { return coords[0]; } + public int y() { return coords[1]; } +} diff --git a/09_Battle/java/Sea.java b/09_Battle/java/Sea.java new file mode 100644 index 00000000..d9987f34 --- /dev/null +++ b/09_Battle/java/Sea.java @@ -0,0 +1,57 @@ +class Sea { + private int tiles[]; + private boolean hits[]; + + private int size; + public Sea(int make_size) { + size = make_size; + tiles = new int[size*size]; + } + + public int size() { return size; } + + public String encodedDump() { + StringBuilder out = new StringBuilder(); + for (int x = 0; x < size; ++x) { + for (int y = 0; y < size; ++y) + out.append(Integer.toString(get(x, y))); + out.append('\n'); + } + return out.toString(); + } + + /* return true if x,y is in the sea and empty + * return false if x,y is occupied or is out of range + */ + public boolean isEmpty(int x, int y) { + if ((x<0)||(x>=size)||(y<0)||(y>=size)) return false; + return (get(x,y) == 0); + } + + /* return the ship number, or zero if no ship */ + public int get(int x, int y) { + return tiles[index(x,y)]; + } + + public void set(int x, int y, int value) { + tiles[index(x, y)] = value; + } + + public int shipHit(int x, int y) { + if (hits[index(x,y)]) return get(x, y); + else return 0; + } + + public void recordHit(int x, int y) { + hits[index(x, y)] = true; + } + + private int index(int x, int y) { + if ((x < 0) || (x >= size)) + throw new ArrayIndexOutOfBoundsException("Program error: x cannot be " + x); + if ((y < 0) || (y >= size)) + throw new ArrayIndexOutOfBoundsException("Program error: y cannot be " + y); + + return y*size + x; + } +} diff --git a/09_Battle/java/Ship.java b/09_Battle/java/Ship.java new file mode 100644 index 00000000..e3fb4f44 --- /dev/null +++ b/09_Battle/java/Ship.java @@ -0,0 +1,142 @@ +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Random; +import java.util.function.Predicate; + +class Ship { + public static final int ORIENT_E=0; + public static final int ORIENT_SE=1; + public static final int ORIENT_S=2; + public static final int ORIENT_SW=3; + + private int id; + private int size; + private String type; + private boolean placed; + private boolean sunk; + private ArrayList hits; + + private int startX; + private int startY; + private int orientX; + private int orientY; + + public Ship(int i, String name, int sz) { + id = i; type = name; size = sz; + sunk = false; placed = false; + hits = new ArrayList<>(Collections.nCopies(size, false)); + } + + public int id() { return id; } + public int size() { return size; } + + public void hit(int x, int y) { + int offset; + if (orientX != 0) { + offset = (x - startX) / orientX; + } else { + offset = (y - startY) / orientY; + } + hits.set(offset, true); + + sunk = hits.stream().allMatch(Predicate.isEqual(true)); + } + + public boolean isSunk() { return sunk; } + + public boolean wasHit(int x, int y) { + int offset; + if (orientX != 0) { + offset = (x - startX) / orientX; + } else { + offset = (y - startY) / orientY; + } + return hits.get(offset); + }; + + public void placeRandom(Sea s) { + Random random = new Random(); + for (int tries = 0 ; tries < 1000 ; ++tries) { + int x = random.nextInt(s.size()); + int y = random.nextInt(s.size()); + int orient = random.nextInt(4); + + if (place(s, x, y, orient)) return; + } + + throw new RuntimeException("Could not place any more ships"); + } + + private boolean extendShip(Sea s, int fromX, int fromY, int toX, int toY) { + if (!s.isEmpty(toX, toY)) return false; // no space + if ((fromX == toX)||(fromY == toY)) return true; // horizontal or vertical + + // we can extend the ship without colliding, but we are going diagonally + // and it should not be possible for two ships to cross each other on + // opposite diagonals. + + // check the two tiles that would cross us here - if either is empty, we are OK + // if they both contain different ships, we are OK + // but if they both contain the same ship, we are crossing! + int corner1 = s.get(fromX, toY); + int corner2 = s.get(toX, fromY); + if ((corner1 == 0) || (corner1 != corner2)) return true; + return false; + } + + public boolean place(Sea s, int x, int y, int orient) { + if (placed) { + throw new RuntimeException("Program error - placed ship " + id + " twice"); + } + switch(orient) { + case ORIENT_E: + orientX = 1; orientY = 0; + break; + case ORIENT_SE: + orientX = 1; orientY = 1; + break; + case ORIENT_S: + orientX = 0; orientY = 1; + break; + case ORIENT_SW: + orientX = -1; orientY = 1; + break; + default: + throw new RuntimeException("Invalid orientation " + orient); + } + + if (!s.isEmpty(x, y)) return false; + startX = x; startY = y; + int tilesPlaced = 1; + int nextX = startX; + int nextY = startY; + while (tilesPlaced < size) { + if (extendShip(s, nextX, nextY, nextX + orientX, nextY + orientY)) { + tilesPlaced += 1; + nextX = nextX + orientX; + nextY = nextY + orientY; + } else { + int backX = startX - orientX; + int backY = startY - orientY; + + if (extendShip(s, startX, startY, backX, backY)) { + tilesPlaced +=1; + startX = backX; + startY = backY; + } else { + return false; + } + } + } + + for (int i = 0; i < size; ++i) { + int sx = startX + i * orientX; + int sy = startY + i * orientY; + s.set(sx, sy, id); + } + placed = true; + return true; + } +} + From 49be31b8e2f1086ed72565715ed3b3ee407b366f Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 10 Jan 2022 20:15:15 +0000 Subject: [PATCH 225/331] Add some comments --- 09_Battle/java/Battle.java | 49 +++++++---- 09_Battle/java/Ship.java | 166 ++++++++++++++++++++++--------------- 2 files changed, 132 insertions(+), 83 deletions(-) diff --git a/09_Battle/java/Battle.java b/09_Battle/java/Battle.java index 627906d0..c0b27906 100644 --- a/09_Battle/java/Battle.java +++ b/09_Battle/java/Battle.java @@ -7,18 +7,26 @@ import java.util.Random; import java.util.function.Predicate; import java.text.NumberFormat; + +/* This class holds the game state and the game logic */ public class Battle { + + /* parameters of the game */ private int seaSize; private int[] sizes; private int[] counts; - + + /* The game setup - the ships and the sea */ private ArrayList ships; private Sea sea; - private int[] losses; - private int hits; - private int misses; + /* game state counts */ + private int[] losses; // how many of each type of ship have been sunk + private int hits; // how many hits the player has made + private int misses; // how many misses the player has made + // Names of ships of each size. The game as written has ships of size 3, 4 and 5 but + // can easily be modified. It makes no sense to have a ship of size zero though. private static String NAMES_BY_SIZE[] = { "error", "size1", @@ -27,10 +35,11 @@ public class Battle { "aircraft carrier", "size5" }; + // Entrypoint public static void main(String args[]) { - Battle game = new Battle(6, - new int[] { 2, 3, 4 }, - new int[] { 2, 2, 2 }); + Battle game = new Battle(6, // Sea is 6 x 6 tiles + new int[] { 2, 3, 4 }, // Ships are of sizes 2, 3, and 4 + new int[] { 2, 2, 2 }); // there are two ships of each size game.play(); } @@ -39,7 +48,7 @@ public class Battle { sizes = shipSizes; counts = shipCounts; - /* validate parameters */ + // validate parameters if (seaSize < 4) throw new RuntimeException("Sea Size " + seaSize + " invalid, must be at least 4"); for (int sz : sizes) { @@ -51,20 +60,25 @@ public class Battle { throw new RuntimeException("Ship counts must match"); } - sea = new Sea(seaSize); - ships = new ArrayList(); - losses = new int[counts.length]; + // Initialize game state + sea = new Sea(seaSize); // holds what ship if any occupies each tile + ships = new ArrayList(); // positions and states of all the ships + losses = new int[counts.length]; // how many ships of each type have been sunk + // Build up the list of all the ships int shipNumber = 1; for (int type = 0; type < counts.length; ++type) { for (int i = 0; i < counts[i]; ++i) { - ships.add(new Ship(shipNumber++, "Ship", sizes[type])); + ships.add(new Ship(shipNumber++, sizes[type])); } } + // When we put the ships in the sea, we put the biggest ones in first, or they might + // not fit ArrayList largestFirst = new ArrayList<>(ships); Collections.sort(largestFirst, Comparator.comparingInt((Ship ship) -> ship.size()).reversed()); + // place each ship into the sea for (Ship ship : largestFirst) { ship.placeRandom(sea); } @@ -79,11 +93,13 @@ public class Battle { System.out.println("Start game"); Input input = new Input(seaSize); try { - while (lost < ships.size()) { - if (! input.readCoordinates()) { + while (lost < ships.size()) { // the game continues while some ships remain unsunk + if (! input.readCoordinates()) { // ... unless there is no more input from the user return; } + // The computer thinks of the sea as a grid of rows, from top to bottom. + // However, the user will use X and Y coordinates, with Y going bottom to top int row = seaSize - input.y(); int col = input.x() - 1; @@ -104,6 +120,9 @@ public class Battle { ship.hit(col, row); ++hits; System.out.println("A direct hit on ship number " + ship.id()); + + // If a ship was hit, we need to know whether it was sunk. + // If so, tell the player and update our counts if (ship.isSunk()) { ++lost; System.out.println("And you sunk it. Hurrah for the good guys."); @@ -142,6 +161,8 @@ public class Battle { } } catch (IOException e) { + // This should not happen running from console, but java requires us to check for it + System.err.println("System error.\n" + e); } } } diff --git a/09_Battle/java/Ship.java b/09_Battle/java/Ship.java index e3fb4f44..23605e5c 100644 --- a/09_Battle/java/Ship.java +++ b/09_Battle/java/Ship.java @@ -4,34 +4,41 @@ import java.util.Comparator; import java.util.Random; import java.util.function.Predicate; +/** A single ship, with its position and where it has been hit */ class Ship { - public static final int ORIENT_E=0; - public static final int ORIENT_SE=1; - public static final int ORIENT_S=2; - public static final int ORIENT_SW=3; + // These are the four directions that ships can be in + public static final int ORIENT_E=0; // goes East from starting position + public static final int ORIENT_SE=1; // goes SouthEast from starting position + public static final int ORIENT_S=2; // goes South from starting position + public static final int ORIENT_SW=3; // goes SouthWest from starting position - private int id; - private int size; - private String type; - private boolean placed; - private boolean sunk; - private ArrayList hits; + private int id; // ship number + private int size; // how many tiles it occupies + private boolean placed; // whether this ship is in the sea yet + private boolean sunk; // whether this ship has been sunk + private ArrayList hits; // which tiles of the ship have been hit - private int startX; + private int startX; // starting position coordinates private int startY; - private int orientX; + private int orientX; // x and y deltas from each tile occupied to the next private int orientY; - public Ship(int i, String name, int sz) { - id = i; type = name; size = sz; + public Ship(int i, int sz) { + id = i; size = sz; sunk = false; placed = false; hits = new ArrayList<>(Collections.nCopies(size, false)); } + /** @returns the ship number */ public int id() { return id; } + /** @returns the ship size */ public int size() { return size; } + /* record the ship as having been hit at the given coordinates */ public void hit(int x, int y) { + // need to work out how many tiles from the ship's starting position the hit is at + // that can be worked out from the difference between the starting X coord and this one + // unless the ship runs N-S, in which case use the Y coord instead int offset; if (orientX != 0) { offset = (x - startX) / orientX; @@ -40,11 +47,13 @@ class Ship { } hits.set(offset, true); + // if every tile of the ship has been hit, the ship is sunk sunk = hits.stream().allMatch(Predicate.isEqual(true)); } public boolean isSunk() { return sunk; } + // whether the ship has already been hit at the given coordinates public boolean wasHit(int x, int y) { int offset; if (orientX != 0) { @@ -55,6 +64,9 @@ class Ship { return hits.get(offset); }; + // Place the ship in the sea. + // choose a random starting position, and a random direction + // if that doesn't fit, keep picking different positions and directions public void placeRandom(Sea s) { Random random = new Random(); for (int tries = 0 ; tries < 1000 ; ++tries) { @@ -68,6 +80,77 @@ class Ship { throw new RuntimeException("Could not place any more ships"); } + // Attempt to fit the ship into the sea, starting from a given position and + // in a given direction + // This is by far the most complicated part of the program. + // It will start at the position provided, and attempt to occupy tiles in the + // requested direction. If it does not fit, either because of the edge of the + // sea, or because of ships already in place, it will try to extend the ship + // in the opposite direction instead. If that is not possible, it fails. + public boolean place(Sea s, int x, int y, int orient) { + if (placed) { + throw new RuntimeException("Program error - placed ship " + id + " twice"); + } + switch(orient) { + case ORIENT_E: // east is increasing X coordinate + orientX = 1; orientY = 0; + break; + case ORIENT_SE: // southeast is increasing X and Y + orientX = 1; orientY = 1; + break; + case ORIENT_S: // south is increasing Y + orientX = 0; orientY = 1; + break; + case ORIENT_SW: // southwest is increasing Y but decreasing X + orientX = -1; orientY = 1; + break; + default: + throw new RuntimeException("Invalid orientation " + orient); + } + + if (!s.isEmpty(x, y)) return false; // starting position is occupied - placing fails + + startX = x; startY = y; + int tilesPlaced = 1; + int nextX = startX; + int nextY = startY; + while (tilesPlaced < size) { + if (extendShip(s, nextX, nextY, nextX + orientX, nextY + orientY)) { + // It is clear to extend the ship forwards + tilesPlaced += 1; + nextX = nextX + orientX; + nextY = nextY + orientY; + } else { + int backX = startX - orientX; + int backY = startY - orientY; + + if (extendShip(s, startX, startY, backX, backY)) { + // We can move the ship backwards, so it can be one tile longer + tilesPlaced +=1; + startX = backX; + startY = backY; + } else { + // Could not make it longer or move it backwards + return false; + } + } + } + + // Mark in the sea which tiles this ship occupies + for (int i = 0; i < size; ++i) { + int sx = startX + i * orientX; + int sy = startY + i * orientY; + s.set(sx, sy, id); + } + + placed = true; + return true; + } + + // Check whether a ship which already occupies the "from" coordinates, + // can also occupy the "to" coordinates. + // They must be within the sea area, empty, and not cause the ship to cross + // over another ship private boolean extendShip(Sea s, int fromX, int fromY, int toX, int toY) { if (!s.isEmpty(toX, toY)) return false; // no space if ((fromX == toX)||(fromY == toY)) return true; // horizontal or vertical @@ -84,59 +167,4 @@ class Ship { if ((corner1 == 0) || (corner1 != corner2)) return true; return false; } - - public boolean place(Sea s, int x, int y, int orient) { - if (placed) { - throw new RuntimeException("Program error - placed ship " + id + " twice"); - } - switch(orient) { - case ORIENT_E: - orientX = 1; orientY = 0; - break; - case ORIENT_SE: - orientX = 1; orientY = 1; - break; - case ORIENT_S: - orientX = 0; orientY = 1; - break; - case ORIENT_SW: - orientX = -1; orientY = 1; - break; - default: - throw new RuntimeException("Invalid orientation " + orient); - } - - if (!s.isEmpty(x, y)) return false; - startX = x; startY = y; - int tilesPlaced = 1; - int nextX = startX; - int nextY = startY; - while (tilesPlaced < size) { - if (extendShip(s, nextX, nextY, nextX + orientX, nextY + orientY)) { - tilesPlaced += 1; - nextX = nextX + orientX; - nextY = nextY + orientY; - } else { - int backX = startX - orientX; - int backY = startY - orientY; - - if (extendShip(s, startX, startY, backX, backY)) { - tilesPlaced +=1; - startX = backX; - startY = backY; - } else { - return false; - } - } - } - - for (int i = 0; i < size; ++i) { - int sx = startX + i * orientX; - int sy = startY + i * orientY; - s.set(sx, sy, id); - } - placed = true; - return true; - } } - From f7f10d52f35e89dc5db764ea571c4e3f57d830c0 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 10 Jan 2022 15:18:46 -0500 Subject: [PATCH 226/331] Formatted "Totals" output Slowly going through and making output true to the original BASIC code --- 75_Roulette/java/src/Roulette.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java index c6e46152..84986db1 100644 --- a/75_Roulette/java/src/Roulette.java +++ b/75_Roulette/java/src/Roulette.java @@ -63,10 +63,9 @@ public class Roulette { betResults(bets,result); out.println(); - - out.println("TOTALS:"); - out.println("\tME: " + houseBalance); - out.println("\tYOU " + playerBalance); + + out.println("TOTALS:\tME\tYOU"); + out.println("\t\t" + houseBalance + "\t" + playerBalance); } while(playAgain()); if(playerBalance <= 0) { From 0614831f460cf286e698b177296e5862fdad39b9 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 10 Jan 2022 20:22:14 +0000 Subject: [PATCH 227/331] Add comments to the sea class --- 09_Battle/java/Sea.java | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/09_Battle/java/Sea.java b/09_Battle/java/Sea.java index d9987f34..f0c31fac 100644 --- a/09_Battle/java/Sea.java +++ b/09_Battle/java/Sea.java @@ -1,8 +1,13 @@ +// Track the content of the sea class Sea { + // the sea is a square grid of tiles. It is a one-dimensional array, and this + // class maps x and y coordinates to an array index + // Each tile is either empty (value of tiles at index is 0) + // or contains a ship (value of tiles at index is the ship number) private int tiles[]; - private boolean hits[]; private int size; + public Sea(int make_size) { size = make_size; tiles = new int[size*size]; @@ -10,6 +15,8 @@ class Sea { public int size() { return size; } + // This writes out a representation of the sea, but in a funny order + // The idea is to give the player the job of working it out public String encodedDump() { StringBuilder out = new StringBuilder(); for (int x = 0; x < size; ++x) { @@ -22,13 +29,17 @@ class Sea { /* return true if x,y is in the sea and empty * return false if x,y is occupied or is out of range + * Doing this in one method makes placing ships much easier */ public boolean isEmpty(int x, int y) { if ((x<0)||(x>=size)||(y<0)||(y>=size)) return false; return (get(x,y) == 0); } - /* return the ship number, or zero if no ship */ + /* return the ship number, or zero if no ship. + * Unlike isEmpty(x,y), these other methods require that the + * coordinates passed be valid + */ public int get(int x, int y) { return tiles[index(x,y)]; } @@ -37,15 +48,7 @@ class Sea { tiles[index(x, y)] = value; } - public int shipHit(int x, int y) { - if (hits[index(x,y)]) return get(x, y); - else return 0; - } - - public void recordHit(int x, int y) { - hits[index(x, y)] = true; - } - + // map the coordinates to the array index private int index(int x, int y) { if ((x < 0) || (x >= size)) throw new ArrayIndexOutOfBoundsException("Program error: x cannot be " + x); From ea5c2cf72d3164654894431acb741ec971ea8a3b Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 10 Jan 2022 20:26:50 +0000 Subject: [PATCH 228/331] Comment the input class --- 09_Battle/java/Input.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/09_Battle/java/Input.java b/09_Battle/java/Input.java index 8a782dba..ee87465f 100644 --- a/09_Battle/java/Input.java +++ b/09_Battle/java/Input.java @@ -3,12 +3,15 @@ import java.io.InputStreamReader; import java.io.IOException; import java.text.NumberFormat; +// This class handles reading input from the player +// Each input is an x and y coordinate +// e.g. 5,3 public class Input { private BufferedReader reader; private NumberFormat parser; - private int scale; - private boolean isQuit; - private int[] coords; + private int scale; // size of the sea, needed to validate input + private boolean isQuit; // whether the input has ended + private int[] coords; // the last coordinates read public Input(int seaSize) { scale = seaSize; @@ -18,22 +21,27 @@ public class Input { public boolean readCoordinates() throws IOException { while (true) { + // Write a prompt System.out.print("\nTarget x,y\n> "); String inputLine = reader.readLine(); if (inputLine == null) { - System.out.println("Game quit\n"); + // If the input stream is ended, there is no way to continue the game + System.out.println("\nGame quit\n"); isQuit = true; return false; } + // split the input into two fields String[] fields = inputLine.split(","); if (fields.length != 2) { + // has to be exactly two System.out.println("Need two coordinates separated by ','"); continue; } coords = new int[2]; boolean error = false; + // each field should contain an integer from 1 to the size of the sea try { for (int c = 0 ; c < 2; ++c ) { int val = Integer.parseInt(fields[c].strip()); @@ -46,6 +54,7 @@ public class Input { } } catch (NumberFormatException ne) { + // this happens if the field is not a valid number System.out.println("Coordinates must be numbers"); error = true; } From 00a8bf8983b0cc36a8b364908ce559d3f387e249 Mon Sep 17 00:00:00 2001 From: Josh Gribbon Date: Mon, 10 Jan 2022 15:42:08 -0500 Subject: [PATCH 229/331] Move file --- .../find-missing-implementations.js | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) rename find-missing-implementations.js => 00_Utilities/find-missing-implementations.js (79%) diff --git a/find-missing-implementations.js b/00_Utilities/find-missing-implementations.js similarity index 79% rename from find-missing-implementations.js rename to 00_Utilities/find-missing-implementations.js index 04cf3f84..1f998444 100644 --- a/find-missing-implementations.js +++ b/00_Utilities/find-missing-implementations.js @@ -15,7 +15,7 @@ const ROOT_PATH = "."; const languages = [ { name: "csharp", extension: "cs" }, { name: "java", extension: "java" }, - { name: "javascript", extension: "js" }, + { name: "javascript", extension: "html" }, { name: "pascal", extension: "pas" }, { name: "perl", extension: "pl" }, { name: "python", extension: "py" }, @@ -45,6 +45,7 @@ const getPuzzleFolders = () => { (async () => { let missingGames = {}; let missingLanguageCounts = {}; + languages.forEach((l) => (missingLanguageCounts[l.name] = 0)); const puzzles = getPuzzleFolders(); for (const puzzle of puzzles) { for (const { name: language, extension } of languages) { @@ -53,12 +54,8 @@ const getPuzzleFolders = () => { extension ); if (files.length === 0) { - if (!missingGames[puzzle]) { - missingGames[puzzle] = []; - } - if (!missingLanguageCounts[language]) { - missingLanguageCounts[language] = 0; - } + if (!missingGames[puzzle]) missingGames[puzzle] = []; + missingGames[puzzle].push(language); missingLanguageCounts[language]++; } @@ -70,15 +67,14 @@ const getPuzzleFolders = () => { } else { console.log(`Missing ${missingCount} implementations:`); - console.log(`\nMissing languages by game:`); - for (const [puzzle, languages] of Object.entries(missingGames)) { - console.log(`${puzzle}: ${languages.join(", ")}`); - } + Object.entries(missingGames).forEach( + ([p, ls]) => (missingGames[p] = ls.join(", ")) + ); + console.log(`\nMissing languages by game:`); + console.table(missingGames); console.log(`\nBy language:`); - for (const [language, count] of Object.entries(missingLanguageCounts)) { - console.log(`${language}: ${count} missing`); - } + console.table(missingLanguageCounts); } })(); From 2d2df367491a06003a9f5147cc1a80fc2e9ea1e5 Mon Sep 17 00:00:00 2001 From: Josh Gribbon Date: Mon, 10 Jan 2022 15:44:23 -0500 Subject: [PATCH 230/331] Fix relative path --- 00_Utilities/find-missing-implementations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/00_Utilities/find-missing-implementations.js b/00_Utilities/find-missing-implementations.js index 1f998444..bd92bd79 100644 --- a/00_Utilities/find-missing-implementations.js +++ b/00_Utilities/find-missing-implementations.js @@ -10,7 +10,7 @@ const fs = require("fs"); const glob = require("glob"); // relative path to the repository root -const ROOT_PATH = "."; +const ROOT_PATH = "../."; const languages = [ { name: "csharp", extension: "cs" }, From 01fb3bd5009102e5bff45395981d047eccbb8756 Mon Sep 17 00:00:00 2001 From: Josh Gribbon Date: Mon, 10 Jan 2022 15:46:51 -0500 Subject: [PATCH 231/331] Skip utilities folder --- 00_Utilities/find-missing-implementations.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/00_Utilities/find-missing-implementations.js b/00_Utilities/find-missing-implementations.js index bd92bd79..61d849fe 100644 --- a/00_Utilities/find-missing-implementations.js +++ b/00_Utilities/find-missing-implementations.js @@ -38,7 +38,10 @@ const getPuzzleFolders = () => { return fs .readdirSync(ROOT_PATH, { withFileTypes: true }) .filter((dirEntry) => dirEntry.isDirectory()) - .filter((dirEntry) => ![".git", "node_modules"].includes(dirEntry.name)) + .filter( + (dirEntry) => + ![".git", "node_modules", "00_Utilities"].includes(dirEntry.name) + ) .map((dirEntry) => dirEntry.name); }; From 5c9443c5222519ab976864b570171f4ba58208c6 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Tue, 11 Jan 2022 11:43:27 +1100 Subject: [PATCH 232/331] Copying Mistale forgot to add 'clean' to the targets for the initial build --- buildJvm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildJvm/README.md b/buildJvm/README.md index a5169abd..e2b9da0b 100644 --- a/buildJvm/README.md +++ b/buildJvm/README.md @@ -7,7 +7,7 @@ We should be using version 17 anyway, because anything less than 17 is deprecate Build all the games: ```shell cd buildJvm - ./gradlew -q assemble installDist distributeBin distributeLib + ./gradlew -q clean assemble installDist distributeBin distributeLib ``` Then, run a game From 7f14b42c73a481e8a3be14649a9c653f26b4949e Mon Sep 17 00:00:00 2001 From: Rob Miller Date: Tue, 11 Jan 2022 17:47:53 +0000 Subject: [PATCH 233/331] Depth Charge: use more idiomatic Ruby Refactor the Depth Charge game (#31) to use more Ruby idioms, without changing its structure, method names, etc. --- 31_Depth_Charge/ruby/depthcharge.rb | 139 ++++++++++++++-------------- 1 file changed, 69 insertions(+), 70 deletions(-) diff --git a/31_Depth_Charge/ruby/depthcharge.rb b/31_Depth_Charge/ruby/depthcharge.rb index ba2a5d83..67ab7cc8 100755 --- a/31_Depth_Charge/ruby/depthcharge.rb +++ b/31_Depth_Charge/ruby/depthcharge.rb @@ -1,59 +1,60 @@ #!/usr/bin/ruby class DepthCharge - def run_game - output_title() - while true - printf("----------\n") - print_instructions() - setup_game() - printf("\n") - game_loop() - break if ! get_input_another_game() + output_title + + loop do + puts "----------" + print_instructions + setup_game + puts + game_loop + break unless get_input_another_game end - printf("OK. HOPE YOU ENJOYED YOURSELF.\n") + puts "OK. HOPE YOU ENJOYED YOURSELF." end def output_title - printf("--- DEPTH CHARGE ---\n") - printf("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n") - printf("\n") + puts "--- DEPTH CHARGE ---" + puts "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" + puts end def get_input_y_or_n(message) - while true - print(message) + loop do + print message value = gets.chomp - if (value == 'Y' || value == 'y') + if value.downcase == "y" return true - elsif value == 'N' || value == 'n' + elsif value.downcase == "n" return false end - printf("PLEASE ENTER Y/y OR N/n...\n\n") + puts "PLEASE ENTER Y/y OR N/n..." + puts end end def get_input_positive_integer(message) - - while true - print(message) + loop do + print message value = gets.chomp - if (value == 'd') - debug_game() + + if value == "d" + debug_game next end - the_input = Integer(value) rescue nil + the_input = Integer(value) rescue 0 - if the_input == nil || the_input < 1 - printf("PLEASE ENTER A POSITIVE NUMBER\n\n") + if the_input < 1 + puts "PLEASE ENTER A POSITIVE NUMBER" + puts next - end return the_input @@ -61,42 +62,39 @@ class DepthCharge end def print_instructions - printf( <<~INSTRUCTIONS -YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER -AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR -MISSION IS TO DESTROY IT. + puts <<~INSTRUCTIONS + YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER + AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR + MISSION IS TO DESTROY IT. -SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A -TRIO OF NUMBERS -- THE FIRST TWO ARE THE -SURFACE COORDINATES (X, Y): - WEST < X < EAST - SOUTH < Y < NORTH + SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A + TRIO OF NUMBERS -- THE FIRST TWO ARE THE + SURFACE COORDINATES (X, Y): + WEST < X < EAST + SOUTH < Y < NORTH -THE THIRD IS THE DEPTH (Z): - SHALLOW < Z < DEEP + THE THIRD IS THE DEPTH (Z): + SHALLOW < Z < DEEP -GOOD LUCK ! + GOOD LUCK ! INSTRUCTIONS - ) end def debug_game - printf("@enemy_x: %d\n", @enemy_x) - printf("@enemy_y: %d\n", @enemy_y) - printf("@enemy_z: %d\n", @enemy_z) - printf("@num_tries: %d\n", @num_tries) - printf("@trial: %d\n", @trial) - printf("\n") + puts "@enemy_x: %d" % @enemy_x + puts "@enemy_y: %d" % @enemy_y + puts "@enemy_z: %d" % @enemy_z + puts "@num_tries: %d" % @num_tries + puts "@trial: %d" % @trial + puts end def setup_game @search_area_dimension = get_input_positive_integer("DIMENSION OF SEARCH AREA: ") - @num_tries = Integer( - Math.log(@search_area_dimension)/Math.log(2) + 1 - ) - setup_enemy() + @num_tries = Integer(Math.log(@search_area_dimension) / Math.log(2) + 1) + setup_enemy end def setup_enemy @@ -113,32 +111,34 @@ GOOD LUCK ! @shot_y = get_input_positive_integer("Y: ") @shot_z = get_input_positive_integer("Z: ") - if ( - (@enemy_x - @shot_x).abs \ - + (@enemy_y - @shot_y).abs \ - + (@enemy_z - @shot_z).abs \ - == 0 - ) - you_win() + + distance = (@enemy_x - @shot_x).abs + + (@enemy_y - @shot_y).abs + + (@enemy_z - @shot_z).abs + + if distance == 0 + you_win return else - missed_shot() + missed_shot end end - printf("\n") - - you_lose() + puts + you_lose end def output_game_status - printf("YOU HAVE %d SHOTS REMAINING.\n", @num_tries - @trial + 1) - printf("TRIAL \#%d\n", @trial) + puts "YOU HAVE %d SHOTS REMAINING." % @num_tries - @trial + 1 + puts "TRIAL \#%d" % @trial end + def you_win - printf("\nB O O M ! ! YOU FOUND IT IN %d TRIES!\n\n", @trial ) + puts "\nB O O M ! ! YOU FOUND IT IN %d TRIES!" % @trial + puts end + def missed_shot missed_directions = [] @@ -160,14 +160,13 @@ GOOD LUCK ! missed_directions.push('TOO SHALLOW') end - printf("SONAR REPORTS SHOT WAS: \n") - printf("%s\n", "\t" + missed_directions.join("\n\t")) + puts "SONAR REPORTS SHOT WAS: " + puts "\t#{missed_directions.join("\n\t")}" end def you_lose - printf("YOU HAVE BEEN TORPEDOED! ABANDON SHIP!\n") - printf("THE SUBMARINE WAS AT %d %d %d\n", @enemy_x, @enemy_y, @enemy_z) - + puts "YOU HAVE BEEN TORPEDOED! ABANDON SHIP!" + puts "THE SUBMARINE WAS AT %d %d %d" % [@enemy_x, @enemy_y, @enemy_z] end def get_input_another_game @@ -176,4 +175,4 @@ GOOD LUCK ! end game = DepthCharge.new -game.run_game() +game.run_game From 2885acd95195bcb167e0866d107cfd471de3d6e3 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 11 Jan 2022 14:10:42 -0500 Subject: [PATCH 234/331] Match Formatting to Original Program --- 75_Roulette/java/src/Roulette.java | 174 +++++++++++++++-------------- 1 file changed, 91 insertions(+), 83 deletions(-) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java index 84986db1..3bb042a5 100644 --- a/75_Roulette/java/src/Roulette.java +++ b/75_Roulette/java/src/Roulette.java @@ -1,7 +1,7 @@ import java.io.InputStream; import java.io.PrintStream; -import java.lang.management.PlatformLoggingMXBean; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.*; public class Roulette { @@ -35,135 +35,143 @@ public class Roulette { out.println(" ROULETTE"); out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); out.println("WELCOME TO THE ROULETTE TABLE\n"); - out.println("DO YOU WANT INSTRUCTIONS"); + out.print("DO YOU WANT INSTRUCTIONS? "); if(scanner.nextLine().toLowerCase().charAt(0) != 'n') { printInstructions(); } + do { Bet[] bets = queryBets(); - out.println("SPINNING...\n\n\n"); + out.print("SPINNING...\n\n"); int result = random.nextInt(1,39); /* Equivalent to following line - if(RED_NUMBERS.contains(result)) { + if(result == 37) { + out.println("00"); + } else if(result == 38) { + out.println("0"); + } else if(RED_NUMBERS.contains(result)) { out.println(result + " RED"); } else { out.println(result + " BLACK"); } */ - switch(result) { - case 37 -> out.print("00"); - case 38 -> out.print("0"); - default -> out.println(result + (RED_NUMBERS.contains(result) ? " RED\n" : " BLACK\n")); - } + out.println(switch(result) { + case 37 -> "00"; + case 38 -> "0"; + default -> result + (RED_NUMBERS.contains(result) ? " RED" : " BLACK"); + }); betResults(bets,result); out.println(); - out.println("TOTALS:\tME\tYOU"); - out.println("\t\t" + houseBalance + "\t" + playerBalance); + out.println("TOTALS:\tME\t\tYOU"); + out.format("\t\t%5d\t%d\n",houseBalance,playerBalance); } while(playAgain()); if(playerBalance <= 0) { out.println("THANKS FOR YOUR MONEY\nI'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL"); - } else if(houseBalance <= 0) { - out.println("TO WHOM SHALL I MAKE THE CHECK"); - String name = scanner.nextLine(); - out.println(); - for(int i = 0; i < 72; i++) { - out.print("-"); - } - out.println(); - for(int i = 0; i < 50; i++) { - out.print(" "); - } - out.println("CHECK NO. " + random.nextInt(0,1000)); - out.println(); - for(int i = 0; i < 40; i++) { - out.print(" "); - } - out.println(LocalDateTime.now()); - out.println("\n"); - out.println("PAY TO THE ORDER OF----- " + name + "------$" + (playerBalance - 1000)); - out.println("\n"); - for(int i = 0; i < 10; i++) { - out.print(" "); - } - out.println("THE MEMORY BANK OF NEW YORK"); - for(int i = 0; i < 40; i++) { - out.print(" "); - } - out.println("THE COMPUTER"); - for(int i = 0; i < 40; i++) { - out.print(" "); - } - out.println("----------X-----"); - for(int i = 0; i < 72; i++) { - out.print("-"); - } - out.println("\n"); - out.println("COME BACK SOON"); + } else { + printCheck(); } + out.println("COME BACK SOON!"); + } + + private void printCheck() { + out.print("TO WHOM SHALL I MAKE THE CHECK? "); + String name = scanner.nextLine(); + + out.println(); + for(int i = 0; i < 72; i++) { + out.print("-"); + } + out.println(); + + for(int i = 0; i < 50; i++) { + out.print(" "); + } + out.println("CHECK NO. " + random.nextInt(0,100)); + + for(int i = 0; i< 40; i++) { + out.print(" "); + } + out.println(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE)); + out.println(); + + out.println("PAY TO THE ORDER OF -----" + name + "----- $" + (playerBalance)); + out.println(); + + for(int i = 0; i < 40; i++) { + out.print(" "); + } + out.println("THE MEMORY BANK OF NEW YORK"); + + for(int i = 0; i < 40; i++) { + out.print(" "); + } + out.println("THE COMPUTER"); + + for(int i = 0; i < 40; i++) { + out.print(" "); + } + out.println("----------X-----"); + + for(int i = 0; i < 72; i++) { + out.print("-"); + } + out.println(); } private boolean playAgain() { - if(playerBalance > 0) { - if(houseBalance <= 0) { - out.println("YOU BROKE THE HOUSE!"); - //using default values - playerBalance = 101000; - } + + if(playerBalance <= 0) { + out.println("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!"); + return false; + } else if(houseBalance <= 0) { + out.println("YOU BROKE THE HOUSE!"); + playerBalance = 10100; + houseBalance = 0; + return false; + } else { out.println("PLAY AGAIN?"); return scanner.nextLine().toLowerCase().charAt(0) == 'y'; - } else { - return false; } } private Bet[] queryBets() { int numBets = -1; while(numBets < 1) { - out.println("HOW MANY BETS"); + out.print("HOW MANY BETS? "); try { numBets = Integer.parseInt(scanner.nextLine()); - } catch(NumberFormatException exception) { - out.println("THAT IS NOT A NUMBER"); - } + } catch(NumberFormatException ignored) {} } Bet[] bets = new Bet[numBets]; for(int i = 0; i < numBets; i++) { - try { - out.println("BET NUMBER " + (i + 1) + ":"); - String[] values = scanner.nextLine().split(","); - int betNumber = Integer.parseInt(values[0]); - int betValue = Integer.parseInt(values[1]); + while(bets[i] == null) { + try { + out.print("NUMBER" + (i + 1) + "? "); + String[] values = scanner.nextLine().split(","); + int betNumber = Integer.parseInt(values[0]); + int betValue = Integer.parseInt(values[1]); - for(int j = 0; j < i; j++) { - if(bets[j].num == betNumber) { - out.println("YOU MADE THAT BET ONCE ALREADY,DUM-DUM"); - throw new Exception(); + for(int j = 0; j < i; j++) { + if(bets[j].num == betNumber) { + out.println("YOU MADE THAT BET ONCE ALREADY,DUM-DUM"); + betNumber = -1; //Since -1 is out of the range, this will throw it out at the end + } } - } - if(betNumber < 1 || betNumber > 50 || betValue < 5 || betValue > 500) { - out.println("INVALID VALUE, TRY AGAIN"); - i--; - continue; - } - - bets[i] = new Bet(betNumber,betValue); - - } catch(Exception exception) { - if(exception instanceof NumberFormatException) { - out.println("SYNTAX ERROR, TRY AGAIN"); - } - i--; + if(betNumber > 0 && betNumber <= 50 && betValue >= 5 && betValue <= 500) { + bets[i] = new Bet(betValue,betNumber); + } + } catch(Exception ignored) {} } } return bets; From f43e31fb83cdb7ca47e59ca3514da82bbf0ca25d Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 11 Jan 2022 14:15:37 -0500 Subject: [PATCH 235/331] Re-Formatted Code --- 75_Roulette/java/src/Roulette.java | 263 +++++++++++++++-------------- 1 file changed, 132 insertions(+), 131 deletions(-) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java index 3bb042a5..5fed5c65 100644 --- a/75_Roulette/java/src/Roulette.java +++ b/75_Roulette/java/src/Roulette.java @@ -2,26 +2,22 @@ import java.io.InputStream; import java.io.PrintStream; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.Random; +import java.util.Scanner; +import java.util.Set; public class Roulette { - private PrintStream out; - private Scanner scanner; - - private int houseBalance, playerBalance; - - private Random random; - private static Set RED_NUMBERS; static { RED_NUMBERS = Set.of(1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36); } - public static void main(String[] args) { - new Roulette(System.out, System.in).play(); - } + private PrintStream out; + private Scanner scanner; + private int houseBalance, playerBalance; + private Random random; public Roulette(PrintStream out, InputStream in) { this.out = out; @@ -31,22 +27,25 @@ public class Roulette { random = new Random(); } + public static void main(String[] args) { + new Roulette(System.out, System.in).play(); + } + public void play() { out.println(" ROULETTE"); out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); out.println("WELCOME TO THE ROULETTE TABLE\n"); out.print("DO YOU WANT INSTRUCTIONS? "); - if(scanner.nextLine().toLowerCase().charAt(0) != 'n') { + if (scanner.nextLine().toLowerCase().charAt(0) != 'n') { printInstructions(); } - do { Bet[] bets = queryBets(); out.print("SPINNING...\n\n"); - int result = random.nextInt(1,39); + int result = random.nextInt(1, 39); /* Equivalent to following line @@ -60,20 +59,19 @@ public class Roulette { out.println(result + " BLACK"); } */ - out.println(switch(result) { + out.println(switch (result) { case 37 -> "00"; case 38 -> "0"; - default -> result + (RED_NUMBERS.contains(result) ? " RED" : " BLACK"); + default -> result + (RED_NUMBERS.contains(result) ? " RED" : " BLACK"); }); - betResults(bets,result); + betResults(bets, result); out.println(); - - out.println("TOTALS:\tME\t\tYOU"); - out.format("\t\t%5d\t%d\n",houseBalance,playerBalance); - } while(playAgain()); - if(playerBalance <= 0) { + out.println("TOTALS:\tME\t\tYOU"); + out.format("\t\t%5d\t%d\n", houseBalance, playerBalance); + } while (playAgain()); + if (playerBalance <= 0) { out.println("THANKS FOR YOUR MONEY\nI'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL"); } else { printCheck(); @@ -81,110 +79,101 @@ public class Roulette { out.println("COME BACK SOON!"); } - private void printCheck() { - out.print("TO WHOM SHALL I MAKE THE CHECK? "); - String name = scanner.nextLine(); - + public void printInstructions() { out.println(); - for(int i = 0; i < 72; i++) { - out.print("-"); - } + out.println("THIS IS THE BETTING LAYOUT"); + out.println(" (*=RED)"); out.println(); - - for(int i = 0; i < 50; i++) { - out.print(" "); - } - out.println("CHECK NO. " + random.nextInt(0,100)); - - for(int i = 0; i< 40; i++) { - out.print(" "); - } - out.println(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE)); + out.println(" 1* 2 3*"); + out.println(" 4 5* 6 "); + out.println(" 7* 8 9*"); + out.println("10 11 12*"); + out.println("---------------"); + out.println("13 14* 15 "); + out.println("16* 17 18*"); + out.println("19* 20 21*"); + out.println("22 23* 24 "); + out.println("---------------"); + out.println("25* 26 27*"); + out.println("28 29 30*"); + out.println("31 32* 33 "); + out.println("34* 35 36*"); + out.println("---------------"); + out.println(" 00 0 "); out.println(); - - out.println("PAY TO THE ORDER OF -----" + name + "----- $" + (playerBalance)); + out.println("TYPES OF BETS"); out.println(); - - for(int i = 0; i < 40; i++) { - out.print(" "); - } - out.println("THE MEMORY BANK OF NEW YORK"); - - for(int i = 0; i < 40; i++) { - out.print(" "); - } - out.println("THE COMPUTER"); - - for(int i = 0; i < 40; i++) { - out.print(" "); - } - out.println("----------X-----"); - - for(int i = 0; i < 72; i++) { - out.print("-"); - } + out.println("THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET"); + out.println("ON THAT NUMBER."); + out.println("THESE PAY OFF 35:1"); out.println(); - } - - private boolean playAgain() { - - if(playerBalance <= 0) { - out.println("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!"); - return false; - } else if(houseBalance <= 0) { - out.println("YOU BROKE THE HOUSE!"); - playerBalance = 10100; - houseBalance = 0; - return false; - } else { - out.println("PLAY AGAIN?"); - return scanner.nextLine().toLowerCase().charAt(0) == 'y'; - } + out.println("THE 2:1 BETS ARE:"); + out.println(" 37) 1-12 40) FIRST COLUMN"); + out.println(" 38) 13-24 41) SECOND COLUMN"); + out.println(" 39) 25-36 42) THIRD COLUMN"); + out.println(); + out.println("THE EVEN MONEY BETS ARE:"); + out.println(" 43) 1-18 46) ODD"); + out.println(" 44) 19-36 47) RED"); + out.println(" 45) EVEN 48) BLACK"); + out.println(); + out.println(" 49)0 AND 50)00 PAY OFF 35:1"); + out.println(" NOTE: 0 AND 00 DO NOT COUNT UNDER ANY"); + out.println(" BETS EXCEPT THEIR OWN."); + out.println(); + out.println("WHEN I ASK FOR EACH BET, TYPE THE NUMBER"); + out.println("AND THE AMOUNT, SEPARATED BY A COMMA."); + out.println("FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500"); + out.println("WHEN I ASK FOR A BET."); + out.println(); + out.println("THE MINIMUM BET IS $5, THE MAXIMUM IS $500."); } private Bet[] queryBets() { int numBets = -1; - while(numBets < 1) { + while (numBets < 1) { out.print("HOW MANY BETS? "); try { numBets = Integer.parseInt(scanner.nextLine()); - } catch(NumberFormatException ignored) {} + } catch (NumberFormatException ignored) { + } } Bet[] bets = new Bet[numBets]; - for(int i = 0; i < numBets; i++) { - while(bets[i] == null) { + for (int i = 0; i < numBets; i++) { + while (bets[i] == null) { try { out.print("NUMBER" + (i + 1) + "? "); String[] values = scanner.nextLine().split(","); int betNumber = Integer.parseInt(values[0]); int betValue = Integer.parseInt(values[1]); - for(int j = 0; j < i; j++) { - if(bets[j].num == betNumber) { + for (int j = 0; j < i; j++) { + if (bets[j].num == betNumber) { out.println("YOU MADE THAT BET ONCE ALREADY,DUM-DUM"); betNumber = -1; //Since -1 is out of the range, this will throw it out at the end } } - if(betNumber > 0 && betNumber <= 50 && betValue >= 5 && betValue <= 500) { - bets[i] = new Bet(betValue,betNumber); + if (betNumber > 0 && betNumber <= 50 && betValue >= 5 && betValue <= 500) { + bets[i] = new Bet(betValue, betNumber); } - } catch(Exception ignored) {} + } catch (Exception ignored) { + } } } return bets; } private void betResults(Bet[] bets, int num) { - for(int i = 0; i < bets.length; i++) { + for (int i = 0; i < bets.length; i++) { Bet bet = bets[i]; /* Using a switch statement of ternary operators that check if a certain condition is met based on the bet value Returns the coefficient that the bet amount should be multiplied by to get the resulting value */ - int coefficient = switch(bet.num) { + int coefficient = switch (bet.num) { case 37 -> (num <= 12) ? 2 : -1; case 38 -> (num > 12 && num <= 24) ? 2 : -1; case 39 -> (num > 24 && num < 37) ? 2 : -1; @@ -204,7 +193,7 @@ public class Roulette { int betResult = bet.amount * coefficient; - if(betResult < 0) { + if (betResult < 0) { out.println("YOU LOSE " + -betResult + " DOLLARS ON BET " + (i + 1)); } else { out.println("YOU WIN " + betResult + " DOLLARS ON BET " + (i + 1)); @@ -215,57 +204,69 @@ public class Roulette { } } - public void printInstructions() { + private boolean playAgain() { + + if (playerBalance <= 0) { + out.println("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!"); + return false; + } else if (houseBalance <= 0) { + out.println("YOU BROKE THE HOUSE!"); + playerBalance = 10100; + houseBalance = 0; + return false; + } else { + out.println("PLAY AGAIN?"); + return scanner.nextLine().toLowerCase().charAt(0) == 'y'; + } + } + + private void printCheck() { + out.print("TO WHOM SHALL I MAKE THE CHECK? "); + String name = scanner.nextLine(); + out.println(); - out.println( "THIS IS THE BETTING LAYOUT"); - out.println( " (*=RED)"); + for (int i = 0; i < 72; i++) { + out.print("-"); + } out.println(); - out.println( " 1* 2 3*"); - out.println( " 4 5* 6 "); - out.println( " 7* 8 9*"); - out.println( "10 11 12*"); - out.println( "---------------"); - out.println( "13 14* 15 "); - out.println( "16* 17 18*"); - out.println( "19* 20 21*"); - out.println( "22 23* 24 "); - out.println( "---------------"); - out.println( "25* 26 27*"); - out.println( "28 29 30*"); - out.println( "31 32* 33 "); - out.println( "34* 35 36*"); - out.println( "---------------"); - out.println( " 00 0 "); + + for (int i = 0; i < 50; i++) { + out.print(" "); + } + out.println("CHECK NO. " + random.nextInt(0, 100)); + + for (int i = 0; i < 40; i++) { + out.print(" "); + } + out.println(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE)); out.println(); - out.println( "TYPES OF BETS"); + + out.println("PAY TO THE ORDER OF -----" + name + "----- $" + (playerBalance)); out.println(); - out.println( "THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET"); - out.println( "ON THAT NUMBER."); - out.println( "THESE PAY OFF 35:1"); + + for (int i = 0; i < 40; i++) { + out.print(" "); + } + out.println("THE MEMORY BANK OF NEW YORK"); + + for (int i = 0; i < 40; i++) { + out.print(" "); + } + out.println("THE COMPUTER"); + + for (int i = 0; i < 40; i++) { + out.print(" "); + } + out.println("----------X-----"); + + for (int i = 0; i < 72; i++) { + out.print("-"); + } out.println(); - out.println( "THE 2:1 BETS ARE:"); - out.println( " 37) 1-12 40) FIRST COLUMN"); - out.println( " 38) 13-24 41) SECOND COLUMN"); - out.println( " 39) 25-36 42) THIRD COLUMN"); - out.println(); - out.println( "THE EVEN MONEY BETS ARE:"); - out.println( " 43) 1-18 46) ODD"); - out.println( " 44) 19-36 47) RED"); - out.println( " 45) EVEN 48) BLACK"); - out.println(); - out.println( " 49)0 AND 50)00 PAY OFF 35:1"); - out.println( " NOTE: 0 AND 00 DO NOT COUNT UNDER ANY"); - out.println( " BETS EXCEPT THEIR OWN."); - out.println(); - out.println( "WHEN I ASK FOR EACH BET, TYPE THE NUMBER"); - out.println( "AND THE AMOUNT, SEPARATED BY A COMMA."); - out.println( "FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500"); - out.println( "WHEN I ASK FOR A BET."); - out.println(); - out.println( "THE MINIMUM BET IS $5, THE MAXIMUM IS $500."); } public class Bet { + final int num, amount; public Bet(int num, int amount) { From 74a3cb72aca72719cd9fc1c16fb9cf784ad8bb64 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 11 Jan 2022 15:09:03 -0500 Subject: [PATCH 236/331] Started Roulette in Python --- 75_Roulette/python/roulette.py | 130 +++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/75_Roulette/python/roulette.py b/75_Roulette/python/roulette.py index 8b137891..db1f5639 100644 --- a/75_Roulette/python/roulette.py +++ b/75_Roulette/python/roulette.py @@ -1 +1,131 @@ + +global RED_NUMBERS +RED_NUMBERS = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36] + +def print_instructions(): + print(""" +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. + + """) + +def query_bets(): + betCount = -1 + while betCount <= 0: + try: + betCount = int(input("HOW MANY BETS? ")) + except: + ... + + bet_IDs = [-1] * betCount + bet_Values = [0] * betCount + + for i in range(betCount): + while(bet_IDs[i] == -1): + try: + inString = input("NUMBER " + str(i + 1) + "? ").split(',') + id,val = int(inString[0]),int(inString[1]) + + # check other bet_IDs + for j in range(i): + if id != -1 and bet_IDs[j] == id: + id = -1 + print("YOU ALREADY MADE THAT BET ONCE, DUM-DUM") + break + + if id > 0 and id <= 50 and val >= 5 and val <= 500: + bet_IDs[i] = id + bet_Values[i] = val + except: + ... + return bet_IDs,bet_Values + +def bet_results(bet_IDs,bet_Values,result): + def get_modifier(id,num): + if id == 37 and num <= 12: + return 2 + elif id == 38 and num > 12 and num <= 24: + return 2 + elif id == 39 and num > 24 and num < 37: + return 2 + elif id == 40 and num < 37 and num % 3 == 1: + return 2 + elif id == 41 and num < 37 and num % 3 == 2: + return 2 + elif id == 42 and num < 37 and num % 3 == 0: + return 2 + elif id == 43 and num <= 18: + return 1 + elif id == 44 and num > 18 and num <= 36: + return 1 + elif id == 45 and num % 2 == 0: + return 1 + elif id == 46 and num % 2 == 1: + return 1 + elif id == 47 and num in RED_NUMBERS: + return 1 + elif id == 48 and num not in RED_NUMBERS: + return 1 + elif id < 37 and id == num: + return 35 + else: + return -1 + + for i in range(len(bet_IDs)): + winnings = bet_Values[i] * get_modifier(bet_IDs[i],result) + + if winnings >= 0: + print("YOU WIN " + str(winnings) + " DOLLARS ON BET " + str(i + 1)) + else: + print("YOU LOSE " + str(winnings * -1) + " DOLLARS ON BET " + str(i + 1)) + +def main(): + ... + +a,b = query_bets() +bet_results(a,b,5) From 614e4740a97008751bf4d11e6a051e07f3cf65a7 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 11 Jan 2022 15:26:53 -0500 Subject: [PATCH 237/331] Added check --- 75_Roulette/python/roulette.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/75_Roulette/python/roulette.py b/75_Roulette/python/roulette.py index db1f5639..c4cb6ccd 100644 --- a/75_Roulette/python/roulette.py +++ b/75_Roulette/python/roulette.py @@ -1,4 +1,5 @@ - +from datetime import date +import random global RED_NUMBERS RED_NUMBERS = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36] @@ -124,8 +125,23 @@ def bet_results(bet_IDs,bet_Values,result): else: print("YOU LOSE " + str(winnings * -1) + " DOLLARS ON BET " + str(i + 1)) +def print_check(amount): + name = input("TO WHOM SHALL I MAKE THE CHECK? ") + + print("-" * 72) + print() + print(" " * 40 + "CHECK NO. " + str(random.randint(0,100))) + print(" " * 40 + str(date.today())) + print() + print("PAY TO THE ORDER OF -----" + name + "----- $" + str(amount)) + print() + print(" " * 40 + "THE MEMORY BANK OF NEW YORK") + print(" " * 40 + "THE COMPUTER") + print(" " * 40 + "----------X-----") + print("-" * 72) + def main(): ... -a,b = query_bets() -bet_results(a,b,5) +# a,b = query_bets() +print_check(5) From 5dff7851296a53d73d4d1e2e5f56604de7cc0d6a Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 11 Jan 2022 15:56:31 -0500 Subject: [PATCH 238/331] Fixed numerical typo --- 75_Roulette/java/src/Roulette.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java index 5fed5c65..77ea2703 100644 --- a/75_Roulette/java/src/Roulette.java +++ b/75_Roulette/java/src/Roulette.java @@ -211,7 +211,7 @@ public class Roulette { return false; } else if (houseBalance <= 0) { out.println("YOU BROKE THE HOUSE!"); - playerBalance = 10100; + playerBalance = 101000; houseBalance = 0; return false; } else { From ea16d14a9ddb7d72287b9da7c91b6cf9b9563645 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 11 Jan 2022 16:01:38 -0500 Subject: [PATCH 239/331] Implemented more Roulette.py --- 75_Roulette/python/roulette.py | 66 ++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/75_Roulette/python/roulette.py b/75_Roulette/python/roulette.py index c4cb6ccd..cca991dd 100644 --- a/75_Roulette/python/roulette.py +++ b/75_Roulette/python/roulette.py @@ -87,6 +87,7 @@ def query_bets(): return bet_IDs,bet_Values def bet_results(bet_IDs,bet_Values,result): + total_winnings = 0 def get_modifier(id,num): if id == 37 and num <= 12: return 2 @@ -119,12 +120,15 @@ def bet_results(bet_IDs,bet_Values,result): for i in range(len(bet_IDs)): winnings = bet_Values[i] * get_modifier(bet_IDs[i],result) + total_winnings += winnings if winnings >= 0: print("YOU WIN " + str(winnings) + " DOLLARS ON BET " + str(i + 1)) else: print("YOU LOSE " + str(winnings * -1) + " DOLLARS ON BET " + str(i + 1)) + return winnings + def print_check(amount): name = input("TO WHOM SHALL I MAKE THE CHECK? ") @@ -141,7 +145,65 @@ def print_check(amount): print("-" * 72) def main(): - ... + player_balance = 1000 + host_balance = 100000 + + print(" " * 32 + "ROULETTE") + print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() + + if stringtobool(input("DO YOU WANT INSTRUCTIONS? ")): + print_instructions() + + while True: + bet_IDs,bet_Values = query_bets() + + print("SPINNING") + print() + print() + + val = random.randint(0,38) + if val == 38: + print("0") + elif val == 37: + print("00") + elif val in RED_NUMBERS: + print(str(val) + " RED") + else: + print(str(val) + " BLACK") + + print() + total_winnings = bet_results(bet_IDs,bet_Values,val) + player_balance += total_winnings + host_balance -= total_winnings + + print() + print("TOTALS:\tME\t\tYOU") + print("\t\t" + str(host_balance) + "\t" + str(player_balance)) + + if player_balance <= 0: + print("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!") + break + elif host_balance <= 0: + print("YOU BROKE THE HOUSE!") + player_balance = 101000 + break + if not stringtobool(input("PLAY AGAIN? ")): + break + + + if player_balance <= 0: + print("THANKS FOR YOUR MONEY") + print("I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL") + else: + print_check(player_balance) + print("COME BACK SOON!") + + +def stringtobool(string): + return string.lower() in ("yes","y","true","t","yes") # a,b = query_bets() -print_check(5) +main() From 1317d9ee16b15b4f1221955e15e3b7c71d8044f9 Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 11 Jan 2022 16:04:44 -0500 Subject: [PATCH 240/331] Player balance is now deducted on bets --- 75_Roulette/java/src/Roulette.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java index 5fed5c65..56bcb1e5 100644 --- a/75_Roulette/java/src/Roulette.java +++ b/75_Roulette/java/src/Roulette.java @@ -157,7 +157,8 @@ public class Roulette { } if (betNumber > 0 && betNumber <= 50 && betValue >= 5 && betValue <= 500) { - bets[i] = new Bet(betValue, betNumber); + bets[i] = new Bet(betNumber,betValue); + playerBalance -= betValue; } } catch (Exception ignored) { } From 5c3a7e67fa2ad872eeeff3d094b31602785dec6d Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 11 Jan 2022 16:05:16 -0500 Subject: [PATCH 241/331] Reverting previous commit --- 75_Roulette/java/src/Roulette.java | 1 - 1 file changed, 1 deletion(-) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/src/Roulette.java index 56bcb1e5..30c25091 100644 --- a/75_Roulette/java/src/Roulette.java +++ b/75_Roulette/java/src/Roulette.java @@ -158,7 +158,6 @@ public class Roulette { if (betNumber > 0 && betNumber <= 50 && betValue >= 5 && betValue <= 500) { bets[i] = new Bet(betNumber,betValue); - playerBalance -= betValue; } } catch (Exception ignored) { } From 11fb8f778fab60218f33071068c3cc1141051d7b Mon Sep 17 00:00:00 2001 From: LittleTealeaf Date: Tue, 11 Jan 2022 16:11:10 -0500 Subject: [PATCH 242/331] Added comments --- 75_Roulette/python/roulette.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/75_Roulette/python/roulette.py b/75_Roulette/python/roulette.py index cca991dd..c839adc7 100644 --- a/75_Roulette/python/roulette.py +++ b/75_Roulette/python/roulette.py @@ -56,6 +56,7 @@ THE MINIMUM BET IS $5, THE MAXIMUM IS $500. """) def query_bets(): + """Queries the user to input their bets""" betCount = -1 while betCount <= 0: try: @@ -87,6 +88,7 @@ def query_bets(): return bet_IDs,bet_Values def bet_results(bet_IDs,bet_Values,result): + """Computes the results, prints them, and returns the total net winnings""" total_winnings = 0 def get_modifier(id,num): if id == 37 and num <= 12: @@ -130,6 +132,7 @@ def bet_results(bet_IDs,bet_Values,result): return winnings def print_check(amount): + """Prints a check of a given amount""" name = input("TO WHOM SHALL I MAKE THE CHECK? ") print("-" * 72) @@ -203,7 +206,8 @@ def main(): def stringtobool(string): + """Converts a string to a bool""" return string.lower() in ("yes","y","true","t","yes") -# a,b = query_bets() -main() +if __name__ == '__main__': + main() From 5c632b2d7eada3dab2f28e8ef4f2b603809c3fbf Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 11 Jan 2022 21:14:23 +0000 Subject: [PATCH 243/331] 75_Roulette in java --- 75_Roulette/java/Bet.java | 65 +++++++++ 75_Roulette/java/Roulette.java | 234 +++++++++++++++++++++++++++++++++ 75_Roulette/java/Wheel.java | 69 ++++++++++ 3 files changed, 368 insertions(+) create mode 100644 75_Roulette/java/Bet.java create mode 100644 75_Roulette/java/Roulette.java create mode 100644 75_Roulette/java/Wheel.java diff --git a/75_Roulette/java/Bet.java b/75_Roulette/java/Bet.java new file mode 100644 index 00000000..6d9ea48a --- /dev/null +++ b/75_Roulette/java/Bet.java @@ -0,0 +1,65 @@ +/* A bet has a target (the code entered, which is 1-36, or special values for + * the various groups, zero and double-zero), and an amount in dollars + */ + +public class Bet { + public int target; + public int amount; + + /* bet on a target, of an amount */ + public Bet(int on, int of) { + target = on; amount = of; + } + + /* check if this is a valid bet - on a real target and of a valid amount */ + public boolean isValid() { + return ((target > 0) && (target <= 50) && + (amount >= 5) && (amount <= 500)); + } + + /* utility to return either the odds amount in the case of a win, or zero for a loss */ + private int m(boolean isWon, int odds) { + return isWon? odds: 0; + } + + /* look at the wheel to see if this bet won. + * returns 0 if it didn't, or the odds if it did + */ + public int winsOn(Wheel w) { + if (target < 37) { + // A number bet 1-36 wins at odds of 35 if it is the exact number + return m(w.isNumber() && (w.number() == target), 35); + } else + switch (target) { + case 37: // 1-12, odds of 2 + return m(w.isNumber() && (w.number() <= 12), 2); + case 38: // 13-24, odds of 2 + return m(w.isNumber() && (w.number() > 12) && (w.number() <= 24), 2); + case 39: // 25-36, odds of 2 + return m(w.isNumber() && (w.number() > 24), 2); + case 40: // Column 1, odds of 2 + return m(w.isNumber() && ((w.number() % 3) == 1), 2); + case 41: // Column 2, odds of 2 + return m(w.isNumber() && ((w.number() % 3) == 2), 2); + case 42: // Column 3, odds of 2 + return m(w.isNumber() && ((w.number() % 3) == 0), 2); + case 43: // 1-18, odds of 1 + return m(w.isNumber() && (w.number() <= 18), 1); + case 44: // 19-36, odds of 1 + return m(w.isNumber() && (w.number() > 18), 1); + case 45: // even, odds of 1 + return m(w.isNumber() && ((w.number() %2) == 0), 1); + case 46: // odd, odds of 1 + return m(w.isNumber() && ((w.number() %2) == 1), 1); + case 47: // red, odds of 1 + return m(w.isNumber() && (w.color() == Wheel.BLACK), 1); + case 48: // black, odds of 1 + return m(w.isNumber() && (w.color() == Wheel.RED), 1); + case 49: // single zero, odds of 35 + return m(w.value().equals("0"), 35); + case 50: // double zero, odds of 35 + return m(w.value().equals("00"), 35); + } + throw new RuntimeException("Program Error - invalid bet"); + } +} diff --git a/75_Roulette/java/Roulette.java b/75_Roulette/java/Roulette.java new file mode 100644 index 00000000..77ae3463 --- /dev/null +++ b/75_Roulette/java/Roulette.java @@ -0,0 +1,234 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Random; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; + +public class Roulette { + public static void main(String args[]) throws Exception { + Roulette r = new Roulette(); + r.play(); + } + + private BufferedReader reader; + private PrintStream writer; + + private int house; // how much money does the house have + private int player; // how much money does the player have + private Wheel wheel = new Wheel(); + + public Roulette() { + reader = new BufferedReader(new InputStreamReader(System.in)); + writer = System.out; + house = 100000; + player = 1000; + } + + // for a test / cheat mode -- set the random number generator to a known value + private void setSeed(long l) { + wheel.setSeed(l); + } + + public void play() { + try { + intro(); + writer.println("WELCOME TO THE ROULETTE TABLE\n" + + "DO YOU WANT INSTRUCTIONS"); + String instr = reader.readLine(); + if (!instr.toUpperCase().startsWith("N")) + instructions(); + + while (betAndSpin()) { // returns true if the game is to continue + } + + if (player <= 0) { + // player ran out of money + writer.println("THANKS FOR YOUR MONEY.\nI'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL"); + } else { + // player has money -- print them a check + writer.println("TO WHOM SHALL I MAKE THE CHECK"); + + String payee = reader.readLine(); + + writer.println("-".repeat(72)); + tab(50); writer.println("CHECK NO. " + (new Random().nextInt(100) + 1)); + writer.println(); + tab(40); writer.println(LocalDate.now().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG))); + writer.println("\n\nPAY TO THE ORDER OF-----" + payee + "-----$ " + player); + writer.print("\n\n"); + tab(10); writer.println("THE MEMORY BANK OF NEW YORK\n"); + tab(40); writer.println("THE COMPUTER"); + tab(40); writer.println("----------X-----\n"); + writer.println("-".repeat(72)); + writer.println("COME BACK SOON!\n"); + } + } + catch (IOException e) { + // this should not happen + System.err.println("System error:\n" + e); + } + } + + /* Write the starting introduction */ + private void intro() throws IOException { + tab(32); writer.println("ROULETTE"); + tab(15); writer.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"); + } + + /* Display the game instructions */ + private void instructions() { + String[] instLines = new String[] { + "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.", + "" }; + writer.println(String.join("\n", instLines)); + } + + /* Take a set of bets from the player, then spin the wheel and work out the winnings * + * This returns true if the game is to continue afterwards + */ + private boolean betAndSpin() throws IOException { + int betCount = 0; + + while (betCount == 0) { // keep asking how many bets until we get a good answer + try { + writer.println("HOW MANY BETS"); + String howMany = reader.readLine(); + betCount = Integer.parseInt(howMany.strip()); + + if ((betCount < 1) || (betCount > 100)) betCount = 0; // bad -- set zero and ask again + } + catch (NumberFormatException e) { + // this happens if the input is not a number + writer.println("INPUT ERROR"); + } + } + + HashSet betsMade = new HashSet<>(); // Bet targets already made, so we can spot repeats + ArrayList bets = new ArrayList<>(); // All the bets for this round + + while (bets.size() < betCount) { + Bet bet = new Bet(0, 0); // an invalid bet to hold the place + while (!bet.isValid()) { // keep asking until it is valid + try { + writer.println("NUMBER " + (bets.size() + 1)); + String fields[] = reader.readLine().split(","); + if (fields.length == 2) { + bet = new Bet(Integer.parseInt(fields[0].strip()), + Integer.parseInt(fields[1].strip())); + } + } + catch (NumberFormatException e) { + writer.println("INPUT ERROR"); + } + } + + // Check if there is already a bet on the same target + if (betsMade.contains(bet.target)) { + writer.println("YOU MADE THAT BET ONCE ALREADY,DUM-DUM"); + } else { + betsMade.add(bet.target); // note this target has now been bet on + bets.add(bet); + } + } + + writer.println("SPINNING\n\n"); + + wheel.spin(); // this deliberately takes some random amount of time + + writer.println(wheel.value()); + + // go through the bets, and evaluate each one + int betNumber = 1; + for (Bet b : bets) { + int multiplier = b.winsOn(wheel); + if (multiplier == 0) { + // lost the amount of the bet + writer.println("YOU LOSE " + b.amount + " DOLLARS ON BET " + betNumber); + house += b.amount; + player -= b.amount; + } else { + // won the amount of the bet, multiplied by the odds + int winnings = b.amount * multiplier; + writer.println("YOU WIN " + winnings + " DOLLARS ON BET " + betNumber); + house -= winnings; + player += winnings; + } + ++betNumber; + } + + writer.println("\nTOTALS:\tME\tYOU\n\t" + house + "\t" + player); + + if (player <= 0) { + writer.println("OOPS! YOU JUST SPENT YOUR LAST DOLLAR"); + return false; // do not repeat since the player has no more money + } + if (house <= 0) { + writer.println("YOU BROKE THE HOUSE!"); + player = 101000; // can't win more than the house started with + return false; // do not repeat since the house has no more money + } + + // player still has money, and the house still has money, so ask the player + // if they want to continue + writer.println("AGAIN"); + String doContinue = reader.readLine(); + + // repeat if the answer was not "n" or "no" + return (!doContinue.toUpperCase().startsWith("N")); + } + + // utility to print n spaces for formatting + private void tab(int n) { + writer.print(" ".repeat(n)); + } +} diff --git a/75_Roulette/java/Wheel.java b/75_Roulette/java/Wheel.java new file mode 100644 index 00000000..497c8b53 --- /dev/null +++ b/75_Roulette/java/Wheel.java @@ -0,0 +1,69 @@ +import java.util.Arrays; +import java.util.HashSet; +import java.util.Random; + +// The roulette wheel +public class Wheel { + // List the numbers which are black + private HashSet black = new HashSet<>(Arrays.asList(new Integer[] { 1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36 })); + + private Random random = new Random(); + private int pocket = 38; + + public static final int ZERO=0; + public static final int BLACK=1; + public static final int RED=2; + + // Set up a wheel. You call "spin", and then can check the result. + public Wheel() { + } + + // Cheat / test mode + void setSeed(long l) { + random.setSeed(l); + } + + // Spin the wheel onto a new random value. + public void spin() { + // keep spinning for a while + do { + try { + // 1 second delay. Where it stops, nobody knows + Thread.sleep(1000); + } + catch (InterruptedException e) {} + + pocket = random.nextInt(38) + 1; + } while (random.nextInt(4) > 0); // keep spinning until it stops + } + + // The string representation of the number; 1-36, 0, or 00 + public String value() { + if (pocket == 37) return "0"; + else if (pocket == 38) return "00"; + else return String.valueOf(pocket); + } + + // True if either 0 or 00 is hit + public boolean zero() { + return (pocket > 36); + } + + // True if anything other than 0 or 00 is hit + public boolean isNumber() { + return (pocket < 37); + } + + // The number rolled + public int number() { + if (zero()) return 0; + else return pocket; + } + + // Either ZERO, BLACK, or RED + public int color() { + if (zero()) return ZERO; + else if (black.contains(pocket)) return BLACK; + else return RED; + } +} From 3d46e147f553868eca2b6c854e4eeb106e77d250 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 11 Jan 2022 21:40:31 +0000 Subject: [PATCH 244/331] readme --- 75_Roulette/java/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/75_Roulette/java/README.md b/75_Roulette/java/README.md index 51edd8d4..2f9c97ca 100644 --- a/75_Roulette/java/README.md +++ b/75_Roulette/java/README.md @@ -1,3 +1,6 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Oracle Java](https://openjdk.java.net/) + +Conversion by Andrew McGuinness (andrew@arobeia.co.uk) + From 09b0e972cdf6b2cab7547396685569a0fc4364d4 Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Tue, 11 Jan 2022 17:00:28 -0500 Subject: [PATCH 245/331] Port 75_Roulette to Perl. The directory includes a Perl script to test the port (roulette-test.t) and a Perl script to generate the test based on output from the BASIC implementation (make-roulette-test.pl). --- 75_Roulette/perl/README.md | 12 + 75_Roulette/perl/make-roulette-test.pl | 263 ++++ 75_Roulette/perl/roulette-test.t | 1967 ++++++++++++++++++++++++ 75_Roulette/perl/roulette.pl | 319 ++++ 4 files changed, 2561 insertions(+) create mode 100755 75_Roulette/perl/make-roulette-test.pl create mode 100644 75_Roulette/perl/roulette-test.t create mode 100755 75_Roulette/perl/roulette.pl diff --git a/75_Roulette/perl/README.md b/75_Roulette/perl/README.md index e69c8b81..e7dcb811 100644 --- a/75_Roulette/perl/README.md +++ b/75_Roulette/perl/README.md @@ -1,3 +1,15 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +This conversion consists of three files in `75_Roulette/perl/`: + +- `roulette.pl` is the port of the BASIC to Perl; +- `roulette-test.t` is a Perl test for correctness of display and payout; +- `make-roulette-test.pl` generates roulette-test.t from roulette.bas. + +The ported version of the game numbers the slots from 0 rather than 1, and uses a dispatch table to figure out the payout. + +The Perl test loads `roulette.pl` and verifies the Perl slot display and payout logic against the BASIC for all combinations of slots and bets. If any tests fail that fact will be noted at the end of the output. + +The test code is generated by reading the BASIC, retaining only the slot display and payout logic (based on line numbers), and wrapping this in code that generates all combinations of bet and spin result. The result is run, and the result is captured and parsed to produce `roulette-test.t`. `make-roulette-test.pl` has some command-line options that may be of interest. `--help` will display the documentation. diff --git a/75_Roulette/perl/make-roulette-test.pl b/75_Roulette/perl/make-roulette-test.pl new file mode 100755 index 00000000..100fd8d7 --- /dev/null +++ b/75_Roulette/perl/make-roulette-test.pl @@ -0,0 +1,263 @@ +#!/usr/bin/env perl + +use 5.014; # For s///r + +use strict; +use warnings; + +use File::Temp; +use Getopt::Long 2.33 qw{ :config auto_version }; +use IPC::Cmd qw{ can_run }; # Core as of Perl 5.9.5. +use Pod::Usage; + +our $VERSION = '0.000_01'; + +my %opt = ( + program => find_basic(), + output => make_default_output(), +); + +GetOptions( \%opt, + qw{ output=s program=s }, + help => sub { pod2usage( { -verbose => 2 } ) }, +) or pod2usage( { -verbose => 0 } ); + +die "No default BASIC found; you must specify --program\n" + unless defined $opt{program}; + +my $game_dir = ( File::Spec->splitdir( $0 ) )[0]; +my $basic_file = File::Spec->catfile( $game_dir, 'roulette.bas' ); +open my $basic_handle, '<', $basic_file + or die "Unable to open $basic_file: $!\n"; + +my $munged = File::Temp->new(); + +print { $munged } <<'EOD'; +1000 Y=50 +1010 DIM B(100),C(100),T(100) +1090 FOR S=1 TO 38 +1095 PRINT "SPIN ";S +1100 FOR C=1 TO Y +1110 B(C)=1 +1120 T(C)=C +1130 NEXT C +EOD + +transcribe( $basic_file, $basic_handle, $munged, 1860, 2810 ); +transcribe( $basic_file, $basic_handle, $munged, 2950 ); + +say { $munged } '4000 NEXT S'; + +$munged->flush(); + +if ( $opt{output} ne '-' ) { + my $dir = ( File::Spec->splitpath( $0 ) )[1]; + my $fn = File::Spec->rel2abs( $opt{output}, $dir ); + $fn = File::Spec->abs2rel( $fn ); + open my $fh, '>', $fn + or die "Unable to open $fn: $!\n"; + warn "Writing $fn\n"; + select $fh; +} + +print <<'EOD'; +package main; + +use 5.010; + +use strict; +use warnings; + +use File::Spec; +use Test::More 0.88; # Because of done_testing(); + +EOD + +print <<"EOD"; +# NOTE: This file is generated by $0. +# Any edits made to it will be lost the next time it is regenerated. +# Caveat coder. + +EOD + +print <<'EOD'; +my $dir = ( File::Spec->splitpath( $0 ) )[1]; +my $script = File::Spec->catfile( $dir, 'roulette.pl' ); +{ + # Modern Perls do not have . in @INC, but we need it there to load a + # relative path. + local @INC = ( File::Spec->curdir(), @INC ); + require $script; # Load game as module +} + +EOD + +my $spin; +my $name; +foreach ( `$opt{program} @{[ $munged->filename() ]}` ) { + s/\N{U+1D}/ /smxg; # Artifact of the BASIC I'm using. + s/ \s+ \z //smx; + s/ \A \s+ //smx; + if ( $_ eq '' ) { + # Ignore empty lines. + } elsif ( m/ \A SPIN \s* ( [0-9]+ ) /smx ) { + $spin = $1 - 1; # BASIC is 1-based, but Perl is 0-based + } elsif ( m/ \A YOU \s+ WIN \s* ( [0-9]+ ) \s* + DOLLARS \s+ ON \s+ BET \s* ( [0-9]+ ) /smx ) { + say "is payout( $spin, $2 ), $1, 'Spin $spin ($name), bet $2 pays $1';"; + } elsif ( m/ \A YOU \s+ LOSE \s* ( [0-9]+ ) \s* + DOLLARS \s+ ON \s+ BET \s* ( [0-9]+ ) /smx ) { + say "is payout( $spin, $2 ), -$1, 'Spin $spin ($name), bet $2 pays -$1';"; + } elsif ( m/ \A \s* ( [0-9]+ ) (?: \s* ( [[:alpha:]]+ ) )? \z /smx ) { + $name = $2 ? sprintf( '%d %s', $1, ucfirst lc $2 ) : $1; + say "is format_spin( $spin ), '$name', 'Spin $spin is $name';"; + } else { + die "Unexpected input $_"; + } +} + +print <<'EOD'; + +done_testing; + +1; + +# ex: set textwidth=72 : +EOD + +sub find_basic { + # yabasic seems not to work + foreach my $prog ( qw{ basic cbmbasic } ) { + return $prog if can_run( $prog ) + } + return undef; +} + +sub make_default_output { + ( my $rslt = $0 ) =~ s/ [.] pl \z /.t/smx; + $rslt =~ s/ .* \b make- //smx; + return $rslt; +} + +sub transcribe { + my ( $in_file, $in_handle, $out_handle, $first_line, $last_line ) = @_; + $last_line //= $first_line; + + while ( <$in_handle> ) { + m/ \A \s* ( [0-9]+ )+ \s /smx + or next; + $1 < $first_line + and next; + say { $out_handle } sprintf '%04d REM BEGIN VERBATIM FROM %s', + $first_line - 10, $in_file; + print { $out_handle } $_; + last; + } + while ( <$in_handle> ) { + m/ \A \s* ( [0-9]+ )+ \s /smx + and $1 > $last_line + and last; + print { $out_handle } $_; + } + say { $out_handle } sprintf '%04d REM END VERBATIM FROM %s', + $last_line + 10, $in_file; + + return; +} + +__END__ + +=head1 TITLE + +make-roulette-test.pl - Generate the tests for 75_Roulette/perl/roulette.pl + +=head1 SYNOPSIS + + perl 75_Roulette/perl/make-roulette-test.pl + perl 75_Roulette/perl/make-roulette-test.pl --program mybasic + perl 75_Roulette/perl/make-roulette-test.pl --help + perl 75_Roulette/perl/make-roulette-test.pl --version + +=head1 OPTIONS + +<<< replace boiler plate >>> + +=head2 --help + +This option displays the documentation for this script. The script then +exits. + +=head2 --output + + --output fubar.t + +This option specifies the output file. This needs to be in the same +directory as F, and defaults to that directory. A single +dash (C<'-'>) is special-cased to send the output to standard out. + +The default is C<--output=test-roulette.t>. + +=head2 --program + + --program my_basic + +This option specifies the name of your BASIC interpreter. This must be +the name of an executable file in your PATH (aliases do not work). + +The default is the first-found in the list C. + +=head2 --version + +This option displays the version of this script. The script then exits. + +=head1 DETAILS + +This Perl script generates F, which tests +F. The latter is expected to be written as a modulino. + +This script assumes that: + +=over + +=item * it is in the same directory as F; + +=item * F is in the first-level subdirectory under the current directory; + +=back + +The generated test assumes that it is in the same directory as +F. + +This script works by abstracting the internals of F and +wrapping them in a loop that generates all possible spins, and places +all possible bets on each spin. The generated BASIC is written to a +temporary file, and executed by a BASIC interpreter. The output is +parsed and used to generate the output. + +Obviously there is some ad-hocery going on, and this script has only +been tested under C, which was what I had on hand. + +B the abstraction process is driven by BASIC line numbers. Any +change of these puts the ad-hocery at risk. + +=head1 AUTHOR + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set textwidth=72 : diff --git a/75_Roulette/perl/roulette-test.t b/75_Roulette/perl/roulette-test.t new file mode 100644 index 00000000..6fe43fa7 --- /dev/null +++ b/75_Roulette/perl/roulette-test.t @@ -0,0 +1,1967 @@ +package main; + +use 5.010; + +use strict; +use warnings; + +use File::Spec; +use Test::More 0.88; # Because of done_testing(); + +# NOTE: This file is generated by 75_Roulette/perl/make-roulette-test.pl. +# Any edits made to it will be lost the next time it is regenerated. +# Caveat coder. + +my $dir = ( File::Spec->splitpath( $0 ) )[1]; +my $script = File::Spec->catfile( $dir, 'roulette.pl' ); +{ + # Modern Perls do not have . in @INC, but we need it there to load a + # relative path. + local @INC = ( File::Spec->curdir(), @INC ); + require $script; # Load game as module +} + +is format_spin( 0 ), '1 Red', 'Spin 0 is 1 Red'; +is payout( 0, 1 ), 35, 'Spin 0 (1 Red), bet 1 pays 35'; +is payout( 0, 2 ), -1, 'Spin 0 (1 Red), bet 2 pays -1'; +is payout( 0, 3 ), -1, 'Spin 0 (1 Red), bet 3 pays -1'; +is payout( 0, 4 ), -1, 'Spin 0 (1 Red), bet 4 pays -1'; +is payout( 0, 5 ), -1, 'Spin 0 (1 Red), bet 5 pays -1'; +is payout( 0, 6 ), -1, 'Spin 0 (1 Red), bet 6 pays -1'; +is payout( 0, 7 ), -1, 'Spin 0 (1 Red), bet 7 pays -1'; +is payout( 0, 8 ), -1, 'Spin 0 (1 Red), bet 8 pays -1'; +is payout( 0, 9 ), -1, 'Spin 0 (1 Red), bet 9 pays -1'; +is payout( 0, 10 ), -1, 'Spin 0 (1 Red), bet 10 pays -1'; +is payout( 0, 11 ), -1, 'Spin 0 (1 Red), bet 11 pays -1'; +is payout( 0, 12 ), -1, 'Spin 0 (1 Red), bet 12 pays -1'; +is payout( 0, 13 ), -1, 'Spin 0 (1 Red), bet 13 pays -1'; +is payout( 0, 14 ), -1, 'Spin 0 (1 Red), bet 14 pays -1'; +is payout( 0, 15 ), -1, 'Spin 0 (1 Red), bet 15 pays -1'; +is payout( 0, 16 ), -1, 'Spin 0 (1 Red), bet 16 pays -1'; +is payout( 0, 17 ), -1, 'Spin 0 (1 Red), bet 17 pays -1'; +is payout( 0, 18 ), -1, 'Spin 0 (1 Red), bet 18 pays -1'; +is payout( 0, 19 ), -1, 'Spin 0 (1 Red), bet 19 pays -1'; +is payout( 0, 20 ), -1, 'Spin 0 (1 Red), bet 20 pays -1'; +is payout( 0, 21 ), -1, 'Spin 0 (1 Red), bet 21 pays -1'; +is payout( 0, 22 ), -1, 'Spin 0 (1 Red), bet 22 pays -1'; +is payout( 0, 23 ), -1, 'Spin 0 (1 Red), bet 23 pays -1'; +is payout( 0, 24 ), -1, 'Spin 0 (1 Red), bet 24 pays -1'; +is payout( 0, 25 ), -1, 'Spin 0 (1 Red), bet 25 pays -1'; +is payout( 0, 26 ), -1, 'Spin 0 (1 Red), bet 26 pays -1'; +is payout( 0, 27 ), -1, 'Spin 0 (1 Red), bet 27 pays -1'; +is payout( 0, 28 ), -1, 'Spin 0 (1 Red), bet 28 pays -1'; +is payout( 0, 29 ), -1, 'Spin 0 (1 Red), bet 29 pays -1'; +is payout( 0, 30 ), -1, 'Spin 0 (1 Red), bet 30 pays -1'; +is payout( 0, 31 ), -1, 'Spin 0 (1 Red), bet 31 pays -1'; +is payout( 0, 32 ), -1, 'Spin 0 (1 Red), bet 32 pays -1'; +is payout( 0, 33 ), -1, 'Spin 0 (1 Red), bet 33 pays -1'; +is payout( 0, 34 ), -1, 'Spin 0 (1 Red), bet 34 pays -1'; +is payout( 0, 35 ), -1, 'Spin 0 (1 Red), bet 35 pays -1'; +is payout( 0, 36 ), -1, 'Spin 0 (1 Red), bet 36 pays -1'; +is payout( 0, 37 ), 2, 'Spin 0 (1 Red), bet 37 pays 2'; +is payout( 0, 38 ), -1, 'Spin 0 (1 Red), bet 38 pays -1'; +is payout( 0, 39 ), -1, 'Spin 0 (1 Red), bet 39 pays -1'; +is payout( 0, 40 ), 2, 'Spin 0 (1 Red), bet 40 pays 2'; +is payout( 0, 41 ), -1, 'Spin 0 (1 Red), bet 41 pays -1'; +is payout( 0, 42 ), -1, 'Spin 0 (1 Red), bet 42 pays -1'; +is payout( 0, 43 ), 1, 'Spin 0 (1 Red), bet 43 pays 1'; +is payout( 0, 44 ), -1, 'Spin 0 (1 Red), bet 44 pays -1'; +is payout( 0, 45 ), -1, 'Spin 0 (1 Red), bet 45 pays -1'; +is payout( 0, 46 ), 1, 'Spin 0 (1 Red), bet 46 pays 1'; +is payout( 0, 47 ), 1, 'Spin 0 (1 Red), bet 47 pays 1'; +is payout( 0, 48 ), -1, 'Spin 0 (1 Red), bet 48 pays -1'; +is payout( 0, 49 ), -1, 'Spin 0 (1 Red), bet 49 pays -1'; +is payout( 0, 50 ), -1, 'Spin 0 (1 Red), bet 50 pays -1'; +is format_spin( 1 ), '2 Black', 'Spin 1 is 2 Black'; +is payout( 1, 1 ), -1, 'Spin 1 (2 Black), bet 1 pays -1'; +is payout( 1, 2 ), 35, 'Spin 1 (2 Black), bet 2 pays 35'; +is payout( 1, 3 ), -1, 'Spin 1 (2 Black), bet 3 pays -1'; +is payout( 1, 4 ), -1, 'Spin 1 (2 Black), bet 4 pays -1'; +is payout( 1, 5 ), -1, 'Spin 1 (2 Black), bet 5 pays -1'; +is payout( 1, 6 ), -1, 'Spin 1 (2 Black), bet 6 pays -1'; +is payout( 1, 7 ), -1, 'Spin 1 (2 Black), bet 7 pays -1'; +is payout( 1, 8 ), -1, 'Spin 1 (2 Black), bet 8 pays -1'; +is payout( 1, 9 ), -1, 'Spin 1 (2 Black), bet 9 pays -1'; +is payout( 1, 10 ), -1, 'Spin 1 (2 Black), bet 10 pays -1'; +is payout( 1, 11 ), -1, 'Spin 1 (2 Black), bet 11 pays -1'; +is payout( 1, 12 ), -1, 'Spin 1 (2 Black), bet 12 pays -1'; +is payout( 1, 13 ), -1, 'Spin 1 (2 Black), bet 13 pays -1'; +is payout( 1, 14 ), -1, 'Spin 1 (2 Black), bet 14 pays -1'; +is payout( 1, 15 ), -1, 'Spin 1 (2 Black), bet 15 pays -1'; +is payout( 1, 16 ), -1, 'Spin 1 (2 Black), bet 16 pays -1'; +is payout( 1, 17 ), -1, 'Spin 1 (2 Black), bet 17 pays -1'; +is payout( 1, 18 ), -1, 'Spin 1 (2 Black), bet 18 pays -1'; +is payout( 1, 19 ), -1, 'Spin 1 (2 Black), bet 19 pays -1'; +is payout( 1, 20 ), -1, 'Spin 1 (2 Black), bet 20 pays -1'; +is payout( 1, 21 ), -1, 'Spin 1 (2 Black), bet 21 pays -1'; +is payout( 1, 22 ), -1, 'Spin 1 (2 Black), bet 22 pays -1'; +is payout( 1, 23 ), -1, 'Spin 1 (2 Black), bet 23 pays -1'; +is payout( 1, 24 ), -1, 'Spin 1 (2 Black), bet 24 pays -1'; +is payout( 1, 25 ), -1, 'Spin 1 (2 Black), bet 25 pays -1'; +is payout( 1, 26 ), -1, 'Spin 1 (2 Black), bet 26 pays -1'; +is payout( 1, 27 ), -1, 'Spin 1 (2 Black), bet 27 pays -1'; +is payout( 1, 28 ), -1, 'Spin 1 (2 Black), bet 28 pays -1'; +is payout( 1, 29 ), -1, 'Spin 1 (2 Black), bet 29 pays -1'; +is payout( 1, 30 ), -1, 'Spin 1 (2 Black), bet 30 pays -1'; +is payout( 1, 31 ), -1, 'Spin 1 (2 Black), bet 31 pays -1'; +is payout( 1, 32 ), -1, 'Spin 1 (2 Black), bet 32 pays -1'; +is payout( 1, 33 ), -1, 'Spin 1 (2 Black), bet 33 pays -1'; +is payout( 1, 34 ), -1, 'Spin 1 (2 Black), bet 34 pays -1'; +is payout( 1, 35 ), -1, 'Spin 1 (2 Black), bet 35 pays -1'; +is payout( 1, 36 ), -1, 'Spin 1 (2 Black), bet 36 pays -1'; +is payout( 1, 37 ), 2, 'Spin 1 (2 Black), bet 37 pays 2'; +is payout( 1, 38 ), -1, 'Spin 1 (2 Black), bet 38 pays -1'; +is payout( 1, 39 ), -1, 'Spin 1 (2 Black), bet 39 pays -1'; +is payout( 1, 40 ), -1, 'Spin 1 (2 Black), bet 40 pays -1'; +is payout( 1, 41 ), 2, 'Spin 1 (2 Black), bet 41 pays 2'; +is payout( 1, 42 ), -1, 'Spin 1 (2 Black), bet 42 pays -1'; +is payout( 1, 43 ), 1, 'Spin 1 (2 Black), bet 43 pays 1'; +is payout( 1, 44 ), -1, 'Spin 1 (2 Black), bet 44 pays -1'; +is payout( 1, 45 ), 1, 'Spin 1 (2 Black), bet 45 pays 1'; +is payout( 1, 46 ), -1, 'Spin 1 (2 Black), bet 46 pays -1'; +is payout( 1, 47 ), -1, 'Spin 1 (2 Black), bet 47 pays -1'; +is payout( 1, 48 ), 1, 'Spin 1 (2 Black), bet 48 pays 1'; +is payout( 1, 49 ), -1, 'Spin 1 (2 Black), bet 49 pays -1'; +is payout( 1, 50 ), -1, 'Spin 1 (2 Black), bet 50 pays -1'; +is format_spin( 2 ), '3 Red', 'Spin 2 is 3 Red'; +is payout( 2, 1 ), -1, 'Spin 2 (3 Red), bet 1 pays -1'; +is payout( 2, 2 ), -1, 'Spin 2 (3 Red), bet 2 pays -1'; +is payout( 2, 3 ), 35, 'Spin 2 (3 Red), bet 3 pays 35'; +is payout( 2, 4 ), -1, 'Spin 2 (3 Red), bet 4 pays -1'; +is payout( 2, 5 ), -1, 'Spin 2 (3 Red), bet 5 pays -1'; +is payout( 2, 6 ), -1, 'Spin 2 (3 Red), bet 6 pays -1'; +is payout( 2, 7 ), -1, 'Spin 2 (3 Red), bet 7 pays -1'; +is payout( 2, 8 ), -1, 'Spin 2 (3 Red), bet 8 pays -1'; +is payout( 2, 9 ), -1, 'Spin 2 (3 Red), bet 9 pays -1'; +is payout( 2, 10 ), -1, 'Spin 2 (3 Red), bet 10 pays -1'; +is payout( 2, 11 ), -1, 'Spin 2 (3 Red), bet 11 pays -1'; +is payout( 2, 12 ), -1, 'Spin 2 (3 Red), bet 12 pays -1'; +is payout( 2, 13 ), -1, 'Spin 2 (3 Red), bet 13 pays -1'; +is payout( 2, 14 ), -1, 'Spin 2 (3 Red), bet 14 pays -1'; +is payout( 2, 15 ), -1, 'Spin 2 (3 Red), bet 15 pays -1'; +is payout( 2, 16 ), -1, 'Spin 2 (3 Red), bet 16 pays -1'; +is payout( 2, 17 ), -1, 'Spin 2 (3 Red), bet 17 pays -1'; +is payout( 2, 18 ), -1, 'Spin 2 (3 Red), bet 18 pays -1'; +is payout( 2, 19 ), -1, 'Spin 2 (3 Red), bet 19 pays -1'; +is payout( 2, 20 ), -1, 'Spin 2 (3 Red), bet 20 pays -1'; +is payout( 2, 21 ), -1, 'Spin 2 (3 Red), bet 21 pays -1'; +is payout( 2, 22 ), -1, 'Spin 2 (3 Red), bet 22 pays -1'; +is payout( 2, 23 ), -1, 'Spin 2 (3 Red), bet 23 pays -1'; +is payout( 2, 24 ), -1, 'Spin 2 (3 Red), bet 24 pays -1'; +is payout( 2, 25 ), -1, 'Spin 2 (3 Red), bet 25 pays -1'; +is payout( 2, 26 ), -1, 'Spin 2 (3 Red), bet 26 pays -1'; +is payout( 2, 27 ), -1, 'Spin 2 (3 Red), bet 27 pays -1'; +is payout( 2, 28 ), -1, 'Spin 2 (3 Red), bet 28 pays -1'; +is payout( 2, 29 ), -1, 'Spin 2 (3 Red), bet 29 pays -1'; +is payout( 2, 30 ), -1, 'Spin 2 (3 Red), bet 30 pays -1'; +is payout( 2, 31 ), -1, 'Spin 2 (3 Red), bet 31 pays -1'; +is payout( 2, 32 ), -1, 'Spin 2 (3 Red), bet 32 pays -1'; +is payout( 2, 33 ), -1, 'Spin 2 (3 Red), bet 33 pays -1'; +is payout( 2, 34 ), -1, 'Spin 2 (3 Red), bet 34 pays -1'; +is payout( 2, 35 ), -1, 'Spin 2 (3 Red), bet 35 pays -1'; +is payout( 2, 36 ), -1, 'Spin 2 (3 Red), bet 36 pays -1'; +is payout( 2, 37 ), 2, 'Spin 2 (3 Red), bet 37 pays 2'; +is payout( 2, 38 ), -1, 'Spin 2 (3 Red), bet 38 pays -1'; +is payout( 2, 39 ), -1, 'Spin 2 (3 Red), bet 39 pays -1'; +is payout( 2, 40 ), -1, 'Spin 2 (3 Red), bet 40 pays -1'; +is payout( 2, 41 ), -1, 'Spin 2 (3 Red), bet 41 pays -1'; +is payout( 2, 42 ), 2, 'Spin 2 (3 Red), bet 42 pays 2'; +is payout( 2, 43 ), 1, 'Spin 2 (3 Red), bet 43 pays 1'; +is payout( 2, 44 ), -1, 'Spin 2 (3 Red), bet 44 pays -1'; +is payout( 2, 45 ), -1, 'Spin 2 (3 Red), bet 45 pays -1'; +is payout( 2, 46 ), 1, 'Spin 2 (3 Red), bet 46 pays 1'; +is payout( 2, 47 ), 1, 'Spin 2 (3 Red), bet 47 pays 1'; +is payout( 2, 48 ), -1, 'Spin 2 (3 Red), bet 48 pays -1'; +is payout( 2, 49 ), -1, 'Spin 2 (3 Red), bet 49 pays -1'; +is payout( 2, 50 ), -1, 'Spin 2 (3 Red), bet 50 pays -1'; +is format_spin( 3 ), '4 Black', 'Spin 3 is 4 Black'; +is payout( 3, 1 ), -1, 'Spin 3 (4 Black), bet 1 pays -1'; +is payout( 3, 2 ), -1, 'Spin 3 (4 Black), bet 2 pays -1'; +is payout( 3, 3 ), -1, 'Spin 3 (4 Black), bet 3 pays -1'; +is payout( 3, 4 ), 35, 'Spin 3 (4 Black), bet 4 pays 35'; +is payout( 3, 5 ), -1, 'Spin 3 (4 Black), bet 5 pays -1'; +is payout( 3, 6 ), -1, 'Spin 3 (4 Black), bet 6 pays -1'; +is payout( 3, 7 ), -1, 'Spin 3 (4 Black), bet 7 pays -1'; +is payout( 3, 8 ), -1, 'Spin 3 (4 Black), bet 8 pays -1'; +is payout( 3, 9 ), -1, 'Spin 3 (4 Black), bet 9 pays -1'; +is payout( 3, 10 ), -1, 'Spin 3 (4 Black), bet 10 pays -1'; +is payout( 3, 11 ), -1, 'Spin 3 (4 Black), bet 11 pays -1'; +is payout( 3, 12 ), -1, 'Spin 3 (4 Black), bet 12 pays -1'; +is payout( 3, 13 ), -1, 'Spin 3 (4 Black), bet 13 pays -1'; +is payout( 3, 14 ), -1, 'Spin 3 (4 Black), bet 14 pays -1'; +is payout( 3, 15 ), -1, 'Spin 3 (4 Black), bet 15 pays -1'; +is payout( 3, 16 ), -1, 'Spin 3 (4 Black), bet 16 pays -1'; +is payout( 3, 17 ), -1, 'Spin 3 (4 Black), bet 17 pays -1'; +is payout( 3, 18 ), -1, 'Spin 3 (4 Black), bet 18 pays -1'; +is payout( 3, 19 ), -1, 'Spin 3 (4 Black), bet 19 pays -1'; +is payout( 3, 20 ), -1, 'Spin 3 (4 Black), bet 20 pays -1'; +is payout( 3, 21 ), -1, 'Spin 3 (4 Black), bet 21 pays -1'; +is payout( 3, 22 ), -1, 'Spin 3 (4 Black), bet 22 pays -1'; +is payout( 3, 23 ), -1, 'Spin 3 (4 Black), bet 23 pays -1'; +is payout( 3, 24 ), -1, 'Spin 3 (4 Black), bet 24 pays -1'; +is payout( 3, 25 ), -1, 'Spin 3 (4 Black), bet 25 pays -1'; +is payout( 3, 26 ), -1, 'Spin 3 (4 Black), bet 26 pays -1'; +is payout( 3, 27 ), -1, 'Spin 3 (4 Black), bet 27 pays -1'; +is payout( 3, 28 ), -1, 'Spin 3 (4 Black), bet 28 pays -1'; +is payout( 3, 29 ), -1, 'Spin 3 (4 Black), bet 29 pays -1'; +is payout( 3, 30 ), -1, 'Spin 3 (4 Black), bet 30 pays -1'; +is payout( 3, 31 ), -1, 'Spin 3 (4 Black), bet 31 pays -1'; +is payout( 3, 32 ), -1, 'Spin 3 (4 Black), bet 32 pays -1'; +is payout( 3, 33 ), -1, 'Spin 3 (4 Black), bet 33 pays -1'; +is payout( 3, 34 ), -1, 'Spin 3 (4 Black), bet 34 pays -1'; +is payout( 3, 35 ), -1, 'Spin 3 (4 Black), bet 35 pays -1'; +is payout( 3, 36 ), -1, 'Spin 3 (4 Black), bet 36 pays -1'; +is payout( 3, 37 ), 2, 'Spin 3 (4 Black), bet 37 pays 2'; +is payout( 3, 38 ), -1, 'Spin 3 (4 Black), bet 38 pays -1'; +is payout( 3, 39 ), -1, 'Spin 3 (4 Black), bet 39 pays -1'; +is payout( 3, 40 ), 2, 'Spin 3 (4 Black), bet 40 pays 2'; +is payout( 3, 41 ), -1, 'Spin 3 (4 Black), bet 41 pays -1'; +is payout( 3, 42 ), -1, 'Spin 3 (4 Black), bet 42 pays -1'; +is payout( 3, 43 ), 1, 'Spin 3 (4 Black), bet 43 pays 1'; +is payout( 3, 44 ), -1, 'Spin 3 (4 Black), bet 44 pays -1'; +is payout( 3, 45 ), 1, 'Spin 3 (4 Black), bet 45 pays 1'; +is payout( 3, 46 ), -1, 'Spin 3 (4 Black), bet 46 pays -1'; +is payout( 3, 47 ), -1, 'Spin 3 (4 Black), bet 47 pays -1'; +is payout( 3, 48 ), 1, 'Spin 3 (4 Black), bet 48 pays 1'; +is payout( 3, 49 ), -1, 'Spin 3 (4 Black), bet 49 pays -1'; +is payout( 3, 50 ), -1, 'Spin 3 (4 Black), bet 50 pays -1'; +is format_spin( 4 ), '5 Red', 'Spin 4 is 5 Red'; +is payout( 4, 1 ), -1, 'Spin 4 (5 Red), bet 1 pays -1'; +is payout( 4, 2 ), -1, 'Spin 4 (5 Red), bet 2 pays -1'; +is payout( 4, 3 ), -1, 'Spin 4 (5 Red), bet 3 pays -1'; +is payout( 4, 4 ), -1, 'Spin 4 (5 Red), bet 4 pays -1'; +is payout( 4, 5 ), 35, 'Spin 4 (5 Red), bet 5 pays 35'; +is payout( 4, 6 ), -1, 'Spin 4 (5 Red), bet 6 pays -1'; +is payout( 4, 7 ), -1, 'Spin 4 (5 Red), bet 7 pays -1'; +is payout( 4, 8 ), -1, 'Spin 4 (5 Red), bet 8 pays -1'; +is payout( 4, 9 ), -1, 'Spin 4 (5 Red), bet 9 pays -1'; +is payout( 4, 10 ), -1, 'Spin 4 (5 Red), bet 10 pays -1'; +is payout( 4, 11 ), -1, 'Spin 4 (5 Red), bet 11 pays -1'; +is payout( 4, 12 ), -1, 'Spin 4 (5 Red), bet 12 pays -1'; +is payout( 4, 13 ), -1, 'Spin 4 (5 Red), bet 13 pays -1'; +is payout( 4, 14 ), -1, 'Spin 4 (5 Red), bet 14 pays -1'; +is payout( 4, 15 ), -1, 'Spin 4 (5 Red), bet 15 pays -1'; +is payout( 4, 16 ), -1, 'Spin 4 (5 Red), bet 16 pays -1'; +is payout( 4, 17 ), -1, 'Spin 4 (5 Red), bet 17 pays -1'; +is payout( 4, 18 ), -1, 'Spin 4 (5 Red), bet 18 pays -1'; +is payout( 4, 19 ), -1, 'Spin 4 (5 Red), bet 19 pays -1'; +is payout( 4, 20 ), -1, 'Spin 4 (5 Red), bet 20 pays -1'; +is payout( 4, 21 ), -1, 'Spin 4 (5 Red), bet 21 pays -1'; +is payout( 4, 22 ), -1, 'Spin 4 (5 Red), bet 22 pays -1'; +is payout( 4, 23 ), -1, 'Spin 4 (5 Red), bet 23 pays -1'; +is payout( 4, 24 ), -1, 'Spin 4 (5 Red), bet 24 pays -1'; +is payout( 4, 25 ), -1, 'Spin 4 (5 Red), bet 25 pays -1'; +is payout( 4, 26 ), -1, 'Spin 4 (5 Red), bet 26 pays -1'; +is payout( 4, 27 ), -1, 'Spin 4 (5 Red), bet 27 pays -1'; +is payout( 4, 28 ), -1, 'Spin 4 (5 Red), bet 28 pays -1'; +is payout( 4, 29 ), -1, 'Spin 4 (5 Red), bet 29 pays -1'; +is payout( 4, 30 ), -1, 'Spin 4 (5 Red), bet 30 pays -1'; +is payout( 4, 31 ), -1, 'Spin 4 (5 Red), bet 31 pays -1'; +is payout( 4, 32 ), -1, 'Spin 4 (5 Red), bet 32 pays -1'; +is payout( 4, 33 ), -1, 'Spin 4 (5 Red), bet 33 pays -1'; +is payout( 4, 34 ), -1, 'Spin 4 (5 Red), bet 34 pays -1'; +is payout( 4, 35 ), -1, 'Spin 4 (5 Red), bet 35 pays -1'; +is payout( 4, 36 ), -1, 'Spin 4 (5 Red), bet 36 pays -1'; +is payout( 4, 37 ), 2, 'Spin 4 (5 Red), bet 37 pays 2'; +is payout( 4, 38 ), -1, 'Spin 4 (5 Red), bet 38 pays -1'; +is payout( 4, 39 ), -1, 'Spin 4 (5 Red), bet 39 pays -1'; +is payout( 4, 40 ), -1, 'Spin 4 (5 Red), bet 40 pays -1'; +is payout( 4, 41 ), 2, 'Spin 4 (5 Red), bet 41 pays 2'; +is payout( 4, 42 ), -1, 'Spin 4 (5 Red), bet 42 pays -1'; +is payout( 4, 43 ), 1, 'Spin 4 (5 Red), bet 43 pays 1'; +is payout( 4, 44 ), -1, 'Spin 4 (5 Red), bet 44 pays -1'; +is payout( 4, 45 ), -1, 'Spin 4 (5 Red), bet 45 pays -1'; +is payout( 4, 46 ), 1, 'Spin 4 (5 Red), bet 46 pays 1'; +is payout( 4, 47 ), 1, 'Spin 4 (5 Red), bet 47 pays 1'; +is payout( 4, 48 ), -1, 'Spin 4 (5 Red), bet 48 pays -1'; +is payout( 4, 49 ), -1, 'Spin 4 (5 Red), bet 49 pays -1'; +is payout( 4, 50 ), -1, 'Spin 4 (5 Red), bet 50 pays -1'; +is format_spin( 5 ), '6 Black', 'Spin 5 is 6 Black'; +is payout( 5, 1 ), -1, 'Spin 5 (6 Black), bet 1 pays -1'; +is payout( 5, 2 ), -1, 'Spin 5 (6 Black), bet 2 pays -1'; +is payout( 5, 3 ), -1, 'Spin 5 (6 Black), bet 3 pays -1'; +is payout( 5, 4 ), -1, 'Spin 5 (6 Black), bet 4 pays -1'; +is payout( 5, 5 ), -1, 'Spin 5 (6 Black), bet 5 pays -1'; +is payout( 5, 6 ), 35, 'Spin 5 (6 Black), bet 6 pays 35'; +is payout( 5, 7 ), -1, 'Spin 5 (6 Black), bet 7 pays -1'; +is payout( 5, 8 ), -1, 'Spin 5 (6 Black), bet 8 pays -1'; +is payout( 5, 9 ), -1, 'Spin 5 (6 Black), bet 9 pays -1'; +is payout( 5, 10 ), -1, 'Spin 5 (6 Black), bet 10 pays -1'; +is payout( 5, 11 ), -1, 'Spin 5 (6 Black), bet 11 pays -1'; +is payout( 5, 12 ), -1, 'Spin 5 (6 Black), bet 12 pays -1'; +is payout( 5, 13 ), -1, 'Spin 5 (6 Black), bet 13 pays -1'; +is payout( 5, 14 ), -1, 'Spin 5 (6 Black), bet 14 pays -1'; +is payout( 5, 15 ), -1, 'Spin 5 (6 Black), bet 15 pays -1'; +is payout( 5, 16 ), -1, 'Spin 5 (6 Black), bet 16 pays -1'; +is payout( 5, 17 ), -1, 'Spin 5 (6 Black), bet 17 pays -1'; +is payout( 5, 18 ), -1, 'Spin 5 (6 Black), bet 18 pays -1'; +is payout( 5, 19 ), -1, 'Spin 5 (6 Black), bet 19 pays -1'; +is payout( 5, 20 ), -1, 'Spin 5 (6 Black), bet 20 pays -1'; +is payout( 5, 21 ), -1, 'Spin 5 (6 Black), bet 21 pays -1'; +is payout( 5, 22 ), -1, 'Spin 5 (6 Black), bet 22 pays -1'; +is payout( 5, 23 ), -1, 'Spin 5 (6 Black), bet 23 pays -1'; +is payout( 5, 24 ), -1, 'Spin 5 (6 Black), bet 24 pays -1'; +is payout( 5, 25 ), -1, 'Spin 5 (6 Black), bet 25 pays -1'; +is payout( 5, 26 ), -1, 'Spin 5 (6 Black), bet 26 pays -1'; +is payout( 5, 27 ), -1, 'Spin 5 (6 Black), bet 27 pays -1'; +is payout( 5, 28 ), -1, 'Spin 5 (6 Black), bet 28 pays -1'; +is payout( 5, 29 ), -1, 'Spin 5 (6 Black), bet 29 pays -1'; +is payout( 5, 30 ), -1, 'Spin 5 (6 Black), bet 30 pays -1'; +is payout( 5, 31 ), -1, 'Spin 5 (6 Black), bet 31 pays -1'; +is payout( 5, 32 ), -1, 'Spin 5 (6 Black), bet 32 pays -1'; +is payout( 5, 33 ), -1, 'Spin 5 (6 Black), bet 33 pays -1'; +is payout( 5, 34 ), -1, 'Spin 5 (6 Black), bet 34 pays -1'; +is payout( 5, 35 ), -1, 'Spin 5 (6 Black), bet 35 pays -1'; +is payout( 5, 36 ), -1, 'Spin 5 (6 Black), bet 36 pays -1'; +is payout( 5, 37 ), 2, 'Spin 5 (6 Black), bet 37 pays 2'; +is payout( 5, 38 ), -1, 'Spin 5 (6 Black), bet 38 pays -1'; +is payout( 5, 39 ), -1, 'Spin 5 (6 Black), bet 39 pays -1'; +is payout( 5, 40 ), -1, 'Spin 5 (6 Black), bet 40 pays -1'; +is payout( 5, 41 ), -1, 'Spin 5 (6 Black), bet 41 pays -1'; +is payout( 5, 42 ), 2, 'Spin 5 (6 Black), bet 42 pays 2'; +is payout( 5, 43 ), 1, 'Spin 5 (6 Black), bet 43 pays 1'; +is payout( 5, 44 ), -1, 'Spin 5 (6 Black), bet 44 pays -1'; +is payout( 5, 45 ), 1, 'Spin 5 (6 Black), bet 45 pays 1'; +is payout( 5, 46 ), -1, 'Spin 5 (6 Black), bet 46 pays -1'; +is payout( 5, 47 ), -1, 'Spin 5 (6 Black), bet 47 pays -1'; +is payout( 5, 48 ), 1, 'Spin 5 (6 Black), bet 48 pays 1'; +is payout( 5, 49 ), -1, 'Spin 5 (6 Black), bet 49 pays -1'; +is payout( 5, 50 ), -1, 'Spin 5 (6 Black), bet 50 pays -1'; +is format_spin( 6 ), '7 Red', 'Spin 6 is 7 Red'; +is payout( 6, 1 ), -1, 'Spin 6 (7 Red), bet 1 pays -1'; +is payout( 6, 2 ), -1, 'Spin 6 (7 Red), bet 2 pays -1'; +is payout( 6, 3 ), -1, 'Spin 6 (7 Red), bet 3 pays -1'; +is payout( 6, 4 ), -1, 'Spin 6 (7 Red), bet 4 pays -1'; +is payout( 6, 5 ), -1, 'Spin 6 (7 Red), bet 5 pays -1'; +is payout( 6, 6 ), -1, 'Spin 6 (7 Red), bet 6 pays -1'; +is payout( 6, 7 ), 35, 'Spin 6 (7 Red), bet 7 pays 35'; +is payout( 6, 8 ), -1, 'Spin 6 (7 Red), bet 8 pays -1'; +is payout( 6, 9 ), -1, 'Spin 6 (7 Red), bet 9 pays -1'; +is payout( 6, 10 ), -1, 'Spin 6 (7 Red), bet 10 pays -1'; +is payout( 6, 11 ), -1, 'Spin 6 (7 Red), bet 11 pays -1'; +is payout( 6, 12 ), -1, 'Spin 6 (7 Red), bet 12 pays -1'; +is payout( 6, 13 ), -1, 'Spin 6 (7 Red), bet 13 pays -1'; +is payout( 6, 14 ), -1, 'Spin 6 (7 Red), bet 14 pays -1'; +is payout( 6, 15 ), -1, 'Spin 6 (7 Red), bet 15 pays -1'; +is payout( 6, 16 ), -1, 'Spin 6 (7 Red), bet 16 pays -1'; +is payout( 6, 17 ), -1, 'Spin 6 (7 Red), bet 17 pays -1'; +is payout( 6, 18 ), -1, 'Spin 6 (7 Red), bet 18 pays -1'; +is payout( 6, 19 ), -1, 'Spin 6 (7 Red), bet 19 pays -1'; +is payout( 6, 20 ), -1, 'Spin 6 (7 Red), bet 20 pays -1'; +is payout( 6, 21 ), -1, 'Spin 6 (7 Red), bet 21 pays -1'; +is payout( 6, 22 ), -1, 'Spin 6 (7 Red), bet 22 pays -1'; +is payout( 6, 23 ), -1, 'Spin 6 (7 Red), bet 23 pays -1'; +is payout( 6, 24 ), -1, 'Spin 6 (7 Red), bet 24 pays -1'; +is payout( 6, 25 ), -1, 'Spin 6 (7 Red), bet 25 pays -1'; +is payout( 6, 26 ), -1, 'Spin 6 (7 Red), bet 26 pays -1'; +is payout( 6, 27 ), -1, 'Spin 6 (7 Red), bet 27 pays -1'; +is payout( 6, 28 ), -1, 'Spin 6 (7 Red), bet 28 pays -1'; +is payout( 6, 29 ), -1, 'Spin 6 (7 Red), bet 29 pays -1'; +is payout( 6, 30 ), -1, 'Spin 6 (7 Red), bet 30 pays -1'; +is payout( 6, 31 ), -1, 'Spin 6 (7 Red), bet 31 pays -1'; +is payout( 6, 32 ), -1, 'Spin 6 (7 Red), bet 32 pays -1'; +is payout( 6, 33 ), -1, 'Spin 6 (7 Red), bet 33 pays -1'; +is payout( 6, 34 ), -1, 'Spin 6 (7 Red), bet 34 pays -1'; +is payout( 6, 35 ), -1, 'Spin 6 (7 Red), bet 35 pays -1'; +is payout( 6, 36 ), -1, 'Spin 6 (7 Red), bet 36 pays -1'; +is payout( 6, 37 ), 2, 'Spin 6 (7 Red), bet 37 pays 2'; +is payout( 6, 38 ), -1, 'Spin 6 (7 Red), bet 38 pays -1'; +is payout( 6, 39 ), -1, 'Spin 6 (7 Red), bet 39 pays -1'; +is payout( 6, 40 ), 2, 'Spin 6 (7 Red), bet 40 pays 2'; +is payout( 6, 41 ), -1, 'Spin 6 (7 Red), bet 41 pays -1'; +is payout( 6, 42 ), -1, 'Spin 6 (7 Red), bet 42 pays -1'; +is payout( 6, 43 ), 1, 'Spin 6 (7 Red), bet 43 pays 1'; +is payout( 6, 44 ), -1, 'Spin 6 (7 Red), bet 44 pays -1'; +is payout( 6, 45 ), -1, 'Spin 6 (7 Red), bet 45 pays -1'; +is payout( 6, 46 ), 1, 'Spin 6 (7 Red), bet 46 pays 1'; +is payout( 6, 47 ), 1, 'Spin 6 (7 Red), bet 47 pays 1'; +is payout( 6, 48 ), -1, 'Spin 6 (7 Red), bet 48 pays -1'; +is payout( 6, 49 ), -1, 'Spin 6 (7 Red), bet 49 pays -1'; +is payout( 6, 50 ), -1, 'Spin 6 (7 Red), bet 50 pays -1'; +is format_spin( 7 ), '8 Black', 'Spin 7 is 8 Black'; +is payout( 7, 1 ), -1, 'Spin 7 (8 Black), bet 1 pays -1'; +is payout( 7, 2 ), -1, 'Spin 7 (8 Black), bet 2 pays -1'; +is payout( 7, 3 ), -1, 'Spin 7 (8 Black), bet 3 pays -1'; +is payout( 7, 4 ), -1, 'Spin 7 (8 Black), bet 4 pays -1'; +is payout( 7, 5 ), -1, 'Spin 7 (8 Black), bet 5 pays -1'; +is payout( 7, 6 ), -1, 'Spin 7 (8 Black), bet 6 pays -1'; +is payout( 7, 7 ), -1, 'Spin 7 (8 Black), bet 7 pays -1'; +is payout( 7, 8 ), 35, 'Spin 7 (8 Black), bet 8 pays 35'; +is payout( 7, 9 ), -1, 'Spin 7 (8 Black), bet 9 pays -1'; +is payout( 7, 10 ), -1, 'Spin 7 (8 Black), bet 10 pays -1'; +is payout( 7, 11 ), -1, 'Spin 7 (8 Black), bet 11 pays -1'; +is payout( 7, 12 ), -1, 'Spin 7 (8 Black), bet 12 pays -1'; +is payout( 7, 13 ), -1, 'Spin 7 (8 Black), bet 13 pays -1'; +is payout( 7, 14 ), -1, 'Spin 7 (8 Black), bet 14 pays -1'; +is payout( 7, 15 ), -1, 'Spin 7 (8 Black), bet 15 pays -1'; +is payout( 7, 16 ), -1, 'Spin 7 (8 Black), bet 16 pays -1'; +is payout( 7, 17 ), -1, 'Spin 7 (8 Black), bet 17 pays -1'; +is payout( 7, 18 ), -1, 'Spin 7 (8 Black), bet 18 pays -1'; +is payout( 7, 19 ), -1, 'Spin 7 (8 Black), bet 19 pays -1'; +is payout( 7, 20 ), -1, 'Spin 7 (8 Black), bet 20 pays -1'; +is payout( 7, 21 ), -1, 'Spin 7 (8 Black), bet 21 pays -1'; +is payout( 7, 22 ), -1, 'Spin 7 (8 Black), bet 22 pays -1'; +is payout( 7, 23 ), -1, 'Spin 7 (8 Black), bet 23 pays -1'; +is payout( 7, 24 ), -1, 'Spin 7 (8 Black), bet 24 pays -1'; +is payout( 7, 25 ), -1, 'Spin 7 (8 Black), bet 25 pays -1'; +is payout( 7, 26 ), -1, 'Spin 7 (8 Black), bet 26 pays -1'; +is payout( 7, 27 ), -1, 'Spin 7 (8 Black), bet 27 pays -1'; +is payout( 7, 28 ), -1, 'Spin 7 (8 Black), bet 28 pays -1'; +is payout( 7, 29 ), -1, 'Spin 7 (8 Black), bet 29 pays -1'; +is payout( 7, 30 ), -1, 'Spin 7 (8 Black), bet 30 pays -1'; +is payout( 7, 31 ), -1, 'Spin 7 (8 Black), bet 31 pays -1'; +is payout( 7, 32 ), -1, 'Spin 7 (8 Black), bet 32 pays -1'; +is payout( 7, 33 ), -1, 'Spin 7 (8 Black), bet 33 pays -1'; +is payout( 7, 34 ), -1, 'Spin 7 (8 Black), bet 34 pays -1'; +is payout( 7, 35 ), -1, 'Spin 7 (8 Black), bet 35 pays -1'; +is payout( 7, 36 ), -1, 'Spin 7 (8 Black), bet 36 pays -1'; +is payout( 7, 37 ), 2, 'Spin 7 (8 Black), bet 37 pays 2'; +is payout( 7, 38 ), -1, 'Spin 7 (8 Black), bet 38 pays -1'; +is payout( 7, 39 ), -1, 'Spin 7 (8 Black), bet 39 pays -1'; +is payout( 7, 40 ), -1, 'Spin 7 (8 Black), bet 40 pays -1'; +is payout( 7, 41 ), 2, 'Spin 7 (8 Black), bet 41 pays 2'; +is payout( 7, 42 ), -1, 'Spin 7 (8 Black), bet 42 pays -1'; +is payout( 7, 43 ), 1, 'Spin 7 (8 Black), bet 43 pays 1'; +is payout( 7, 44 ), -1, 'Spin 7 (8 Black), bet 44 pays -1'; +is payout( 7, 45 ), 1, 'Spin 7 (8 Black), bet 45 pays 1'; +is payout( 7, 46 ), -1, 'Spin 7 (8 Black), bet 46 pays -1'; +is payout( 7, 47 ), -1, 'Spin 7 (8 Black), bet 47 pays -1'; +is payout( 7, 48 ), 1, 'Spin 7 (8 Black), bet 48 pays 1'; +is payout( 7, 49 ), -1, 'Spin 7 (8 Black), bet 49 pays -1'; +is payout( 7, 50 ), -1, 'Spin 7 (8 Black), bet 50 pays -1'; +is format_spin( 8 ), '9 Red', 'Spin 8 is 9 Red'; +is payout( 8, 1 ), -1, 'Spin 8 (9 Red), bet 1 pays -1'; +is payout( 8, 2 ), -1, 'Spin 8 (9 Red), bet 2 pays -1'; +is payout( 8, 3 ), -1, 'Spin 8 (9 Red), bet 3 pays -1'; +is payout( 8, 4 ), -1, 'Spin 8 (9 Red), bet 4 pays -1'; +is payout( 8, 5 ), -1, 'Spin 8 (9 Red), bet 5 pays -1'; +is payout( 8, 6 ), -1, 'Spin 8 (9 Red), bet 6 pays -1'; +is payout( 8, 7 ), -1, 'Spin 8 (9 Red), bet 7 pays -1'; +is payout( 8, 8 ), -1, 'Spin 8 (9 Red), bet 8 pays -1'; +is payout( 8, 9 ), 35, 'Spin 8 (9 Red), bet 9 pays 35'; +is payout( 8, 10 ), -1, 'Spin 8 (9 Red), bet 10 pays -1'; +is payout( 8, 11 ), -1, 'Spin 8 (9 Red), bet 11 pays -1'; +is payout( 8, 12 ), -1, 'Spin 8 (9 Red), bet 12 pays -1'; +is payout( 8, 13 ), -1, 'Spin 8 (9 Red), bet 13 pays -1'; +is payout( 8, 14 ), -1, 'Spin 8 (9 Red), bet 14 pays -1'; +is payout( 8, 15 ), -1, 'Spin 8 (9 Red), bet 15 pays -1'; +is payout( 8, 16 ), -1, 'Spin 8 (9 Red), bet 16 pays -1'; +is payout( 8, 17 ), -1, 'Spin 8 (9 Red), bet 17 pays -1'; +is payout( 8, 18 ), -1, 'Spin 8 (9 Red), bet 18 pays -1'; +is payout( 8, 19 ), -1, 'Spin 8 (9 Red), bet 19 pays -1'; +is payout( 8, 20 ), -1, 'Spin 8 (9 Red), bet 20 pays -1'; +is payout( 8, 21 ), -1, 'Spin 8 (9 Red), bet 21 pays -1'; +is payout( 8, 22 ), -1, 'Spin 8 (9 Red), bet 22 pays -1'; +is payout( 8, 23 ), -1, 'Spin 8 (9 Red), bet 23 pays -1'; +is payout( 8, 24 ), -1, 'Spin 8 (9 Red), bet 24 pays -1'; +is payout( 8, 25 ), -1, 'Spin 8 (9 Red), bet 25 pays -1'; +is payout( 8, 26 ), -1, 'Spin 8 (9 Red), bet 26 pays -1'; +is payout( 8, 27 ), -1, 'Spin 8 (9 Red), bet 27 pays -1'; +is payout( 8, 28 ), -1, 'Spin 8 (9 Red), bet 28 pays -1'; +is payout( 8, 29 ), -1, 'Spin 8 (9 Red), bet 29 pays -1'; +is payout( 8, 30 ), -1, 'Spin 8 (9 Red), bet 30 pays -1'; +is payout( 8, 31 ), -1, 'Spin 8 (9 Red), bet 31 pays -1'; +is payout( 8, 32 ), -1, 'Spin 8 (9 Red), bet 32 pays -1'; +is payout( 8, 33 ), -1, 'Spin 8 (9 Red), bet 33 pays -1'; +is payout( 8, 34 ), -1, 'Spin 8 (9 Red), bet 34 pays -1'; +is payout( 8, 35 ), -1, 'Spin 8 (9 Red), bet 35 pays -1'; +is payout( 8, 36 ), -1, 'Spin 8 (9 Red), bet 36 pays -1'; +is payout( 8, 37 ), 2, 'Spin 8 (9 Red), bet 37 pays 2'; +is payout( 8, 38 ), -1, 'Spin 8 (9 Red), bet 38 pays -1'; +is payout( 8, 39 ), -1, 'Spin 8 (9 Red), bet 39 pays -1'; +is payout( 8, 40 ), -1, 'Spin 8 (9 Red), bet 40 pays -1'; +is payout( 8, 41 ), -1, 'Spin 8 (9 Red), bet 41 pays -1'; +is payout( 8, 42 ), 2, 'Spin 8 (9 Red), bet 42 pays 2'; +is payout( 8, 43 ), 1, 'Spin 8 (9 Red), bet 43 pays 1'; +is payout( 8, 44 ), -1, 'Spin 8 (9 Red), bet 44 pays -1'; +is payout( 8, 45 ), -1, 'Spin 8 (9 Red), bet 45 pays -1'; +is payout( 8, 46 ), 1, 'Spin 8 (9 Red), bet 46 pays 1'; +is payout( 8, 47 ), 1, 'Spin 8 (9 Red), bet 47 pays 1'; +is payout( 8, 48 ), -1, 'Spin 8 (9 Red), bet 48 pays -1'; +is payout( 8, 49 ), -1, 'Spin 8 (9 Red), bet 49 pays -1'; +is payout( 8, 50 ), -1, 'Spin 8 (9 Red), bet 50 pays -1'; +is format_spin( 9 ), '10 Black', 'Spin 9 is 10 Black'; +is payout( 9, 1 ), -1, 'Spin 9 (10 Black), bet 1 pays -1'; +is payout( 9, 2 ), -1, 'Spin 9 (10 Black), bet 2 pays -1'; +is payout( 9, 3 ), -1, 'Spin 9 (10 Black), bet 3 pays -1'; +is payout( 9, 4 ), -1, 'Spin 9 (10 Black), bet 4 pays -1'; +is payout( 9, 5 ), -1, 'Spin 9 (10 Black), bet 5 pays -1'; +is payout( 9, 6 ), -1, 'Spin 9 (10 Black), bet 6 pays -1'; +is payout( 9, 7 ), -1, 'Spin 9 (10 Black), bet 7 pays -1'; +is payout( 9, 8 ), -1, 'Spin 9 (10 Black), bet 8 pays -1'; +is payout( 9, 9 ), -1, 'Spin 9 (10 Black), bet 9 pays -1'; +is payout( 9, 10 ), 35, 'Spin 9 (10 Black), bet 10 pays 35'; +is payout( 9, 11 ), -1, 'Spin 9 (10 Black), bet 11 pays -1'; +is payout( 9, 12 ), -1, 'Spin 9 (10 Black), bet 12 pays -1'; +is payout( 9, 13 ), -1, 'Spin 9 (10 Black), bet 13 pays -1'; +is payout( 9, 14 ), -1, 'Spin 9 (10 Black), bet 14 pays -1'; +is payout( 9, 15 ), -1, 'Spin 9 (10 Black), bet 15 pays -1'; +is payout( 9, 16 ), -1, 'Spin 9 (10 Black), bet 16 pays -1'; +is payout( 9, 17 ), -1, 'Spin 9 (10 Black), bet 17 pays -1'; +is payout( 9, 18 ), -1, 'Spin 9 (10 Black), bet 18 pays -1'; +is payout( 9, 19 ), -1, 'Spin 9 (10 Black), bet 19 pays -1'; +is payout( 9, 20 ), -1, 'Spin 9 (10 Black), bet 20 pays -1'; +is payout( 9, 21 ), -1, 'Spin 9 (10 Black), bet 21 pays -1'; +is payout( 9, 22 ), -1, 'Spin 9 (10 Black), bet 22 pays -1'; +is payout( 9, 23 ), -1, 'Spin 9 (10 Black), bet 23 pays -1'; +is payout( 9, 24 ), -1, 'Spin 9 (10 Black), bet 24 pays -1'; +is payout( 9, 25 ), -1, 'Spin 9 (10 Black), bet 25 pays -1'; +is payout( 9, 26 ), -1, 'Spin 9 (10 Black), bet 26 pays -1'; +is payout( 9, 27 ), -1, 'Spin 9 (10 Black), bet 27 pays -1'; +is payout( 9, 28 ), -1, 'Spin 9 (10 Black), bet 28 pays -1'; +is payout( 9, 29 ), -1, 'Spin 9 (10 Black), bet 29 pays -1'; +is payout( 9, 30 ), -1, 'Spin 9 (10 Black), bet 30 pays -1'; +is payout( 9, 31 ), -1, 'Spin 9 (10 Black), bet 31 pays -1'; +is payout( 9, 32 ), -1, 'Spin 9 (10 Black), bet 32 pays -1'; +is payout( 9, 33 ), -1, 'Spin 9 (10 Black), bet 33 pays -1'; +is payout( 9, 34 ), -1, 'Spin 9 (10 Black), bet 34 pays -1'; +is payout( 9, 35 ), -1, 'Spin 9 (10 Black), bet 35 pays -1'; +is payout( 9, 36 ), -1, 'Spin 9 (10 Black), bet 36 pays -1'; +is payout( 9, 37 ), 2, 'Spin 9 (10 Black), bet 37 pays 2'; +is payout( 9, 38 ), -1, 'Spin 9 (10 Black), bet 38 pays -1'; +is payout( 9, 39 ), -1, 'Spin 9 (10 Black), bet 39 pays -1'; +is payout( 9, 40 ), 2, 'Spin 9 (10 Black), bet 40 pays 2'; +is payout( 9, 41 ), -1, 'Spin 9 (10 Black), bet 41 pays -1'; +is payout( 9, 42 ), -1, 'Spin 9 (10 Black), bet 42 pays -1'; +is payout( 9, 43 ), 1, 'Spin 9 (10 Black), bet 43 pays 1'; +is payout( 9, 44 ), -1, 'Spin 9 (10 Black), bet 44 pays -1'; +is payout( 9, 45 ), 1, 'Spin 9 (10 Black), bet 45 pays 1'; +is payout( 9, 46 ), -1, 'Spin 9 (10 Black), bet 46 pays -1'; +is payout( 9, 47 ), -1, 'Spin 9 (10 Black), bet 47 pays -1'; +is payout( 9, 48 ), 1, 'Spin 9 (10 Black), bet 48 pays 1'; +is payout( 9, 49 ), -1, 'Spin 9 (10 Black), bet 49 pays -1'; +is payout( 9, 50 ), -1, 'Spin 9 (10 Black), bet 50 pays -1'; +is format_spin( 10 ), '11 Black', 'Spin 10 is 11 Black'; +is payout( 10, 1 ), -1, 'Spin 10 (11 Black), bet 1 pays -1'; +is payout( 10, 2 ), -1, 'Spin 10 (11 Black), bet 2 pays -1'; +is payout( 10, 3 ), -1, 'Spin 10 (11 Black), bet 3 pays -1'; +is payout( 10, 4 ), -1, 'Spin 10 (11 Black), bet 4 pays -1'; +is payout( 10, 5 ), -1, 'Spin 10 (11 Black), bet 5 pays -1'; +is payout( 10, 6 ), -1, 'Spin 10 (11 Black), bet 6 pays -1'; +is payout( 10, 7 ), -1, 'Spin 10 (11 Black), bet 7 pays -1'; +is payout( 10, 8 ), -1, 'Spin 10 (11 Black), bet 8 pays -1'; +is payout( 10, 9 ), -1, 'Spin 10 (11 Black), bet 9 pays -1'; +is payout( 10, 10 ), -1, 'Spin 10 (11 Black), bet 10 pays -1'; +is payout( 10, 11 ), 35, 'Spin 10 (11 Black), bet 11 pays 35'; +is payout( 10, 12 ), -1, 'Spin 10 (11 Black), bet 12 pays -1'; +is payout( 10, 13 ), -1, 'Spin 10 (11 Black), bet 13 pays -1'; +is payout( 10, 14 ), -1, 'Spin 10 (11 Black), bet 14 pays -1'; +is payout( 10, 15 ), -1, 'Spin 10 (11 Black), bet 15 pays -1'; +is payout( 10, 16 ), -1, 'Spin 10 (11 Black), bet 16 pays -1'; +is payout( 10, 17 ), -1, 'Spin 10 (11 Black), bet 17 pays -1'; +is payout( 10, 18 ), -1, 'Spin 10 (11 Black), bet 18 pays -1'; +is payout( 10, 19 ), -1, 'Spin 10 (11 Black), bet 19 pays -1'; +is payout( 10, 20 ), -1, 'Spin 10 (11 Black), bet 20 pays -1'; +is payout( 10, 21 ), -1, 'Spin 10 (11 Black), bet 21 pays -1'; +is payout( 10, 22 ), -1, 'Spin 10 (11 Black), bet 22 pays -1'; +is payout( 10, 23 ), -1, 'Spin 10 (11 Black), bet 23 pays -1'; +is payout( 10, 24 ), -1, 'Spin 10 (11 Black), bet 24 pays -1'; +is payout( 10, 25 ), -1, 'Spin 10 (11 Black), bet 25 pays -1'; +is payout( 10, 26 ), -1, 'Spin 10 (11 Black), bet 26 pays -1'; +is payout( 10, 27 ), -1, 'Spin 10 (11 Black), bet 27 pays -1'; +is payout( 10, 28 ), -1, 'Spin 10 (11 Black), bet 28 pays -1'; +is payout( 10, 29 ), -1, 'Spin 10 (11 Black), bet 29 pays -1'; +is payout( 10, 30 ), -1, 'Spin 10 (11 Black), bet 30 pays -1'; +is payout( 10, 31 ), -1, 'Spin 10 (11 Black), bet 31 pays -1'; +is payout( 10, 32 ), -1, 'Spin 10 (11 Black), bet 32 pays -1'; +is payout( 10, 33 ), -1, 'Spin 10 (11 Black), bet 33 pays -1'; +is payout( 10, 34 ), -1, 'Spin 10 (11 Black), bet 34 pays -1'; +is payout( 10, 35 ), -1, 'Spin 10 (11 Black), bet 35 pays -1'; +is payout( 10, 36 ), -1, 'Spin 10 (11 Black), bet 36 pays -1'; +is payout( 10, 37 ), 2, 'Spin 10 (11 Black), bet 37 pays 2'; +is payout( 10, 38 ), -1, 'Spin 10 (11 Black), bet 38 pays -1'; +is payout( 10, 39 ), -1, 'Spin 10 (11 Black), bet 39 pays -1'; +is payout( 10, 40 ), -1, 'Spin 10 (11 Black), bet 40 pays -1'; +is payout( 10, 41 ), 2, 'Spin 10 (11 Black), bet 41 pays 2'; +is payout( 10, 42 ), -1, 'Spin 10 (11 Black), bet 42 pays -1'; +is payout( 10, 43 ), 1, 'Spin 10 (11 Black), bet 43 pays 1'; +is payout( 10, 44 ), -1, 'Spin 10 (11 Black), bet 44 pays -1'; +is payout( 10, 45 ), -1, 'Spin 10 (11 Black), bet 45 pays -1'; +is payout( 10, 46 ), 1, 'Spin 10 (11 Black), bet 46 pays 1'; +is payout( 10, 47 ), -1, 'Spin 10 (11 Black), bet 47 pays -1'; +is payout( 10, 48 ), 1, 'Spin 10 (11 Black), bet 48 pays 1'; +is payout( 10, 49 ), -1, 'Spin 10 (11 Black), bet 49 pays -1'; +is payout( 10, 50 ), -1, 'Spin 10 (11 Black), bet 50 pays -1'; +is format_spin( 11 ), '12 Red', 'Spin 11 is 12 Red'; +is payout( 11, 1 ), -1, 'Spin 11 (12 Red), bet 1 pays -1'; +is payout( 11, 2 ), -1, 'Spin 11 (12 Red), bet 2 pays -1'; +is payout( 11, 3 ), -1, 'Spin 11 (12 Red), bet 3 pays -1'; +is payout( 11, 4 ), -1, 'Spin 11 (12 Red), bet 4 pays -1'; +is payout( 11, 5 ), -1, 'Spin 11 (12 Red), bet 5 pays -1'; +is payout( 11, 6 ), -1, 'Spin 11 (12 Red), bet 6 pays -1'; +is payout( 11, 7 ), -1, 'Spin 11 (12 Red), bet 7 pays -1'; +is payout( 11, 8 ), -1, 'Spin 11 (12 Red), bet 8 pays -1'; +is payout( 11, 9 ), -1, 'Spin 11 (12 Red), bet 9 pays -1'; +is payout( 11, 10 ), -1, 'Spin 11 (12 Red), bet 10 pays -1'; +is payout( 11, 11 ), -1, 'Spin 11 (12 Red), bet 11 pays -1'; +is payout( 11, 12 ), 35, 'Spin 11 (12 Red), bet 12 pays 35'; +is payout( 11, 13 ), -1, 'Spin 11 (12 Red), bet 13 pays -1'; +is payout( 11, 14 ), -1, 'Spin 11 (12 Red), bet 14 pays -1'; +is payout( 11, 15 ), -1, 'Spin 11 (12 Red), bet 15 pays -1'; +is payout( 11, 16 ), -1, 'Spin 11 (12 Red), bet 16 pays -1'; +is payout( 11, 17 ), -1, 'Spin 11 (12 Red), bet 17 pays -1'; +is payout( 11, 18 ), -1, 'Spin 11 (12 Red), bet 18 pays -1'; +is payout( 11, 19 ), -1, 'Spin 11 (12 Red), bet 19 pays -1'; +is payout( 11, 20 ), -1, 'Spin 11 (12 Red), bet 20 pays -1'; +is payout( 11, 21 ), -1, 'Spin 11 (12 Red), bet 21 pays -1'; +is payout( 11, 22 ), -1, 'Spin 11 (12 Red), bet 22 pays -1'; +is payout( 11, 23 ), -1, 'Spin 11 (12 Red), bet 23 pays -1'; +is payout( 11, 24 ), -1, 'Spin 11 (12 Red), bet 24 pays -1'; +is payout( 11, 25 ), -1, 'Spin 11 (12 Red), bet 25 pays -1'; +is payout( 11, 26 ), -1, 'Spin 11 (12 Red), bet 26 pays -1'; +is payout( 11, 27 ), -1, 'Spin 11 (12 Red), bet 27 pays -1'; +is payout( 11, 28 ), -1, 'Spin 11 (12 Red), bet 28 pays -1'; +is payout( 11, 29 ), -1, 'Spin 11 (12 Red), bet 29 pays -1'; +is payout( 11, 30 ), -1, 'Spin 11 (12 Red), bet 30 pays -1'; +is payout( 11, 31 ), -1, 'Spin 11 (12 Red), bet 31 pays -1'; +is payout( 11, 32 ), -1, 'Spin 11 (12 Red), bet 32 pays -1'; +is payout( 11, 33 ), -1, 'Spin 11 (12 Red), bet 33 pays -1'; +is payout( 11, 34 ), -1, 'Spin 11 (12 Red), bet 34 pays -1'; +is payout( 11, 35 ), -1, 'Spin 11 (12 Red), bet 35 pays -1'; +is payout( 11, 36 ), -1, 'Spin 11 (12 Red), bet 36 pays -1'; +is payout( 11, 37 ), 2, 'Spin 11 (12 Red), bet 37 pays 2'; +is payout( 11, 38 ), -1, 'Spin 11 (12 Red), bet 38 pays -1'; +is payout( 11, 39 ), -1, 'Spin 11 (12 Red), bet 39 pays -1'; +is payout( 11, 40 ), -1, 'Spin 11 (12 Red), bet 40 pays -1'; +is payout( 11, 41 ), -1, 'Spin 11 (12 Red), bet 41 pays -1'; +is payout( 11, 42 ), 2, 'Spin 11 (12 Red), bet 42 pays 2'; +is payout( 11, 43 ), 1, 'Spin 11 (12 Red), bet 43 pays 1'; +is payout( 11, 44 ), -1, 'Spin 11 (12 Red), bet 44 pays -1'; +is payout( 11, 45 ), 1, 'Spin 11 (12 Red), bet 45 pays 1'; +is payout( 11, 46 ), -1, 'Spin 11 (12 Red), bet 46 pays -1'; +is payout( 11, 47 ), 1, 'Spin 11 (12 Red), bet 47 pays 1'; +is payout( 11, 48 ), -1, 'Spin 11 (12 Red), bet 48 pays -1'; +is payout( 11, 49 ), -1, 'Spin 11 (12 Red), bet 49 pays -1'; +is payout( 11, 50 ), -1, 'Spin 11 (12 Red), bet 50 pays -1'; +is format_spin( 12 ), '13 Black', 'Spin 12 is 13 Black'; +is payout( 12, 1 ), -1, 'Spin 12 (13 Black), bet 1 pays -1'; +is payout( 12, 2 ), -1, 'Spin 12 (13 Black), bet 2 pays -1'; +is payout( 12, 3 ), -1, 'Spin 12 (13 Black), bet 3 pays -1'; +is payout( 12, 4 ), -1, 'Spin 12 (13 Black), bet 4 pays -1'; +is payout( 12, 5 ), -1, 'Spin 12 (13 Black), bet 5 pays -1'; +is payout( 12, 6 ), -1, 'Spin 12 (13 Black), bet 6 pays -1'; +is payout( 12, 7 ), -1, 'Spin 12 (13 Black), bet 7 pays -1'; +is payout( 12, 8 ), -1, 'Spin 12 (13 Black), bet 8 pays -1'; +is payout( 12, 9 ), -1, 'Spin 12 (13 Black), bet 9 pays -1'; +is payout( 12, 10 ), -1, 'Spin 12 (13 Black), bet 10 pays -1'; +is payout( 12, 11 ), -1, 'Spin 12 (13 Black), bet 11 pays -1'; +is payout( 12, 12 ), -1, 'Spin 12 (13 Black), bet 12 pays -1'; +is payout( 12, 13 ), 35, 'Spin 12 (13 Black), bet 13 pays 35'; +is payout( 12, 14 ), -1, 'Spin 12 (13 Black), bet 14 pays -1'; +is payout( 12, 15 ), -1, 'Spin 12 (13 Black), bet 15 pays -1'; +is payout( 12, 16 ), -1, 'Spin 12 (13 Black), bet 16 pays -1'; +is payout( 12, 17 ), -1, 'Spin 12 (13 Black), bet 17 pays -1'; +is payout( 12, 18 ), -1, 'Spin 12 (13 Black), bet 18 pays -1'; +is payout( 12, 19 ), -1, 'Spin 12 (13 Black), bet 19 pays -1'; +is payout( 12, 20 ), -1, 'Spin 12 (13 Black), bet 20 pays -1'; +is payout( 12, 21 ), -1, 'Spin 12 (13 Black), bet 21 pays -1'; +is payout( 12, 22 ), -1, 'Spin 12 (13 Black), bet 22 pays -1'; +is payout( 12, 23 ), -1, 'Spin 12 (13 Black), bet 23 pays -1'; +is payout( 12, 24 ), -1, 'Spin 12 (13 Black), bet 24 pays -1'; +is payout( 12, 25 ), -1, 'Spin 12 (13 Black), bet 25 pays -1'; +is payout( 12, 26 ), -1, 'Spin 12 (13 Black), bet 26 pays -1'; +is payout( 12, 27 ), -1, 'Spin 12 (13 Black), bet 27 pays -1'; +is payout( 12, 28 ), -1, 'Spin 12 (13 Black), bet 28 pays -1'; +is payout( 12, 29 ), -1, 'Spin 12 (13 Black), bet 29 pays -1'; +is payout( 12, 30 ), -1, 'Spin 12 (13 Black), bet 30 pays -1'; +is payout( 12, 31 ), -1, 'Spin 12 (13 Black), bet 31 pays -1'; +is payout( 12, 32 ), -1, 'Spin 12 (13 Black), bet 32 pays -1'; +is payout( 12, 33 ), -1, 'Spin 12 (13 Black), bet 33 pays -1'; +is payout( 12, 34 ), -1, 'Spin 12 (13 Black), bet 34 pays -1'; +is payout( 12, 35 ), -1, 'Spin 12 (13 Black), bet 35 pays -1'; +is payout( 12, 36 ), -1, 'Spin 12 (13 Black), bet 36 pays -1'; +is payout( 12, 37 ), -1, 'Spin 12 (13 Black), bet 37 pays -1'; +is payout( 12, 38 ), 2, 'Spin 12 (13 Black), bet 38 pays 2'; +is payout( 12, 39 ), -1, 'Spin 12 (13 Black), bet 39 pays -1'; +is payout( 12, 40 ), 2, 'Spin 12 (13 Black), bet 40 pays 2'; +is payout( 12, 41 ), -1, 'Spin 12 (13 Black), bet 41 pays -1'; +is payout( 12, 42 ), -1, 'Spin 12 (13 Black), bet 42 pays -1'; +is payout( 12, 43 ), 1, 'Spin 12 (13 Black), bet 43 pays 1'; +is payout( 12, 44 ), -1, 'Spin 12 (13 Black), bet 44 pays -1'; +is payout( 12, 45 ), -1, 'Spin 12 (13 Black), bet 45 pays -1'; +is payout( 12, 46 ), 1, 'Spin 12 (13 Black), bet 46 pays 1'; +is payout( 12, 47 ), -1, 'Spin 12 (13 Black), bet 47 pays -1'; +is payout( 12, 48 ), 1, 'Spin 12 (13 Black), bet 48 pays 1'; +is payout( 12, 49 ), -1, 'Spin 12 (13 Black), bet 49 pays -1'; +is payout( 12, 50 ), -1, 'Spin 12 (13 Black), bet 50 pays -1'; +is format_spin( 13 ), '14 Red', 'Spin 13 is 14 Red'; +is payout( 13, 1 ), -1, 'Spin 13 (14 Red), bet 1 pays -1'; +is payout( 13, 2 ), -1, 'Spin 13 (14 Red), bet 2 pays -1'; +is payout( 13, 3 ), -1, 'Spin 13 (14 Red), bet 3 pays -1'; +is payout( 13, 4 ), -1, 'Spin 13 (14 Red), bet 4 pays -1'; +is payout( 13, 5 ), -1, 'Spin 13 (14 Red), bet 5 pays -1'; +is payout( 13, 6 ), -1, 'Spin 13 (14 Red), bet 6 pays -1'; +is payout( 13, 7 ), -1, 'Spin 13 (14 Red), bet 7 pays -1'; +is payout( 13, 8 ), -1, 'Spin 13 (14 Red), bet 8 pays -1'; +is payout( 13, 9 ), -1, 'Spin 13 (14 Red), bet 9 pays -1'; +is payout( 13, 10 ), -1, 'Spin 13 (14 Red), bet 10 pays -1'; +is payout( 13, 11 ), -1, 'Spin 13 (14 Red), bet 11 pays -1'; +is payout( 13, 12 ), -1, 'Spin 13 (14 Red), bet 12 pays -1'; +is payout( 13, 13 ), -1, 'Spin 13 (14 Red), bet 13 pays -1'; +is payout( 13, 14 ), 35, 'Spin 13 (14 Red), bet 14 pays 35'; +is payout( 13, 15 ), -1, 'Spin 13 (14 Red), bet 15 pays -1'; +is payout( 13, 16 ), -1, 'Spin 13 (14 Red), bet 16 pays -1'; +is payout( 13, 17 ), -1, 'Spin 13 (14 Red), bet 17 pays -1'; +is payout( 13, 18 ), -1, 'Spin 13 (14 Red), bet 18 pays -1'; +is payout( 13, 19 ), -1, 'Spin 13 (14 Red), bet 19 pays -1'; +is payout( 13, 20 ), -1, 'Spin 13 (14 Red), bet 20 pays -1'; +is payout( 13, 21 ), -1, 'Spin 13 (14 Red), bet 21 pays -1'; +is payout( 13, 22 ), -1, 'Spin 13 (14 Red), bet 22 pays -1'; +is payout( 13, 23 ), -1, 'Spin 13 (14 Red), bet 23 pays -1'; +is payout( 13, 24 ), -1, 'Spin 13 (14 Red), bet 24 pays -1'; +is payout( 13, 25 ), -1, 'Spin 13 (14 Red), bet 25 pays -1'; +is payout( 13, 26 ), -1, 'Spin 13 (14 Red), bet 26 pays -1'; +is payout( 13, 27 ), -1, 'Spin 13 (14 Red), bet 27 pays -1'; +is payout( 13, 28 ), -1, 'Spin 13 (14 Red), bet 28 pays -1'; +is payout( 13, 29 ), -1, 'Spin 13 (14 Red), bet 29 pays -1'; +is payout( 13, 30 ), -1, 'Spin 13 (14 Red), bet 30 pays -1'; +is payout( 13, 31 ), -1, 'Spin 13 (14 Red), bet 31 pays -1'; +is payout( 13, 32 ), -1, 'Spin 13 (14 Red), bet 32 pays -1'; +is payout( 13, 33 ), -1, 'Spin 13 (14 Red), bet 33 pays -1'; +is payout( 13, 34 ), -1, 'Spin 13 (14 Red), bet 34 pays -1'; +is payout( 13, 35 ), -1, 'Spin 13 (14 Red), bet 35 pays -1'; +is payout( 13, 36 ), -1, 'Spin 13 (14 Red), bet 36 pays -1'; +is payout( 13, 37 ), -1, 'Spin 13 (14 Red), bet 37 pays -1'; +is payout( 13, 38 ), 2, 'Spin 13 (14 Red), bet 38 pays 2'; +is payout( 13, 39 ), -1, 'Spin 13 (14 Red), bet 39 pays -1'; +is payout( 13, 40 ), -1, 'Spin 13 (14 Red), bet 40 pays -1'; +is payout( 13, 41 ), 2, 'Spin 13 (14 Red), bet 41 pays 2'; +is payout( 13, 42 ), -1, 'Spin 13 (14 Red), bet 42 pays -1'; +is payout( 13, 43 ), 1, 'Spin 13 (14 Red), bet 43 pays 1'; +is payout( 13, 44 ), -1, 'Spin 13 (14 Red), bet 44 pays -1'; +is payout( 13, 45 ), 1, 'Spin 13 (14 Red), bet 45 pays 1'; +is payout( 13, 46 ), -1, 'Spin 13 (14 Red), bet 46 pays -1'; +is payout( 13, 47 ), 1, 'Spin 13 (14 Red), bet 47 pays 1'; +is payout( 13, 48 ), -1, 'Spin 13 (14 Red), bet 48 pays -1'; +is payout( 13, 49 ), -1, 'Spin 13 (14 Red), bet 49 pays -1'; +is payout( 13, 50 ), -1, 'Spin 13 (14 Red), bet 50 pays -1'; +is format_spin( 14 ), '15 Black', 'Spin 14 is 15 Black'; +is payout( 14, 1 ), -1, 'Spin 14 (15 Black), bet 1 pays -1'; +is payout( 14, 2 ), -1, 'Spin 14 (15 Black), bet 2 pays -1'; +is payout( 14, 3 ), -1, 'Spin 14 (15 Black), bet 3 pays -1'; +is payout( 14, 4 ), -1, 'Spin 14 (15 Black), bet 4 pays -1'; +is payout( 14, 5 ), -1, 'Spin 14 (15 Black), bet 5 pays -1'; +is payout( 14, 6 ), -1, 'Spin 14 (15 Black), bet 6 pays -1'; +is payout( 14, 7 ), -1, 'Spin 14 (15 Black), bet 7 pays -1'; +is payout( 14, 8 ), -1, 'Spin 14 (15 Black), bet 8 pays -1'; +is payout( 14, 9 ), -1, 'Spin 14 (15 Black), bet 9 pays -1'; +is payout( 14, 10 ), -1, 'Spin 14 (15 Black), bet 10 pays -1'; +is payout( 14, 11 ), -1, 'Spin 14 (15 Black), bet 11 pays -1'; +is payout( 14, 12 ), -1, 'Spin 14 (15 Black), bet 12 pays -1'; +is payout( 14, 13 ), -1, 'Spin 14 (15 Black), bet 13 pays -1'; +is payout( 14, 14 ), -1, 'Spin 14 (15 Black), bet 14 pays -1'; +is payout( 14, 15 ), 35, 'Spin 14 (15 Black), bet 15 pays 35'; +is payout( 14, 16 ), -1, 'Spin 14 (15 Black), bet 16 pays -1'; +is payout( 14, 17 ), -1, 'Spin 14 (15 Black), bet 17 pays -1'; +is payout( 14, 18 ), -1, 'Spin 14 (15 Black), bet 18 pays -1'; +is payout( 14, 19 ), -1, 'Spin 14 (15 Black), bet 19 pays -1'; +is payout( 14, 20 ), -1, 'Spin 14 (15 Black), bet 20 pays -1'; +is payout( 14, 21 ), -1, 'Spin 14 (15 Black), bet 21 pays -1'; +is payout( 14, 22 ), -1, 'Spin 14 (15 Black), bet 22 pays -1'; +is payout( 14, 23 ), -1, 'Spin 14 (15 Black), bet 23 pays -1'; +is payout( 14, 24 ), -1, 'Spin 14 (15 Black), bet 24 pays -1'; +is payout( 14, 25 ), -1, 'Spin 14 (15 Black), bet 25 pays -1'; +is payout( 14, 26 ), -1, 'Spin 14 (15 Black), bet 26 pays -1'; +is payout( 14, 27 ), -1, 'Spin 14 (15 Black), bet 27 pays -1'; +is payout( 14, 28 ), -1, 'Spin 14 (15 Black), bet 28 pays -1'; +is payout( 14, 29 ), -1, 'Spin 14 (15 Black), bet 29 pays -1'; +is payout( 14, 30 ), -1, 'Spin 14 (15 Black), bet 30 pays -1'; +is payout( 14, 31 ), -1, 'Spin 14 (15 Black), bet 31 pays -1'; +is payout( 14, 32 ), -1, 'Spin 14 (15 Black), bet 32 pays -1'; +is payout( 14, 33 ), -1, 'Spin 14 (15 Black), bet 33 pays -1'; +is payout( 14, 34 ), -1, 'Spin 14 (15 Black), bet 34 pays -1'; +is payout( 14, 35 ), -1, 'Spin 14 (15 Black), bet 35 pays -1'; +is payout( 14, 36 ), -1, 'Spin 14 (15 Black), bet 36 pays -1'; +is payout( 14, 37 ), -1, 'Spin 14 (15 Black), bet 37 pays -1'; +is payout( 14, 38 ), 2, 'Spin 14 (15 Black), bet 38 pays 2'; +is payout( 14, 39 ), -1, 'Spin 14 (15 Black), bet 39 pays -1'; +is payout( 14, 40 ), -1, 'Spin 14 (15 Black), bet 40 pays -1'; +is payout( 14, 41 ), -1, 'Spin 14 (15 Black), bet 41 pays -1'; +is payout( 14, 42 ), 2, 'Spin 14 (15 Black), bet 42 pays 2'; +is payout( 14, 43 ), 1, 'Spin 14 (15 Black), bet 43 pays 1'; +is payout( 14, 44 ), -1, 'Spin 14 (15 Black), bet 44 pays -1'; +is payout( 14, 45 ), -1, 'Spin 14 (15 Black), bet 45 pays -1'; +is payout( 14, 46 ), 1, 'Spin 14 (15 Black), bet 46 pays 1'; +is payout( 14, 47 ), -1, 'Spin 14 (15 Black), bet 47 pays -1'; +is payout( 14, 48 ), 1, 'Spin 14 (15 Black), bet 48 pays 1'; +is payout( 14, 49 ), -1, 'Spin 14 (15 Black), bet 49 pays -1'; +is payout( 14, 50 ), -1, 'Spin 14 (15 Black), bet 50 pays -1'; +is format_spin( 15 ), '16 Red', 'Spin 15 is 16 Red'; +is payout( 15, 1 ), -1, 'Spin 15 (16 Red), bet 1 pays -1'; +is payout( 15, 2 ), -1, 'Spin 15 (16 Red), bet 2 pays -1'; +is payout( 15, 3 ), -1, 'Spin 15 (16 Red), bet 3 pays -1'; +is payout( 15, 4 ), -1, 'Spin 15 (16 Red), bet 4 pays -1'; +is payout( 15, 5 ), -1, 'Spin 15 (16 Red), bet 5 pays -1'; +is payout( 15, 6 ), -1, 'Spin 15 (16 Red), bet 6 pays -1'; +is payout( 15, 7 ), -1, 'Spin 15 (16 Red), bet 7 pays -1'; +is payout( 15, 8 ), -1, 'Spin 15 (16 Red), bet 8 pays -1'; +is payout( 15, 9 ), -1, 'Spin 15 (16 Red), bet 9 pays -1'; +is payout( 15, 10 ), -1, 'Spin 15 (16 Red), bet 10 pays -1'; +is payout( 15, 11 ), -1, 'Spin 15 (16 Red), bet 11 pays -1'; +is payout( 15, 12 ), -1, 'Spin 15 (16 Red), bet 12 pays -1'; +is payout( 15, 13 ), -1, 'Spin 15 (16 Red), bet 13 pays -1'; +is payout( 15, 14 ), -1, 'Spin 15 (16 Red), bet 14 pays -1'; +is payout( 15, 15 ), -1, 'Spin 15 (16 Red), bet 15 pays -1'; +is payout( 15, 16 ), 35, 'Spin 15 (16 Red), bet 16 pays 35'; +is payout( 15, 17 ), -1, 'Spin 15 (16 Red), bet 17 pays -1'; +is payout( 15, 18 ), -1, 'Spin 15 (16 Red), bet 18 pays -1'; +is payout( 15, 19 ), -1, 'Spin 15 (16 Red), bet 19 pays -1'; +is payout( 15, 20 ), -1, 'Spin 15 (16 Red), bet 20 pays -1'; +is payout( 15, 21 ), -1, 'Spin 15 (16 Red), bet 21 pays -1'; +is payout( 15, 22 ), -1, 'Spin 15 (16 Red), bet 22 pays -1'; +is payout( 15, 23 ), -1, 'Spin 15 (16 Red), bet 23 pays -1'; +is payout( 15, 24 ), -1, 'Spin 15 (16 Red), bet 24 pays -1'; +is payout( 15, 25 ), -1, 'Spin 15 (16 Red), bet 25 pays -1'; +is payout( 15, 26 ), -1, 'Spin 15 (16 Red), bet 26 pays -1'; +is payout( 15, 27 ), -1, 'Spin 15 (16 Red), bet 27 pays -1'; +is payout( 15, 28 ), -1, 'Spin 15 (16 Red), bet 28 pays -1'; +is payout( 15, 29 ), -1, 'Spin 15 (16 Red), bet 29 pays -1'; +is payout( 15, 30 ), -1, 'Spin 15 (16 Red), bet 30 pays -1'; +is payout( 15, 31 ), -1, 'Spin 15 (16 Red), bet 31 pays -1'; +is payout( 15, 32 ), -1, 'Spin 15 (16 Red), bet 32 pays -1'; +is payout( 15, 33 ), -1, 'Spin 15 (16 Red), bet 33 pays -1'; +is payout( 15, 34 ), -1, 'Spin 15 (16 Red), bet 34 pays -1'; +is payout( 15, 35 ), -1, 'Spin 15 (16 Red), bet 35 pays -1'; +is payout( 15, 36 ), -1, 'Spin 15 (16 Red), bet 36 pays -1'; +is payout( 15, 37 ), -1, 'Spin 15 (16 Red), bet 37 pays -1'; +is payout( 15, 38 ), 2, 'Spin 15 (16 Red), bet 38 pays 2'; +is payout( 15, 39 ), -1, 'Spin 15 (16 Red), bet 39 pays -1'; +is payout( 15, 40 ), 2, 'Spin 15 (16 Red), bet 40 pays 2'; +is payout( 15, 41 ), -1, 'Spin 15 (16 Red), bet 41 pays -1'; +is payout( 15, 42 ), -1, 'Spin 15 (16 Red), bet 42 pays -1'; +is payout( 15, 43 ), 1, 'Spin 15 (16 Red), bet 43 pays 1'; +is payout( 15, 44 ), -1, 'Spin 15 (16 Red), bet 44 pays -1'; +is payout( 15, 45 ), 1, 'Spin 15 (16 Red), bet 45 pays 1'; +is payout( 15, 46 ), -1, 'Spin 15 (16 Red), bet 46 pays -1'; +is payout( 15, 47 ), 1, 'Spin 15 (16 Red), bet 47 pays 1'; +is payout( 15, 48 ), -1, 'Spin 15 (16 Red), bet 48 pays -1'; +is payout( 15, 49 ), -1, 'Spin 15 (16 Red), bet 49 pays -1'; +is payout( 15, 50 ), -1, 'Spin 15 (16 Red), bet 50 pays -1'; +is format_spin( 16 ), '17 Black', 'Spin 16 is 17 Black'; +is payout( 16, 1 ), -1, 'Spin 16 (17 Black), bet 1 pays -1'; +is payout( 16, 2 ), -1, 'Spin 16 (17 Black), bet 2 pays -1'; +is payout( 16, 3 ), -1, 'Spin 16 (17 Black), bet 3 pays -1'; +is payout( 16, 4 ), -1, 'Spin 16 (17 Black), bet 4 pays -1'; +is payout( 16, 5 ), -1, 'Spin 16 (17 Black), bet 5 pays -1'; +is payout( 16, 6 ), -1, 'Spin 16 (17 Black), bet 6 pays -1'; +is payout( 16, 7 ), -1, 'Spin 16 (17 Black), bet 7 pays -1'; +is payout( 16, 8 ), -1, 'Spin 16 (17 Black), bet 8 pays -1'; +is payout( 16, 9 ), -1, 'Spin 16 (17 Black), bet 9 pays -1'; +is payout( 16, 10 ), -1, 'Spin 16 (17 Black), bet 10 pays -1'; +is payout( 16, 11 ), -1, 'Spin 16 (17 Black), bet 11 pays -1'; +is payout( 16, 12 ), -1, 'Spin 16 (17 Black), bet 12 pays -1'; +is payout( 16, 13 ), -1, 'Spin 16 (17 Black), bet 13 pays -1'; +is payout( 16, 14 ), -1, 'Spin 16 (17 Black), bet 14 pays -1'; +is payout( 16, 15 ), -1, 'Spin 16 (17 Black), bet 15 pays -1'; +is payout( 16, 16 ), -1, 'Spin 16 (17 Black), bet 16 pays -1'; +is payout( 16, 17 ), 35, 'Spin 16 (17 Black), bet 17 pays 35'; +is payout( 16, 18 ), -1, 'Spin 16 (17 Black), bet 18 pays -1'; +is payout( 16, 19 ), -1, 'Spin 16 (17 Black), bet 19 pays -1'; +is payout( 16, 20 ), -1, 'Spin 16 (17 Black), bet 20 pays -1'; +is payout( 16, 21 ), -1, 'Spin 16 (17 Black), bet 21 pays -1'; +is payout( 16, 22 ), -1, 'Spin 16 (17 Black), bet 22 pays -1'; +is payout( 16, 23 ), -1, 'Spin 16 (17 Black), bet 23 pays -1'; +is payout( 16, 24 ), -1, 'Spin 16 (17 Black), bet 24 pays -1'; +is payout( 16, 25 ), -1, 'Spin 16 (17 Black), bet 25 pays -1'; +is payout( 16, 26 ), -1, 'Spin 16 (17 Black), bet 26 pays -1'; +is payout( 16, 27 ), -1, 'Spin 16 (17 Black), bet 27 pays -1'; +is payout( 16, 28 ), -1, 'Spin 16 (17 Black), bet 28 pays -1'; +is payout( 16, 29 ), -1, 'Spin 16 (17 Black), bet 29 pays -1'; +is payout( 16, 30 ), -1, 'Spin 16 (17 Black), bet 30 pays -1'; +is payout( 16, 31 ), -1, 'Spin 16 (17 Black), bet 31 pays -1'; +is payout( 16, 32 ), -1, 'Spin 16 (17 Black), bet 32 pays -1'; +is payout( 16, 33 ), -1, 'Spin 16 (17 Black), bet 33 pays -1'; +is payout( 16, 34 ), -1, 'Spin 16 (17 Black), bet 34 pays -1'; +is payout( 16, 35 ), -1, 'Spin 16 (17 Black), bet 35 pays -1'; +is payout( 16, 36 ), -1, 'Spin 16 (17 Black), bet 36 pays -1'; +is payout( 16, 37 ), -1, 'Spin 16 (17 Black), bet 37 pays -1'; +is payout( 16, 38 ), 2, 'Spin 16 (17 Black), bet 38 pays 2'; +is payout( 16, 39 ), -1, 'Spin 16 (17 Black), bet 39 pays -1'; +is payout( 16, 40 ), -1, 'Spin 16 (17 Black), bet 40 pays -1'; +is payout( 16, 41 ), 2, 'Spin 16 (17 Black), bet 41 pays 2'; +is payout( 16, 42 ), -1, 'Spin 16 (17 Black), bet 42 pays -1'; +is payout( 16, 43 ), 1, 'Spin 16 (17 Black), bet 43 pays 1'; +is payout( 16, 44 ), -1, 'Spin 16 (17 Black), bet 44 pays -1'; +is payout( 16, 45 ), -1, 'Spin 16 (17 Black), bet 45 pays -1'; +is payout( 16, 46 ), 1, 'Spin 16 (17 Black), bet 46 pays 1'; +is payout( 16, 47 ), -1, 'Spin 16 (17 Black), bet 47 pays -1'; +is payout( 16, 48 ), 1, 'Spin 16 (17 Black), bet 48 pays 1'; +is payout( 16, 49 ), -1, 'Spin 16 (17 Black), bet 49 pays -1'; +is payout( 16, 50 ), -1, 'Spin 16 (17 Black), bet 50 pays -1'; +is format_spin( 17 ), '18 Red', 'Spin 17 is 18 Red'; +is payout( 17, 1 ), -1, 'Spin 17 (18 Red), bet 1 pays -1'; +is payout( 17, 2 ), -1, 'Spin 17 (18 Red), bet 2 pays -1'; +is payout( 17, 3 ), -1, 'Spin 17 (18 Red), bet 3 pays -1'; +is payout( 17, 4 ), -1, 'Spin 17 (18 Red), bet 4 pays -1'; +is payout( 17, 5 ), -1, 'Spin 17 (18 Red), bet 5 pays -1'; +is payout( 17, 6 ), -1, 'Spin 17 (18 Red), bet 6 pays -1'; +is payout( 17, 7 ), -1, 'Spin 17 (18 Red), bet 7 pays -1'; +is payout( 17, 8 ), -1, 'Spin 17 (18 Red), bet 8 pays -1'; +is payout( 17, 9 ), -1, 'Spin 17 (18 Red), bet 9 pays -1'; +is payout( 17, 10 ), -1, 'Spin 17 (18 Red), bet 10 pays -1'; +is payout( 17, 11 ), -1, 'Spin 17 (18 Red), bet 11 pays -1'; +is payout( 17, 12 ), -1, 'Spin 17 (18 Red), bet 12 pays -1'; +is payout( 17, 13 ), -1, 'Spin 17 (18 Red), bet 13 pays -1'; +is payout( 17, 14 ), -1, 'Spin 17 (18 Red), bet 14 pays -1'; +is payout( 17, 15 ), -1, 'Spin 17 (18 Red), bet 15 pays -1'; +is payout( 17, 16 ), -1, 'Spin 17 (18 Red), bet 16 pays -1'; +is payout( 17, 17 ), -1, 'Spin 17 (18 Red), bet 17 pays -1'; +is payout( 17, 18 ), 35, 'Spin 17 (18 Red), bet 18 pays 35'; +is payout( 17, 19 ), -1, 'Spin 17 (18 Red), bet 19 pays -1'; +is payout( 17, 20 ), -1, 'Spin 17 (18 Red), bet 20 pays -1'; +is payout( 17, 21 ), -1, 'Spin 17 (18 Red), bet 21 pays -1'; +is payout( 17, 22 ), -1, 'Spin 17 (18 Red), bet 22 pays -1'; +is payout( 17, 23 ), -1, 'Spin 17 (18 Red), bet 23 pays -1'; +is payout( 17, 24 ), -1, 'Spin 17 (18 Red), bet 24 pays -1'; +is payout( 17, 25 ), -1, 'Spin 17 (18 Red), bet 25 pays -1'; +is payout( 17, 26 ), -1, 'Spin 17 (18 Red), bet 26 pays -1'; +is payout( 17, 27 ), -1, 'Spin 17 (18 Red), bet 27 pays -1'; +is payout( 17, 28 ), -1, 'Spin 17 (18 Red), bet 28 pays -1'; +is payout( 17, 29 ), -1, 'Spin 17 (18 Red), bet 29 pays -1'; +is payout( 17, 30 ), -1, 'Spin 17 (18 Red), bet 30 pays -1'; +is payout( 17, 31 ), -1, 'Spin 17 (18 Red), bet 31 pays -1'; +is payout( 17, 32 ), -1, 'Spin 17 (18 Red), bet 32 pays -1'; +is payout( 17, 33 ), -1, 'Spin 17 (18 Red), bet 33 pays -1'; +is payout( 17, 34 ), -1, 'Spin 17 (18 Red), bet 34 pays -1'; +is payout( 17, 35 ), -1, 'Spin 17 (18 Red), bet 35 pays -1'; +is payout( 17, 36 ), -1, 'Spin 17 (18 Red), bet 36 pays -1'; +is payout( 17, 37 ), -1, 'Spin 17 (18 Red), bet 37 pays -1'; +is payout( 17, 38 ), 2, 'Spin 17 (18 Red), bet 38 pays 2'; +is payout( 17, 39 ), -1, 'Spin 17 (18 Red), bet 39 pays -1'; +is payout( 17, 40 ), -1, 'Spin 17 (18 Red), bet 40 pays -1'; +is payout( 17, 41 ), -1, 'Spin 17 (18 Red), bet 41 pays -1'; +is payout( 17, 42 ), 2, 'Spin 17 (18 Red), bet 42 pays 2'; +is payout( 17, 43 ), 1, 'Spin 17 (18 Red), bet 43 pays 1'; +is payout( 17, 44 ), -1, 'Spin 17 (18 Red), bet 44 pays -1'; +is payout( 17, 45 ), 1, 'Spin 17 (18 Red), bet 45 pays 1'; +is payout( 17, 46 ), -1, 'Spin 17 (18 Red), bet 46 pays -1'; +is payout( 17, 47 ), 1, 'Spin 17 (18 Red), bet 47 pays 1'; +is payout( 17, 48 ), -1, 'Spin 17 (18 Red), bet 48 pays -1'; +is payout( 17, 49 ), -1, 'Spin 17 (18 Red), bet 49 pays -1'; +is payout( 17, 50 ), -1, 'Spin 17 (18 Red), bet 50 pays -1'; +is format_spin( 18 ), '19 Red', 'Spin 18 is 19 Red'; +is payout( 18, 1 ), -1, 'Spin 18 (19 Red), bet 1 pays -1'; +is payout( 18, 2 ), -1, 'Spin 18 (19 Red), bet 2 pays -1'; +is payout( 18, 3 ), -1, 'Spin 18 (19 Red), bet 3 pays -1'; +is payout( 18, 4 ), -1, 'Spin 18 (19 Red), bet 4 pays -1'; +is payout( 18, 5 ), -1, 'Spin 18 (19 Red), bet 5 pays -1'; +is payout( 18, 6 ), -1, 'Spin 18 (19 Red), bet 6 pays -1'; +is payout( 18, 7 ), -1, 'Spin 18 (19 Red), bet 7 pays -1'; +is payout( 18, 8 ), -1, 'Spin 18 (19 Red), bet 8 pays -1'; +is payout( 18, 9 ), -1, 'Spin 18 (19 Red), bet 9 pays -1'; +is payout( 18, 10 ), -1, 'Spin 18 (19 Red), bet 10 pays -1'; +is payout( 18, 11 ), -1, 'Spin 18 (19 Red), bet 11 pays -1'; +is payout( 18, 12 ), -1, 'Spin 18 (19 Red), bet 12 pays -1'; +is payout( 18, 13 ), -1, 'Spin 18 (19 Red), bet 13 pays -1'; +is payout( 18, 14 ), -1, 'Spin 18 (19 Red), bet 14 pays -1'; +is payout( 18, 15 ), -1, 'Spin 18 (19 Red), bet 15 pays -1'; +is payout( 18, 16 ), -1, 'Spin 18 (19 Red), bet 16 pays -1'; +is payout( 18, 17 ), -1, 'Spin 18 (19 Red), bet 17 pays -1'; +is payout( 18, 18 ), -1, 'Spin 18 (19 Red), bet 18 pays -1'; +is payout( 18, 19 ), 35, 'Spin 18 (19 Red), bet 19 pays 35'; +is payout( 18, 20 ), -1, 'Spin 18 (19 Red), bet 20 pays -1'; +is payout( 18, 21 ), -1, 'Spin 18 (19 Red), bet 21 pays -1'; +is payout( 18, 22 ), -1, 'Spin 18 (19 Red), bet 22 pays -1'; +is payout( 18, 23 ), -1, 'Spin 18 (19 Red), bet 23 pays -1'; +is payout( 18, 24 ), -1, 'Spin 18 (19 Red), bet 24 pays -1'; +is payout( 18, 25 ), -1, 'Spin 18 (19 Red), bet 25 pays -1'; +is payout( 18, 26 ), -1, 'Spin 18 (19 Red), bet 26 pays -1'; +is payout( 18, 27 ), -1, 'Spin 18 (19 Red), bet 27 pays -1'; +is payout( 18, 28 ), -1, 'Spin 18 (19 Red), bet 28 pays -1'; +is payout( 18, 29 ), -1, 'Spin 18 (19 Red), bet 29 pays -1'; +is payout( 18, 30 ), -1, 'Spin 18 (19 Red), bet 30 pays -1'; +is payout( 18, 31 ), -1, 'Spin 18 (19 Red), bet 31 pays -1'; +is payout( 18, 32 ), -1, 'Spin 18 (19 Red), bet 32 pays -1'; +is payout( 18, 33 ), -1, 'Spin 18 (19 Red), bet 33 pays -1'; +is payout( 18, 34 ), -1, 'Spin 18 (19 Red), bet 34 pays -1'; +is payout( 18, 35 ), -1, 'Spin 18 (19 Red), bet 35 pays -1'; +is payout( 18, 36 ), -1, 'Spin 18 (19 Red), bet 36 pays -1'; +is payout( 18, 37 ), -1, 'Spin 18 (19 Red), bet 37 pays -1'; +is payout( 18, 38 ), 2, 'Spin 18 (19 Red), bet 38 pays 2'; +is payout( 18, 39 ), -1, 'Spin 18 (19 Red), bet 39 pays -1'; +is payout( 18, 40 ), 2, 'Spin 18 (19 Red), bet 40 pays 2'; +is payout( 18, 41 ), -1, 'Spin 18 (19 Red), bet 41 pays -1'; +is payout( 18, 42 ), -1, 'Spin 18 (19 Red), bet 42 pays -1'; +is payout( 18, 43 ), -1, 'Spin 18 (19 Red), bet 43 pays -1'; +is payout( 18, 44 ), 1, 'Spin 18 (19 Red), bet 44 pays 1'; +is payout( 18, 45 ), -1, 'Spin 18 (19 Red), bet 45 pays -1'; +is payout( 18, 46 ), 1, 'Spin 18 (19 Red), bet 46 pays 1'; +is payout( 18, 47 ), 1, 'Spin 18 (19 Red), bet 47 pays 1'; +is payout( 18, 48 ), -1, 'Spin 18 (19 Red), bet 48 pays -1'; +is payout( 18, 49 ), -1, 'Spin 18 (19 Red), bet 49 pays -1'; +is payout( 18, 50 ), -1, 'Spin 18 (19 Red), bet 50 pays -1'; +is format_spin( 19 ), '20 Black', 'Spin 19 is 20 Black'; +is payout( 19, 1 ), -1, 'Spin 19 (20 Black), bet 1 pays -1'; +is payout( 19, 2 ), -1, 'Spin 19 (20 Black), bet 2 pays -1'; +is payout( 19, 3 ), -1, 'Spin 19 (20 Black), bet 3 pays -1'; +is payout( 19, 4 ), -1, 'Spin 19 (20 Black), bet 4 pays -1'; +is payout( 19, 5 ), -1, 'Spin 19 (20 Black), bet 5 pays -1'; +is payout( 19, 6 ), -1, 'Spin 19 (20 Black), bet 6 pays -1'; +is payout( 19, 7 ), -1, 'Spin 19 (20 Black), bet 7 pays -1'; +is payout( 19, 8 ), -1, 'Spin 19 (20 Black), bet 8 pays -1'; +is payout( 19, 9 ), -1, 'Spin 19 (20 Black), bet 9 pays -1'; +is payout( 19, 10 ), -1, 'Spin 19 (20 Black), bet 10 pays -1'; +is payout( 19, 11 ), -1, 'Spin 19 (20 Black), bet 11 pays -1'; +is payout( 19, 12 ), -1, 'Spin 19 (20 Black), bet 12 pays -1'; +is payout( 19, 13 ), -1, 'Spin 19 (20 Black), bet 13 pays -1'; +is payout( 19, 14 ), -1, 'Spin 19 (20 Black), bet 14 pays -1'; +is payout( 19, 15 ), -1, 'Spin 19 (20 Black), bet 15 pays -1'; +is payout( 19, 16 ), -1, 'Spin 19 (20 Black), bet 16 pays -1'; +is payout( 19, 17 ), -1, 'Spin 19 (20 Black), bet 17 pays -1'; +is payout( 19, 18 ), -1, 'Spin 19 (20 Black), bet 18 pays -1'; +is payout( 19, 19 ), -1, 'Spin 19 (20 Black), bet 19 pays -1'; +is payout( 19, 20 ), 35, 'Spin 19 (20 Black), bet 20 pays 35'; +is payout( 19, 21 ), -1, 'Spin 19 (20 Black), bet 21 pays -1'; +is payout( 19, 22 ), -1, 'Spin 19 (20 Black), bet 22 pays -1'; +is payout( 19, 23 ), -1, 'Spin 19 (20 Black), bet 23 pays -1'; +is payout( 19, 24 ), -1, 'Spin 19 (20 Black), bet 24 pays -1'; +is payout( 19, 25 ), -1, 'Spin 19 (20 Black), bet 25 pays -1'; +is payout( 19, 26 ), -1, 'Spin 19 (20 Black), bet 26 pays -1'; +is payout( 19, 27 ), -1, 'Spin 19 (20 Black), bet 27 pays -1'; +is payout( 19, 28 ), -1, 'Spin 19 (20 Black), bet 28 pays -1'; +is payout( 19, 29 ), -1, 'Spin 19 (20 Black), bet 29 pays -1'; +is payout( 19, 30 ), -1, 'Spin 19 (20 Black), bet 30 pays -1'; +is payout( 19, 31 ), -1, 'Spin 19 (20 Black), bet 31 pays -1'; +is payout( 19, 32 ), -1, 'Spin 19 (20 Black), bet 32 pays -1'; +is payout( 19, 33 ), -1, 'Spin 19 (20 Black), bet 33 pays -1'; +is payout( 19, 34 ), -1, 'Spin 19 (20 Black), bet 34 pays -1'; +is payout( 19, 35 ), -1, 'Spin 19 (20 Black), bet 35 pays -1'; +is payout( 19, 36 ), -1, 'Spin 19 (20 Black), bet 36 pays -1'; +is payout( 19, 37 ), -1, 'Spin 19 (20 Black), bet 37 pays -1'; +is payout( 19, 38 ), 2, 'Spin 19 (20 Black), bet 38 pays 2'; +is payout( 19, 39 ), -1, 'Spin 19 (20 Black), bet 39 pays -1'; +is payout( 19, 40 ), -1, 'Spin 19 (20 Black), bet 40 pays -1'; +is payout( 19, 41 ), 2, 'Spin 19 (20 Black), bet 41 pays 2'; +is payout( 19, 42 ), -1, 'Spin 19 (20 Black), bet 42 pays -1'; +is payout( 19, 43 ), -1, 'Spin 19 (20 Black), bet 43 pays -1'; +is payout( 19, 44 ), 1, 'Spin 19 (20 Black), bet 44 pays 1'; +is payout( 19, 45 ), 1, 'Spin 19 (20 Black), bet 45 pays 1'; +is payout( 19, 46 ), -1, 'Spin 19 (20 Black), bet 46 pays -1'; +is payout( 19, 47 ), -1, 'Spin 19 (20 Black), bet 47 pays -1'; +is payout( 19, 48 ), 1, 'Spin 19 (20 Black), bet 48 pays 1'; +is payout( 19, 49 ), -1, 'Spin 19 (20 Black), bet 49 pays -1'; +is payout( 19, 50 ), -1, 'Spin 19 (20 Black), bet 50 pays -1'; +is format_spin( 20 ), '21 Red', 'Spin 20 is 21 Red'; +is payout( 20, 1 ), -1, 'Spin 20 (21 Red), bet 1 pays -1'; +is payout( 20, 2 ), -1, 'Spin 20 (21 Red), bet 2 pays -1'; +is payout( 20, 3 ), -1, 'Spin 20 (21 Red), bet 3 pays -1'; +is payout( 20, 4 ), -1, 'Spin 20 (21 Red), bet 4 pays -1'; +is payout( 20, 5 ), -1, 'Spin 20 (21 Red), bet 5 pays -1'; +is payout( 20, 6 ), -1, 'Spin 20 (21 Red), bet 6 pays -1'; +is payout( 20, 7 ), -1, 'Spin 20 (21 Red), bet 7 pays -1'; +is payout( 20, 8 ), -1, 'Spin 20 (21 Red), bet 8 pays -1'; +is payout( 20, 9 ), -1, 'Spin 20 (21 Red), bet 9 pays -1'; +is payout( 20, 10 ), -1, 'Spin 20 (21 Red), bet 10 pays -1'; +is payout( 20, 11 ), -1, 'Spin 20 (21 Red), bet 11 pays -1'; +is payout( 20, 12 ), -1, 'Spin 20 (21 Red), bet 12 pays -1'; +is payout( 20, 13 ), -1, 'Spin 20 (21 Red), bet 13 pays -1'; +is payout( 20, 14 ), -1, 'Spin 20 (21 Red), bet 14 pays -1'; +is payout( 20, 15 ), -1, 'Spin 20 (21 Red), bet 15 pays -1'; +is payout( 20, 16 ), -1, 'Spin 20 (21 Red), bet 16 pays -1'; +is payout( 20, 17 ), -1, 'Spin 20 (21 Red), bet 17 pays -1'; +is payout( 20, 18 ), -1, 'Spin 20 (21 Red), bet 18 pays -1'; +is payout( 20, 19 ), -1, 'Spin 20 (21 Red), bet 19 pays -1'; +is payout( 20, 20 ), -1, 'Spin 20 (21 Red), bet 20 pays -1'; +is payout( 20, 21 ), 35, 'Spin 20 (21 Red), bet 21 pays 35'; +is payout( 20, 22 ), -1, 'Spin 20 (21 Red), bet 22 pays -1'; +is payout( 20, 23 ), -1, 'Spin 20 (21 Red), bet 23 pays -1'; +is payout( 20, 24 ), -1, 'Spin 20 (21 Red), bet 24 pays -1'; +is payout( 20, 25 ), -1, 'Spin 20 (21 Red), bet 25 pays -1'; +is payout( 20, 26 ), -1, 'Spin 20 (21 Red), bet 26 pays -1'; +is payout( 20, 27 ), -1, 'Spin 20 (21 Red), bet 27 pays -1'; +is payout( 20, 28 ), -1, 'Spin 20 (21 Red), bet 28 pays -1'; +is payout( 20, 29 ), -1, 'Spin 20 (21 Red), bet 29 pays -1'; +is payout( 20, 30 ), -1, 'Spin 20 (21 Red), bet 30 pays -1'; +is payout( 20, 31 ), -1, 'Spin 20 (21 Red), bet 31 pays -1'; +is payout( 20, 32 ), -1, 'Spin 20 (21 Red), bet 32 pays -1'; +is payout( 20, 33 ), -1, 'Spin 20 (21 Red), bet 33 pays -1'; +is payout( 20, 34 ), -1, 'Spin 20 (21 Red), bet 34 pays -1'; +is payout( 20, 35 ), -1, 'Spin 20 (21 Red), bet 35 pays -1'; +is payout( 20, 36 ), -1, 'Spin 20 (21 Red), bet 36 pays -1'; +is payout( 20, 37 ), -1, 'Spin 20 (21 Red), bet 37 pays -1'; +is payout( 20, 38 ), 2, 'Spin 20 (21 Red), bet 38 pays 2'; +is payout( 20, 39 ), -1, 'Spin 20 (21 Red), bet 39 pays -1'; +is payout( 20, 40 ), -1, 'Spin 20 (21 Red), bet 40 pays -1'; +is payout( 20, 41 ), -1, 'Spin 20 (21 Red), bet 41 pays -1'; +is payout( 20, 42 ), 2, 'Spin 20 (21 Red), bet 42 pays 2'; +is payout( 20, 43 ), -1, 'Spin 20 (21 Red), bet 43 pays -1'; +is payout( 20, 44 ), 1, 'Spin 20 (21 Red), bet 44 pays 1'; +is payout( 20, 45 ), -1, 'Spin 20 (21 Red), bet 45 pays -1'; +is payout( 20, 46 ), 1, 'Spin 20 (21 Red), bet 46 pays 1'; +is payout( 20, 47 ), 1, 'Spin 20 (21 Red), bet 47 pays 1'; +is payout( 20, 48 ), -1, 'Spin 20 (21 Red), bet 48 pays -1'; +is payout( 20, 49 ), -1, 'Spin 20 (21 Red), bet 49 pays -1'; +is payout( 20, 50 ), -1, 'Spin 20 (21 Red), bet 50 pays -1'; +is format_spin( 21 ), '22 Black', 'Spin 21 is 22 Black'; +is payout( 21, 1 ), -1, 'Spin 21 (22 Black), bet 1 pays -1'; +is payout( 21, 2 ), -1, 'Spin 21 (22 Black), bet 2 pays -1'; +is payout( 21, 3 ), -1, 'Spin 21 (22 Black), bet 3 pays -1'; +is payout( 21, 4 ), -1, 'Spin 21 (22 Black), bet 4 pays -1'; +is payout( 21, 5 ), -1, 'Spin 21 (22 Black), bet 5 pays -1'; +is payout( 21, 6 ), -1, 'Spin 21 (22 Black), bet 6 pays -1'; +is payout( 21, 7 ), -1, 'Spin 21 (22 Black), bet 7 pays -1'; +is payout( 21, 8 ), -1, 'Spin 21 (22 Black), bet 8 pays -1'; +is payout( 21, 9 ), -1, 'Spin 21 (22 Black), bet 9 pays -1'; +is payout( 21, 10 ), -1, 'Spin 21 (22 Black), bet 10 pays -1'; +is payout( 21, 11 ), -1, 'Spin 21 (22 Black), bet 11 pays -1'; +is payout( 21, 12 ), -1, 'Spin 21 (22 Black), bet 12 pays -1'; +is payout( 21, 13 ), -1, 'Spin 21 (22 Black), bet 13 pays -1'; +is payout( 21, 14 ), -1, 'Spin 21 (22 Black), bet 14 pays -1'; +is payout( 21, 15 ), -1, 'Spin 21 (22 Black), bet 15 pays -1'; +is payout( 21, 16 ), -1, 'Spin 21 (22 Black), bet 16 pays -1'; +is payout( 21, 17 ), -1, 'Spin 21 (22 Black), bet 17 pays -1'; +is payout( 21, 18 ), -1, 'Spin 21 (22 Black), bet 18 pays -1'; +is payout( 21, 19 ), -1, 'Spin 21 (22 Black), bet 19 pays -1'; +is payout( 21, 20 ), -1, 'Spin 21 (22 Black), bet 20 pays -1'; +is payout( 21, 21 ), -1, 'Spin 21 (22 Black), bet 21 pays -1'; +is payout( 21, 22 ), 35, 'Spin 21 (22 Black), bet 22 pays 35'; +is payout( 21, 23 ), -1, 'Spin 21 (22 Black), bet 23 pays -1'; +is payout( 21, 24 ), -1, 'Spin 21 (22 Black), bet 24 pays -1'; +is payout( 21, 25 ), -1, 'Spin 21 (22 Black), bet 25 pays -1'; +is payout( 21, 26 ), -1, 'Spin 21 (22 Black), bet 26 pays -1'; +is payout( 21, 27 ), -1, 'Spin 21 (22 Black), bet 27 pays -1'; +is payout( 21, 28 ), -1, 'Spin 21 (22 Black), bet 28 pays -1'; +is payout( 21, 29 ), -1, 'Spin 21 (22 Black), bet 29 pays -1'; +is payout( 21, 30 ), -1, 'Spin 21 (22 Black), bet 30 pays -1'; +is payout( 21, 31 ), -1, 'Spin 21 (22 Black), bet 31 pays -1'; +is payout( 21, 32 ), -1, 'Spin 21 (22 Black), bet 32 pays -1'; +is payout( 21, 33 ), -1, 'Spin 21 (22 Black), bet 33 pays -1'; +is payout( 21, 34 ), -1, 'Spin 21 (22 Black), bet 34 pays -1'; +is payout( 21, 35 ), -1, 'Spin 21 (22 Black), bet 35 pays -1'; +is payout( 21, 36 ), -1, 'Spin 21 (22 Black), bet 36 pays -1'; +is payout( 21, 37 ), -1, 'Spin 21 (22 Black), bet 37 pays -1'; +is payout( 21, 38 ), 2, 'Spin 21 (22 Black), bet 38 pays 2'; +is payout( 21, 39 ), -1, 'Spin 21 (22 Black), bet 39 pays -1'; +is payout( 21, 40 ), 2, 'Spin 21 (22 Black), bet 40 pays 2'; +is payout( 21, 41 ), -1, 'Spin 21 (22 Black), bet 41 pays -1'; +is payout( 21, 42 ), -1, 'Spin 21 (22 Black), bet 42 pays -1'; +is payout( 21, 43 ), -1, 'Spin 21 (22 Black), bet 43 pays -1'; +is payout( 21, 44 ), 1, 'Spin 21 (22 Black), bet 44 pays 1'; +is payout( 21, 45 ), 1, 'Spin 21 (22 Black), bet 45 pays 1'; +is payout( 21, 46 ), -1, 'Spin 21 (22 Black), bet 46 pays -1'; +is payout( 21, 47 ), -1, 'Spin 21 (22 Black), bet 47 pays -1'; +is payout( 21, 48 ), 1, 'Spin 21 (22 Black), bet 48 pays 1'; +is payout( 21, 49 ), -1, 'Spin 21 (22 Black), bet 49 pays -1'; +is payout( 21, 50 ), -1, 'Spin 21 (22 Black), bet 50 pays -1'; +is format_spin( 22 ), '23 Red', 'Spin 22 is 23 Red'; +is payout( 22, 1 ), -1, 'Spin 22 (23 Red), bet 1 pays -1'; +is payout( 22, 2 ), -1, 'Spin 22 (23 Red), bet 2 pays -1'; +is payout( 22, 3 ), -1, 'Spin 22 (23 Red), bet 3 pays -1'; +is payout( 22, 4 ), -1, 'Spin 22 (23 Red), bet 4 pays -1'; +is payout( 22, 5 ), -1, 'Spin 22 (23 Red), bet 5 pays -1'; +is payout( 22, 6 ), -1, 'Spin 22 (23 Red), bet 6 pays -1'; +is payout( 22, 7 ), -1, 'Spin 22 (23 Red), bet 7 pays -1'; +is payout( 22, 8 ), -1, 'Spin 22 (23 Red), bet 8 pays -1'; +is payout( 22, 9 ), -1, 'Spin 22 (23 Red), bet 9 pays -1'; +is payout( 22, 10 ), -1, 'Spin 22 (23 Red), bet 10 pays -1'; +is payout( 22, 11 ), -1, 'Spin 22 (23 Red), bet 11 pays -1'; +is payout( 22, 12 ), -1, 'Spin 22 (23 Red), bet 12 pays -1'; +is payout( 22, 13 ), -1, 'Spin 22 (23 Red), bet 13 pays -1'; +is payout( 22, 14 ), -1, 'Spin 22 (23 Red), bet 14 pays -1'; +is payout( 22, 15 ), -1, 'Spin 22 (23 Red), bet 15 pays -1'; +is payout( 22, 16 ), -1, 'Spin 22 (23 Red), bet 16 pays -1'; +is payout( 22, 17 ), -1, 'Spin 22 (23 Red), bet 17 pays -1'; +is payout( 22, 18 ), -1, 'Spin 22 (23 Red), bet 18 pays -1'; +is payout( 22, 19 ), -1, 'Spin 22 (23 Red), bet 19 pays -1'; +is payout( 22, 20 ), -1, 'Spin 22 (23 Red), bet 20 pays -1'; +is payout( 22, 21 ), -1, 'Spin 22 (23 Red), bet 21 pays -1'; +is payout( 22, 22 ), -1, 'Spin 22 (23 Red), bet 22 pays -1'; +is payout( 22, 23 ), 35, 'Spin 22 (23 Red), bet 23 pays 35'; +is payout( 22, 24 ), -1, 'Spin 22 (23 Red), bet 24 pays -1'; +is payout( 22, 25 ), -1, 'Spin 22 (23 Red), bet 25 pays -1'; +is payout( 22, 26 ), -1, 'Spin 22 (23 Red), bet 26 pays -1'; +is payout( 22, 27 ), -1, 'Spin 22 (23 Red), bet 27 pays -1'; +is payout( 22, 28 ), -1, 'Spin 22 (23 Red), bet 28 pays -1'; +is payout( 22, 29 ), -1, 'Spin 22 (23 Red), bet 29 pays -1'; +is payout( 22, 30 ), -1, 'Spin 22 (23 Red), bet 30 pays -1'; +is payout( 22, 31 ), -1, 'Spin 22 (23 Red), bet 31 pays -1'; +is payout( 22, 32 ), -1, 'Spin 22 (23 Red), bet 32 pays -1'; +is payout( 22, 33 ), -1, 'Spin 22 (23 Red), bet 33 pays -1'; +is payout( 22, 34 ), -1, 'Spin 22 (23 Red), bet 34 pays -1'; +is payout( 22, 35 ), -1, 'Spin 22 (23 Red), bet 35 pays -1'; +is payout( 22, 36 ), -1, 'Spin 22 (23 Red), bet 36 pays -1'; +is payout( 22, 37 ), -1, 'Spin 22 (23 Red), bet 37 pays -1'; +is payout( 22, 38 ), 2, 'Spin 22 (23 Red), bet 38 pays 2'; +is payout( 22, 39 ), -1, 'Spin 22 (23 Red), bet 39 pays -1'; +is payout( 22, 40 ), -1, 'Spin 22 (23 Red), bet 40 pays -1'; +is payout( 22, 41 ), 2, 'Spin 22 (23 Red), bet 41 pays 2'; +is payout( 22, 42 ), -1, 'Spin 22 (23 Red), bet 42 pays -1'; +is payout( 22, 43 ), -1, 'Spin 22 (23 Red), bet 43 pays -1'; +is payout( 22, 44 ), 1, 'Spin 22 (23 Red), bet 44 pays 1'; +is payout( 22, 45 ), -1, 'Spin 22 (23 Red), bet 45 pays -1'; +is payout( 22, 46 ), 1, 'Spin 22 (23 Red), bet 46 pays 1'; +is payout( 22, 47 ), 1, 'Spin 22 (23 Red), bet 47 pays 1'; +is payout( 22, 48 ), -1, 'Spin 22 (23 Red), bet 48 pays -1'; +is payout( 22, 49 ), -1, 'Spin 22 (23 Red), bet 49 pays -1'; +is payout( 22, 50 ), -1, 'Spin 22 (23 Red), bet 50 pays -1'; +is format_spin( 23 ), '24 Black', 'Spin 23 is 24 Black'; +is payout( 23, 1 ), -1, 'Spin 23 (24 Black), bet 1 pays -1'; +is payout( 23, 2 ), -1, 'Spin 23 (24 Black), bet 2 pays -1'; +is payout( 23, 3 ), -1, 'Spin 23 (24 Black), bet 3 pays -1'; +is payout( 23, 4 ), -1, 'Spin 23 (24 Black), bet 4 pays -1'; +is payout( 23, 5 ), -1, 'Spin 23 (24 Black), bet 5 pays -1'; +is payout( 23, 6 ), -1, 'Spin 23 (24 Black), bet 6 pays -1'; +is payout( 23, 7 ), -1, 'Spin 23 (24 Black), bet 7 pays -1'; +is payout( 23, 8 ), -1, 'Spin 23 (24 Black), bet 8 pays -1'; +is payout( 23, 9 ), -1, 'Spin 23 (24 Black), bet 9 pays -1'; +is payout( 23, 10 ), -1, 'Spin 23 (24 Black), bet 10 pays -1'; +is payout( 23, 11 ), -1, 'Spin 23 (24 Black), bet 11 pays -1'; +is payout( 23, 12 ), -1, 'Spin 23 (24 Black), bet 12 pays -1'; +is payout( 23, 13 ), -1, 'Spin 23 (24 Black), bet 13 pays -1'; +is payout( 23, 14 ), -1, 'Spin 23 (24 Black), bet 14 pays -1'; +is payout( 23, 15 ), -1, 'Spin 23 (24 Black), bet 15 pays -1'; +is payout( 23, 16 ), -1, 'Spin 23 (24 Black), bet 16 pays -1'; +is payout( 23, 17 ), -1, 'Spin 23 (24 Black), bet 17 pays -1'; +is payout( 23, 18 ), -1, 'Spin 23 (24 Black), bet 18 pays -1'; +is payout( 23, 19 ), -1, 'Spin 23 (24 Black), bet 19 pays -1'; +is payout( 23, 20 ), -1, 'Spin 23 (24 Black), bet 20 pays -1'; +is payout( 23, 21 ), -1, 'Spin 23 (24 Black), bet 21 pays -1'; +is payout( 23, 22 ), -1, 'Spin 23 (24 Black), bet 22 pays -1'; +is payout( 23, 23 ), -1, 'Spin 23 (24 Black), bet 23 pays -1'; +is payout( 23, 24 ), 35, 'Spin 23 (24 Black), bet 24 pays 35'; +is payout( 23, 25 ), -1, 'Spin 23 (24 Black), bet 25 pays -1'; +is payout( 23, 26 ), -1, 'Spin 23 (24 Black), bet 26 pays -1'; +is payout( 23, 27 ), -1, 'Spin 23 (24 Black), bet 27 pays -1'; +is payout( 23, 28 ), -1, 'Spin 23 (24 Black), bet 28 pays -1'; +is payout( 23, 29 ), -1, 'Spin 23 (24 Black), bet 29 pays -1'; +is payout( 23, 30 ), -1, 'Spin 23 (24 Black), bet 30 pays -1'; +is payout( 23, 31 ), -1, 'Spin 23 (24 Black), bet 31 pays -1'; +is payout( 23, 32 ), -1, 'Spin 23 (24 Black), bet 32 pays -1'; +is payout( 23, 33 ), -1, 'Spin 23 (24 Black), bet 33 pays -1'; +is payout( 23, 34 ), -1, 'Spin 23 (24 Black), bet 34 pays -1'; +is payout( 23, 35 ), -1, 'Spin 23 (24 Black), bet 35 pays -1'; +is payout( 23, 36 ), -1, 'Spin 23 (24 Black), bet 36 pays -1'; +is payout( 23, 37 ), -1, 'Spin 23 (24 Black), bet 37 pays -1'; +is payout( 23, 38 ), 2, 'Spin 23 (24 Black), bet 38 pays 2'; +is payout( 23, 39 ), -1, 'Spin 23 (24 Black), bet 39 pays -1'; +is payout( 23, 40 ), -1, 'Spin 23 (24 Black), bet 40 pays -1'; +is payout( 23, 41 ), -1, 'Spin 23 (24 Black), bet 41 pays -1'; +is payout( 23, 42 ), 2, 'Spin 23 (24 Black), bet 42 pays 2'; +is payout( 23, 43 ), -1, 'Spin 23 (24 Black), bet 43 pays -1'; +is payout( 23, 44 ), 1, 'Spin 23 (24 Black), bet 44 pays 1'; +is payout( 23, 45 ), 1, 'Spin 23 (24 Black), bet 45 pays 1'; +is payout( 23, 46 ), -1, 'Spin 23 (24 Black), bet 46 pays -1'; +is payout( 23, 47 ), -1, 'Spin 23 (24 Black), bet 47 pays -1'; +is payout( 23, 48 ), 1, 'Spin 23 (24 Black), bet 48 pays 1'; +is payout( 23, 49 ), -1, 'Spin 23 (24 Black), bet 49 pays -1'; +is payout( 23, 50 ), -1, 'Spin 23 (24 Black), bet 50 pays -1'; +is format_spin( 24 ), '25 Red', 'Spin 24 is 25 Red'; +is payout( 24, 1 ), -1, 'Spin 24 (25 Red), bet 1 pays -1'; +is payout( 24, 2 ), -1, 'Spin 24 (25 Red), bet 2 pays -1'; +is payout( 24, 3 ), -1, 'Spin 24 (25 Red), bet 3 pays -1'; +is payout( 24, 4 ), -1, 'Spin 24 (25 Red), bet 4 pays -1'; +is payout( 24, 5 ), -1, 'Spin 24 (25 Red), bet 5 pays -1'; +is payout( 24, 6 ), -1, 'Spin 24 (25 Red), bet 6 pays -1'; +is payout( 24, 7 ), -1, 'Spin 24 (25 Red), bet 7 pays -1'; +is payout( 24, 8 ), -1, 'Spin 24 (25 Red), bet 8 pays -1'; +is payout( 24, 9 ), -1, 'Spin 24 (25 Red), bet 9 pays -1'; +is payout( 24, 10 ), -1, 'Spin 24 (25 Red), bet 10 pays -1'; +is payout( 24, 11 ), -1, 'Spin 24 (25 Red), bet 11 pays -1'; +is payout( 24, 12 ), -1, 'Spin 24 (25 Red), bet 12 pays -1'; +is payout( 24, 13 ), -1, 'Spin 24 (25 Red), bet 13 pays -1'; +is payout( 24, 14 ), -1, 'Spin 24 (25 Red), bet 14 pays -1'; +is payout( 24, 15 ), -1, 'Spin 24 (25 Red), bet 15 pays -1'; +is payout( 24, 16 ), -1, 'Spin 24 (25 Red), bet 16 pays -1'; +is payout( 24, 17 ), -1, 'Spin 24 (25 Red), bet 17 pays -1'; +is payout( 24, 18 ), -1, 'Spin 24 (25 Red), bet 18 pays -1'; +is payout( 24, 19 ), -1, 'Spin 24 (25 Red), bet 19 pays -1'; +is payout( 24, 20 ), -1, 'Spin 24 (25 Red), bet 20 pays -1'; +is payout( 24, 21 ), -1, 'Spin 24 (25 Red), bet 21 pays -1'; +is payout( 24, 22 ), -1, 'Spin 24 (25 Red), bet 22 pays -1'; +is payout( 24, 23 ), -1, 'Spin 24 (25 Red), bet 23 pays -1'; +is payout( 24, 24 ), -1, 'Spin 24 (25 Red), bet 24 pays -1'; +is payout( 24, 25 ), 35, 'Spin 24 (25 Red), bet 25 pays 35'; +is payout( 24, 26 ), -1, 'Spin 24 (25 Red), bet 26 pays -1'; +is payout( 24, 27 ), -1, 'Spin 24 (25 Red), bet 27 pays -1'; +is payout( 24, 28 ), -1, 'Spin 24 (25 Red), bet 28 pays -1'; +is payout( 24, 29 ), -1, 'Spin 24 (25 Red), bet 29 pays -1'; +is payout( 24, 30 ), -1, 'Spin 24 (25 Red), bet 30 pays -1'; +is payout( 24, 31 ), -1, 'Spin 24 (25 Red), bet 31 pays -1'; +is payout( 24, 32 ), -1, 'Spin 24 (25 Red), bet 32 pays -1'; +is payout( 24, 33 ), -1, 'Spin 24 (25 Red), bet 33 pays -1'; +is payout( 24, 34 ), -1, 'Spin 24 (25 Red), bet 34 pays -1'; +is payout( 24, 35 ), -1, 'Spin 24 (25 Red), bet 35 pays -1'; +is payout( 24, 36 ), -1, 'Spin 24 (25 Red), bet 36 pays -1'; +is payout( 24, 37 ), -1, 'Spin 24 (25 Red), bet 37 pays -1'; +is payout( 24, 38 ), -1, 'Spin 24 (25 Red), bet 38 pays -1'; +is payout( 24, 39 ), 2, 'Spin 24 (25 Red), bet 39 pays 2'; +is payout( 24, 40 ), 2, 'Spin 24 (25 Red), bet 40 pays 2'; +is payout( 24, 41 ), -1, 'Spin 24 (25 Red), bet 41 pays -1'; +is payout( 24, 42 ), -1, 'Spin 24 (25 Red), bet 42 pays -1'; +is payout( 24, 43 ), -1, 'Spin 24 (25 Red), bet 43 pays -1'; +is payout( 24, 44 ), 1, 'Spin 24 (25 Red), bet 44 pays 1'; +is payout( 24, 45 ), -1, 'Spin 24 (25 Red), bet 45 pays -1'; +is payout( 24, 46 ), 1, 'Spin 24 (25 Red), bet 46 pays 1'; +is payout( 24, 47 ), 1, 'Spin 24 (25 Red), bet 47 pays 1'; +is payout( 24, 48 ), -1, 'Spin 24 (25 Red), bet 48 pays -1'; +is payout( 24, 49 ), -1, 'Spin 24 (25 Red), bet 49 pays -1'; +is payout( 24, 50 ), -1, 'Spin 24 (25 Red), bet 50 pays -1'; +is format_spin( 25 ), '26 Black', 'Spin 25 is 26 Black'; +is payout( 25, 1 ), -1, 'Spin 25 (26 Black), bet 1 pays -1'; +is payout( 25, 2 ), -1, 'Spin 25 (26 Black), bet 2 pays -1'; +is payout( 25, 3 ), -1, 'Spin 25 (26 Black), bet 3 pays -1'; +is payout( 25, 4 ), -1, 'Spin 25 (26 Black), bet 4 pays -1'; +is payout( 25, 5 ), -1, 'Spin 25 (26 Black), bet 5 pays -1'; +is payout( 25, 6 ), -1, 'Spin 25 (26 Black), bet 6 pays -1'; +is payout( 25, 7 ), -1, 'Spin 25 (26 Black), bet 7 pays -1'; +is payout( 25, 8 ), -1, 'Spin 25 (26 Black), bet 8 pays -1'; +is payout( 25, 9 ), -1, 'Spin 25 (26 Black), bet 9 pays -1'; +is payout( 25, 10 ), -1, 'Spin 25 (26 Black), bet 10 pays -1'; +is payout( 25, 11 ), -1, 'Spin 25 (26 Black), bet 11 pays -1'; +is payout( 25, 12 ), -1, 'Spin 25 (26 Black), bet 12 pays -1'; +is payout( 25, 13 ), -1, 'Spin 25 (26 Black), bet 13 pays -1'; +is payout( 25, 14 ), -1, 'Spin 25 (26 Black), bet 14 pays -1'; +is payout( 25, 15 ), -1, 'Spin 25 (26 Black), bet 15 pays -1'; +is payout( 25, 16 ), -1, 'Spin 25 (26 Black), bet 16 pays -1'; +is payout( 25, 17 ), -1, 'Spin 25 (26 Black), bet 17 pays -1'; +is payout( 25, 18 ), -1, 'Spin 25 (26 Black), bet 18 pays -1'; +is payout( 25, 19 ), -1, 'Spin 25 (26 Black), bet 19 pays -1'; +is payout( 25, 20 ), -1, 'Spin 25 (26 Black), bet 20 pays -1'; +is payout( 25, 21 ), -1, 'Spin 25 (26 Black), bet 21 pays -1'; +is payout( 25, 22 ), -1, 'Spin 25 (26 Black), bet 22 pays -1'; +is payout( 25, 23 ), -1, 'Spin 25 (26 Black), bet 23 pays -1'; +is payout( 25, 24 ), -1, 'Spin 25 (26 Black), bet 24 pays -1'; +is payout( 25, 25 ), -1, 'Spin 25 (26 Black), bet 25 pays -1'; +is payout( 25, 26 ), 35, 'Spin 25 (26 Black), bet 26 pays 35'; +is payout( 25, 27 ), -1, 'Spin 25 (26 Black), bet 27 pays -1'; +is payout( 25, 28 ), -1, 'Spin 25 (26 Black), bet 28 pays -1'; +is payout( 25, 29 ), -1, 'Spin 25 (26 Black), bet 29 pays -1'; +is payout( 25, 30 ), -1, 'Spin 25 (26 Black), bet 30 pays -1'; +is payout( 25, 31 ), -1, 'Spin 25 (26 Black), bet 31 pays -1'; +is payout( 25, 32 ), -1, 'Spin 25 (26 Black), bet 32 pays -1'; +is payout( 25, 33 ), -1, 'Spin 25 (26 Black), bet 33 pays -1'; +is payout( 25, 34 ), -1, 'Spin 25 (26 Black), bet 34 pays -1'; +is payout( 25, 35 ), -1, 'Spin 25 (26 Black), bet 35 pays -1'; +is payout( 25, 36 ), -1, 'Spin 25 (26 Black), bet 36 pays -1'; +is payout( 25, 37 ), -1, 'Spin 25 (26 Black), bet 37 pays -1'; +is payout( 25, 38 ), -1, 'Spin 25 (26 Black), bet 38 pays -1'; +is payout( 25, 39 ), 2, 'Spin 25 (26 Black), bet 39 pays 2'; +is payout( 25, 40 ), -1, 'Spin 25 (26 Black), bet 40 pays -1'; +is payout( 25, 41 ), 2, 'Spin 25 (26 Black), bet 41 pays 2'; +is payout( 25, 42 ), -1, 'Spin 25 (26 Black), bet 42 pays -1'; +is payout( 25, 43 ), -1, 'Spin 25 (26 Black), bet 43 pays -1'; +is payout( 25, 44 ), 1, 'Spin 25 (26 Black), bet 44 pays 1'; +is payout( 25, 45 ), 1, 'Spin 25 (26 Black), bet 45 pays 1'; +is payout( 25, 46 ), -1, 'Spin 25 (26 Black), bet 46 pays -1'; +is payout( 25, 47 ), -1, 'Spin 25 (26 Black), bet 47 pays -1'; +is payout( 25, 48 ), 1, 'Spin 25 (26 Black), bet 48 pays 1'; +is payout( 25, 49 ), -1, 'Spin 25 (26 Black), bet 49 pays -1'; +is payout( 25, 50 ), -1, 'Spin 25 (26 Black), bet 50 pays -1'; +is format_spin( 26 ), '27 Red', 'Spin 26 is 27 Red'; +is payout( 26, 1 ), -1, 'Spin 26 (27 Red), bet 1 pays -1'; +is payout( 26, 2 ), -1, 'Spin 26 (27 Red), bet 2 pays -1'; +is payout( 26, 3 ), -1, 'Spin 26 (27 Red), bet 3 pays -1'; +is payout( 26, 4 ), -1, 'Spin 26 (27 Red), bet 4 pays -1'; +is payout( 26, 5 ), -1, 'Spin 26 (27 Red), bet 5 pays -1'; +is payout( 26, 6 ), -1, 'Spin 26 (27 Red), bet 6 pays -1'; +is payout( 26, 7 ), -1, 'Spin 26 (27 Red), bet 7 pays -1'; +is payout( 26, 8 ), -1, 'Spin 26 (27 Red), bet 8 pays -1'; +is payout( 26, 9 ), -1, 'Spin 26 (27 Red), bet 9 pays -1'; +is payout( 26, 10 ), -1, 'Spin 26 (27 Red), bet 10 pays -1'; +is payout( 26, 11 ), -1, 'Spin 26 (27 Red), bet 11 pays -1'; +is payout( 26, 12 ), -1, 'Spin 26 (27 Red), bet 12 pays -1'; +is payout( 26, 13 ), -1, 'Spin 26 (27 Red), bet 13 pays -1'; +is payout( 26, 14 ), -1, 'Spin 26 (27 Red), bet 14 pays -1'; +is payout( 26, 15 ), -1, 'Spin 26 (27 Red), bet 15 pays -1'; +is payout( 26, 16 ), -1, 'Spin 26 (27 Red), bet 16 pays -1'; +is payout( 26, 17 ), -1, 'Spin 26 (27 Red), bet 17 pays -1'; +is payout( 26, 18 ), -1, 'Spin 26 (27 Red), bet 18 pays -1'; +is payout( 26, 19 ), -1, 'Spin 26 (27 Red), bet 19 pays -1'; +is payout( 26, 20 ), -1, 'Spin 26 (27 Red), bet 20 pays -1'; +is payout( 26, 21 ), -1, 'Spin 26 (27 Red), bet 21 pays -1'; +is payout( 26, 22 ), -1, 'Spin 26 (27 Red), bet 22 pays -1'; +is payout( 26, 23 ), -1, 'Spin 26 (27 Red), bet 23 pays -1'; +is payout( 26, 24 ), -1, 'Spin 26 (27 Red), bet 24 pays -1'; +is payout( 26, 25 ), -1, 'Spin 26 (27 Red), bet 25 pays -1'; +is payout( 26, 26 ), -1, 'Spin 26 (27 Red), bet 26 pays -1'; +is payout( 26, 27 ), 35, 'Spin 26 (27 Red), bet 27 pays 35'; +is payout( 26, 28 ), -1, 'Spin 26 (27 Red), bet 28 pays -1'; +is payout( 26, 29 ), -1, 'Spin 26 (27 Red), bet 29 pays -1'; +is payout( 26, 30 ), -1, 'Spin 26 (27 Red), bet 30 pays -1'; +is payout( 26, 31 ), -1, 'Spin 26 (27 Red), bet 31 pays -1'; +is payout( 26, 32 ), -1, 'Spin 26 (27 Red), bet 32 pays -1'; +is payout( 26, 33 ), -1, 'Spin 26 (27 Red), bet 33 pays -1'; +is payout( 26, 34 ), -1, 'Spin 26 (27 Red), bet 34 pays -1'; +is payout( 26, 35 ), -1, 'Spin 26 (27 Red), bet 35 pays -1'; +is payout( 26, 36 ), -1, 'Spin 26 (27 Red), bet 36 pays -1'; +is payout( 26, 37 ), -1, 'Spin 26 (27 Red), bet 37 pays -1'; +is payout( 26, 38 ), -1, 'Spin 26 (27 Red), bet 38 pays -1'; +is payout( 26, 39 ), 2, 'Spin 26 (27 Red), bet 39 pays 2'; +is payout( 26, 40 ), -1, 'Spin 26 (27 Red), bet 40 pays -1'; +is payout( 26, 41 ), -1, 'Spin 26 (27 Red), bet 41 pays -1'; +is payout( 26, 42 ), 2, 'Spin 26 (27 Red), bet 42 pays 2'; +is payout( 26, 43 ), -1, 'Spin 26 (27 Red), bet 43 pays -1'; +is payout( 26, 44 ), 1, 'Spin 26 (27 Red), bet 44 pays 1'; +is payout( 26, 45 ), -1, 'Spin 26 (27 Red), bet 45 pays -1'; +is payout( 26, 46 ), 1, 'Spin 26 (27 Red), bet 46 pays 1'; +is payout( 26, 47 ), 1, 'Spin 26 (27 Red), bet 47 pays 1'; +is payout( 26, 48 ), -1, 'Spin 26 (27 Red), bet 48 pays -1'; +is payout( 26, 49 ), -1, 'Spin 26 (27 Red), bet 49 pays -1'; +is payout( 26, 50 ), -1, 'Spin 26 (27 Red), bet 50 pays -1'; +is format_spin( 27 ), '28 Black', 'Spin 27 is 28 Black'; +is payout( 27, 1 ), -1, 'Spin 27 (28 Black), bet 1 pays -1'; +is payout( 27, 2 ), -1, 'Spin 27 (28 Black), bet 2 pays -1'; +is payout( 27, 3 ), -1, 'Spin 27 (28 Black), bet 3 pays -1'; +is payout( 27, 4 ), -1, 'Spin 27 (28 Black), bet 4 pays -1'; +is payout( 27, 5 ), -1, 'Spin 27 (28 Black), bet 5 pays -1'; +is payout( 27, 6 ), -1, 'Spin 27 (28 Black), bet 6 pays -1'; +is payout( 27, 7 ), -1, 'Spin 27 (28 Black), bet 7 pays -1'; +is payout( 27, 8 ), -1, 'Spin 27 (28 Black), bet 8 pays -1'; +is payout( 27, 9 ), -1, 'Spin 27 (28 Black), bet 9 pays -1'; +is payout( 27, 10 ), -1, 'Spin 27 (28 Black), bet 10 pays -1'; +is payout( 27, 11 ), -1, 'Spin 27 (28 Black), bet 11 pays -1'; +is payout( 27, 12 ), -1, 'Spin 27 (28 Black), bet 12 pays -1'; +is payout( 27, 13 ), -1, 'Spin 27 (28 Black), bet 13 pays -1'; +is payout( 27, 14 ), -1, 'Spin 27 (28 Black), bet 14 pays -1'; +is payout( 27, 15 ), -1, 'Spin 27 (28 Black), bet 15 pays -1'; +is payout( 27, 16 ), -1, 'Spin 27 (28 Black), bet 16 pays -1'; +is payout( 27, 17 ), -1, 'Spin 27 (28 Black), bet 17 pays -1'; +is payout( 27, 18 ), -1, 'Spin 27 (28 Black), bet 18 pays -1'; +is payout( 27, 19 ), -1, 'Spin 27 (28 Black), bet 19 pays -1'; +is payout( 27, 20 ), -1, 'Spin 27 (28 Black), bet 20 pays -1'; +is payout( 27, 21 ), -1, 'Spin 27 (28 Black), bet 21 pays -1'; +is payout( 27, 22 ), -1, 'Spin 27 (28 Black), bet 22 pays -1'; +is payout( 27, 23 ), -1, 'Spin 27 (28 Black), bet 23 pays -1'; +is payout( 27, 24 ), -1, 'Spin 27 (28 Black), bet 24 pays -1'; +is payout( 27, 25 ), -1, 'Spin 27 (28 Black), bet 25 pays -1'; +is payout( 27, 26 ), -1, 'Spin 27 (28 Black), bet 26 pays -1'; +is payout( 27, 27 ), -1, 'Spin 27 (28 Black), bet 27 pays -1'; +is payout( 27, 28 ), 35, 'Spin 27 (28 Black), bet 28 pays 35'; +is payout( 27, 29 ), -1, 'Spin 27 (28 Black), bet 29 pays -1'; +is payout( 27, 30 ), -1, 'Spin 27 (28 Black), bet 30 pays -1'; +is payout( 27, 31 ), -1, 'Spin 27 (28 Black), bet 31 pays -1'; +is payout( 27, 32 ), -1, 'Spin 27 (28 Black), bet 32 pays -1'; +is payout( 27, 33 ), -1, 'Spin 27 (28 Black), bet 33 pays -1'; +is payout( 27, 34 ), -1, 'Spin 27 (28 Black), bet 34 pays -1'; +is payout( 27, 35 ), -1, 'Spin 27 (28 Black), bet 35 pays -1'; +is payout( 27, 36 ), -1, 'Spin 27 (28 Black), bet 36 pays -1'; +is payout( 27, 37 ), -1, 'Spin 27 (28 Black), bet 37 pays -1'; +is payout( 27, 38 ), -1, 'Spin 27 (28 Black), bet 38 pays -1'; +is payout( 27, 39 ), 2, 'Spin 27 (28 Black), bet 39 pays 2'; +is payout( 27, 40 ), 2, 'Spin 27 (28 Black), bet 40 pays 2'; +is payout( 27, 41 ), -1, 'Spin 27 (28 Black), bet 41 pays -1'; +is payout( 27, 42 ), -1, 'Spin 27 (28 Black), bet 42 pays -1'; +is payout( 27, 43 ), -1, 'Spin 27 (28 Black), bet 43 pays -1'; +is payout( 27, 44 ), 1, 'Spin 27 (28 Black), bet 44 pays 1'; +is payout( 27, 45 ), 1, 'Spin 27 (28 Black), bet 45 pays 1'; +is payout( 27, 46 ), -1, 'Spin 27 (28 Black), bet 46 pays -1'; +is payout( 27, 47 ), -1, 'Spin 27 (28 Black), bet 47 pays -1'; +is payout( 27, 48 ), 1, 'Spin 27 (28 Black), bet 48 pays 1'; +is payout( 27, 49 ), -1, 'Spin 27 (28 Black), bet 49 pays -1'; +is payout( 27, 50 ), -1, 'Spin 27 (28 Black), bet 50 pays -1'; +is format_spin( 28 ), '29 Black', 'Spin 28 is 29 Black'; +is payout( 28, 1 ), -1, 'Spin 28 (29 Black), bet 1 pays -1'; +is payout( 28, 2 ), -1, 'Spin 28 (29 Black), bet 2 pays -1'; +is payout( 28, 3 ), -1, 'Spin 28 (29 Black), bet 3 pays -1'; +is payout( 28, 4 ), -1, 'Spin 28 (29 Black), bet 4 pays -1'; +is payout( 28, 5 ), -1, 'Spin 28 (29 Black), bet 5 pays -1'; +is payout( 28, 6 ), -1, 'Spin 28 (29 Black), bet 6 pays -1'; +is payout( 28, 7 ), -1, 'Spin 28 (29 Black), bet 7 pays -1'; +is payout( 28, 8 ), -1, 'Spin 28 (29 Black), bet 8 pays -1'; +is payout( 28, 9 ), -1, 'Spin 28 (29 Black), bet 9 pays -1'; +is payout( 28, 10 ), -1, 'Spin 28 (29 Black), bet 10 pays -1'; +is payout( 28, 11 ), -1, 'Spin 28 (29 Black), bet 11 pays -1'; +is payout( 28, 12 ), -1, 'Spin 28 (29 Black), bet 12 pays -1'; +is payout( 28, 13 ), -1, 'Spin 28 (29 Black), bet 13 pays -1'; +is payout( 28, 14 ), -1, 'Spin 28 (29 Black), bet 14 pays -1'; +is payout( 28, 15 ), -1, 'Spin 28 (29 Black), bet 15 pays -1'; +is payout( 28, 16 ), -1, 'Spin 28 (29 Black), bet 16 pays -1'; +is payout( 28, 17 ), -1, 'Spin 28 (29 Black), bet 17 pays -1'; +is payout( 28, 18 ), -1, 'Spin 28 (29 Black), bet 18 pays -1'; +is payout( 28, 19 ), -1, 'Spin 28 (29 Black), bet 19 pays -1'; +is payout( 28, 20 ), -1, 'Spin 28 (29 Black), bet 20 pays -1'; +is payout( 28, 21 ), -1, 'Spin 28 (29 Black), bet 21 pays -1'; +is payout( 28, 22 ), -1, 'Spin 28 (29 Black), bet 22 pays -1'; +is payout( 28, 23 ), -1, 'Spin 28 (29 Black), bet 23 pays -1'; +is payout( 28, 24 ), -1, 'Spin 28 (29 Black), bet 24 pays -1'; +is payout( 28, 25 ), -1, 'Spin 28 (29 Black), bet 25 pays -1'; +is payout( 28, 26 ), -1, 'Spin 28 (29 Black), bet 26 pays -1'; +is payout( 28, 27 ), -1, 'Spin 28 (29 Black), bet 27 pays -1'; +is payout( 28, 28 ), -1, 'Spin 28 (29 Black), bet 28 pays -1'; +is payout( 28, 29 ), 35, 'Spin 28 (29 Black), bet 29 pays 35'; +is payout( 28, 30 ), -1, 'Spin 28 (29 Black), bet 30 pays -1'; +is payout( 28, 31 ), -1, 'Spin 28 (29 Black), bet 31 pays -1'; +is payout( 28, 32 ), -1, 'Spin 28 (29 Black), bet 32 pays -1'; +is payout( 28, 33 ), -1, 'Spin 28 (29 Black), bet 33 pays -1'; +is payout( 28, 34 ), -1, 'Spin 28 (29 Black), bet 34 pays -1'; +is payout( 28, 35 ), -1, 'Spin 28 (29 Black), bet 35 pays -1'; +is payout( 28, 36 ), -1, 'Spin 28 (29 Black), bet 36 pays -1'; +is payout( 28, 37 ), -1, 'Spin 28 (29 Black), bet 37 pays -1'; +is payout( 28, 38 ), -1, 'Spin 28 (29 Black), bet 38 pays -1'; +is payout( 28, 39 ), 2, 'Spin 28 (29 Black), bet 39 pays 2'; +is payout( 28, 40 ), -1, 'Spin 28 (29 Black), bet 40 pays -1'; +is payout( 28, 41 ), 2, 'Spin 28 (29 Black), bet 41 pays 2'; +is payout( 28, 42 ), -1, 'Spin 28 (29 Black), bet 42 pays -1'; +is payout( 28, 43 ), -1, 'Spin 28 (29 Black), bet 43 pays -1'; +is payout( 28, 44 ), 1, 'Spin 28 (29 Black), bet 44 pays 1'; +is payout( 28, 45 ), -1, 'Spin 28 (29 Black), bet 45 pays -1'; +is payout( 28, 46 ), 1, 'Spin 28 (29 Black), bet 46 pays 1'; +is payout( 28, 47 ), -1, 'Spin 28 (29 Black), bet 47 pays -1'; +is payout( 28, 48 ), 1, 'Spin 28 (29 Black), bet 48 pays 1'; +is payout( 28, 49 ), -1, 'Spin 28 (29 Black), bet 49 pays -1'; +is payout( 28, 50 ), -1, 'Spin 28 (29 Black), bet 50 pays -1'; +is format_spin( 29 ), '30 Red', 'Spin 29 is 30 Red'; +is payout( 29, 1 ), -1, 'Spin 29 (30 Red), bet 1 pays -1'; +is payout( 29, 2 ), -1, 'Spin 29 (30 Red), bet 2 pays -1'; +is payout( 29, 3 ), -1, 'Spin 29 (30 Red), bet 3 pays -1'; +is payout( 29, 4 ), -1, 'Spin 29 (30 Red), bet 4 pays -1'; +is payout( 29, 5 ), -1, 'Spin 29 (30 Red), bet 5 pays -1'; +is payout( 29, 6 ), -1, 'Spin 29 (30 Red), bet 6 pays -1'; +is payout( 29, 7 ), -1, 'Spin 29 (30 Red), bet 7 pays -1'; +is payout( 29, 8 ), -1, 'Spin 29 (30 Red), bet 8 pays -1'; +is payout( 29, 9 ), -1, 'Spin 29 (30 Red), bet 9 pays -1'; +is payout( 29, 10 ), -1, 'Spin 29 (30 Red), bet 10 pays -1'; +is payout( 29, 11 ), -1, 'Spin 29 (30 Red), bet 11 pays -1'; +is payout( 29, 12 ), -1, 'Spin 29 (30 Red), bet 12 pays -1'; +is payout( 29, 13 ), -1, 'Spin 29 (30 Red), bet 13 pays -1'; +is payout( 29, 14 ), -1, 'Spin 29 (30 Red), bet 14 pays -1'; +is payout( 29, 15 ), -1, 'Spin 29 (30 Red), bet 15 pays -1'; +is payout( 29, 16 ), -1, 'Spin 29 (30 Red), bet 16 pays -1'; +is payout( 29, 17 ), -1, 'Spin 29 (30 Red), bet 17 pays -1'; +is payout( 29, 18 ), -1, 'Spin 29 (30 Red), bet 18 pays -1'; +is payout( 29, 19 ), -1, 'Spin 29 (30 Red), bet 19 pays -1'; +is payout( 29, 20 ), -1, 'Spin 29 (30 Red), bet 20 pays -1'; +is payout( 29, 21 ), -1, 'Spin 29 (30 Red), bet 21 pays -1'; +is payout( 29, 22 ), -1, 'Spin 29 (30 Red), bet 22 pays -1'; +is payout( 29, 23 ), -1, 'Spin 29 (30 Red), bet 23 pays -1'; +is payout( 29, 24 ), -1, 'Spin 29 (30 Red), bet 24 pays -1'; +is payout( 29, 25 ), -1, 'Spin 29 (30 Red), bet 25 pays -1'; +is payout( 29, 26 ), -1, 'Spin 29 (30 Red), bet 26 pays -1'; +is payout( 29, 27 ), -1, 'Spin 29 (30 Red), bet 27 pays -1'; +is payout( 29, 28 ), -1, 'Spin 29 (30 Red), bet 28 pays -1'; +is payout( 29, 29 ), -1, 'Spin 29 (30 Red), bet 29 pays -1'; +is payout( 29, 30 ), 35, 'Spin 29 (30 Red), bet 30 pays 35'; +is payout( 29, 31 ), -1, 'Spin 29 (30 Red), bet 31 pays -1'; +is payout( 29, 32 ), -1, 'Spin 29 (30 Red), bet 32 pays -1'; +is payout( 29, 33 ), -1, 'Spin 29 (30 Red), bet 33 pays -1'; +is payout( 29, 34 ), -1, 'Spin 29 (30 Red), bet 34 pays -1'; +is payout( 29, 35 ), -1, 'Spin 29 (30 Red), bet 35 pays -1'; +is payout( 29, 36 ), -1, 'Spin 29 (30 Red), bet 36 pays -1'; +is payout( 29, 37 ), -1, 'Spin 29 (30 Red), bet 37 pays -1'; +is payout( 29, 38 ), -1, 'Spin 29 (30 Red), bet 38 pays -1'; +is payout( 29, 39 ), 2, 'Spin 29 (30 Red), bet 39 pays 2'; +is payout( 29, 40 ), -1, 'Spin 29 (30 Red), bet 40 pays -1'; +is payout( 29, 41 ), -1, 'Spin 29 (30 Red), bet 41 pays -1'; +is payout( 29, 42 ), 2, 'Spin 29 (30 Red), bet 42 pays 2'; +is payout( 29, 43 ), -1, 'Spin 29 (30 Red), bet 43 pays -1'; +is payout( 29, 44 ), 1, 'Spin 29 (30 Red), bet 44 pays 1'; +is payout( 29, 45 ), 1, 'Spin 29 (30 Red), bet 45 pays 1'; +is payout( 29, 46 ), -1, 'Spin 29 (30 Red), bet 46 pays -1'; +is payout( 29, 47 ), 1, 'Spin 29 (30 Red), bet 47 pays 1'; +is payout( 29, 48 ), -1, 'Spin 29 (30 Red), bet 48 pays -1'; +is payout( 29, 49 ), -1, 'Spin 29 (30 Red), bet 49 pays -1'; +is payout( 29, 50 ), -1, 'Spin 29 (30 Red), bet 50 pays -1'; +is format_spin( 30 ), '31 Black', 'Spin 30 is 31 Black'; +is payout( 30, 1 ), -1, 'Spin 30 (31 Black), bet 1 pays -1'; +is payout( 30, 2 ), -1, 'Spin 30 (31 Black), bet 2 pays -1'; +is payout( 30, 3 ), -1, 'Spin 30 (31 Black), bet 3 pays -1'; +is payout( 30, 4 ), -1, 'Spin 30 (31 Black), bet 4 pays -1'; +is payout( 30, 5 ), -1, 'Spin 30 (31 Black), bet 5 pays -1'; +is payout( 30, 6 ), -1, 'Spin 30 (31 Black), bet 6 pays -1'; +is payout( 30, 7 ), -1, 'Spin 30 (31 Black), bet 7 pays -1'; +is payout( 30, 8 ), -1, 'Spin 30 (31 Black), bet 8 pays -1'; +is payout( 30, 9 ), -1, 'Spin 30 (31 Black), bet 9 pays -1'; +is payout( 30, 10 ), -1, 'Spin 30 (31 Black), bet 10 pays -1'; +is payout( 30, 11 ), -1, 'Spin 30 (31 Black), bet 11 pays -1'; +is payout( 30, 12 ), -1, 'Spin 30 (31 Black), bet 12 pays -1'; +is payout( 30, 13 ), -1, 'Spin 30 (31 Black), bet 13 pays -1'; +is payout( 30, 14 ), -1, 'Spin 30 (31 Black), bet 14 pays -1'; +is payout( 30, 15 ), -1, 'Spin 30 (31 Black), bet 15 pays -1'; +is payout( 30, 16 ), -1, 'Spin 30 (31 Black), bet 16 pays -1'; +is payout( 30, 17 ), -1, 'Spin 30 (31 Black), bet 17 pays -1'; +is payout( 30, 18 ), -1, 'Spin 30 (31 Black), bet 18 pays -1'; +is payout( 30, 19 ), -1, 'Spin 30 (31 Black), bet 19 pays -1'; +is payout( 30, 20 ), -1, 'Spin 30 (31 Black), bet 20 pays -1'; +is payout( 30, 21 ), -1, 'Spin 30 (31 Black), bet 21 pays -1'; +is payout( 30, 22 ), -1, 'Spin 30 (31 Black), bet 22 pays -1'; +is payout( 30, 23 ), -1, 'Spin 30 (31 Black), bet 23 pays -1'; +is payout( 30, 24 ), -1, 'Spin 30 (31 Black), bet 24 pays -1'; +is payout( 30, 25 ), -1, 'Spin 30 (31 Black), bet 25 pays -1'; +is payout( 30, 26 ), -1, 'Spin 30 (31 Black), bet 26 pays -1'; +is payout( 30, 27 ), -1, 'Spin 30 (31 Black), bet 27 pays -1'; +is payout( 30, 28 ), -1, 'Spin 30 (31 Black), bet 28 pays -1'; +is payout( 30, 29 ), -1, 'Spin 30 (31 Black), bet 29 pays -1'; +is payout( 30, 30 ), -1, 'Spin 30 (31 Black), bet 30 pays -1'; +is payout( 30, 31 ), 35, 'Spin 30 (31 Black), bet 31 pays 35'; +is payout( 30, 32 ), -1, 'Spin 30 (31 Black), bet 32 pays -1'; +is payout( 30, 33 ), -1, 'Spin 30 (31 Black), bet 33 pays -1'; +is payout( 30, 34 ), -1, 'Spin 30 (31 Black), bet 34 pays -1'; +is payout( 30, 35 ), -1, 'Spin 30 (31 Black), bet 35 pays -1'; +is payout( 30, 36 ), -1, 'Spin 30 (31 Black), bet 36 pays -1'; +is payout( 30, 37 ), -1, 'Spin 30 (31 Black), bet 37 pays -1'; +is payout( 30, 38 ), -1, 'Spin 30 (31 Black), bet 38 pays -1'; +is payout( 30, 39 ), 2, 'Spin 30 (31 Black), bet 39 pays 2'; +is payout( 30, 40 ), 2, 'Spin 30 (31 Black), bet 40 pays 2'; +is payout( 30, 41 ), -1, 'Spin 30 (31 Black), bet 41 pays -1'; +is payout( 30, 42 ), -1, 'Spin 30 (31 Black), bet 42 pays -1'; +is payout( 30, 43 ), -1, 'Spin 30 (31 Black), bet 43 pays -1'; +is payout( 30, 44 ), 1, 'Spin 30 (31 Black), bet 44 pays 1'; +is payout( 30, 45 ), -1, 'Spin 30 (31 Black), bet 45 pays -1'; +is payout( 30, 46 ), 1, 'Spin 30 (31 Black), bet 46 pays 1'; +is payout( 30, 47 ), -1, 'Spin 30 (31 Black), bet 47 pays -1'; +is payout( 30, 48 ), 1, 'Spin 30 (31 Black), bet 48 pays 1'; +is payout( 30, 49 ), -1, 'Spin 30 (31 Black), bet 49 pays -1'; +is payout( 30, 50 ), -1, 'Spin 30 (31 Black), bet 50 pays -1'; +is format_spin( 31 ), '32 Red', 'Spin 31 is 32 Red'; +is payout( 31, 1 ), -1, 'Spin 31 (32 Red), bet 1 pays -1'; +is payout( 31, 2 ), -1, 'Spin 31 (32 Red), bet 2 pays -1'; +is payout( 31, 3 ), -1, 'Spin 31 (32 Red), bet 3 pays -1'; +is payout( 31, 4 ), -1, 'Spin 31 (32 Red), bet 4 pays -1'; +is payout( 31, 5 ), -1, 'Spin 31 (32 Red), bet 5 pays -1'; +is payout( 31, 6 ), -1, 'Spin 31 (32 Red), bet 6 pays -1'; +is payout( 31, 7 ), -1, 'Spin 31 (32 Red), bet 7 pays -1'; +is payout( 31, 8 ), -1, 'Spin 31 (32 Red), bet 8 pays -1'; +is payout( 31, 9 ), -1, 'Spin 31 (32 Red), bet 9 pays -1'; +is payout( 31, 10 ), -1, 'Spin 31 (32 Red), bet 10 pays -1'; +is payout( 31, 11 ), -1, 'Spin 31 (32 Red), bet 11 pays -1'; +is payout( 31, 12 ), -1, 'Spin 31 (32 Red), bet 12 pays -1'; +is payout( 31, 13 ), -1, 'Spin 31 (32 Red), bet 13 pays -1'; +is payout( 31, 14 ), -1, 'Spin 31 (32 Red), bet 14 pays -1'; +is payout( 31, 15 ), -1, 'Spin 31 (32 Red), bet 15 pays -1'; +is payout( 31, 16 ), -1, 'Spin 31 (32 Red), bet 16 pays -1'; +is payout( 31, 17 ), -1, 'Spin 31 (32 Red), bet 17 pays -1'; +is payout( 31, 18 ), -1, 'Spin 31 (32 Red), bet 18 pays -1'; +is payout( 31, 19 ), -1, 'Spin 31 (32 Red), bet 19 pays -1'; +is payout( 31, 20 ), -1, 'Spin 31 (32 Red), bet 20 pays -1'; +is payout( 31, 21 ), -1, 'Spin 31 (32 Red), bet 21 pays -1'; +is payout( 31, 22 ), -1, 'Spin 31 (32 Red), bet 22 pays -1'; +is payout( 31, 23 ), -1, 'Spin 31 (32 Red), bet 23 pays -1'; +is payout( 31, 24 ), -1, 'Spin 31 (32 Red), bet 24 pays -1'; +is payout( 31, 25 ), -1, 'Spin 31 (32 Red), bet 25 pays -1'; +is payout( 31, 26 ), -1, 'Spin 31 (32 Red), bet 26 pays -1'; +is payout( 31, 27 ), -1, 'Spin 31 (32 Red), bet 27 pays -1'; +is payout( 31, 28 ), -1, 'Spin 31 (32 Red), bet 28 pays -1'; +is payout( 31, 29 ), -1, 'Spin 31 (32 Red), bet 29 pays -1'; +is payout( 31, 30 ), -1, 'Spin 31 (32 Red), bet 30 pays -1'; +is payout( 31, 31 ), -1, 'Spin 31 (32 Red), bet 31 pays -1'; +is payout( 31, 32 ), 35, 'Spin 31 (32 Red), bet 32 pays 35'; +is payout( 31, 33 ), -1, 'Spin 31 (32 Red), bet 33 pays -1'; +is payout( 31, 34 ), -1, 'Spin 31 (32 Red), bet 34 pays -1'; +is payout( 31, 35 ), -1, 'Spin 31 (32 Red), bet 35 pays -1'; +is payout( 31, 36 ), -1, 'Spin 31 (32 Red), bet 36 pays -1'; +is payout( 31, 37 ), -1, 'Spin 31 (32 Red), bet 37 pays -1'; +is payout( 31, 38 ), -1, 'Spin 31 (32 Red), bet 38 pays -1'; +is payout( 31, 39 ), 2, 'Spin 31 (32 Red), bet 39 pays 2'; +is payout( 31, 40 ), -1, 'Spin 31 (32 Red), bet 40 pays -1'; +is payout( 31, 41 ), 2, 'Spin 31 (32 Red), bet 41 pays 2'; +is payout( 31, 42 ), -1, 'Spin 31 (32 Red), bet 42 pays -1'; +is payout( 31, 43 ), -1, 'Spin 31 (32 Red), bet 43 pays -1'; +is payout( 31, 44 ), 1, 'Spin 31 (32 Red), bet 44 pays 1'; +is payout( 31, 45 ), 1, 'Spin 31 (32 Red), bet 45 pays 1'; +is payout( 31, 46 ), -1, 'Spin 31 (32 Red), bet 46 pays -1'; +is payout( 31, 47 ), 1, 'Spin 31 (32 Red), bet 47 pays 1'; +is payout( 31, 48 ), -1, 'Spin 31 (32 Red), bet 48 pays -1'; +is payout( 31, 49 ), -1, 'Spin 31 (32 Red), bet 49 pays -1'; +is payout( 31, 50 ), -1, 'Spin 31 (32 Red), bet 50 pays -1'; +is format_spin( 32 ), '33 Black', 'Spin 32 is 33 Black'; +is payout( 32, 1 ), -1, 'Spin 32 (33 Black), bet 1 pays -1'; +is payout( 32, 2 ), -1, 'Spin 32 (33 Black), bet 2 pays -1'; +is payout( 32, 3 ), -1, 'Spin 32 (33 Black), bet 3 pays -1'; +is payout( 32, 4 ), -1, 'Spin 32 (33 Black), bet 4 pays -1'; +is payout( 32, 5 ), -1, 'Spin 32 (33 Black), bet 5 pays -1'; +is payout( 32, 6 ), -1, 'Spin 32 (33 Black), bet 6 pays -1'; +is payout( 32, 7 ), -1, 'Spin 32 (33 Black), bet 7 pays -1'; +is payout( 32, 8 ), -1, 'Spin 32 (33 Black), bet 8 pays -1'; +is payout( 32, 9 ), -1, 'Spin 32 (33 Black), bet 9 pays -1'; +is payout( 32, 10 ), -1, 'Spin 32 (33 Black), bet 10 pays -1'; +is payout( 32, 11 ), -1, 'Spin 32 (33 Black), bet 11 pays -1'; +is payout( 32, 12 ), -1, 'Spin 32 (33 Black), bet 12 pays -1'; +is payout( 32, 13 ), -1, 'Spin 32 (33 Black), bet 13 pays -1'; +is payout( 32, 14 ), -1, 'Spin 32 (33 Black), bet 14 pays -1'; +is payout( 32, 15 ), -1, 'Spin 32 (33 Black), bet 15 pays -1'; +is payout( 32, 16 ), -1, 'Spin 32 (33 Black), bet 16 pays -1'; +is payout( 32, 17 ), -1, 'Spin 32 (33 Black), bet 17 pays -1'; +is payout( 32, 18 ), -1, 'Spin 32 (33 Black), bet 18 pays -1'; +is payout( 32, 19 ), -1, 'Spin 32 (33 Black), bet 19 pays -1'; +is payout( 32, 20 ), -1, 'Spin 32 (33 Black), bet 20 pays -1'; +is payout( 32, 21 ), -1, 'Spin 32 (33 Black), bet 21 pays -1'; +is payout( 32, 22 ), -1, 'Spin 32 (33 Black), bet 22 pays -1'; +is payout( 32, 23 ), -1, 'Spin 32 (33 Black), bet 23 pays -1'; +is payout( 32, 24 ), -1, 'Spin 32 (33 Black), bet 24 pays -1'; +is payout( 32, 25 ), -1, 'Spin 32 (33 Black), bet 25 pays -1'; +is payout( 32, 26 ), -1, 'Spin 32 (33 Black), bet 26 pays -1'; +is payout( 32, 27 ), -1, 'Spin 32 (33 Black), bet 27 pays -1'; +is payout( 32, 28 ), -1, 'Spin 32 (33 Black), bet 28 pays -1'; +is payout( 32, 29 ), -1, 'Spin 32 (33 Black), bet 29 pays -1'; +is payout( 32, 30 ), -1, 'Spin 32 (33 Black), bet 30 pays -1'; +is payout( 32, 31 ), -1, 'Spin 32 (33 Black), bet 31 pays -1'; +is payout( 32, 32 ), -1, 'Spin 32 (33 Black), bet 32 pays -1'; +is payout( 32, 33 ), 35, 'Spin 32 (33 Black), bet 33 pays 35'; +is payout( 32, 34 ), -1, 'Spin 32 (33 Black), bet 34 pays -1'; +is payout( 32, 35 ), -1, 'Spin 32 (33 Black), bet 35 pays -1'; +is payout( 32, 36 ), -1, 'Spin 32 (33 Black), bet 36 pays -1'; +is payout( 32, 37 ), -1, 'Spin 32 (33 Black), bet 37 pays -1'; +is payout( 32, 38 ), -1, 'Spin 32 (33 Black), bet 38 pays -1'; +is payout( 32, 39 ), 2, 'Spin 32 (33 Black), bet 39 pays 2'; +is payout( 32, 40 ), -1, 'Spin 32 (33 Black), bet 40 pays -1'; +is payout( 32, 41 ), -1, 'Spin 32 (33 Black), bet 41 pays -1'; +is payout( 32, 42 ), 2, 'Spin 32 (33 Black), bet 42 pays 2'; +is payout( 32, 43 ), -1, 'Spin 32 (33 Black), bet 43 pays -1'; +is payout( 32, 44 ), 1, 'Spin 32 (33 Black), bet 44 pays 1'; +is payout( 32, 45 ), -1, 'Spin 32 (33 Black), bet 45 pays -1'; +is payout( 32, 46 ), 1, 'Spin 32 (33 Black), bet 46 pays 1'; +is payout( 32, 47 ), -1, 'Spin 32 (33 Black), bet 47 pays -1'; +is payout( 32, 48 ), 1, 'Spin 32 (33 Black), bet 48 pays 1'; +is payout( 32, 49 ), -1, 'Spin 32 (33 Black), bet 49 pays -1'; +is payout( 32, 50 ), -1, 'Spin 32 (33 Black), bet 50 pays -1'; +is format_spin( 33 ), '34 Red', 'Spin 33 is 34 Red'; +is payout( 33, 1 ), -1, 'Spin 33 (34 Red), bet 1 pays -1'; +is payout( 33, 2 ), -1, 'Spin 33 (34 Red), bet 2 pays -1'; +is payout( 33, 3 ), -1, 'Spin 33 (34 Red), bet 3 pays -1'; +is payout( 33, 4 ), -1, 'Spin 33 (34 Red), bet 4 pays -1'; +is payout( 33, 5 ), -1, 'Spin 33 (34 Red), bet 5 pays -1'; +is payout( 33, 6 ), -1, 'Spin 33 (34 Red), bet 6 pays -1'; +is payout( 33, 7 ), -1, 'Spin 33 (34 Red), bet 7 pays -1'; +is payout( 33, 8 ), -1, 'Spin 33 (34 Red), bet 8 pays -1'; +is payout( 33, 9 ), -1, 'Spin 33 (34 Red), bet 9 pays -1'; +is payout( 33, 10 ), -1, 'Spin 33 (34 Red), bet 10 pays -1'; +is payout( 33, 11 ), -1, 'Spin 33 (34 Red), bet 11 pays -1'; +is payout( 33, 12 ), -1, 'Spin 33 (34 Red), bet 12 pays -1'; +is payout( 33, 13 ), -1, 'Spin 33 (34 Red), bet 13 pays -1'; +is payout( 33, 14 ), -1, 'Spin 33 (34 Red), bet 14 pays -1'; +is payout( 33, 15 ), -1, 'Spin 33 (34 Red), bet 15 pays -1'; +is payout( 33, 16 ), -1, 'Spin 33 (34 Red), bet 16 pays -1'; +is payout( 33, 17 ), -1, 'Spin 33 (34 Red), bet 17 pays -1'; +is payout( 33, 18 ), -1, 'Spin 33 (34 Red), bet 18 pays -1'; +is payout( 33, 19 ), -1, 'Spin 33 (34 Red), bet 19 pays -1'; +is payout( 33, 20 ), -1, 'Spin 33 (34 Red), bet 20 pays -1'; +is payout( 33, 21 ), -1, 'Spin 33 (34 Red), bet 21 pays -1'; +is payout( 33, 22 ), -1, 'Spin 33 (34 Red), bet 22 pays -1'; +is payout( 33, 23 ), -1, 'Spin 33 (34 Red), bet 23 pays -1'; +is payout( 33, 24 ), -1, 'Spin 33 (34 Red), bet 24 pays -1'; +is payout( 33, 25 ), -1, 'Spin 33 (34 Red), bet 25 pays -1'; +is payout( 33, 26 ), -1, 'Spin 33 (34 Red), bet 26 pays -1'; +is payout( 33, 27 ), -1, 'Spin 33 (34 Red), bet 27 pays -1'; +is payout( 33, 28 ), -1, 'Spin 33 (34 Red), bet 28 pays -1'; +is payout( 33, 29 ), -1, 'Spin 33 (34 Red), bet 29 pays -1'; +is payout( 33, 30 ), -1, 'Spin 33 (34 Red), bet 30 pays -1'; +is payout( 33, 31 ), -1, 'Spin 33 (34 Red), bet 31 pays -1'; +is payout( 33, 32 ), -1, 'Spin 33 (34 Red), bet 32 pays -1'; +is payout( 33, 33 ), -1, 'Spin 33 (34 Red), bet 33 pays -1'; +is payout( 33, 34 ), 35, 'Spin 33 (34 Red), bet 34 pays 35'; +is payout( 33, 35 ), -1, 'Spin 33 (34 Red), bet 35 pays -1'; +is payout( 33, 36 ), -1, 'Spin 33 (34 Red), bet 36 pays -1'; +is payout( 33, 37 ), -1, 'Spin 33 (34 Red), bet 37 pays -1'; +is payout( 33, 38 ), -1, 'Spin 33 (34 Red), bet 38 pays -1'; +is payout( 33, 39 ), 2, 'Spin 33 (34 Red), bet 39 pays 2'; +is payout( 33, 40 ), 2, 'Spin 33 (34 Red), bet 40 pays 2'; +is payout( 33, 41 ), -1, 'Spin 33 (34 Red), bet 41 pays -1'; +is payout( 33, 42 ), -1, 'Spin 33 (34 Red), bet 42 pays -1'; +is payout( 33, 43 ), -1, 'Spin 33 (34 Red), bet 43 pays -1'; +is payout( 33, 44 ), 1, 'Spin 33 (34 Red), bet 44 pays 1'; +is payout( 33, 45 ), 1, 'Spin 33 (34 Red), bet 45 pays 1'; +is payout( 33, 46 ), -1, 'Spin 33 (34 Red), bet 46 pays -1'; +is payout( 33, 47 ), 1, 'Spin 33 (34 Red), bet 47 pays 1'; +is payout( 33, 48 ), -1, 'Spin 33 (34 Red), bet 48 pays -1'; +is payout( 33, 49 ), -1, 'Spin 33 (34 Red), bet 49 pays -1'; +is payout( 33, 50 ), -1, 'Spin 33 (34 Red), bet 50 pays -1'; +is format_spin( 34 ), '35 Black', 'Spin 34 is 35 Black'; +is payout( 34, 1 ), -1, 'Spin 34 (35 Black), bet 1 pays -1'; +is payout( 34, 2 ), -1, 'Spin 34 (35 Black), bet 2 pays -1'; +is payout( 34, 3 ), -1, 'Spin 34 (35 Black), bet 3 pays -1'; +is payout( 34, 4 ), -1, 'Spin 34 (35 Black), bet 4 pays -1'; +is payout( 34, 5 ), -1, 'Spin 34 (35 Black), bet 5 pays -1'; +is payout( 34, 6 ), -1, 'Spin 34 (35 Black), bet 6 pays -1'; +is payout( 34, 7 ), -1, 'Spin 34 (35 Black), bet 7 pays -1'; +is payout( 34, 8 ), -1, 'Spin 34 (35 Black), bet 8 pays -1'; +is payout( 34, 9 ), -1, 'Spin 34 (35 Black), bet 9 pays -1'; +is payout( 34, 10 ), -1, 'Spin 34 (35 Black), bet 10 pays -1'; +is payout( 34, 11 ), -1, 'Spin 34 (35 Black), bet 11 pays -1'; +is payout( 34, 12 ), -1, 'Spin 34 (35 Black), bet 12 pays -1'; +is payout( 34, 13 ), -1, 'Spin 34 (35 Black), bet 13 pays -1'; +is payout( 34, 14 ), -1, 'Spin 34 (35 Black), bet 14 pays -1'; +is payout( 34, 15 ), -1, 'Spin 34 (35 Black), bet 15 pays -1'; +is payout( 34, 16 ), -1, 'Spin 34 (35 Black), bet 16 pays -1'; +is payout( 34, 17 ), -1, 'Spin 34 (35 Black), bet 17 pays -1'; +is payout( 34, 18 ), -1, 'Spin 34 (35 Black), bet 18 pays -1'; +is payout( 34, 19 ), -1, 'Spin 34 (35 Black), bet 19 pays -1'; +is payout( 34, 20 ), -1, 'Spin 34 (35 Black), bet 20 pays -1'; +is payout( 34, 21 ), -1, 'Spin 34 (35 Black), bet 21 pays -1'; +is payout( 34, 22 ), -1, 'Spin 34 (35 Black), bet 22 pays -1'; +is payout( 34, 23 ), -1, 'Spin 34 (35 Black), bet 23 pays -1'; +is payout( 34, 24 ), -1, 'Spin 34 (35 Black), bet 24 pays -1'; +is payout( 34, 25 ), -1, 'Spin 34 (35 Black), bet 25 pays -1'; +is payout( 34, 26 ), -1, 'Spin 34 (35 Black), bet 26 pays -1'; +is payout( 34, 27 ), -1, 'Spin 34 (35 Black), bet 27 pays -1'; +is payout( 34, 28 ), -1, 'Spin 34 (35 Black), bet 28 pays -1'; +is payout( 34, 29 ), -1, 'Spin 34 (35 Black), bet 29 pays -1'; +is payout( 34, 30 ), -1, 'Spin 34 (35 Black), bet 30 pays -1'; +is payout( 34, 31 ), -1, 'Spin 34 (35 Black), bet 31 pays -1'; +is payout( 34, 32 ), -1, 'Spin 34 (35 Black), bet 32 pays -1'; +is payout( 34, 33 ), -1, 'Spin 34 (35 Black), bet 33 pays -1'; +is payout( 34, 34 ), -1, 'Spin 34 (35 Black), bet 34 pays -1'; +is payout( 34, 35 ), 35, 'Spin 34 (35 Black), bet 35 pays 35'; +is payout( 34, 36 ), -1, 'Spin 34 (35 Black), bet 36 pays -1'; +is payout( 34, 37 ), -1, 'Spin 34 (35 Black), bet 37 pays -1'; +is payout( 34, 38 ), -1, 'Spin 34 (35 Black), bet 38 pays -1'; +is payout( 34, 39 ), 2, 'Spin 34 (35 Black), bet 39 pays 2'; +is payout( 34, 40 ), -1, 'Spin 34 (35 Black), bet 40 pays -1'; +is payout( 34, 41 ), 2, 'Spin 34 (35 Black), bet 41 pays 2'; +is payout( 34, 42 ), -1, 'Spin 34 (35 Black), bet 42 pays -1'; +is payout( 34, 43 ), -1, 'Spin 34 (35 Black), bet 43 pays -1'; +is payout( 34, 44 ), 1, 'Spin 34 (35 Black), bet 44 pays 1'; +is payout( 34, 45 ), -1, 'Spin 34 (35 Black), bet 45 pays -1'; +is payout( 34, 46 ), 1, 'Spin 34 (35 Black), bet 46 pays 1'; +is payout( 34, 47 ), -1, 'Spin 34 (35 Black), bet 47 pays -1'; +is payout( 34, 48 ), 1, 'Spin 34 (35 Black), bet 48 pays 1'; +is payout( 34, 49 ), -1, 'Spin 34 (35 Black), bet 49 pays -1'; +is payout( 34, 50 ), -1, 'Spin 34 (35 Black), bet 50 pays -1'; +is format_spin( 35 ), '36 Red', 'Spin 35 is 36 Red'; +is payout( 35, 1 ), -1, 'Spin 35 (36 Red), bet 1 pays -1'; +is payout( 35, 2 ), -1, 'Spin 35 (36 Red), bet 2 pays -1'; +is payout( 35, 3 ), -1, 'Spin 35 (36 Red), bet 3 pays -1'; +is payout( 35, 4 ), -1, 'Spin 35 (36 Red), bet 4 pays -1'; +is payout( 35, 5 ), -1, 'Spin 35 (36 Red), bet 5 pays -1'; +is payout( 35, 6 ), -1, 'Spin 35 (36 Red), bet 6 pays -1'; +is payout( 35, 7 ), -1, 'Spin 35 (36 Red), bet 7 pays -1'; +is payout( 35, 8 ), -1, 'Spin 35 (36 Red), bet 8 pays -1'; +is payout( 35, 9 ), -1, 'Spin 35 (36 Red), bet 9 pays -1'; +is payout( 35, 10 ), -1, 'Spin 35 (36 Red), bet 10 pays -1'; +is payout( 35, 11 ), -1, 'Spin 35 (36 Red), bet 11 pays -1'; +is payout( 35, 12 ), -1, 'Spin 35 (36 Red), bet 12 pays -1'; +is payout( 35, 13 ), -1, 'Spin 35 (36 Red), bet 13 pays -1'; +is payout( 35, 14 ), -1, 'Spin 35 (36 Red), bet 14 pays -1'; +is payout( 35, 15 ), -1, 'Spin 35 (36 Red), bet 15 pays -1'; +is payout( 35, 16 ), -1, 'Spin 35 (36 Red), bet 16 pays -1'; +is payout( 35, 17 ), -1, 'Spin 35 (36 Red), bet 17 pays -1'; +is payout( 35, 18 ), -1, 'Spin 35 (36 Red), bet 18 pays -1'; +is payout( 35, 19 ), -1, 'Spin 35 (36 Red), bet 19 pays -1'; +is payout( 35, 20 ), -1, 'Spin 35 (36 Red), bet 20 pays -1'; +is payout( 35, 21 ), -1, 'Spin 35 (36 Red), bet 21 pays -1'; +is payout( 35, 22 ), -1, 'Spin 35 (36 Red), bet 22 pays -1'; +is payout( 35, 23 ), -1, 'Spin 35 (36 Red), bet 23 pays -1'; +is payout( 35, 24 ), -1, 'Spin 35 (36 Red), bet 24 pays -1'; +is payout( 35, 25 ), -1, 'Spin 35 (36 Red), bet 25 pays -1'; +is payout( 35, 26 ), -1, 'Spin 35 (36 Red), bet 26 pays -1'; +is payout( 35, 27 ), -1, 'Spin 35 (36 Red), bet 27 pays -1'; +is payout( 35, 28 ), -1, 'Spin 35 (36 Red), bet 28 pays -1'; +is payout( 35, 29 ), -1, 'Spin 35 (36 Red), bet 29 pays -1'; +is payout( 35, 30 ), -1, 'Spin 35 (36 Red), bet 30 pays -1'; +is payout( 35, 31 ), -1, 'Spin 35 (36 Red), bet 31 pays -1'; +is payout( 35, 32 ), -1, 'Spin 35 (36 Red), bet 32 pays -1'; +is payout( 35, 33 ), -1, 'Spin 35 (36 Red), bet 33 pays -1'; +is payout( 35, 34 ), -1, 'Spin 35 (36 Red), bet 34 pays -1'; +is payout( 35, 35 ), -1, 'Spin 35 (36 Red), bet 35 pays -1'; +is payout( 35, 36 ), 35, 'Spin 35 (36 Red), bet 36 pays 35'; +is payout( 35, 37 ), -1, 'Spin 35 (36 Red), bet 37 pays -1'; +is payout( 35, 38 ), -1, 'Spin 35 (36 Red), bet 38 pays -1'; +is payout( 35, 39 ), 2, 'Spin 35 (36 Red), bet 39 pays 2'; +is payout( 35, 40 ), -1, 'Spin 35 (36 Red), bet 40 pays -1'; +is payout( 35, 41 ), -1, 'Spin 35 (36 Red), bet 41 pays -1'; +is payout( 35, 42 ), 2, 'Spin 35 (36 Red), bet 42 pays 2'; +is payout( 35, 43 ), -1, 'Spin 35 (36 Red), bet 43 pays -1'; +is payout( 35, 44 ), 1, 'Spin 35 (36 Red), bet 44 pays 1'; +is payout( 35, 45 ), 1, 'Spin 35 (36 Red), bet 45 pays 1'; +is payout( 35, 46 ), -1, 'Spin 35 (36 Red), bet 46 pays -1'; +is payout( 35, 47 ), 1, 'Spin 35 (36 Red), bet 47 pays 1'; +is payout( 35, 48 ), -1, 'Spin 35 (36 Red), bet 48 pays -1'; +is payout( 35, 49 ), -1, 'Spin 35 (36 Red), bet 49 pays -1'; +is payout( 35, 50 ), -1, 'Spin 35 (36 Red), bet 50 pays -1'; +is format_spin( 36 ), '0', 'Spin 36 is 0'; +is payout( 36, 1 ), -1, 'Spin 36 (0), bet 1 pays -1'; +is payout( 36, 2 ), -1, 'Spin 36 (0), bet 2 pays -1'; +is payout( 36, 3 ), -1, 'Spin 36 (0), bet 3 pays -1'; +is payout( 36, 4 ), -1, 'Spin 36 (0), bet 4 pays -1'; +is payout( 36, 5 ), -1, 'Spin 36 (0), bet 5 pays -1'; +is payout( 36, 6 ), -1, 'Spin 36 (0), bet 6 pays -1'; +is payout( 36, 7 ), -1, 'Spin 36 (0), bet 7 pays -1'; +is payout( 36, 8 ), -1, 'Spin 36 (0), bet 8 pays -1'; +is payout( 36, 9 ), -1, 'Spin 36 (0), bet 9 pays -1'; +is payout( 36, 10 ), -1, 'Spin 36 (0), bet 10 pays -1'; +is payout( 36, 11 ), -1, 'Spin 36 (0), bet 11 pays -1'; +is payout( 36, 12 ), -1, 'Spin 36 (0), bet 12 pays -1'; +is payout( 36, 13 ), -1, 'Spin 36 (0), bet 13 pays -1'; +is payout( 36, 14 ), -1, 'Spin 36 (0), bet 14 pays -1'; +is payout( 36, 15 ), -1, 'Spin 36 (0), bet 15 pays -1'; +is payout( 36, 16 ), -1, 'Spin 36 (0), bet 16 pays -1'; +is payout( 36, 17 ), -1, 'Spin 36 (0), bet 17 pays -1'; +is payout( 36, 18 ), -1, 'Spin 36 (0), bet 18 pays -1'; +is payout( 36, 19 ), -1, 'Spin 36 (0), bet 19 pays -1'; +is payout( 36, 20 ), -1, 'Spin 36 (0), bet 20 pays -1'; +is payout( 36, 21 ), -1, 'Spin 36 (0), bet 21 pays -1'; +is payout( 36, 22 ), -1, 'Spin 36 (0), bet 22 pays -1'; +is payout( 36, 23 ), -1, 'Spin 36 (0), bet 23 pays -1'; +is payout( 36, 24 ), -1, 'Spin 36 (0), bet 24 pays -1'; +is payout( 36, 25 ), -1, 'Spin 36 (0), bet 25 pays -1'; +is payout( 36, 26 ), -1, 'Spin 36 (0), bet 26 pays -1'; +is payout( 36, 27 ), -1, 'Spin 36 (0), bet 27 pays -1'; +is payout( 36, 28 ), -1, 'Spin 36 (0), bet 28 pays -1'; +is payout( 36, 29 ), -1, 'Spin 36 (0), bet 29 pays -1'; +is payout( 36, 30 ), -1, 'Spin 36 (0), bet 30 pays -1'; +is payout( 36, 31 ), -1, 'Spin 36 (0), bet 31 pays -1'; +is payout( 36, 32 ), -1, 'Spin 36 (0), bet 32 pays -1'; +is payout( 36, 33 ), -1, 'Spin 36 (0), bet 33 pays -1'; +is payout( 36, 34 ), -1, 'Spin 36 (0), bet 34 pays -1'; +is payout( 36, 35 ), -1, 'Spin 36 (0), bet 35 pays -1'; +is payout( 36, 36 ), -1, 'Spin 36 (0), bet 36 pays -1'; +is payout( 36, 37 ), -1, 'Spin 36 (0), bet 37 pays -1'; +is payout( 36, 38 ), -1, 'Spin 36 (0), bet 38 pays -1'; +is payout( 36, 39 ), -1, 'Spin 36 (0), bet 39 pays -1'; +is payout( 36, 40 ), -1, 'Spin 36 (0), bet 40 pays -1'; +is payout( 36, 41 ), -1, 'Spin 36 (0), bet 41 pays -1'; +is payout( 36, 42 ), -1, 'Spin 36 (0), bet 42 pays -1'; +is payout( 36, 43 ), -1, 'Spin 36 (0), bet 43 pays -1'; +is payout( 36, 44 ), -1, 'Spin 36 (0), bet 44 pays -1'; +is payout( 36, 45 ), -1, 'Spin 36 (0), bet 45 pays -1'; +is payout( 36, 46 ), -1, 'Spin 36 (0), bet 46 pays -1'; +is payout( 36, 47 ), -1, 'Spin 36 (0), bet 47 pays -1'; +is payout( 36, 48 ), -1, 'Spin 36 (0), bet 48 pays -1'; +is payout( 36, 49 ), 35, 'Spin 36 (0), bet 49 pays 35'; +is payout( 36, 50 ), -1, 'Spin 36 (0), bet 50 pays -1'; +is format_spin( 37 ), '00', 'Spin 37 is 00'; +is payout( 37, 1 ), -1, 'Spin 37 (00), bet 1 pays -1'; +is payout( 37, 2 ), -1, 'Spin 37 (00), bet 2 pays -1'; +is payout( 37, 3 ), -1, 'Spin 37 (00), bet 3 pays -1'; +is payout( 37, 4 ), -1, 'Spin 37 (00), bet 4 pays -1'; +is payout( 37, 5 ), -1, 'Spin 37 (00), bet 5 pays -1'; +is payout( 37, 6 ), -1, 'Spin 37 (00), bet 6 pays -1'; +is payout( 37, 7 ), -1, 'Spin 37 (00), bet 7 pays -1'; +is payout( 37, 8 ), -1, 'Spin 37 (00), bet 8 pays -1'; +is payout( 37, 9 ), -1, 'Spin 37 (00), bet 9 pays -1'; +is payout( 37, 10 ), -1, 'Spin 37 (00), bet 10 pays -1'; +is payout( 37, 11 ), -1, 'Spin 37 (00), bet 11 pays -1'; +is payout( 37, 12 ), -1, 'Spin 37 (00), bet 12 pays -1'; +is payout( 37, 13 ), -1, 'Spin 37 (00), bet 13 pays -1'; +is payout( 37, 14 ), -1, 'Spin 37 (00), bet 14 pays -1'; +is payout( 37, 15 ), -1, 'Spin 37 (00), bet 15 pays -1'; +is payout( 37, 16 ), -1, 'Spin 37 (00), bet 16 pays -1'; +is payout( 37, 17 ), -1, 'Spin 37 (00), bet 17 pays -1'; +is payout( 37, 18 ), -1, 'Spin 37 (00), bet 18 pays -1'; +is payout( 37, 19 ), -1, 'Spin 37 (00), bet 19 pays -1'; +is payout( 37, 20 ), -1, 'Spin 37 (00), bet 20 pays -1'; +is payout( 37, 21 ), -1, 'Spin 37 (00), bet 21 pays -1'; +is payout( 37, 22 ), -1, 'Spin 37 (00), bet 22 pays -1'; +is payout( 37, 23 ), -1, 'Spin 37 (00), bet 23 pays -1'; +is payout( 37, 24 ), -1, 'Spin 37 (00), bet 24 pays -1'; +is payout( 37, 25 ), -1, 'Spin 37 (00), bet 25 pays -1'; +is payout( 37, 26 ), -1, 'Spin 37 (00), bet 26 pays -1'; +is payout( 37, 27 ), -1, 'Spin 37 (00), bet 27 pays -1'; +is payout( 37, 28 ), -1, 'Spin 37 (00), bet 28 pays -1'; +is payout( 37, 29 ), -1, 'Spin 37 (00), bet 29 pays -1'; +is payout( 37, 30 ), -1, 'Spin 37 (00), bet 30 pays -1'; +is payout( 37, 31 ), -1, 'Spin 37 (00), bet 31 pays -1'; +is payout( 37, 32 ), -1, 'Spin 37 (00), bet 32 pays -1'; +is payout( 37, 33 ), -1, 'Spin 37 (00), bet 33 pays -1'; +is payout( 37, 34 ), -1, 'Spin 37 (00), bet 34 pays -1'; +is payout( 37, 35 ), -1, 'Spin 37 (00), bet 35 pays -1'; +is payout( 37, 36 ), -1, 'Spin 37 (00), bet 36 pays -1'; +is payout( 37, 37 ), -1, 'Spin 37 (00), bet 37 pays -1'; +is payout( 37, 38 ), -1, 'Spin 37 (00), bet 38 pays -1'; +is payout( 37, 39 ), -1, 'Spin 37 (00), bet 39 pays -1'; +is payout( 37, 40 ), -1, 'Spin 37 (00), bet 40 pays -1'; +is payout( 37, 41 ), -1, 'Spin 37 (00), bet 41 pays -1'; +is payout( 37, 42 ), -1, 'Spin 37 (00), bet 42 pays -1'; +is payout( 37, 43 ), -1, 'Spin 37 (00), bet 43 pays -1'; +is payout( 37, 44 ), -1, 'Spin 37 (00), bet 44 pays -1'; +is payout( 37, 45 ), -1, 'Spin 37 (00), bet 45 pays -1'; +is payout( 37, 46 ), -1, 'Spin 37 (00), bet 46 pays -1'; +is payout( 37, 47 ), -1, 'Spin 37 (00), bet 47 pays -1'; +is payout( 37, 48 ), -1, 'Spin 37 (00), bet 48 pays -1'; +is payout( 37, 49 ), -1, 'Spin 37 (00), bet 49 pays -1'; +is payout( 37, 50 ), 35, 'Spin 37 (00), bet 50 pays 35'; + +done_testing; + +1; + +# ex: set textwidth=72 : diff --git a/75_Roulette/perl/roulette.pl b/75_Roulette/perl/roulette.pl new file mode 100755 index 00000000..ad3ce965 --- /dev/null +++ b/75_Roulette/perl/roulette.pl @@ -0,0 +1,319 @@ +#!/usr/bin/env perl + +use 5.010; # To get 'state' and 'say' + +use strict; # Require explicit declaration of variables +use warnings; # Enable optional compiler warnings + +use English; # Use more friendly names for Perl's magic variables +use POSIX qw{ strftime }; # Time formatting +use Term::ReadLine; # Prompt and return user input + +our $VERSION = '0.000_01'; + +# A main() function is not usual in Perl scripts. I have installed one +# here to make the script into a "modulino." The next line executes +# main() if and only if caller() returns false. It will do this if we +# were loaded by another Perl script but not otherwise. This was done so +# I could test the payout and spin formatting logic. +main() unless caller; + +sub main { + + print <<'EOD'; + ROULETTE + Creative Computing Morristown, New Jersey + + + + +Welcome to the roulette table. + +EOD + + if ( get_yes_no( 'Do you want instructions' ) ) { + print <<'EOD'; + +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. + +EOD +} + + my $P = 1000; + my $D = 100000.; + + while ( 1 ) { # Iterate indefinitely + + my $Y = get_input( 'How many bets? ', + sub { m/ \A [0-9]+ \z /smx && $ARG > 0 && $ARG <= 50 }, + "Please enter a positive integer no greater than 50\n", + ); + my @B; + my @T; + foreach my $C ( 1 .. $Y ) { + my ( $X, $Z ) = split qr< , >smx, get_input( + "Number $C: ", + sub { m/ \A ( [0-9]+ ) , ( [0-9]+ ) \z /smx + && $1 > 0 && $1 <= 50 && $2 >= 5 && $2 <= 500 }, + "Please enter two comma-separated positive numbers\n", + ); + if ( $B[$X] ) { + say 'You made that bet once already, dum-dum.'; + redo; + } + $B[$X] = $Z; # BASIC does $B[$C] = $Z + $T[$C] = $X; + } + + print <<'EOD'; + + Spinning ... + +EOD + my $S = int rand 38; # Zero-based, versus 1-based in BASIC + + say format_spin( $S ); + + say ''; + + foreach my $C ( 1 .. $Y ) { + my $X = $T[$C]; + my $payout = payout( $S, $X ) * $B[$X]; + $D -= $payout; + $P += $payout; + if ( $payout > 0 ) { + say "You win $payout dollars on bet $C"; + } else { + $payout = -$payout; + say "You lose $payout dollars on bet $C"; + } + } + say "Totals\tMe\tYou"; + say "\t$D\t$P"; + say ''; + + + last unless get_yes_no( 'Again' ); + } + + say ''; + + if ( $P > 0 ) { + my $B = get_input( + 'To whom shall I make out the check? ', + ); + my $check_number = 1000 + int rand 9000; + my $todays_date = strftime( '%B %d, %Y', localtime ); + print <<"EOD"; + +------------------------------------------------------------ Check number $check_number + + $todays_date + +Pay to the order of ------ $B ----- \$$P + + The Memory Bank of New York + + The Computer + ---------X----- + +------------------------------------------------------------------------------- + +Come back soon! +EOD + } else { + print <<'EOD'; +Thanks for your money. +I'll use it to buy a solid gold roulette wheel +EOD + } +} + +{ + # Define the kind of each possible spin. 0 is '0' or '00', 1 is + # black, and 2 is red. We assign the values in a BEGIN block because + # execution never actually reaches this point in the script. + my @kind; + BEGIN { + @kind = ( 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, + 2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 0, + 0 ); + } + + # Convert the spin (0-37) to its name on the wheel. + sub format_spin { + my ( $number ) = @_; + state $format = [ + sub { '0' x ( $_[0] - 35 ) }, + sub { sprintf '%s Black', $_[0] + 1 }, + sub { sprintf '%s Red', $_[0] + 1 }, + ]; + return $format->[$kind[$number]]( $number ); + } + + # Compute the payout given the spin (0-37) and the bet (1-50). + sub payout { + my ( $number, $bet ) = @_; + # We compute the payout on '0' and '00' directly, since under + # our rules they are only eligible for the 35-to-1 bet. + $kind[$number] + or return $number == $bet - 49 + 36 ? 35 : -1; + --$bet; # #bet is 1-based coming in + # Dispatch table for computing the payout for spins 0-36. + state $payout = [ + ( sub { $_[0] == $_[1] ? 35 : -1 } ) x 36, + ( sub { int( $_[0] / 12 ) == $_[1] - 36 ? 2 : -1 } ) x 3, + ( sub { $_[0] % 3 == $_[1] - 39 ? 2 : -1 } ) x 3, + ( sub { int( $_[0] / 18 ) == $_[1] - 42 ? 1 : -1 } ) x 2, + ( sub { $_[0] % 2 == 45 - $_[1] ? 1 : -1 } ) x 2, + ( sub { $kind[$_[0]] == 48 - $_[1] ? 1 : -1 } ) x 2, + ( sub { -1 } ) x 2, # Bet on '0' or '00' loses + ]; + return $payout->[$bet]->( $number, $bet ); + } +} + +# Get input from the user. The arguments are: +# * The prompt +# * A reference to validation code. This code receives the response in +# $ARG and returns true for a valid response. +# * A warning to print if the response is not valid. This must end in a +# return. +# The first valid response is returned. An end-of-file terminates the +# script. +sub get_input { + my ( $prompt, $validate, $warning ) = @ARG; + + # If no validator is passed, default to one that always returns + # true. + $validate ||= sub { 1 }; + + # Create the readline object. The 'state' causes the variable to be + # initialized only once, no matter how many times this subroutine is + # called. The do { ... } is a compound statement used because we + # need to tweak the created object before we store it. + state $term = do { + my $obj = Term::ReadLine->new( 'reverse' ); + $obj->ornaments( 0 ); + $obj; + }; + + while ( 1 ) { # Iterate indefinitely + + # Read the input into the topic variable, localized to prevent + # Spooky Action at a Distance. We exit on undef, which signals + # end-of-file. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Return the input if it is valid. + return $ARG if $validate->(); + + # Issue the warning, and go around the merry-go-round again. + warn $warning; + } +} + +# Get a yes-or-no answer. The argument is the prompt, which will have +# '? [y/n]: ' appended. The donkey work is done by get_input(), which is +# requested to validate the response as beginning with 'y' or 'n', +# case-insensitive. The return is a true value for 'y' and a false value +# for 'n'. +sub get_yes_no { + my ( $prompt ) = @ARG; + state $map_answer = { + n => 0, + y => 1, + }; + my $resp = lc get_input( + "$prompt? [y/n]: ", + sub { m/ \A [yn] /smxi }, + "Please respond 'y' or 'n'\n", + ); + return $map_answer->{ substr $resp, 0, 1 }; +} + +__END__ + +=head1 TITLE + +roulette - Play the game 'Roulette' from Basic Computer Games + +=head1 SYNOPSIS + + roulette.pl + +=head1 DETAILS + +This Perl script is a port of roulette, which is the 75th +entry in Basic Computer Games. + +The main internal changes are converting the roulette slot numbering to +0-based and replacing most of the payout logic with a dispatch table. +These changes were tested for correctness against the original BASIC. + +=head1 PORTED BY + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set expandtab tabstop=4 textwidth=72 : From 71bc3b95f4ae936ef00b034a41d8dd07bb9edb15 Mon Sep 17 00:00:00 2001 From: Mark Wieder Date: Tue, 11 Jan 2022 15:12:06 -0800 Subject: [PATCH 246/331] Slot machine in ruby --- 80_Slots/ruby/slots.rb | 152 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 80_Slots/ruby/slots.rb diff --git a/80_Slots/ruby/slots.rb b/80_Slots/ruby/slots.rb new file mode 100644 index 00000000..a4c3e7ef --- /dev/null +++ b/80_Slots/ruby/slots.rb @@ -0,0 +1,152 @@ +$pot = 0 + +def greeting + puts "SLOTS".center(80) + puts "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".center(80) + puts "\n\n" + + # PRODUCED BY FRED MIRABELLE AND BOB HARPER ON JAN 29, 1973 + # IT SIMULATES THE SLOT MACHINE. + + puts "You are in the H&M Casino, in front of one of our" + puts "one-arm bandits. You can bet from $1 to $100." + puts "To pull the arm, punch the return key after making your bet." + puts "\nBet zero to end the game." +end + +def overLimit + puts "House Limit is $100" +end + +def underMinimum + puts "Minimum Bet is $1" +end + +# bells don't work on my machine. YMMV +# I'm displaying dashes between the reels + +def tenBells + 10.times do + # beep if you can + print "-" + end +end + +def fiveBells + "-----" +end + +def goodbye + puts "\n\n\n" + # end the game + exit +end + +def payUp + puts "PAY UP! PLEASE LEAVE YOUR MONEY ON THE TERMINAL." +end + +def brokeEven + puts "HEY, YOU BROKE EVEN." +end + +def collectWinnings + puts "COLLECT YOUR WINNINGS FROM THE H&M CASHIER." +end + +def win winType, bet + case winType + when "jackpot" + winMessage = "***JACKPOT***" + winnings = 101 + when "topDollar" + winMessage = "**TOP DOLLAR**" + winnings = 11 + when "doubleBar" + winMessage = "*DOUBLE BAR!!*" + winnings = 6 + when "double" + winMessage = "DOUBLE!!" + winnings = 3 + end + puts "\nYou won: " + winMessage + $pot += (winnings * bet) +end + +greeting + +#$pot = 0 +while true + reelArray = ["BAR","BELL","ORANGE","LEMON","PLUM","CHERRY"] + print "\nYOUR BET? " + # get input, remove leading and trailing whitespace, cast to integer + bet = gets.strip.to_i + + if bet == 0 then + goodbye + elsif bet > 100 then + overLimit # error if more than $100 + elsif bet < 1 then + underMinimum # have to bet at least a dollar + else + # valid bet, continue + tenBells # ding + + # assign a random value from the array to each of the three reels + reel1 = reelArray[rand(5)] + reel2 = reelArray[rand(5)] + reel3 = reelArray[rand(5)] + + # print the slot machine reels + puts "\n\n" + reel1 + fiveBells + reel2 + fiveBells + reel3 + + # see if we have a match in the first two reels + if reel1 == reel2 then + if reel2 == reel3 then + if reel3 == "BAR" then + # all three reels are "BAR" + win "jackpot", bet + else + # all three reels match but aren't "BAR" + win "topDollar", bet + end + elsif reel2 == "BAR" then + # reels 1 and 2 are both "BAR" + win "doubleBar", bet + else + # reels 1 and 2 match but aren't "BAR" + win "double", bet + end + # otherwise see if there's a match in the remaining reels + elsif reel1 == reel3 or reel2 == reel3 then + if reel3 == "BAR" then + # two reels match, both "BAR" + win "doubleBar", bet + else + # two reels match, but not "BAR" + win "double", bet + end + else + # bad news - no matches + puts "\nYou lost" + # decrement your standings by the bet amount + $pot -= bet + end + + puts "Your standings are: " + $pot.to_s + print "\nAgain? " # YES to continue + # get input, remove leading and trailing whitespace, make uppercase + again = gets.strip.upcase + if again != "Y" && again != "YES" then + # that's enough... evaluate the pot and quit + if $pot < 0 then + payUp + elsif $pot == 0 then + brokeEven + else # yay! + collectWinnings + end + goodbye + end + end +end From 1c1276778b562850563d6391c0c89eb056844f30 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:40:05 -0300 Subject: [PATCH 247/331] Just starting out. --- 55_Life/csharp/.gitignore | 509 +++++++++++++++++++++++++++++++++++++ 55_Life/csharp/Life.csproj | 9 + 55_Life/csharp/Life.sln | 16 ++ 55_Life/csharp/Program.cs | 37 +++ 4 files changed, 571 insertions(+) create mode 100644 55_Life/csharp/.gitignore create mode 100644 55_Life/csharp/Life.csproj create mode 100644 55_Life/csharp/Life.sln create mode 100644 55_Life/csharp/Program.cs diff --git a/55_Life/csharp/.gitignore b/55_Life/csharp/.gitignore new file mode 100644 index 00000000..e96e7522 --- /dev/null +++ b/55_Life/csharp/.gitignore @@ -0,0 +1,509 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/dotnetcore,rider,visualstudio,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=dotnetcore,rider,visualstudio,visualstudiocode + +### DotnetCore ### +# .NET Core build folders +bin/ +obj/ + +# Common node modules locations +/node_modules +/wwwroot/node_modules + +### Rider ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# Support for Project snippet scope + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +*.code-workspace + +# Local History for Visual Studio Code + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + +### VisualStudio Patch ### +# Additional files built by Visual Studio + +# End of https://www.toptal.com/developers/gitignore/api/dotnetcore,rider,visualstudio,visualstudiocode diff --git a/55_Life/csharp/Life.csproj b/55_Life/csharp/Life.csproj new file mode 100644 index 00000000..7311ef16 --- /dev/null +++ b/55_Life/csharp/Life.csproj @@ -0,0 +1,9 @@ + + + + Exe + net6.0 + enable + + + diff --git a/55_Life/csharp/Life.sln b/55_Life/csharp/Life.sln new file mode 100644 index 00000000..1f6131b8 --- /dev/null +++ b/55_Life/csharp/Life.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Life", "Life.csproj", "{28B02688-78D1-4B3E-B998-BCC78C292D03}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {28B02688-78D1-4B3E-B998-BCC78C292D03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28B02688-78D1-4B3E-B998-BCC78C292D03}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28B02688-78D1-4B3E-B998-BCC78C292D03}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28B02688-78D1-4B3E-B998-BCC78C292D03}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs new file mode 100644 index 00000000..e12d5b7d --- /dev/null +++ b/55_Life/csharp/Program.cs @@ -0,0 +1,37 @@ +// See https://aka.ms/new-console-template for more information + +const int MaxWidth = 70; +const int MaxHeight = 24; + +PrintHeader(); + +int x1 = 1, y1 = 1; +int x2 = 24, y2 = 70; +var a = new float[24, 70]; +var b = new string[24]; +var c = 1; + +Console.WriteLine("ENTER YOUR PATTERN:"); +b[c] = Console.ReadLine(); +if (b[c] == "DONE") + b[c] = "" + + +void PrintHeader() +{ + const int pageWidth = 64; + + void PrintCentered(string text) + { + var spaceCount = (pageWidth - text.Length) / 2; + Console.Write(new string(' ', spaceCount)); + Console.WriteLine(text); + } + + PrintCentered("LIFE"); + PrintCentered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); +} + From ade38d696998a222e693a37916132c2cdc8dbffd Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:40:50 -0300 Subject: [PATCH 248/331] Another step. --- 55_Life/csharp/Program.cs | 151 ++++++++++++++++++++++++++++++++++---- 1 file changed, 137 insertions(+), 14 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index e12d5b7d..6a8ed618 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -1,21 +1,23 @@ // See https://aka.ms/new-console-template for more information -const int MaxWidth = 70; -const int MaxHeight = 24; +IEnumerable ReadPattern(int limitHeight) +{ + for (var i = 0; i < limitHeight; i++) + { + var input = Console.ReadLine(); + if (input.ToUpper() == "DONE") + { + yield return string.Empty; + break; + } -PrintHeader(); - -int x1 = 1, y1 = 1; -int x2 = 24, y2 = 70; -var a = new float[24, 70]; -var b = new string[24]; -var c = 1; - -Console.WriteLine("ENTER YOUR PATTERN:"); -b[c] = Console.ReadLine(); -if (b[c] == "DONE") - b[c] = "" + // kept for compatibility + if (input.StartsWith('.')) + yield return input.Substring(1, input.Length - 2); + yield return input; + } +} void PrintHeader() { @@ -35,3 +37,124 @@ void PrintHeader() Console.WriteLine(); } +(int index, string value) GetLongestInput(IEnumerable strings) +{ + return strings + .Select((value, index) => (index, value)) + .OrderByDescending(input => input.value.Length) + .First(); +} + + +PrintHeader(); + +Console.WriteLine("ENTER YOUR PATTERN:"); +// var pattern = ReadPattern(limitHeight: MaxHeight).ToArray(); +var pattern = new string[] { "a", "bdc", "", "pattern" }; // FOR DEBUGGING PURPOSES +var (index, value) = GetLongestInput(pattern); +Console.WriteLine("" + index + ", " + value); + +// B = pattern + +int x1 = (11 - index / 2) - 1; +int y1 = (33 - value.Length / 2) - 1; +const int MaxWidth = 70; // Y2 +const int MaxHeight = 24; // X2 + +var a = new int[24, 70]; // TODO understand it +int population = 0; + +// count initial population? +for (var x = 0; x < pattern.Length; x++) +{ + for (var y = 0; y < pattern[x].Length; y++) + { + if (pattern[x][y] != ' ') + { + a[x1 + x, y1 + y] = 1; + population++; + } + } +} + +void ProcessGeneration() +{ + void PrintPopulation(int generation, int population) + { + Console.WriteLine($"GENERATION: {generation}\tPOPULATION: {population}"); + var i9 = false; // TODO understand + if (i9) + Console.WriteLine("INVALID!"); + } + int generation = 1; + PrintPopulation(generation, population); + + int x3 = MaxHeight, y3 = MaxWidth; + int x4 = 1, y4 = 1; + + for (int x = 0; x < x1; x++) + { + Console.WriteLine(); + } + + for (var x = x1; x < MaxHeight; x++) + { + Console.WriteLine(); + for (var y = y1; y < MaxWidth; y++) + { + if (a[x, y] == 2) + { + a[x, y] = 0; // birth? + continue; + } + + if (a[x, y] == 3) + { + a[x, y] = 1; + Console.WriteLine(new string('\t', y+1) + "*"); + continue; + } + + // TODO understand what it does + if (x < x3) x3 = x; + if (x > x4) x4 = x; + if (y < y3) y3 = y; + if (y < y4) y4 = y; + } + } + +} + +PrintMatrix(a); +void PrintMatrix(int[,] matrix) +{ + Console.WriteLine("Matrix:"); + for (int x = 0; x < matrix.GetLength(0); x++) + { + for (int y = 0; y < matrix.GetLength(1); y++) + { + Console.Write(matrix[x, y].ToString()); + } + Console.WriteLine(); + } +} + +Console.WriteLine(); +Console.WriteLine(); +Console.WriteLine(); +ProcessGeneration(); + + + + + + +// int x1 = 1, y1 = 1; +// int x2 = 24, y2 = 70; + +// var b = new string[24]; + + + + + From 53d2943f934dbbb38e78ae3e9d1d0d81e6fcfefd Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:41:28 -0300 Subject: [PATCH 249/331] Not working yet. --- 55_Life/csharp/Program.cs | 204 +++++++++++++++++++++++++++----------- 1 file changed, 148 insertions(+), 56 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 6a8ed618..ab995aa5 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -1,5 +1,7 @@ // See https://aka.ms/new-console-template for more information +using System.Xml; + IEnumerable ReadPattern(int limitHeight) { for (var i = 0; i < limitHeight; i++) @@ -50,82 +52,43 @@ PrintHeader(); Console.WriteLine("ENTER YOUR PATTERN:"); // var pattern = ReadPattern(limitHeight: MaxHeight).ToArray(); -var pattern = new string[] { "a", "bdc", "", "pattern" }; // FOR DEBUGGING PURPOSES +var pattern = new[] +{ + " ", + " * ", + " * ", + " * ", + " " +}; // FOR DEBUGGING PURPOSES var (index, value) = GetLongestInput(pattern); Console.WriteLine("" + index + ", " + value); // B = pattern -int x1 = (11 - index / 2) - 1; -int y1 = (33 - value.Length / 2) - 1; + const int MaxWidth = 70; // Y2 const int MaxHeight = 24; // X2 -var a = new int[24, 70]; // TODO understand it +var matrix = new int[24, 70]; // TODO understand it int population = 0; +var isInvalid = false; // TODO understand -// count initial population? + +int x1 = (11 - index / 2) - 1; // middle x +int y1 = (33 - value.Length / 2) - 1; // middle y for (var x = 0; x < pattern.Length; x++) { for (var y = 0; y < pattern[x].Length; y++) { if (pattern[x][y] != ' ') { - a[x1 + x, y1 + y] = 1; - population++; + matrix[x1 + x, y1 + y] = 1; // copy the pattern to the middle of the simulation + population++; // increments the population } } } -void ProcessGeneration() -{ - void PrintPopulation(int generation, int population) - { - Console.WriteLine($"GENERATION: {generation}\tPOPULATION: {population}"); - var i9 = false; // TODO understand - if (i9) - Console.WriteLine("INVALID!"); - } - int generation = 1; - PrintPopulation(generation, population); - - int x3 = MaxHeight, y3 = MaxWidth; - int x4 = 1, y4 = 1; - - for (int x = 0; x < x1; x++) - { - Console.WriteLine(); - } - - for (var x = x1; x < MaxHeight; x++) - { - Console.WriteLine(); - for (var y = y1; y < MaxWidth; y++) - { - if (a[x, y] == 2) - { - a[x, y] = 0; // birth? - continue; - } - - if (a[x, y] == 3) - { - a[x, y] = 1; - Console.WriteLine(new string('\t', y+1) + "*"); - continue; - } - - // TODO understand what it does - if (x < x3) x3 = x; - if (x > x4) x4 = x; - if (y < y3) y3 = y; - if (y < y4) y4 = y; - } - } - -} - -PrintMatrix(a); +PrintMatrix(matrix); void PrintMatrix(int[,] matrix) { Console.WriteLine("Matrix:"); @@ -139,6 +102,135 @@ void PrintMatrix(int[,] matrix) } } + + +int generation = 0; + +void ProcessGeneration() +{ + generation++; + void PrintPopulation(int generation, int population) + { + Console.WriteLine($"GENERATION: {generation}\tPOPULATION: {population}"); + if (isInvalid) + Console.WriteLine("INVALID!"); + } + PrintPopulation(generation, population); + + int nextMaxX = MaxHeight, nextMaxY = MaxWidth; + int nextMinX = 1, nextMinY = 1; + + for (int x = 0; x < x1; x++) + { + Console.WriteLine(); + } + + for (var x = x1; x < MaxHeight; x++) + { + Console.WriteLine(); + for (var y = y1; y < MaxWidth; y++) + { + if (matrix[x, y] == 2) + { + matrix[x, y] = 0; + continue; + } + + if (matrix[x, y] == 3) + { + matrix[x, y] = 1; // birth? + Console.WriteLine(new string(' ', y+1) + "*"); + continue; + } + + nextMinX = Math.Min(x, nextMinX); + nextMaxX = Math.Max(x, nextMaxX); + nextMinY = Math.Min(y, nextMinY); + nextMaxY = Math.Max(y, nextMaxY); + } + } + + var x2 = MaxHeight; + for (int x = x2 + 1; x < MaxHeight; x++) // TODO test +1 + { + Console.WriteLine(); + } + + x1 = nextMaxX; + x2 = nextMinX; + y1 = nextMaxY; + var y2 = nextMinY; + + // TODO boundaries? review + if (x1 < 3) + { + x1 = 3; + isInvalid = true; + } + + if (x2 > 22) + { + x2 = 22; + isInvalid = true; + } + + if (y1 < 3) + { + y1 = 3; + isInvalid = true; + } + + if (y2 > 68) + { + y2 = 68; + isInvalid = true; + } + + ProcessPopulation(); + // TODO line 635 + + void ProcessPopulation() + { + var population = 0; + for (int x = x1 - 1; x < x2 + 1; x++) // TODO review indices + { + for (int y = y1 - 1; y < y2 + 1; y++) // TODO review indices + { + var counter = 0; + for (int i = x - 1; i < x + 1; i++) + { + for (int j = y - 1; j < y + 1; j++) + { + if (matrix[i, j] == 1 || matrix[i, j] == 2) + counter++; + } + } + + if (matrix[x, y] == 0) + { + if (counter == 3) + { + matrix[x, y] = 2; + population++; + } + } + else if (counter is < 3 or > 4) + { + matrix[x, y] = 2; + } + else + { + population++; + } + } + } + } + PrintMatrix(matrix); + ProcessGeneration(); +} + + + Console.WriteLine(); Console.WriteLine(); Console.WriteLine(); From be5e35f7e0c887b53304543d1a055326c12b9c3c Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:42:40 -0300 Subject: [PATCH 250/331] Got it working. --- 55_Life/csharp/Program.cs | 347 ++++++++++++++++++++++++-------------- 1 file changed, 216 insertions(+), 131 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index ab995aa5..0f78a6e4 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -1,6 +1,6 @@ // See https://aka.ms/new-console-template for more information -using System.Xml; +using System.Text; IEnumerable ReadPattern(int limitHeight) { @@ -47,6 +47,10 @@ void PrintHeader() .First(); } +try +{ + + PrintHeader(); @@ -54,11 +58,9 @@ Console.WriteLine("ENTER YOUR PATTERN:"); // var pattern = ReadPattern(limitHeight: MaxHeight).ToArray(); var pattern = new[] { - " ", - " * ", - " * ", - " * ", - " " + "*", + "*", + "*" }; // FOR DEBUGGING PURPOSES var (index, value) = GetLongestInput(pattern); Console.WriteLine("" + index + ", " + value); @@ -69,26 +71,42 @@ Console.WriteLine("" + index + ", " + value); const int MaxWidth = 70; // Y2 const int MaxHeight = 24; // X2 -var matrix = new int[24, 70]; // TODO understand it -int population = 0; +// var matrix = new int[24, 70]; // TODO understand it +var matrixSpace = new MatrixSpace(height: 24, width: 70); +// int population = 0; var isInvalid = false; // TODO understand -int x1 = (11 - index / 2) - 1; // middle x -int y1 = (33 - value.Length / 2) - 1; // middle y -for (var x = 0; x < pattern.Length; x++) -{ - for (var y = 0; y < pattern[x].Length; y++) + +int minX = (11 - index / 2) - 1; // middle x +int minY = (33 - value.Length / 2) - 1; // middle y +int maxX = MaxHeight; +int maxY = MaxWidth; +var simulation = InitializeSimulation(pattern, matrixSpace); + + + +Simulation InitializeSimulation(string[] inputPattern, MatrixSpace matrixToInitialize) { + var newSimulation = new Simulation(); + + for (var x = 0; x < inputPattern.Length; x++) { - if (pattern[x][y] != ' ') + for (var y = 0; y < inputPattern[x].Length; y++) { - matrix[x1 + x, y1 + y] = 1; // copy the pattern to the middle of the simulation - population++; // increments the population + if (inputPattern[x][y] != ' ') + { + matrixToInitialize.Matrix[minX + x, minY + y] = 1; // copy the pattern to the middle of the simulation + // population++; // increments the population + newSimulation.IncreasePopulation(); + } } } + + return newSimulation; } -PrintMatrix(matrix); + +// PrintMatrix(matrixSpace.Matrix); void PrintMatrix(int[,] matrix) { Console.WriteLine("Matrix:"); @@ -96,149 +114,191 @@ void PrintMatrix(int[,] matrix) { for (int y = 0; y < matrix.GetLength(1); y++) { - Console.Write(matrix[x, y].ToString()); + var character = matrix[x, y] == 0 ? ' ' : '*'; + Console.Write(character); } Console.WriteLine(); } } - - -int generation = 0; - -void ProcessGeneration() -{ - generation++; - void PrintPopulation(int generation, int population) + void ProcessGeneration() { - Console.WriteLine($"GENERATION: {generation}\tPOPULATION: {population}"); - if (isInvalid) - Console.WriteLine("INVALID!"); - } - PrintPopulation(generation, population); - - int nextMaxX = MaxHeight, nextMaxY = MaxWidth; - int nextMinX = 1, nextMinY = 1; - - for (int x = 0; x < x1; x++) - { - Console.WriteLine(); - } - - for (var x = x1; x < MaxHeight; x++) - { - Console.WriteLine(); - for (var y = y1; y < MaxWidth; y++) + var matrix = matrixSpace.Matrix; // TODO refactor + + // generation++; + + void PrintPopulation(int generation, int population) { - if (matrix[x, y] == 2) - { - matrix[x, y] = 0; - continue; - } - - if (matrix[x, y] == 3) - { - matrix[x, y] = 1; // birth? - Console.WriteLine(new string(' ', y+1) + "*"); - continue; - } - - nextMinX = Math.Min(x, nextMinX); - nextMaxX = Math.Max(x, nextMaxX); - nextMinY = Math.Min(y, nextMinY); - nextMaxY = Math.Max(y, nextMaxY); + Console.WriteLine($"GENERATION: {generation}\tPOPULATION: {population}"); + if (isInvalid) + Console.WriteLine("INVALID!"); } - } + PrintPopulation(simulation.Generation, simulation.Population); - var x2 = MaxHeight; - for (int x = x2 + 1; x < MaxHeight; x++) // TODO test +1 - { - Console.WriteLine(); - } + simulation.StartNewGeneration(); - x1 = nextMaxX; - x2 = nextMinX; - y1 = nextMaxY; - var y2 = nextMinY; - - // TODO boundaries? review - if (x1 < 3) - { - x1 = 3; - isInvalid = true; - } + // LINE 215 + // x3 = 24 = MaxHeight + // y3 = 70 = MaxWidth + // x4 = 1 + // y4 = 1 + // g = g + 1 - if (x2 > 22) - { - x2 = 22; - isInvalid = true; - } - - if (y1 < 3) - { - y1 = 3; - isInvalid = true; - } - - if (y2 > 68) - { - y2 = 68; - isInvalid = true; - } - - ProcessPopulation(); - // TODO line 635 - - void ProcessPopulation() - { - var population = 0; - for (int x = x1 - 1; x < x2 + 1; x++) // TODO review indices + int nextMinX = MaxHeight - 1; // x4 + int nextMinY = MaxWidth - 1; // y4 + int nextMaxX = 0; // x3 + int nextMaxY = 0; // y3 + + + // prints lines before + for (int x = 0; x < minX; x++) { - for (int y = y1 - 1; y < y2 + 1; y++) // TODO review indices + Console.WriteLine(); + } + + // prints matrix and + for (var x = minX; x < maxX; x++) + { + var printedLine = Enumerable.Repeat(' ', MaxWidth).ToList(); + for (var y = minY; y < maxY; y++) { - var counter = 0; - for (int i = x - 1; i < x + 1; i++) + if (matrix[x, y] == 2) { - for (int j = y - 1; j < y + 1; j++) - { - if (matrix[i, j] == 1 || matrix[i, j] == 2) - counter++; - } + matrix[x, y] = 0; + continue; + } + if (matrix[x, y] == 3) + { + matrix[x, y] = 1; + } + else if (matrix[x, y] != 1) + { + continue; } - if (matrix[x, y] == 0) + printedLine[y] = '*'; + + nextMinX = Math.Min(x, nextMinX); + nextMaxX = Math.Max(x+1, nextMaxX); + nextMinY = Math.Min(y, nextMinY); + nextMaxY = Math.Max(y+1, nextMaxY); + } + Console.WriteLine(string.Join(separator: null, values: printedLine)); + } + + // prints lines after + for (int x = maxX + 1; x < MaxHeight; x++) // TODO test +1 + { + Console.WriteLine(); + } + Console.WriteLine(); + + minX = nextMinX; + maxX = nextMaxX; + minY = nextMinY; + maxY = nextMaxY; + + // TODO boundaries? review + if (minX < 3) + { + minX = 3; + isInvalid = true; + } + if (maxX > 22) + { + maxX = 22; + isInvalid = true; + } + if (minY < 3) + { + minY = 3; + isInvalid = true; + } + if (maxY > 68) + { + maxY = 68; + isInvalid = true; + } + + // LINE 309 + ProcessPopulation(); + + void ProcessPopulation() + { + // var population = 0; + for (int x = minX - 1; x < maxX + 2; x++) // TODO review indices + { + for (int y = minY - 1; y < maxY + 2; y++) // TODO review indices { - if (counter == 3) + var neighbors = 0; + for (int i = x - 1; i < x + 2; i++) // TODO review indices + { + for (int j = y - 1; j < y + 2; j++) // TODO review indices + { + if (matrix[i, j] == 1 || matrix[i, j] == 2) + neighbors++; + } + } + // PrintMatrix(matrix); + if (matrix[x, y] == 0) + { + if (neighbors == 3) + { + matrix[x, y] = 3; + // population++; + simulation.IncreasePopulation(); + } + } + else if (neighbors is < 3 or > 4) { matrix[x, y] = 2; - population++; + } + else + { + // population++; + simulation.IncreasePopulation(); } } - else if (counter is < 3 or > 4) - { - matrix[x, y] = 2; - } - else - { - population++; - } } + + // LINE 635 + minX--; + minY--; + maxX++; + maxY++; } + // PrintMatrix(matrix); + ProcessGeneration(); } - PrintMatrix(matrix); + + + + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); ProcessGeneration(); } +catch (Exception e) +{ + Console.WriteLine(e); +} +public class Simulation +{ + public int Generation { get; private set; } + public int Population { get; private set; } + public void StartNewGeneration() + { + Generation++; + Population = 0; + } -Console.WriteLine(); -Console.WriteLine(); -Console.WriteLine(); -ProcessGeneration(); - - - - + public void IncreasePopulation() + { + Population++; + } +} // int x1 = 1, y1 = 1; @@ -250,3 +310,28 @@ ProcessGeneration(); +public class MatrixSpace +{ + public int[,] Matrix { get; } + + public MatrixSpace(int height, int width) + { + Matrix = new int[height, width]; + } + + public override string ToString() + { + var stringBuilder = new StringBuilder(); + for (var x = 0; x < Matrix.GetLength(0); x++) + { + for (var y = 0; y < Matrix.GetLength(1); y++) + { + var character = Matrix[x, y] == 0 ? " ": Matrix[x, y].ToString(); + stringBuilder.Append(character); + } + + stringBuilder.AppendLine(); + } + return stringBuilder.ToString(); + } +} From 44b1ada7d4882f59cd8b51b33c2deb221722de31 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:43:14 -0300 Subject: [PATCH 251/331] Eliminated StackOverflow bug. --- 55_Life/csharp/Program.cs | 66 +++++++++++++++------------------------ 1 file changed, 26 insertions(+), 40 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 0f78a6e4..0496fd91 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -47,10 +47,6 @@ void PrintHeader() .First(); } -try -{ - - PrintHeader(); @@ -106,33 +102,22 @@ Simulation InitializeSimulation(string[] inputPattern, MatrixSpace matrixToIniti } -// PrintMatrix(matrixSpace.Matrix); -void PrintMatrix(int[,] matrix) +void ProcessGeneration() { - Console.WriteLine("Matrix:"); - for (int x = 0; x < matrix.GetLength(0); x++) - { - for (int y = 0; y < matrix.GetLength(1); y++) - { - var character = matrix[x, y] == 0 ? ' ' : '*'; - Console.Write(character); - } - Console.WriteLine(); - } -} + var matrix = matrixSpace.Matrix; // TODO refactor - void ProcessGeneration() + while (true) { - var matrix = matrixSpace.Matrix; // TODO refactor - + // generation++; - + void PrintPopulation(int generation, int population) { Console.WriteLine($"GENERATION: {generation}\tPOPULATION: {population}"); if (isInvalid) Console.WriteLine("INVALID!"); } + PrintPopulation(simulation.Generation, simulation.Population); simulation.StartNewGeneration(); @@ -148,14 +133,14 @@ void PrintMatrix(int[,] matrix) int nextMinY = MaxWidth - 1; // y4 int nextMaxX = 0; // x3 int nextMaxY = 0; // y3 - - + + // prints lines before for (int x = 0; x < minX; x++) { Console.WriteLine(); } - + // prints matrix and for (var x = minX; x < maxX; x++) { @@ -164,9 +149,10 @@ void PrintMatrix(int[,] matrix) { if (matrix[x, y] == 2) { - matrix[x, y] = 0; + matrix[x, y] = 0; continue; } + if (matrix[x, y] == 3) { matrix[x, y] = 1; @@ -179,10 +165,11 @@ void PrintMatrix(int[,] matrix) printedLine[y] = '*'; nextMinX = Math.Min(x, nextMinX); - nextMaxX = Math.Max(x+1, nextMaxX); + nextMaxX = Math.Max(x + 1, nextMaxX); nextMinY = Math.Min(y, nextMinY); - nextMaxY = Math.Max(y+1, nextMaxY); + nextMaxY = Math.Max(y + 1, nextMaxY); } + Console.WriteLine(string.Join(separator: null, values: printedLine)); } @@ -191,29 +178,33 @@ void PrintMatrix(int[,] matrix) { Console.WriteLine(); } + Console.WriteLine(); minX = nextMinX; maxX = nextMaxX; minY = nextMinY; maxY = nextMaxY; - + // TODO boundaries? review if (minX < 3) { minX = 3; isInvalid = true; } + if (maxX > 22) { maxX = 22; isInvalid = true; } + if (minY < 3) { minY = 3; isInvalid = true; } + if (maxY > 68) { maxY = 68; @@ -239,6 +230,7 @@ void PrintMatrix(int[,] matrix) neighbors++; } } + // PrintMatrix(matrix); if (matrix[x, y] == 0) { @@ -268,20 +260,14 @@ void PrintMatrix(int[,] matrix) maxY++; } // PrintMatrix(matrix); - ProcessGeneration(); } - - - - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine(); - ProcessGeneration(); -} -catch (Exception e) -{ - Console.WriteLine(e); } + +Console.WriteLine(); +Console.WriteLine(); +Console.WriteLine(); +ProcessGeneration(); + public class Simulation { public int Generation { get; private set; } From d9ab235585aab5558a2c10d6211ad192bf9e7c27 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:43:44 -0300 Subject: [PATCH 252/331] Some initial refactorings. --- 55_Life/csharp/Program.cs | 201 +++++++++++++++++--------------------- 1 file changed, 90 insertions(+), 111 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 0496fd91..ec925faa 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -39,16 +39,10 @@ void PrintHeader() Console.WriteLine(); } -(int index, string value) GetLongestInput(IEnumerable strings) -{ - return strings - .Select((value, index) => (index, value)) - .OrderByDescending(input => input.value.Length) - .First(); -} -PrintHeader(); + + Console.WriteLine("ENTER YOUR PATTERN:"); // var pattern = ReadPattern(limitHeight: MaxHeight).ToArray(); @@ -58,59 +52,59 @@ var pattern = new[] "*", "*" }; // FOR DEBUGGING PURPOSES +// var pattern = new[] +// { +// "**", +// "**", +// }; // FOR DEBUGGING PURPOSES +// var pattern = new[] +// { +// "***", +// "*", +// }; // FOR DEBUGGING PURPOSES + + +const int MaxWidth = 70; +const int MaxHeight = 24; + +var isInvalid = false; + var (index, value) = GetLongestInput(pattern); -Console.WriteLine("" + index + ", " + value); - -// B = pattern - - -const int MaxWidth = 70; // Y2 -const int MaxHeight = 24; // X2 - -// var matrix = new int[24, 70]; // TODO understand it -var matrixSpace = new MatrixSpace(height: 24, width: 70); -// int population = 0; -var isInvalid = false; // TODO understand - - - int minX = (11 - index / 2) - 1; // middle x int minY = (33 - value.Length / 2) - 1; // middle y int maxX = MaxHeight; int maxY = MaxWidth; -var simulation = InitializeSimulation(pattern, matrixSpace); +var matrix = new Matrix(height: MaxHeight, width: MaxWidth); +var simulation = InitializeSimulation(pattern, matrix); + +PrintHeader(); +Console.WriteLine(); +Console.WriteLine(); +Console.WriteLine(); +ProcessGeneration(); - -Simulation InitializeSimulation(string[] inputPattern, MatrixSpace matrixToInitialize) { +Simulation InitializeSimulation(IReadOnlyList inputPattern, Matrix matrixToInitialize) { var newSimulation = new Simulation(); - for (var x = 0; x < inputPattern.Length; x++) + for (var x = 0; x < inputPattern.Count; x++) { for (var y = 0; y < inputPattern[x].Length; y++) { - if (inputPattern[x][y] != ' ') - { - matrixToInitialize.Matrix[minX + x, minY + y] = 1; // copy the pattern to the middle of the simulation - // population++; // increments the population - newSimulation.IncreasePopulation(); - } + if (inputPattern[x][y] == ' ') continue; + + matrixToInitialize[minX + x, minY + y] = 1; // copy the pattern to the middle of the simulation + newSimulation.IncreasePopulation(); } } return newSimulation; } - void ProcessGeneration() { - var matrix = matrixSpace.Matrix; // TODO refactor - while (true) { - - // generation++; - void PrintPopulation(int generation, int population) { Console.WriteLine($"GENERATION: {generation}\tPOPULATION: {population}"); @@ -123,25 +117,18 @@ void ProcessGeneration() simulation.StartNewGeneration(); // LINE 215 - // x3 = 24 = MaxHeight - // y3 = 70 = MaxWidth - // x4 = 1 - // y4 = 1 - // g = g + 1 + var nextMinX = MaxHeight - 1; + var nextMinY = MaxWidth - 1; + var nextMaxX = 0; + var nextMaxY = 0; - int nextMinX = MaxHeight - 1; // x4 - int nextMinY = MaxWidth - 1; // y4 - int nextMaxX = 0; // x3 - int nextMaxY = 0; // y3 - - - // prints lines before - for (int x = 0; x < minX; x++) + // prints empty lines before alive cells + for (var x = 0; x < minX; x++) { Console.WriteLine(); } - // prints matrix and + // refreshes the matrix and updates search area for (var x = minX; x < maxX; x++) { var printedLine = Enumerable.Repeat(' ', MaxWidth).ToList(); @@ -152,7 +139,6 @@ void ProcessGeneration() matrix[x, y] = 0; continue; } - if (matrix[x, y] == 3) { matrix[x, y] = 1; @@ -173,12 +159,11 @@ void ProcessGeneration() Console.WriteLine(string.Join(separator: null, values: printedLine)); } - // prints lines after - for (int x = maxX + 1; x < MaxHeight; x++) // TODO test +1 + // prints empty lines after alive cells + for (int x = maxX + 1; x < MaxHeight; x++) { Console.WriteLine(); } - Console.WriteLine(); minX = nextMinX; @@ -211,62 +196,60 @@ void ProcessGeneration() isInvalid = true; } - // LINE 309 - ProcessPopulation(); - - void ProcessPopulation() + for (var x = minX - 1; x < maxX + 2; x++) { - // var population = 0; - for (int x = minX - 1; x < maxX + 2; x++) // TODO review indices + for (var y = minY - 1; y < maxY + 2; y++) { - for (int y = minY - 1; y < maxY + 2; y++) // TODO review indices + int CountNeighbors() { var neighbors = 0; - for (int i = x - 1; i < x + 2; i++) // TODO review indices + for (var i = x - 1; i < x + 2; i++) { - for (int j = y - 1; j < y + 2; j++) // TODO review indices + for (var j = y - 1; j < y + 2; j++) { if (matrix[i, j] == 1 || matrix[i, j] == 2) neighbors++; } } - // PrintMatrix(matrix); - if (matrix[x, y] == 0) + return neighbors; + } + + var neighbors = CountNeighbors(); + if (matrix[x, y] == 0) + { + if (neighbors == 3) { - if (neighbors == 3) - { - matrix[x, y] = 3; - // population++; - simulation.IncreasePopulation(); - } - } - else if (neighbors is < 3 or > 4) - { - matrix[x, y] = 2; - } - else - { - // population++; + matrix[x, y] = 3; simulation.IncreasePopulation(); } } + else if (neighbors is < 3 or > 4) + { + matrix[x, y] = 2; + } + else + { + simulation.IncreasePopulation(); + } } - - // LINE 635 - minX--; - minY--; - maxX++; - maxY++; } - // PrintMatrix(matrix); + + // expands search area to accommodate new cells + minX--; + minY--; + maxX++; + maxY++; } } -Console.WriteLine(); -Console.WriteLine(); -Console.WriteLine(); -ProcessGeneration(); +(int index, string value) GetLongestInput(IEnumerable strings) +{ + return strings + .Select((value, index) => (index, value)) + .OrderByDescending(input => input.value.Length) + .First(); +} public class Simulation { @@ -286,33 +269,29 @@ public class Simulation } } - -// int x1 = 1, y1 = 1; -// int x2 = 24, y2 = 70; - -// var b = new string[24]; - - - - - -public class MatrixSpace +class Matrix { - public int[,] Matrix { get; } + private readonly int[,] _matrix; - public MatrixSpace(int height, int width) + public Matrix(int height, int width) { - Matrix = new int[height, width]; + _matrix = new int[height, width]; } + public int this[int x, int y] + { + get => _matrix[x, y]; + set => _matrix[x, y] = value; + } + public override string ToString() { var stringBuilder = new StringBuilder(); - for (var x = 0; x < Matrix.GetLength(0); x++) + for (var x = 0; x < _matrix.GetLength(0); x++) { - for (var y = 0; y < Matrix.GetLength(1); y++) + for (var y = 0; y < _matrix.GetLength(1); y++) { - var character = Matrix[x, y] == 0 ? " ": Matrix[x, y].ToString(); + var character = _matrix[x, y] == 0 ? " ": _matrix[x, y].ToString(); stringBuilder.Append(character); } @@ -320,4 +299,4 @@ public class MatrixSpace } return stringBuilder.ToString(); } -} +} \ No newline at end of file From e53b9d9cf18fc89e6aa34130b5eb1b16cd8e782b Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:44:13 -0300 Subject: [PATCH 253/331] Further refactoring, naming procedures. --- 55_Life/csharp/Program.cs | 186 ++++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 97 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index ec925faa..cc594435 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -2,47 +2,8 @@ using System.Text; -IEnumerable ReadPattern(int limitHeight) -{ - for (var i = 0; i < limitHeight; i++) - { - var input = Console.ReadLine(); - if (input.ToUpper() == "DONE") - { - yield return string.Empty; - break; - } - - // kept for compatibility - if (input.StartsWith('.')) - yield return input.Substring(1, input.Length - 2); - - yield return input; - } -} - -void PrintHeader() -{ - const int pageWidth = 64; - - void PrintCentered(string text) - { - var spaceCount = (pageWidth - text.Length) / 2; - Console.Write(new string(' ', spaceCount)); - Console.WriteLine(text); - } - - PrintCentered("LIFE"); - PrintCentered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine(); -} - - - - - +const int MaxWidth = 70; +const int MaxHeight = 24; Console.WriteLine("ENTER YOUR PATTERN:"); // var pattern = ReadPattern(limitHeight: MaxHeight).ToArray(); @@ -63,26 +24,63 @@ var pattern = new[] // "*", // }; // FOR DEBUGGING PURPOSES - -const int MaxWidth = 70; -const int MaxHeight = 24; - var isInvalid = false; -var (index, value) = GetLongestInput(pattern); -int minX = (11 - index / 2) - 1; // middle x -int minY = (33 - value.Length / 2) - 1; // middle y -int maxX = MaxHeight; -int maxY = MaxWidth; +var (index, value) = FindLongestInput(pattern); +var minX = (11 - index / 2) - 1; // middle x +var minY = (33 - value.Length / 2) - 1; // middle y +var maxX = MaxHeight; +var maxY = MaxWidth; var matrix = new Matrix(height: MaxHeight, width: MaxWidth); var simulation = InitializeSimulation(pattern, matrix); PrintHeader(); -Console.WriteLine(); -Console.WriteLine(); -Console.WriteLine(); ProcessGeneration(); +IEnumerable ReadPattern(int limitHeight) +{ + for (var i = 0; i < limitHeight; i++) + { + var input = Console.ReadLine(); + if (input.ToUpper() == "DONE") + { + yield return string.Empty; + break; + } + + // kept for compatibility + if (input.StartsWith('.')) + yield return input.Substring(1, input.Length - 2); + + yield return input; + } +} + +(int index, string value) FindLongestInput(IEnumerable strings) +{ + return strings + .Select((value, index) => (index, value)) + .OrderByDescending(input => input.value.Length) + .First(); +} + +void PrintHeader() +{ + void PrintCentered(string text) + { + const int pageWidth = 64; + + var spaceCount = (pageWidth - text.Length) / 2; + Console.Write(new string(' ', spaceCount)); + Console.WriteLine(text); + } + + PrintCentered("LIFE"); + PrintCentered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); +} Simulation InitializeSimulation(IReadOnlyList inputPattern, Matrix matrixToInitialize) { var newSimulation = new Simulation(); @@ -103,26 +101,24 @@ Simulation InitializeSimulation(IReadOnlyList inputPattern, Matrix matri void ProcessGeneration() { + void PrintPopulation(int generation, int population) + { + Console.WriteLine($"GENERATION: {generation}\tPOPULATION: {population}"); + if (isInvalid) + Console.WriteLine("INVALID!"); + } + while (true) { - void PrintPopulation(int generation, int population) - { - Console.WriteLine($"GENERATION: {generation}\tPOPULATION: {population}"); - if (isInvalid) - Console.WriteLine("INVALID!"); - } - PrintPopulation(simulation.Generation, simulation.Population); - simulation.StartNewGeneration(); - // LINE 215 var nextMinX = MaxHeight - 1; var nextMinY = MaxWidth - 1; var nextMaxX = 0; var nextMaxY = 0; - // prints empty lines before alive cells + // prints the empty lines before search area for (var x = 0; x < minX; x++) { Console.WriteLine(); @@ -159,42 +155,46 @@ void ProcessGeneration() Console.WriteLine(string.Join(separator: null, values: printedLine)); } - // prints empty lines after alive cells - for (int x = maxX + 1; x < MaxHeight; x++) + // prints empty lines after search area + for (var x = maxX + 1; x < MaxHeight; x++) { Console.WriteLine(); } Console.WriteLine(); - minX = nextMinX; - maxX = nextMaxX; - minY = nextMinY; - maxY = nextMaxY; - - // TODO boundaries? review - if (minX < 3) + void UpdateSearchArea() { - minX = 3; - isInvalid = true; - } + minX = nextMinX; + maxX = nextMaxX; + minY = nextMinY; + maxY = nextMaxY; - if (maxX > 22) - { - maxX = 22; - isInvalid = true; - } + // TODO boundaries? review + if (minX < 3) + { + minX = 3; + isInvalid = true; + } - if (minY < 3) - { - minY = 3; - isInvalid = true; - } + if (maxX > 22) + { + maxX = 22; + isInvalid = true; + } - if (maxY > 68) - { - maxY = 68; - isInvalid = true; + if (minY < 3) + { + minY = 3; + isInvalid = true; + } + + if (maxY > 68) + { + maxY = 68; + isInvalid = true; + } } + UpdateSearchArea(); for (var x = minX - 1; x < maxX + 2; x++) { @@ -243,14 +243,6 @@ void ProcessGeneration() } } -(int index, string value) GetLongestInput(IEnumerable strings) -{ - return strings - .Select((value, index) => (index, value)) - .OrderByDescending(input => input.value.Length) - .First(); -} - public class Simulation { public int Generation { get; private set; } From 778af346d723fec512d30e451ad84a22ab1cb9a6 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:45:00 -0300 Subject: [PATCH 254/331] Added enum Cell to enhance clarity. --- 55_Life/csharp/Program.cs | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index cc594435..0abb68f1 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -1,10 +1,13 @@ // See https://aka.ms/new-console-template for more information +using System.Drawing; using System.Text; const int MaxWidth = 70; const int MaxHeight = 24; + + Console.WriteLine("ENTER YOUR PATTERN:"); // var pattern = ReadPattern(limitHeight: MaxHeight).ToArray(); var pattern = new[] @@ -91,7 +94,7 @@ Simulation InitializeSimulation(IReadOnlyList inputPattern, Matrix matri { if (inputPattern[x][y] == ' ') continue; - matrixToInitialize[minX + x, minY + y] = 1; // copy the pattern to the middle of the simulation + matrixToInitialize[minX + x, minY + y] = Cell.NeutralCell; // copy the pattern to the middle of the simulation newSimulation.IncreasePopulation(); } } @@ -130,16 +133,16 @@ void ProcessGeneration() var printedLine = Enumerable.Repeat(' ', MaxWidth).ToList(); for (var y = minY; y < maxY; y++) { - if (matrix[x, y] == 2) + if (matrix[x, y] == Cell.DyingCel) { matrix[x, y] = 0; continue; } - if (matrix[x, y] == 3) + if (matrix[x, y] == Cell.NewCell) { - matrix[x, y] = 1; + matrix[x, y] = Cell.NeutralCell; } - else if (matrix[x, y] != 1) + else if (matrix[x, y] != Cell.NeutralCell) { continue; } @@ -207,7 +210,7 @@ void ProcessGeneration() { for (var j = y - 1; j < y + 2; j++) { - if (matrix[i, j] == 1 || matrix[i, j] == 2) + if (matrix[i, j] == Cell.NeutralCell || matrix[i, j] == Cell.DyingCel) neighbors++; } } @@ -220,13 +223,13 @@ void ProcessGeneration() { if (neighbors == 3) { - matrix[x, y] = 3; + matrix[x, y] = Cell.NewCell; simulation.IncreasePopulation(); } } else if (neighbors is < 3 or > 4) { - matrix[x, y] = 2; + matrix[x, y] = Cell.DyingCel; } else { @@ -243,6 +246,14 @@ void ProcessGeneration() } } +internal enum Cell +{ + EmptyCell = 0, + NeutralCell = 1, + DyingCel = 2, + NewCell =3 +} + public class Simulation { public int Generation { get; private set; } @@ -263,14 +274,14 @@ public class Simulation class Matrix { - private readonly int[,] _matrix; + private readonly Cell[,] _matrix; public Matrix(int height, int width) { - _matrix = new int[height, width]; + _matrix = new Cell[height, width]; } - public int this[int x, int y] + public Cell this[int x, int y] { get => _matrix[x, y]; set => _matrix[x, y] = value; @@ -283,7 +294,7 @@ class Matrix { for (var y = 0; y < _matrix.GetLength(1); y++) { - var character = _matrix[x, y] == 0 ? " ": _matrix[x, y].ToString(); + var character = _matrix[x, y] == 0 ? " ": ((int)_matrix[x, y]).ToString(); stringBuilder.Append(character); } From 4870a14909b6055440c0445b5db1571004353518 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:45:34 -0300 Subject: [PATCH 255/331] Refactoring, plus adding real user input again. --- 55_Life/csharp/Program.cs | 72 ++++++++++++++------------------------- 1 file changed, 25 insertions(+), 47 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 0abb68f1..b9aef5dd 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -1,40 +1,16 @@ -// See https://aka.ms/new-console-template for more information - -using System.Drawing; -using System.Text; - -const int MaxWidth = 70; -const int MaxHeight = 24; - +using System.Text; +const int maxWidth = 70; +const int maxHeight = 24; Console.WriteLine("ENTER YOUR PATTERN:"); -// var pattern = ReadPattern(limitHeight: MaxHeight).ToArray(); -var pattern = new[] -{ - "*", - "*", - "*" -}; // FOR DEBUGGING PURPOSES -// var pattern = new[] -// { -// "**", -// "**", -// }; // FOR DEBUGGING PURPOSES -// var pattern = new[] -// { -// "***", -// "*", -// }; // FOR DEBUGGING PURPOSES +var pattern = ReadPattern(limitHeight: maxHeight).ToArray(); -var isInvalid = false; +var (minX, minY) = FindTopLeftCorner(pattern); +var maxX = maxHeight; +var maxY = maxWidth; -var (index, value) = FindLongestInput(pattern); -var minX = (11 - index / 2) - 1; // middle x -var minY = (33 - value.Length / 2) - 1; // middle y -var maxX = MaxHeight; -var maxY = MaxWidth; -var matrix = new Matrix(height: MaxHeight, width: MaxWidth); +var matrix = new Matrix(height: maxHeight, width: maxWidth); var simulation = InitializeSimulation(pattern, matrix); PrintHeader(); @@ -59,12 +35,15 @@ IEnumerable ReadPattern(int limitHeight) } } -(int index, string value) FindLongestInput(IEnumerable strings) +(int minX, int minY) FindTopLeftCorner(IEnumerable patternLines) { - return strings + var longestInput = patternLines .Select((value, index) => (index, value)) .OrderByDescending(input => input.value.Length) .First(); + var centerX = (11 - longestInput.index / 2) - 1; + var centerY = (33 - longestInput.value.Length / 2) - 1; + return (centerX, centerY); } void PrintHeader() @@ -88,13 +67,14 @@ void PrintHeader() Simulation InitializeSimulation(IReadOnlyList inputPattern, Matrix matrixToInitialize) { var newSimulation = new Simulation(); + // copies the pattern to the middle of the simulation and counts initial population for (var x = 0; x < inputPattern.Count; x++) { for (var y = 0; y < inputPattern[x].Length; y++) { if (inputPattern[x][y] == ' ') continue; - matrixToInitialize[minX + x, minY + y] = Cell.NeutralCell; // copy the pattern to the middle of the simulation + matrixToInitialize[minX + x, minY + y] = Cell.NeutralCell; newSimulation.IncreasePopulation(); } } @@ -104,20 +84,19 @@ Simulation InitializeSimulation(IReadOnlyList inputPattern, Matrix matri void ProcessGeneration() { - void PrintPopulation(int generation, int population) - { - Console.WriteLine($"GENERATION: {generation}\tPOPULATION: {population}"); - if (isInvalid) - Console.WriteLine("INVALID!"); - } + var isInvalid = false; while (true) { - PrintPopulation(simulation.Generation, simulation.Population); + // Thread.Sleep(millisecondsTimeout: 1000); + Console.WriteLine($"GENERATION: {simulation.Generation}\tPOPULATION: {simulation.Population}"); + if (isInvalid) + Console.WriteLine("INVALID!"); + simulation.StartNewGeneration(); - var nextMinX = MaxHeight - 1; - var nextMinY = MaxWidth - 1; + var nextMinX = maxHeight - 1; + var nextMinY = maxWidth - 1; var nextMaxX = 0; var nextMaxY = 0; @@ -130,7 +109,7 @@ void ProcessGeneration() // refreshes the matrix and updates search area for (var x = minX; x < maxX; x++) { - var printedLine = Enumerable.Repeat(' ', MaxWidth).ToList(); + var printedLine = Enumerable.Repeat(' ', maxWidth).ToList(); for (var y = minY; y < maxY; y++) { if (matrix[x, y] == Cell.DyingCel) @@ -159,7 +138,7 @@ void ProcessGeneration() } // prints empty lines after search area - for (var x = maxX + 1; x < MaxHeight; x++) + for (var x = maxX + 1; x < maxHeight; x++) { Console.WriteLine(); } @@ -172,7 +151,6 @@ void ProcessGeneration() minY = nextMinY; maxY = nextMaxY; - // TODO boundaries? review if (minX < 3) { minX = 3; From cd478a4a948d575ebb0ab55f34f555ac95c93bd8 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:46:07 -0300 Subject: [PATCH 256/331] Added argument to configure a pause in between iterations, allowing the player to enjoy watching the evolution of the game of life. --- 55_Life/csharp/Program.cs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index b9aef5dd..07a06eac 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -82,13 +82,32 @@ Simulation InitializeSimulation(IReadOnlyList inputPattern, Matrix matri return newSimulation; } +TimeSpan GetPauseBetweenIterations() +{ + if (args.Length == 2) + { + var parameter = args[0].ToLower(); + if (parameter.Contains("wait")) + { + var value = args[1]; + if (int.TryParse(value, out var sleepMilliseconds)) + return TimeSpan.FromMilliseconds(sleepMilliseconds); + } + } + + return TimeSpan.Zero; +} + void ProcessGeneration() { + var pauseBetweenIterations = GetPauseBetweenIterations(); var isInvalid = false; while (true) { - // Thread.Sleep(millisecondsTimeout: 1000); + if (pauseBetweenIterations > TimeSpan.Zero) + Thread.Sleep(pauseBetweenIterations); + Console.WriteLine($"GENERATION: {simulation.Generation}\tPOPULATION: {simulation.Population}"); if (isInvalid) Console.WriteLine("INVALID!"); From 3ffd2fdc520145d42b65becb51b6ae9cc87163aa Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:46:39 -0300 Subject: [PATCH 257/331] Refactoring and documenting the solution. --- 55_Life/csharp/Program.cs | 50 +++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 07a06eac..f2b66b88 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -14,7 +14,7 @@ var matrix = new Matrix(height: maxHeight, width: maxWidth); var simulation = InitializeSimulation(pattern, matrix); PrintHeader(); -ProcessGeneration(); +ProcessSimulation(); IEnumerable ReadPattern(int limitHeight) { @@ -27,7 +27,9 @@ IEnumerable ReadPattern(int limitHeight) break; } - // kept for compatibility + // In the original version, BASIC would trim the spaces in the beginning of an input, so the original + // game allowed you to input an '.' before the spaces to circumvent this limitation. This behavior was + // kept for compatibility. if (input.StartsWith('.')) yield return input.Substring(1, input.Length - 2); @@ -67,14 +69,14 @@ void PrintHeader() Simulation InitializeSimulation(IReadOnlyList inputPattern, Matrix matrixToInitialize) { var newSimulation = new Simulation(); - // copies the pattern to the middle of the simulation and counts initial population + // translates the pattern to the middle of the simulation and counts initial population for (var x = 0; x < inputPattern.Count; x++) { for (var y = 0; y < inputPattern[x].Length; y++) { if (inputPattern[x][y] == ' ') continue; - matrixToInitialize[minX + x, minY + y] = Cell.NeutralCell; + matrixToInitialize[minX + x, minY + y] = CellState.Stable; newSimulation.IncreasePopulation(); } } @@ -98,7 +100,7 @@ TimeSpan GetPauseBetweenIterations() return TimeSpan.Zero; } -void ProcessGeneration() +void ProcessSimulation() { var pauseBetweenIterations = GetPauseBetweenIterations(); var isInvalid = false; @@ -131,16 +133,16 @@ void ProcessGeneration() var printedLine = Enumerable.Repeat(' ', maxWidth).ToList(); for (var y = minY; y < maxY; y++) { - if (matrix[x, y] == Cell.DyingCel) + if (matrix[x, y] == CellState.Dying) { - matrix[x, y] = 0; + matrix[x, y] = CellState.Empty; continue; } - if (matrix[x, y] == Cell.NewCell) + if (matrix[x, y] == CellState.New) { - matrix[x, y] = Cell.NeutralCell; + matrix[x, y] = CellState.Stable; } - else if (matrix[x, y] != Cell.NeutralCell) + else if (matrix[x, y] != CellState.Stable) { continue; } @@ -207,7 +209,7 @@ void ProcessGeneration() { for (var j = y - 1; j < y + 2; j++) { - if (matrix[i, j] == Cell.NeutralCell || matrix[i, j] == Cell.DyingCel) + if (matrix[i, j] == CellState.Stable || matrix[i, j] == CellState.Dying) neighbors++; } } @@ -220,13 +222,13 @@ void ProcessGeneration() { if (neighbors == 3) { - matrix[x, y] = Cell.NewCell; + matrix[x, y] = CellState.New; simulation.IncreasePopulation(); } } else if (neighbors is < 3 or > 4) { - matrix[x, y] = Cell.DyingCel; + matrix[x, y] = CellState.Dying; } else { @@ -243,12 +245,15 @@ void ProcessGeneration() } } -internal enum Cell +/// +/// Indicates the state of a given cell in the simulation. +/// +internal enum CellState { - EmptyCell = 0, - NeutralCell = 1, - DyingCel = 2, - NewCell =3 + Empty = 0, + Stable = 1, + Dying = 2, + New = 3 } public class Simulation @@ -269,16 +274,19 @@ public class Simulation } } +/// +/// This class was created to aid debugging, through the implementation of the ToString() method. +/// class Matrix { - private readonly Cell[,] _matrix; + private readonly CellState[,] _matrix; public Matrix(int height, int width) { - _matrix = new Cell[height, width]; + _matrix = new CellState[height, width]; } - public Cell this[int x, int y] + public CellState this[int x, int y] { get => _matrix[x, y]; set => _matrix[x, y] = value; From c7c3d68a2eed69735ae4664f3c0d7925f9545464 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:47:08 -0300 Subject: [PATCH 258/331] Moving pause location to the end of iteration. --- 55_Life/csharp/Program.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index f2b66b88..1c21b5f7 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -107,9 +107,6 @@ void ProcessSimulation() while (true) { - if (pauseBetweenIterations > TimeSpan.Zero) - Thread.Sleep(pauseBetweenIterations); - Console.WriteLine($"GENERATION: {simulation.Generation}\tPOPULATION: {simulation.Population}"); if (isInvalid) Console.WriteLine("INVALID!"); @@ -242,6 +239,9 @@ void ProcessSimulation() minY--; maxX++; maxY++; + + if (pauseBetweenIterations > TimeSpan.Zero) + Thread.Sleep(pauseBetweenIterations); } } From 985e1886ac32763896a363f585e7c7f5618b3a31 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:48:13 -0300 Subject: [PATCH 259/331] Adding comment about the port. --- 55_Life/csharp/Program.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 1c21b5f7..2ed1ec62 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -1,4 +1,16 @@ -using System.Text; +/* + * LIFE + * An implementation of John Conway's popular cellular automaton + * Ported by Dyego Alekssander Maas + * + * An example pattern would be: + * " * " + * "***" + * "DONE" (indicates that the simulation can start) + * + * You can find patterns to play with here: http://pi.math.cornell.edu/~lipa/mec/lesson6.html +*/ +using System.Text; const int maxWidth = 70; const int maxHeight = 24; From 8c02ea39d272a157613318a0884cea6fc734faca Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Tue, 11 Jan 2022 20:58:07 -0300 Subject: [PATCH 260/331] Documented the --wait argument. --- 55_Life/csharp/Program.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 2ed1ec62..47ed7386 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -9,6 +9,10 @@ * "DONE" (indicates that the simulation can start) * * You can find patterns to play with here: http://pi.math.cornell.edu/~lipa/mec/lesson6.html + * + * Optionally, you can run this program with the "--wait 1000" argument, the number being the time in milliseconds + * that the application will pause between each iteration. This is enables you to watch the simulation unfolding. + * By default, there is no pause between iterations. */ using System.Text; From b28a12f52afec5cd5955190dbd189015d8c05f78 Mon Sep 17 00:00:00 2001 From: Tim Buchalka <70119791+journich@users.noreply.github.com> Date: Wed, 12 Jan 2022 12:22:37 +1030 Subject: [PATCH 261/331] Document both contributions of this game Notes relating to both contributed versions of Acey Ducey for Java. --- 01_Acey_Ducey/java/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/01_Acey_Ducey/java/README.md b/01_Acey_Ducey/java/README.md index 51edd8d4..4153020a 100644 --- a/01_Acey_Ducey/java/README.md +++ b/01_Acey_Ducey/java/README.md @@ -1,3 +1,9 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Oracle Java](https://openjdk.java.net/) + +Two versions of Acey Ducey have been contributed. + +The original upload supported JDK 8/JDK 11 and uses multiple files and the second uses features in JDK 17 and is implemented in a single file AceyDucey17.java. + +Both are in the src folder. From daa06846bf2de4b3e57ba10c1e0c0b8491a0dae5 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 11 Jan 2022 20:59:56 -0500 Subject: [PATCH 262/331] moved implementations to individual folders --- 75_Roulette/java/{src => iterative}/Roulette.java | 0 75_Roulette/java/{ => oop}/Bet.java | 0 75_Roulette/java/{ => oop}/Roulette.java | 0 75_Roulette/java/{ => oop}/Wheel.java | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename 75_Roulette/java/{src => iterative}/Roulette.java (100%) rename 75_Roulette/java/{ => oop}/Bet.java (100%) rename 75_Roulette/java/{ => oop}/Roulette.java (100%) rename 75_Roulette/java/{ => oop}/Wheel.java (100%) diff --git a/75_Roulette/java/src/Roulette.java b/75_Roulette/java/iterative/Roulette.java similarity index 100% rename from 75_Roulette/java/src/Roulette.java rename to 75_Roulette/java/iterative/Roulette.java diff --git a/75_Roulette/java/Bet.java b/75_Roulette/java/oop/Bet.java similarity index 100% rename from 75_Roulette/java/Bet.java rename to 75_Roulette/java/oop/Bet.java diff --git a/75_Roulette/java/Roulette.java b/75_Roulette/java/oop/Roulette.java similarity index 100% rename from 75_Roulette/java/Roulette.java rename to 75_Roulette/java/oop/Roulette.java diff --git a/75_Roulette/java/Wheel.java b/75_Roulette/java/oop/Wheel.java similarity index 100% rename from 75_Roulette/java/Wheel.java rename to 75_Roulette/java/oop/Wheel.java From 76d5f2dde2dfc0422895aa6f9b93fc59ba9dd3ba Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 11 Jan 2022 21:03:33 -0500 Subject: [PATCH 263/331] Expanded README to describe different implementations --- 75_Roulette/java/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/75_Roulette/java/README.md b/75_Roulette/java/README.md index 2f9c97ca..8514a9ad 100644 --- a/75_Roulette/java/README.md +++ b/75_Roulette/java/README.md @@ -2,5 +2,7 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/gam Conversion to [Oracle Java](https://openjdk.java.net/) -Conversion by Andrew McGuinness (andrew@arobeia.co.uk) +Two versions of Roulette has been contributed. They are indicated within given sub-folders +- [oop](./oop) - Conversion by Andrew McGuinness (andrew@arobeia.co.uk) +- [iterative](./iterative) - Conversion by Thomas Kwashnak ([Github](https://github.com/LittleTealeaf)). Implements features from JDK 17 \ No newline at end of file From f87d306b0f5ba33047320c586dc7445d48bccf62 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 11 Jan 2022 21:05:35 -0500 Subject: [PATCH 264/331] Added some descriptors to iterative --- 75_Roulette/java/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/75_Roulette/java/README.md b/75_Roulette/java/README.md index 8514a9ad..bc05d92c 100644 --- a/75_Roulette/java/README.md +++ b/75_Roulette/java/README.md @@ -5,4 +5,6 @@ Conversion to [Oracle Java](https://openjdk.java.net/) Two versions of Roulette has been contributed. They are indicated within given sub-folders - [oop](./oop) - Conversion by Andrew McGuinness (andrew@arobeia.co.uk) -- [iterative](./iterative) - Conversion by Thomas Kwashnak ([Github](https://github.com/LittleTealeaf)). Implements features from JDK 17 \ No newline at end of file +- [iterative](./iterative) - Conversion by Thomas Kwashnak ([Github](https://github.com/LittleTealeaf)). + - Implements features from JDK 17. + - Does make use of some object oriented programming, but acts as a more iterative solution. \ No newline at end of file From f61148b2e4c7608c5d7cbbf08ddfcbfd9c5afebf Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Tue, 11 Jan 2022 21:19:47 -0500 Subject: [PATCH 265/331] Convert 21_Calendar to Perl. This is pretty much a complete rewrite. It displays the current year, but that can be changed by specifying the desired year on the command line. It MAY even be sensitive enough to locale to produce output in languages other than English. --- 21_Calendar/perl/README.md | 10 +++ 21_Calendar/perl/calendar.pl | 130 +++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100755 21_Calendar/perl/calendar.pl diff --git a/21_Calendar/perl/README.md b/21_Calendar/perl/README.md index e69c8b81..043be194 100644 --- a/21_Calendar/perl/README.md +++ b/21_Calendar/perl/README.md @@ -1,3 +1,13 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +Actually, this is not so much a port as a complete rewrite, making use of +Perl's Posix time functionality. The calendar is for the current year (not +1979), but you can get another year by specifying it on the command line, e.g. + + `perl 21_Calendar/perl/calendar.pl 2001` + +It *may* even produce output in languages other than English. But the +leftmost column will still be Sunday, even in locales where it is +typically Monday. diff --git a/21_Calendar/perl/calendar.pl b/21_Calendar/perl/calendar.pl new file mode 100755 index 00000000..96ba387b --- /dev/null +++ b/21_Calendar/perl/calendar.pl @@ -0,0 +1,130 @@ +#!/usr/bin/env perl + +use 5.010; # To get 'state' and 'say' + +use strict; # Require explicit declaration of variables +use warnings; # Enable optional compiler warnings + +use English; # Use more friendly names for Perl's magic variables +use POSIX qw{ strftime }; +use Term::ReadLine; # Prompt and return user input +use Time::Local (); + +BEGIN { + *time_gm = + Time::Local->can( 'timegm_modern' ) || + Time::Local->can( 'timegm' ); +} + +our $VERSION = '0.000_01'; + +use constant COLUMN_WIDTH => 6; +use constant SECONDS_PER_DAY => 86400; + +binmode STDOUT, ':encoding(utf-8)'; + +my $year = @ARGV ? $ARGV[0] : ( localtime )[5] + 1900; +my $is_leap_year = is_leap_year( $year ); +my $year_len = 365 + $is_leap_year; +print <<'EOD'; + CALENDAR + Creative Computing Morristown, New Jersey + + +EOD + +my @mon_len = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ); +$mon_len[1] += $is_leap_year; + +foreach my $month ( 0 .. 11 ) { + my $epoch = time_gm( 0, 0, 0, 1, $month, $year ); + my @start_time = gmtime( $epoch ); + my ( $week_day, $year_day ) = @start_time[ 6, 7 ]; + my $label = strftime( '%B %Y', @start_time ); + $label .= ' ' x ( ( 14 - length $label ) / 2 ); + printf "\n** %3d ****** %14s ****** %3d **\n", + $year_day, $label, $year_len - $year_day; + { + my $day = 1 + ( 7 - $week_day ) % 7; + foreach my $wd ( 0 .. 6 ) { + my $ep = time_gm( 0, 0, 0, $day + $wd, $month, $year ); + printf '%*s', COLUMN_WIDTH, strftime( '%a', gmtime $ep ); + } + print "\n"; + } + say '*' x ( COLUMN_WIDTH * 7 ); + print ' ' x ( COLUMN_WIDTH * $week_day ); + my $month_day = 1; + while ( $week_day < 7 ) { + printf '%*d', COLUMN_WIDTH, $month_day++; + $week_day++; + } + print "\n"; + $week_day = 0; + while ( $month_day <= $mon_len[$month] ) { + printf '%*d', COLUMN_WIDTH, $month_day++; + $week_day++; + unless ( $week_day % 7 ) { + print "\n"; + $week_day = 0; + } + } + print "\n" if $week_day; + +} + +sub is_leap_year { + my ( $year ) = 1; + return 0 if $year % 4; + return 1 if $year % 100; + return 0 if $year % 400; + return 1; +} + +__END__ + +=head1 TITLE + +calendar - Play the game 'Calendar' from Basic Computer Games + +=head1 SYNOPSIS + + calendar.pl + +=head1 DETAILS + +This Perl script is a port of calendar, which is the 21st +entry in Basic Computer Games. + +Actually, it is not so much a port as a complete rewrite, making use of +Perl's Posix time functionality. The calendar is for the current year +(not 1979), but you can get another year by specifying it on the command +line, e.g. + + perl 21_Calendar/perl/calendar.pl 2001 + +It B even produce output in languages other than English. But the +leftmost column will still be Sunday, even in locales where it is +typically Monday. + +=head1 PORTED BY + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set expandtab tabstop=4 textwidth=72 : From 84d473d8f29e65b23ce12a859a45479974b5fe0c Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 17:56:26 +0800 Subject: [PATCH 266/331] Create reverser that reverses an array at a given position. --- .../Reverse.Tests/Reverse.Tests.csproj | 26 ++++++++++++ .../Reverse/Reverse.Tests/ReverserTests.cs | 41 +++++++++++++++++++ 73_Reverse/csharp/Reverse/Reverse.sln | 31 ++++++++++++++ 73_Reverse/csharp/Reverse/Reverse/Program.cs | 12 ++++++ .../csharp/Reverse/Reverse/Reverse.csproj | 8 ++++ 73_Reverse/csharp/Reverse/Reverse/Reverser.cs | 16 ++++++++ 6 files changed, 134 insertions(+) create mode 100644 73_Reverse/csharp/Reverse/Reverse.Tests/Reverse.Tests.csproj create mode 100644 73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs create mode 100644 73_Reverse/csharp/Reverse/Reverse.sln create mode 100644 73_Reverse/csharp/Reverse/Reverse/Program.cs create mode 100644 73_Reverse/csharp/Reverse/Reverse/Reverse.csproj create mode 100644 73_Reverse/csharp/Reverse/Reverse/Reverser.cs diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/Reverse.Tests.csproj b/73_Reverse/csharp/Reverse/Reverse.Tests/Reverse.Tests.csproj new file mode 100644 index 00000000..97b7bcce --- /dev/null +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/Reverse.Tests.csproj @@ -0,0 +1,26 @@ + + + + net5.0 + + false + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs new file mode 100644 index 00000000..2ab52d69 --- /dev/null +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs @@ -0,0 +1,41 @@ +using System.Linq; +using Xunit; + +namespace Reverse.Tests +{ + public class ReverserTests + { + [Theory] + [InlineData(new int[] { 1 }, new int[] { 1 })] + [InlineData(new int[] { 1, 2 }, new int[] { 2, 1 })] + [InlineData(new int[] { 1, 2, 3 }, new int[] { 3, 2, 1 })] + public void ReverserReversesTheArray(int[] input, int[] output) + { + Reverser.Reverse(input, input.Length); + + Assert.True(input.SequenceEqual(output)); + } + + [Fact] + public void ReverserReversesTheArrayAtTheSpecifiedIndex() + { + var input = new int[] { 1, 2, 3, 4 }; + var output = new int[] { 2, 1, 3, 4 }; + + Reverser.Reverse(input, 2); + + Assert.True(input.SequenceEqual(output)); + } + + [Fact] + public void ReversingAtIndexOneDoesNotChangeTheArray() + { + var input = new int[] { 1, 2 }; + var output = new int[] { 1, 2 }; + + Reverser.Reverse(input, 1); + + Assert.True(input.SequenceEqual(output)); + } + } +} diff --git a/73_Reverse/csharp/Reverse/Reverse.sln b/73_Reverse/csharp/Reverse/Reverse.sln new file mode 100644 index 00000000..96c338be --- /dev/null +++ b/73_Reverse/csharp/Reverse/Reverse.sln @@ -0,0 +1,31 @@ + +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}") = "Reverse", "Reverse\Reverse.csproj", "{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reverse.Tests", "Reverse.Tests\Reverse.Tests.csproj", "{96E824F8-0353-4FF2-9FEA-F850E2BE7312}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Release|Any CPU.Build.0 = Release|Any CPU + {96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1DCA2723-D126-4B37-A698-D40DA03643A9} + EndGlobalSection +EndGlobal diff --git a/73_Reverse/csharp/Reverse/Reverse/Program.cs b/73_Reverse/csharp/Reverse/Reverse/Program.cs new file mode 100644 index 00000000..72ae99ef --- /dev/null +++ b/73_Reverse/csharp/Reverse/Reverse/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace Reverse +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverse.csproj b/73_Reverse/csharp/Reverse/Reverse/Reverse.csproj new file mode 100644 index 00000000..20827042 --- /dev/null +++ b/73_Reverse/csharp/Reverse/Reverse/Reverse.csproj @@ -0,0 +1,8 @@ + + + + Exe + net5.0 + + + diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs new file mode 100644 index 00000000..ed9b8748 --- /dev/null +++ b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs @@ -0,0 +1,16 @@ +namespace Reverse +{ + public class Reverser + { + public static void Reverse(int[] arrayToReverse, int indexToReverseTo) + { + for (int i = 0; i < indexToReverseTo / 2; i++) + { + int temp = arrayToReverse[i]; + int upperIndex = indexToReverseTo - 1 - i; + arrayToReverse[i] = arrayToReverse[upperIndex]; + arrayToReverse[upperIndex] = temp; + } + } + } +} From 2a809aabc99cb582bab93e259e1b3ec2d03a555b Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 18:09:57 +0800 Subject: [PATCH 267/331] Protect against index out of range exceptions --- .../csharp/Reverse/Reverse.Tests/ReverserTests.cs | 11 +++++++++++ 73_Reverse/csharp/Reverse/Reverse/Reverser.cs | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs index 2ab52d69..7320ef92 100644 --- a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs @@ -37,5 +37,16 @@ namespace Reverse.Tests Assert.True(input.SequenceEqual(output)); } + + [Fact] + public void Reverse_WithIndexGreaterThanArrayLength_DoesNothing() + { + var input = new int[] { 1, 2 }; + var output = new int[] { 1, 2 }; + + Reverser.Reverse(input, input.Length + 1); + + Assert.True(input.SequenceEqual(output)); + } } } diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs index ed9b8748..be3b194f 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs @@ -4,6 +4,11 @@ { public static void Reverse(int[] arrayToReverse, int indexToReverseTo) { + if (indexToReverseTo > arrayToReverse.Length) + { + return; + } + for (int i = 0; i < indexToReverseTo / 2; i++) { int temp = arrayToReverse[i]; From 8e54c0e930d87eef2ed0408591d73fcc9ce30541 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 18:12:15 +0800 Subject: [PATCH 268/331] rename tests. --- 73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs index 7320ef92..c263dbe5 100644 --- a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs @@ -9,7 +9,7 @@ namespace Reverse.Tests [InlineData(new int[] { 1 }, new int[] { 1 })] [InlineData(new int[] { 1, 2 }, new int[] { 2, 1 })] [InlineData(new int[] { 1, 2, 3 }, new int[] { 3, 2, 1 })] - public void ReverserReversesTheArray(int[] input, int[] output) + public void Reverse_WillReverseEntireArray(int[] input, int[] output) { Reverser.Reverse(input, input.Length); @@ -17,7 +17,7 @@ namespace Reverse.Tests } [Fact] - public void ReverserReversesTheArrayAtTheSpecifiedIndex() + public void Reverse_WithSpecifiedIndex_ReversesItemsUpToThatIndex() { var input = new int[] { 1, 2, 3, 4 }; var output = new int[] { 2, 1, 3, 4 }; @@ -28,7 +28,7 @@ namespace Reverse.Tests } [Fact] - public void ReversingAtIndexOneDoesNotChangeTheArray() + public void Reverse_WithIndexOne_DoesNothing() { var input = new int[] { 1, 2 }; var output = new int[] { 1, 2 }; From b1cfa83ac56edcc867613064ee4496ea924d4084 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 19:00:20 +0800 Subject: [PATCH 269/331] Add method for checking if a given array is in ascending order. --- .../Reverse/Reverse.Tests/ReverserTests.cs | 18 ++++++++++++++++++ 73_Reverse/csharp/Reverse/Reverse/Reverser.cs | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs index c263dbe5..d00640da 100644 --- a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs @@ -48,5 +48,23 @@ namespace Reverse.Tests Assert.True(input.SequenceEqual(output)); } + [Theory] + [InlineData(new int[] { 1 })] + [InlineData(new int[] { 1, 2 })] + [InlineData(new int[] { 1, 1 })] + public void IsArrayInAscendingOrder_WhenArrayElementsAreInNumericAscendingOrder_ReturnsTrue(int[] input) + { + var result = Reverser.IsArrayInAscendingOrder(input); + + Assert.True(result); + } + + [Fact] + public void IsArrayInOrder_WhenArrayElementsAreNotInNumericAscendingOrder_ReturnsFalse() + { + var result = Reverser.IsArrayInAscendingOrder(new int[] { 2, 1 }); + + Assert.False(result); + } } } diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs index be3b194f..e37e3d2f 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs @@ -17,5 +17,18 @@ arrayToReverse[upperIndex] = temp; } } + + public static bool IsArrayInAscendingOrder(int[] array) + { + for (int i = 1; i < array.Length; i++) + { + if (array[i] < array[i - 1]) + { + return false; + } + } + + return true; + } } } From 1d4651bfef143b766b7599f3e58086919390b8a1 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 19:00:51 +0800 Subject: [PATCH 270/331] Add method for creating a random array of distinct values. --- .../Generators/PositiveIntegerGenerator.cs | 10 +++++++ .../Reverse.Tests/Reverse.Tests.csproj | 1 + .../Reverse/Reverse.Tests/ReverserTests.cs | 30 +++++++++++++++++++ 73_Reverse/csharp/Reverse/Reverse/Reverser.cs | 25 +++++++++++++++- 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 73_Reverse/csharp/Reverse/Reverse.Tests/Generators/PositiveIntegerGenerator.cs diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/Generators/PositiveIntegerGenerator.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/Generators/PositiveIntegerGenerator.cs new file mode 100644 index 00000000..66889bb5 --- /dev/null +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/Generators/PositiveIntegerGenerator.cs @@ -0,0 +1,10 @@ +using FsCheck; + +namespace Reverse.Tests.Generators +{ + public static class PositiveIntegerGenerator + { + public static Arbitrary Generate() => + Arb.Default.Int32().Filter(x => x > 0); + } +} diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/Reverse.Tests.csproj b/73_Reverse/csharp/Reverse/Reverse.Tests/Reverse.Tests.csproj index 97b7bcce..260de5e1 100644 --- a/73_Reverse/csharp/Reverse/Reverse.Tests/Reverse.Tests.csproj +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/Reverse.Tests.csproj @@ -7,6 +7,7 @@ + diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs index d00640da..a6beeeb3 100644 --- a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs @@ -1,3 +1,5 @@ +using FsCheck.Xunit; +using Reverse.Tests.Generators; using System.Linq; using Xunit; @@ -48,6 +50,34 @@ namespace Reverse.Tests Assert.True(input.SequenceEqual(output)); } + + [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })] + public void CreateRandomArray_ReturnsRandomArrayOfSpecifiedLength() + { + var result = Reverser.CreateRandomArray(5); + + Assert.Equal(5, result.Length); + } + + [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })] + public void CreateRandomArray_MaxElementValueIsEqualToSize(int size) + { + var result = Reverser.CreateRandomArray(size); + + Assert.Equal(size, result.Max()); + } + + [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })] + public void CreateRandomArray_ReturnsRandomArrayWithDistinctElements(int size) + { + var array = Reverser.CreateRandomArray(size); + + var arrayGroup = array.GroupBy(x => x); + var duplicateFound = arrayGroup.Any(x => x.Count() > 1); + + Assert.False(duplicateFound); + } + [Theory] [InlineData(new int[] { 1 })] [InlineData(new int[] { 1, 2 })] diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs index e37e3d2f..62db79f1 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs @@ -1,4 +1,6 @@ -namespace Reverse +using System; + +namespace Reverse { public class Reverser { @@ -18,6 +20,27 @@ } } + public static int[] CreateRandomArray(int size) + { + var array = new int[size]; + for (int i = 1; i <= size; i++) + { + array[i - 1] = i; + } + + var rnd = new Random(); + + for (int i = size; i > 1;) + { + int k = rnd.Next(i); + --i; + int temp = array[i]; + array[i] = array[k]; + array[k] = temp; + } + return array; + } + public static bool IsArrayInAscendingOrder(int[] array) { for (int i = 1; i < array.Length; i++) From 08282e1a7dd45ed8ccfc8c234c4b10aade41d7db Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 19:29:09 +0800 Subject: [PATCH 271/331] Configure console app --- 73_Reverse/csharp/Reverse/Reverse/Program.cs | 95 +++++++++++++++++++- 1 file changed, 94 insertions(+), 1 deletion(-) diff --git a/73_Reverse/csharp/Reverse/Reverse/Program.cs b/73_Reverse/csharp/Reverse/Reverse/Program.cs index 72ae99ef..d1de060c 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Program.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Text; namespace Reverse { @@ -6,7 +7,99 @@ namespace Reverse { static void Main(string[] args) { - Console.WriteLine("Hello World!"); + PrintTitle(); + Console.Write("DO YOU WANT THE RULES? "); + var needRulesInput = Console.ReadLine(); + + if (string.Equals(needRulesInput, "YES", StringComparison.OrdinalIgnoreCase)) + { + DisplayRules(); + } + + var tryAgain = string.Empty; + while (!string.Equals(tryAgain, "NO", StringComparison.OrdinalIgnoreCase)) + { + var array = Reverser.CreateRandomArray(9); + Console.WriteLine(PrintArrayContents(array)); + var arrayIsNotInAscendingOrder = true; + var numberOfMoves = 0; + while (arrayIsNotInAscendingOrder) + { + int index = ReadNextInput(); + + if (index == 0) + { + break; + } + + Reverser.Reverse(array, index); + Console.WriteLine(PrintArrayContents(array)); + + if (Reverser.IsArrayInAscendingOrder(array)) + { + arrayIsNotInAscendingOrder = false; + Console.WriteLine($"YOU WON IT IN {numberOfMoves} MOVES!!!"); + } + numberOfMoves++; + } + + Console.Write("TRY AGAIN (YES OR NO)"); + tryAgain = Console.ReadLine(); + } + + Console.WriteLine("OK HOPE YOU HAD FUN"); + } + + private static int ReadNextInput() + { + Console.Write("HOW MANY SHALL I REVERSE? "); + var input = ReadIntegerInput(); + while (input > 9 || input < 0) + { + if (input > 9) + { + Console.WriteLine("OOPS! TOO MANY! I CAN REVERSE AT MOST THIS MANY"); + } + + if (input < 0) + { + Console.WriteLine("OOPS! TOO FEW! I CAN REVERSE BETWEEN 1 AND THIS MANY"); + } + Console.Write("HOW MANY SHALL I REVERSE? "); + input = ReadIntegerInput(); + } + + return input; + } + + private static int ReadIntegerInput() + { + var input = Console.ReadLine(); + int.TryParse(input, out var index); + return index; + } + + private static string PrintArrayContents(int[] arr) + { + var sb = new StringBuilder(); + + foreach (int i in arr) + { + sb.Append(" " + i + " "); + } + + return sb.ToString(); + } + + private static void PrintTitle() + { + Console.WriteLine("REVERSE"); + Console.WriteLine("CREATIVE COMPUTING MORRISTON, NEW JERSEY"); + } + + private static void DisplayRules() + { + Console.WriteLine("RULES"); } } } From a819a535bb0b4d35c947d0845eca474ea67b0e42 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 20:00:59 +0800 Subject: [PATCH 272/331] Define instance methods for reverser. --- .../Reverse/Reverse.Tests/ReverserTests.cs | 89 +++++++++++-------- .../Reverse/Reverse.Tests/TestReverser.cs | 17 ++++ 73_Reverse/csharp/Reverse/Reverse/Reverser.cs | 17 ++++ 3 files changed, 86 insertions(+), 37 deletions(-) create mode 100644 73_Reverse/csharp/Reverse/Reverse.Tests/TestReverser.cs diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs index a6beeeb3..9df7d3d5 100644 --- a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs @@ -7,15 +7,45 @@ namespace Reverse.Tests { public class ReverserTests { + [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })] + public void Constructor_CreatesRandomArrayOfSpecifiedLength(int size) + { + var sut = new TestReverser(size); + + Assert.Equal(size, sut.GetArray().Length); + } + + [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })] + public void ConstructorArray_MaxElementValueIsEqualToSize(int size) + { + var sut = new TestReverser(size); + + Assert.Equal(size, sut.GetArray().Max()); + } + + [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })] + public void ConstructorArray_ReturnsRandomArrayWithDistinctElements(int size) + { + var sut = new TestReverser(size); + var array = sut.GetArray(); + var arrayGroup = array.GroupBy(x => x); + var duplicateFound = arrayGroup.Any(x => x.Count() > 1); + + Assert.False(duplicateFound); + } + [Theory] [InlineData(new int[] { 1 }, new int[] { 1 })] [InlineData(new int[] { 1, 2 }, new int[] { 2, 1 })] [InlineData(new int[] { 1, 2, 3 }, new int[] { 3, 2, 1 })] public void Reverse_WillReverseEntireArray(int[] input, int[] output) { - Reverser.Reverse(input, input.Length); + var sut = new TestReverser(1); + sut.SetArray(input); - Assert.True(input.SequenceEqual(output)); + sut.Reverse(input.Length); + + Assert.True(sut.GetArray().SequenceEqual(output)); } [Fact] @@ -23,10 +53,12 @@ namespace Reverse.Tests { var input = new int[] { 1, 2, 3, 4 }; var output = new int[] { 2, 1, 3, 4 }; + var sut = new TestReverser(1); + sut.SetArray(input); - Reverser.Reverse(input, 2); + sut.Reverse(2); - Assert.True(input.SequenceEqual(output)); + Assert.True(sut.GetArray().SequenceEqual(output)); } [Fact] @@ -34,10 +66,12 @@ namespace Reverse.Tests { var input = new int[] { 1, 2 }; var output = new int[] { 1, 2 }; + var sut = new TestReverser(1); + sut.SetArray(input); - Reverser.Reverse(input, 1); + sut.Reverse(1); - Assert.True(input.SequenceEqual(output)); + Assert.True(sut.GetArray().SequenceEqual(output)); } [Fact] @@ -45,37 +79,12 @@ namespace Reverse.Tests { var input = new int[] { 1, 2 }; var output = new int[] { 1, 2 }; + var sut = new TestReverser(1); + sut.SetArray(input); - Reverser.Reverse(input, input.Length + 1); + sut.Reverse(sut.GetArray().Length + 1); - Assert.True(input.SequenceEqual(output)); - } - - [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })] - public void CreateRandomArray_ReturnsRandomArrayOfSpecifiedLength() - { - var result = Reverser.CreateRandomArray(5); - - Assert.Equal(5, result.Length); - } - - [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })] - public void CreateRandomArray_MaxElementValueIsEqualToSize(int size) - { - var result = Reverser.CreateRandomArray(size); - - Assert.Equal(size, result.Max()); - } - - [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })] - public void CreateRandomArray_ReturnsRandomArrayWithDistinctElements(int size) - { - var array = Reverser.CreateRandomArray(size); - - var arrayGroup = array.GroupBy(x => x); - var duplicateFound = arrayGroup.Any(x => x.Count() > 1); - - Assert.False(duplicateFound); + Assert.True(sut.GetArray().SequenceEqual(output)); } [Theory] @@ -84,7 +93,10 @@ namespace Reverse.Tests [InlineData(new int[] { 1, 1 })] public void IsArrayInAscendingOrder_WhenArrayElementsAreInNumericAscendingOrder_ReturnsTrue(int[] input) { - var result = Reverser.IsArrayInAscendingOrder(input); + var sut = new TestReverser(1); + sut.SetArray(input); + + var result = sut.IsArrayInAscendingOrder(); Assert.True(result); } @@ -92,7 +104,10 @@ namespace Reverse.Tests [Fact] public void IsArrayInOrder_WhenArrayElementsAreNotInNumericAscendingOrder_ReturnsFalse() { - var result = Reverser.IsArrayInAscendingOrder(new int[] { 2, 1 }); + var sut = new TestReverser(1); + sut.SetArray(new int[] { 2, 1 }); + + var result = sut.IsArrayInAscendingOrder(); Assert.False(result); } diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/TestReverser.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/TestReverser.cs new file mode 100644 index 00000000..a53004e1 --- /dev/null +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/TestReverser.cs @@ -0,0 +1,17 @@ +namespace Reverse.Tests +{ + internal class TestReverser : Reverser + { + public TestReverser(int arraySize) : base(arraySize) { } + + public int[] GetArray() + { + return _array; + } + + public void SetArray(int[] array) + { + _array = array; + } + } +} diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs index 62db79f1..426713c4 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs @@ -4,6 +4,23 @@ namespace Reverse { public class Reverser { + protected int[] _array; + + public Reverser(int arraySize) + { + _array = CreateRandomArray(arraySize); + } + + public void Reverse(int index) + { + Reverse(_array, index); + } + + public bool IsArrayInAscendingOrder() + { + return IsArrayInAscendingOrder(_array); + } + public static void Reverse(int[] arrayToReverse, int indexToReverseTo) { if (indexToReverseTo > arrayToReverse.Length) From eb27f8612ea3c89f40a1e8f61430798e8800656e Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 20:05:17 +0800 Subject: [PATCH 273/331] Add GetArrayString method. --- .../csharp/Reverse/Reverse.Tests/ReverserTests.cs | 11 +++++++++++ 73_Reverse/csharp/Reverse/Reverse/Reverser.cs | 13 +++++++++++++ 2 files changed, 24 insertions(+) diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs index 9df7d3d5..bd00436f 100644 --- a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs @@ -111,5 +111,16 @@ namespace Reverse.Tests Assert.False(result); } + + [Fact] + public void GetArrayString_ReturnsSpaceSeparatedElementsOfArrayInStringFormat() + { + var sut = new TestReverser(1); + sut.SetArray(new int[] { 1, 2 }); + + var result = sut.GetArrayString(); + + Assert.Equal(" 1 2 ", result); + } } } diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs index 426713c4..f2d720b4 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs @@ -1,4 +1,5 @@ using System; +using System.Text; namespace Reverse { @@ -70,5 +71,17 @@ namespace Reverse return true; } + + public string GetArrayString() + { + var sb = new StringBuilder(); + + foreach (int i in _array) + { + sb.Append(" " + i + " "); + } + + return sb.ToString(); + } } } From 67d1c84f2e76693e54782eb3608f027fca9eee3b Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 20:13:03 +0800 Subject: [PATCH 274/331] Update program to reference instance of reverser. --- 73_Reverse/csharp/Reverse/Reverse/Program.cs | 30 +++++++------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/73_Reverse/csharp/Reverse/Reverse/Program.cs b/73_Reverse/csharp/Reverse/Reverse/Program.cs index d1de060c..7beee62b 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Program.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Program.cs @@ -1,10 +1,10 @@ using System; -using System.Text; namespace Reverse { class Program { + private static int arrayLength = 9; static void Main(string[] args) { PrintTitle(); @@ -19,8 +19,10 @@ namespace Reverse var tryAgain = string.Empty; while (!string.Equals(tryAgain, "NO", StringComparison.OrdinalIgnoreCase)) { - var array = Reverser.CreateRandomArray(9); - Console.WriteLine(PrintArrayContents(array)); + var reverser = new Reverser(arrayLength); + + Console.WriteLine(reverser.GetArrayString()); + var arrayIsNotInAscendingOrder = true; var numberOfMoves = 0; while (arrayIsNotInAscendingOrder) @@ -32,10 +34,10 @@ namespace Reverse break; } - Reverser.Reverse(array, index); - Console.WriteLine(PrintArrayContents(array)); + reverser.Reverse(index); + Console.WriteLine(reverser.GetArrayString()); - if (Reverser.IsArrayInAscendingOrder(array)) + if (reverser.IsArrayInAscendingOrder()) { arrayIsNotInAscendingOrder = false; Console.WriteLine($"YOU WON IT IN {numberOfMoves} MOVES!!!"); @@ -58,12 +60,12 @@ namespace Reverse { if (input > 9) { - Console.WriteLine("OOPS! TOO MANY! I CAN REVERSE AT MOST THIS MANY"); + Console.WriteLine($"OOPS! TOO MANY! I CAN REVERSE AT MOST {arrayLength}"); } if (input < 0) { - Console.WriteLine("OOPS! TOO FEW! I CAN REVERSE BETWEEN 1 AND THIS MANY"); + Console.WriteLine($"OOPS! TOO FEW! I CAN REVERSE BETWEEN 1 AND {arrayLength}"); } Console.Write("HOW MANY SHALL I REVERSE? "); input = ReadIntegerInput(); @@ -79,18 +81,6 @@ namespace Reverse return index; } - private static string PrintArrayContents(int[] arr) - { - var sb = new StringBuilder(); - - foreach (int i in arr) - { - sb.Append(" " + i + " "); - } - - return sb.ToString(); - } - private static void PrintTitle() { Console.WriteLine("REVERSE"); From 0a7e386c366038a43620ad02d5a2f82eb75ca301 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 20:13:57 +0800 Subject: [PATCH 275/331] Remove static method. --- 73_Reverse/csharp/Reverse/Reverse/Reverser.cs | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs index f2d720b4..cd94bf4f 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs @@ -19,7 +19,15 @@ namespace Reverse public bool IsArrayInAscendingOrder() { - return IsArrayInAscendingOrder(_array); + for (int i = 1; i < _array.Length; i++) + { + if (_array[i] < _array[i - 1]) + { + return false; + } + } + + return true; } public static void Reverse(int[] arrayToReverse, int indexToReverseTo) @@ -59,19 +67,6 @@ namespace Reverse return array; } - public static bool IsArrayInAscendingOrder(int[] array) - { - for (int i = 1; i < array.Length; i++) - { - if (array[i] < array[i - 1]) - { - return false; - } - } - - return true; - } - public string GetArrayString() { var sb = new StringBuilder(); From 4dc1e57789cec996479ac90c4466e996e2702c9e Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 20:14:33 +0800 Subject: [PATCH 276/331] Make static method private. --- 73_Reverse/csharp/Reverse/Reverse/Reverser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs index cd94bf4f..99e60ea4 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs @@ -46,7 +46,7 @@ namespace Reverse } } - public static int[] CreateRandomArray(int size) + private int[] CreateRandomArray(int size) { var array = new int[size]; for (int i = 1; i <= size; i++) From 2758c3375cd204b0dce26f661fedf1ee011565ce Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 20:15:37 +0800 Subject: [PATCH 277/331] Remove static method. --- 73_Reverse/csharp/Reverse/Reverse/Reverser.cs | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs index 99e60ea4..2d2ea700 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs @@ -14,7 +14,18 @@ namespace Reverse public void Reverse(int index) { - Reverse(_array, index); + if (index > _array.Length) + { + return; + } + + for (int i = 0; i < index / 2; i++) + { + int temp = _array[i]; + int upperIndex = index - 1 - i; + _array[i] = _array[upperIndex]; + _array[upperIndex] = temp; + } } public bool IsArrayInAscendingOrder() @@ -30,22 +41,6 @@ namespace Reverse return true; } - public static void Reverse(int[] arrayToReverse, int indexToReverseTo) - { - if (indexToReverseTo > arrayToReverse.Length) - { - return; - } - - for (int i = 0; i < indexToReverseTo / 2; i++) - { - int temp = arrayToReverse[i]; - int upperIndex = indexToReverseTo - 1 - i; - arrayToReverse[i] = arrayToReverse[upperIndex]; - arrayToReverse[upperIndex] = temp; - } - } - private int[] CreateRandomArray(int size) { var array = new int[size]; From 3e9f1354b3de2b202c4fd8f0861c1fc0ae687f55 Mon Sep 17 00:00:00 2001 From: "Brax Antti (Oy Samlink Ab)" Date: Wed, 12 Jan 2022 14:26:18 +0200 Subject: [PATCH 278/331] Convert 20_Buzzword to Java The original version was a straight forward monolithic BASIC-to-Java conversion. Updated to use common Java coding conventions. - Split the single static main method into classes. The static part only contains the bootstrap code for the game. - Split the word list into three arrays so that there is no need to use error-prone calculations when choosing the random words. - Placed the Scanner in a try-with-resources block to ensure that the scanner gets closed when it is no longer needed. --- 20_Buzzword/java/src/Buzzword.java | 44 ++++------------- 20_Buzzword/java/src/BuzzwordSupplier.java | 39 +++++++++++++++ 20_Buzzword/java/src/UserInterface.java | 57 ++++++++++++++++++++++ 3 files changed, 106 insertions(+), 34 deletions(-) create mode 100644 20_Buzzword/java/src/BuzzwordSupplier.java create mode 100644 20_Buzzword/java/src/UserInterface.java diff --git a/20_Buzzword/java/src/Buzzword.java b/20_Buzzword/java/src/Buzzword.java index 82ed9100..248b4a77 100755 --- a/20_Buzzword/java/src/Buzzword.java +++ b/20_Buzzword/java/src/Buzzword.java @@ -1,41 +1,17 @@ import java.util.Scanner; -import static java.lang.System.out; -// This is very close to the original BASIC. Changes: -// 1) the array indexing is adjusted by 1 -// 2) the user can enter a lower case "y" -// 3) moved the word list to the top 8~) public class Buzzword { - private static final String[] A = { - "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" - }; - private static Scanner scanner = new Scanner( System.in ); - public static void main( final String [] args ) { - out.println( " BUZZWORD GENERATOR" ); - out.println( " CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" ); - out.println();out.println();out.println(); - out.println( "THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN" ); - out.println( "'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS" ); - out.println( "AND SPEECHES. WHENEVER A QUESTION MARK IS PRINTED," ); - out.println( "TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT." ); - out.println();out.println();out.println( "HERE'S THE FIRST PHRASE:" ); - do { - out.print( A[ (int)( 13 * Math.random() ) ] + " " ); - out.print( A[ (int)( 13 * Math.random() + 13 ) ] + " " ); - out.print( A[ (int)( 13 * Math.random() + 26 ) ] ); out.println(); - out.print( "?" ); + public static void main(final String[] args) { + try ( + // Scanner is a Closeable so it must be closed + // before the program ends. + final Scanner scanner = new Scanner(System.in); + ) { + final BuzzwordSupplier buzzwords = new BuzzwordSupplier(); + final UserInterface userInterface = new UserInterface( + scanner, buzzwords); + userInterface.run(); } - while ( "Y".equals( scanner.nextLine().toUpperCase() ) ); - out.println( "COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!" ); } } diff --git a/20_Buzzword/java/src/BuzzwordSupplier.java b/20_Buzzword/java/src/BuzzwordSupplier.java new file mode 100644 index 00000000..679969f9 --- /dev/null +++ b/20_Buzzword/java/src/BuzzwordSupplier.java @@ -0,0 +1,39 @@ +import java.util.Random; +import java.util.function.Supplier; + +/** + * A string supplier that provides an endless stream of random buzzwords. + */ +public class BuzzwordSupplier implements Supplier { + + private static final String[] SET_1 = { + "ABILITY","BASAL","BEHAVIORAL","CHILD-CENTERED", + "DIFFERENTIATED","DISCOVERY","FLEXIBLE","HETEROGENEOUS", + "HOMOGENEOUS","MANIPULATIVE","MODULAR","TAVISTOCK", + "INDIVIDUALIZED" }; + + private static final String[] SET_2 = { + "LEARNING","EVALUATIVE","OBJECTIVE", + "COGNITIVE","ENRICHMENT","SCHEDULING","HUMANISTIC", + "INTEGRATED","NON-GRADED","TRAINING","VERTICAL AGE", + "MOTIVATIONAL","CREATIVE" }; + + private static final String[] SET_3 = { + "GROUPING","MODIFICATION", "ACCOUNTABILITY","PROCESS", + "CORE CURRICULUM","ALGORITHM", "PERFORMANCE", + "REINFORCEMENT","OPEN CLASSROOM","RESOURCE", "STRUCTURE", + "FACILITY","ENVIRONMENT" }; + + private final Random random = new Random(); + + /** + * Create a buzzword by concatenating a random word from each of the + * three word sets. + */ + @Override + public String get() { + return SET_1[random.nextInt(SET_1.length)] + ' ' + + SET_2[random.nextInt(SET_2.length)] + ' ' + + SET_3[random.nextInt(SET_3.length)]; + } +} diff --git a/20_Buzzword/java/src/UserInterface.java b/20_Buzzword/java/src/UserInterface.java new file mode 100644 index 00000000..cbfbe3eb --- /dev/null +++ b/20_Buzzword/java/src/UserInterface.java @@ -0,0 +1,57 @@ +import static java.lang.System.out; + +import java.util.Scanner; +import java.util.function.Supplier; + +/** + * A command line user interface that outputs a buzzword every + * time the user requests a new one. + */ +public class UserInterface implements Runnable { + + /** + * Input from the user. + */ + private final Scanner input; + + /** + * The buzzword generator. + */ + private final Supplier buzzwords; + + /** + * Create a new user interface. + * + * @param input The input scanner with which the user gives commands. + * @param buzzwords The buzzword supplier. + */ + public UserInterface(final Scanner input, + final Supplier buzzwords) { + this.input = input; + this.buzzwords = buzzwords; + } + + @Override + public void run() { + out.println(" BUZZWORD GENERATOR"); + out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + out.println(); + out.println(); + out.println(); + out.println("THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN"); + out.println("'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS"); + out.println("AND SPEECHES. WHENEVER A QUESTION MARK IS PRINTED,"); + out.println("TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT."); + out.println(); + out.println(); + out.println("HERE'S THE FIRST PHRASE:"); + + do { + out.println(buzzwords.get()); + out.println(); + out.print("?"); + } while ("Y".equals(input.nextLine().toUpperCase())); + + out.println("COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!"); + } +} From 329fe3137c4b2a5400cc76a11ef31dd3829fe7a0 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Wed, 12 Jan 2022 20:26:18 +0800 Subject: [PATCH 279/331] Add rules. --- 73_Reverse/csharp/Reverse/Reverse/Program.cs | 35 +++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/73_Reverse/csharp/Reverse/Reverse/Program.cs b/73_Reverse/csharp/Reverse/Reverse/Program.cs index 7beee62b..2f95cc55 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Program.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Program.cs @@ -10,7 +10,7 @@ namespace Reverse PrintTitle(); Console.Write("DO YOU WANT THE RULES? "); var needRulesInput = Console.ReadLine(); - + Console.WriteLine(); if (string.Equals(needRulesInput, "YES", StringComparison.OrdinalIgnoreCase)) { DisplayRules(); @@ -21,8 +21,8 @@ namespace Reverse { var reverser = new Reverser(arrayLength); - Console.WriteLine(reverser.GetArrayString()); - + Console.WriteLine("HERE WE GO ... THE LIST IS:\n"); + PrintList(reverser.GetArrayString()); var arrayIsNotInAscendingOrder = true; var numberOfMoves = 0; while (arrayIsNotInAscendingOrder) @@ -35,7 +35,7 @@ namespace Reverse } reverser.Reverse(index); - Console.WriteLine(reverser.GetArrayString()); + PrintList(reverser.GetArrayString()); if (reverser.IsArrayInAscendingOrder()) { @@ -81,6 +81,13 @@ namespace Reverse return index; } + private static void PrintList(string list) + { + Console.WriteLine(); + Console.WriteLine(list); + Console.WriteLine(); + } + private static void PrintTitle() { Console.WriteLine("REVERSE"); @@ -89,7 +96,25 @@ namespace Reverse private static void DisplayRules() { - Console.WriteLine("RULES"); + Console.WriteLine("THIS IS THE GAME OF 'REVERSE'. TO WIN, ALL YOU HAVE"); + Console.WriteLine("TO DO IS ARRANGE A LIST OF NUMBERS (1 THOUGH 9 )"); + Console.WriteLine("IN NUMBERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU"); + Console.WriteLine("TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO"); + Console.WriteLine("REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:"); + Console.WriteLine(); + Console.WriteLine(" 2 3 4 5 1 6 7 8 9"); + Console.WriteLine(); + Console.WriteLine("AND YOU REVERSE 4, THE RESULT WILL BE:"); + Console.WriteLine(); + Console.WriteLine(" 5 4 3 2 1 6 7 8 9"); + Console.WriteLine(); + Console.WriteLine("NOW IF YOU REVERSE 5, YOU WIN!"); + Console.WriteLine(); + Console.WriteLine(" 1 2 3 4 5 6 7 8 9"); + Console.WriteLine(); + Console.WriteLine("NO DOUBT YOU WILL LIKE THIS GAME, BUT "); + Console.WriteLine("IF YOU WANT TO QUIT, REVERSE 0 (ZERO)"); + Console.WriteLine(); } } } From c8633c6051a665bcaaae6a69eec20b14b2adf5fe Mon Sep 17 00:00:00 2001 From: "Brax Antti (Oy Samlink Ab)" Date: Wed, 12 Jan 2022 14:33:55 +0200 Subject: [PATCH 280/331] Convert 20_Buzzword to Java Provide the output PrintStream dependency to UserInterface in the constructor instead of have it hard coded to System.out. --- 20_Buzzword/java/src/Buzzword.java | 2 +- 20_Buzzword/java/src/UserInterface.java | 45 ++++++++++++++----------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/20_Buzzword/java/src/Buzzword.java b/20_Buzzword/java/src/Buzzword.java index 248b4a77..85fecfd3 100755 --- a/20_Buzzword/java/src/Buzzword.java +++ b/20_Buzzword/java/src/Buzzword.java @@ -10,7 +10,7 @@ public class Buzzword { ) { final BuzzwordSupplier buzzwords = new BuzzwordSupplier(); final UserInterface userInterface = new UserInterface( - scanner, buzzwords); + scanner, System.out, buzzwords); userInterface.run(); } } diff --git a/20_Buzzword/java/src/UserInterface.java b/20_Buzzword/java/src/UserInterface.java index cbfbe3eb..103e88c8 100644 --- a/20_Buzzword/java/src/UserInterface.java +++ b/20_Buzzword/java/src/UserInterface.java @@ -1,5 +1,4 @@ -import static java.lang.System.out; - +import java.io.PrintStream; import java.util.Scanner; import java.util.function.Supplier; @@ -14,6 +13,11 @@ public class UserInterface implements Runnable { */ private final Scanner input; + /** + * Output to the user. + */ + private final PrintStream output; + /** * The buzzword generator. */ @@ -23,35 +27,38 @@ public class UserInterface implements Runnable { * Create a new user interface. * * @param input The input scanner with which the user gives commands. + * @param output The output to show messages to the user. * @param buzzwords The buzzword supplier. */ public UserInterface(final Scanner input, - final Supplier buzzwords) { + final PrintStream output, + final Supplier buzzwords) { this.input = input; + this.output = output; this.buzzwords = buzzwords; } @Override public void run() { - out.println(" BUZZWORD GENERATOR"); - out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); - out.println(); - out.println(); - out.println(); - out.println("THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN"); - out.println("'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS"); - out.println("AND SPEECHES. WHENEVER A QUESTION MARK IS PRINTED,"); - out.println("TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT."); - out.println(); - out.println(); - out.println("HERE'S THE FIRST PHRASE:"); + output.println(" BUZZWORD GENERATOR"); + output.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + output.println(); + output.println(); + output.println(); + output.println("THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN"); + output.println("'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS"); + output.println("AND SPEECHES. WHENEVER A QUESTION MARK IS PRINTED,"); + output.println("TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT."); + output.println(); + output.println(); + output.println("HERE'S THE FIRST PHRASE:"); do { - out.println(buzzwords.get()); - out.println(); - out.print("?"); + output.println(buzzwords.get()); + output.println(); + output.print("?"); } while ("Y".equals(input.nextLine().toUpperCase())); - out.println("COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!"); + output.println("COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!"); } } From 337e7976d13b1aea8ac8282c6bf440c2abbf202a Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 09:50:35 -0300 Subject: [PATCH 281/331] Performance optimization, reducing the amount of writes to the console necessary to output each iteration's matrix. --- 55_Life/csharp/Program.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 47ed7386..17e6fb18 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -132,12 +132,14 @@ void ProcessSimulation() var nextMinX = maxHeight - 1; var nextMinY = maxWidth - 1; var nextMaxX = 0; - var nextMaxY = 0; + var nextMaxY = 0; + + var matrixOutput = new StringBuilder(); // prints the empty lines before search area for (var x = 0; x < minX; x++) { - Console.WriteLine(); + matrixOutput.AppendLine(); } // refreshes the matrix and updates search area @@ -168,14 +170,15 @@ void ProcessSimulation() nextMaxY = Math.Max(y + 1, nextMaxY); } - Console.WriteLine(string.Join(separator: null, values: printedLine)); + matrixOutput.AppendLine(string.Join(separator: null, values: printedLine)); } // prints empty lines after search area for (var x = maxX + 1; x < maxHeight; x++) { - Console.WriteLine(); + matrixOutput.AppendLine(); } + Console.WriteLine(matrixOutput); Console.WriteLine(); void UpdateSearchArea() From f3d63355df68b53aaa31808b71cd690371235eaa Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 10:09:31 -0300 Subject: [PATCH 282/331] Adding instructions on how to run the example. --- 55_Life/csharp/Program.cs | 18 +----------------- 55_Life/csharp/README.md | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 17e6fb18..1b70ed3a 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -1,20 +1,4 @@ -/* - * LIFE - * An implementation of John Conway's popular cellular automaton - * Ported by Dyego Alekssander Maas - * - * An example pattern would be: - * " * " - * "***" - * "DONE" (indicates that the simulation can start) - * - * You can find patterns to play with here: http://pi.math.cornell.edu/~lipa/mec/lesson6.html - * - * Optionally, you can run this program with the "--wait 1000" argument, the number being the time in milliseconds - * that the application will pause between each iteration. This is enables you to watch the simulation unfolding. - * By default, there is no pause between iterations. -*/ -using System.Text; +using System.Text; const int maxWidth = 70; const int maxHeight = 24; diff --git a/55_Life/csharp/README.md b/55_Life/csharp/README.md index 4daabb5c..3bf2d48a 100644 --- a/55_Life/csharp/README.md +++ b/55_Life/csharp/README.md @@ -1,3 +1,26 @@ +# Life + +An implementation of John Conway's popular cellular automaton, also know as **Conway's Game of Life**. The original source was downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html). + +Ported by Dyego Alekssander Maas. + +## How to run + +This program requires you to install [.NET 6 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0). After installed, you just need to run `dotnet run` from this directory in the terminal. + +## Know more about Conway's Game of Life + +You can find more about Conway's Game of Life on this page of the [Cornell Math Explorers' Club](http://pi.math.cornell.edu/~lipa/mec/lesson6.html), alongside many examples of patterns you can try. + +### Optional parameters + +Optionally, you can run this program with the `--wait 1000` argument, the number being the time in milliseconds +that the application will pause between each iteration. This is enables you to watch the simulation unfolding. By default, there is no pause between iterations. + +The complete command would be `dotnet run --wait 1000`. + +## Instructions to the port + 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/) From f62111606403a5914cedcdfa07b03a984ed11073 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 10:50:36 -0300 Subject: [PATCH 283/331] Adding instructions on how to enter patterns, and also some examples. --- 55_Life/csharp/README.md | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/55_Life/csharp/README.md b/55_Life/csharp/README.md index 3bf2d48a..5b4ffe62 100644 --- a/55_Life/csharp/README.md +++ b/55_Life/csharp/README.md @@ -19,6 +19,51 @@ that the application will pause between each iteration. This is enables you to w The complete command would be `dotnet run --wait 1000`. +## Entering patterns + +Once running the game, you are expected to enter a pattern. This pattern consists of multiple lines of text with either **spaces** or **some character**, usually an asterisk (`*`). + +Spaces represent empty cells. Asterisks represent alive cells. + +After entering the pattern, you need to enter the word "DONE". It is not case sensitive. An example of pattern would be: + +``` + * +*** +DONE +``` + +### Some patterns you could try + +``` + * +*** +``` + +``` +* +*** +``` + +``` +** +** +``` + +``` + * + * +* +``` + +This one is known as **glider**: + +``` +*** +* + * +``` + ## Instructions to the port Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) From d0ab16bac2fae9eee3f8b932fca56b442bb11f53 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 12 Jan 2022 13:07:07 -0500 Subject: [PATCH 284/331] Fixed formatting of tabs into spaces --- 48_High_IQ/python/High_IQ.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 1f32e300..cbb5960b 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -56,8 +56,8 @@ def play_game(): def main(): # if input("Do you want instrunctions?\n").lower().startswith("y"): - print("\t" * 33 + "H-I-Q") - print("\t" * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print(" " * 33 + "H-I-Q") + print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print_instructions() play_game() From 4485faa7e32ff91bb21b67715dc94d39e1afa9ed Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Wed, 12 Jan 2022 13:22:32 -0500 Subject: [PATCH 285/331] Update High_IQ.py --- 48_High_IQ/python/High_IQ.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index cbb5960b..b2e71b6c 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -47,12 +47,30 @@ def print_board(board): print(" " * 2 + board[67] + board[68] + board[69]) def play_game(): - print("Lets play a game") board = new_board() while not is_game_finished(board): print_board(board) + while not move(board): + print("ILLEGAL MOVE! TRY AGAIN") +def move(board): + try: + start = int(input("MOVE WHICH PIECE? ")) + if not (board[start] == "'!'): + return False + + end = int(input("TO WHERE? ")) + if not (board[end] == 'O'): + return False + difference = abs(end - start) + if difference != 2 and difference != 18: + return False + center = (end + start) / 2 + + except: + return False + return True def main(): # if input("Do you want instrunctions?\n").lower().startswith("y"): From b0da05a04e1b83ae1857cb41d81470c6253ccc08 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Wed, 12 Jan 2022 10:27:50 -0800 Subject: [PATCH 286/331] Update README.md add Emulation and Bugfixes section --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 266aaac8..6ed7cb51 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ Each project has subfolders corresponding to the languages we'd like to see the - Delphi / Object Pascal - Perl + + ### Project goals Feel free to begin converting these classic games into the above list of modern, memory safe languages. But first, a few guidelines: @@ -39,6 +41,16 @@ Feel free to begin converting these classic games into the above list of modern, - **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 + +We want the general behavior of the original programs to be preserved, _however_, we also want to update them, specifically: + +- allow both UPPERCASE and lowercase input and display +- incorporate any bugfixes to the original programs; see the `readme.md` in the game folder +- improved error handling for bad or erroneous input + +Please note that on the back of the Basic Computer Games book it says **Microsoft 8K Basic, Rev 4.0 was the version David Ahl used to test**, so that is the level of compatibility we are looking for.  QBasic on the DOS emulation is a later version of Basic but one that retains downwards compatibility so far in our testing. We're working on a recommended emulation to verify behavior. + ### Have fun! Thank you for taking part in this project to update a classic programming book -- one of the most influential programming books in computing history -- for 2022 and beyond! From 159aa46e2126799991e4229c78076ef3fcc994b3 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 16:04:14 -0300 Subject: [PATCH 287/331] Fixed pattern reading when inputing DONE, which would lead to incorrect sizing of the pattern transcribed to the matrix and caused drifting in relation to the original. --- 55_Life/csharp/Program.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 1b70ed3a..ffdf1799 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -23,7 +23,6 @@ IEnumerable ReadPattern(int limitHeight) var input = Console.ReadLine(); if (input.ToUpper() == "DONE") { - yield return string.Empty; break; } From 73665d8b091f4dbf8bee2101d572c99c75909cb7 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 16:04:57 -0300 Subject: [PATCH 288/331] Fixes cropping that would happen when using an dot (.) in the beggining of the text. --- 55_Life/csharp/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index ffdf1799..f5bb7f38 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -30,7 +30,7 @@ IEnumerable ReadPattern(int limitHeight) // game allowed you to input an '.' before the spaces to circumvent this limitation. This behavior was // kept for compatibility. if (input.StartsWith('.')) - yield return input.Substring(1, input.Length - 2); + yield return input.Substring(1, input.Length - 1); yield return input; } From f25adca07a0f50619835097ae460ef97af46f078 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 16:07:35 -0300 Subject: [PATCH 289/331] Fix the initialization of the matrix, which was displacing the pattern in the initial position onto the matrix, which caused the evolution of the simulation to variate in relation with the original game in Basic when once the cells reached the boarder (invalid cases). --- 55_Life/csharp/Program.cs | 48 +++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index f5bb7f38..3aeb088e 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -4,11 +4,12 @@ const int maxWidth = 70; const int maxHeight = 24; Console.WriteLine("ENTER YOUR PATTERN:"); -var pattern = ReadPattern(limitHeight: maxHeight).ToArray(); +var pattern = new Pattern(ReadPattern(limitHeight: maxHeight).ToArray()); -var (minX, minY) = FindTopLeftCorner(pattern); -var maxX = maxHeight; -var maxY = maxWidth; +var minX = 10 - pattern.Height / 2; // was 11 +var minY = 32 - pattern.Width / 2; // was 33 +var maxX = maxHeight - 1; +var maxY = maxWidth - 1; var matrix = new Matrix(height: maxHeight, width: maxWidth); var simulation = InitializeSimulation(pattern, matrix); @@ -36,17 +37,6 @@ IEnumerable ReadPattern(int limitHeight) } } -(int minX, int minY) FindTopLeftCorner(IEnumerable patternLines) -{ - var longestInput = patternLines - .Select((value, index) => (index, value)) - .OrderByDescending(input => input.value.Length) - .First(); - var centerX = (11 - longestInput.index / 2) - 1; - var centerY = (33 - longestInput.value.Length / 2) - 1; - return (centerX, centerY); -} - void PrintHeader() { void PrintCentered(string text) @@ -65,15 +55,16 @@ void PrintHeader() Console.WriteLine(); } -Simulation InitializeSimulation(IReadOnlyList inputPattern, Matrix matrixToInitialize) { +Simulation InitializeSimulation(Pattern pattern, Matrix matrixToInitialize) { var newSimulation = new Simulation(); - // translates the pattern to the middle of the simulation and counts initial population - for (var x = 0; x < inputPattern.Count; x++) + // transcribes the pattern to the middle of the simulation and counts initial population + for (var x = 0; x < pattern.Height; x++) { - for (var y = 0; y < inputPattern[x].Length; y++) + for (var y = 0; y < pattern.Width; y++) { - if (inputPattern[x][y] == ' ') continue; + if (pattern.Content[x][y] == ' ') + continue; matrixToInitialize[minX + x, minY + y] = CellState.Stable; newSimulation.IncreasePopulation(); @@ -247,6 +238,23 @@ void ProcessSimulation() } } +public class Pattern +{ + public string[] Content { get; } + public int Height { get; } + public int Width { get; } + + public Pattern(IReadOnlyCollection patternLines) + { + Height = patternLines.Count; + Width = patternLines.Max(x => x.Length); + + Content = patternLines + .Select(x => x.PadRight(Width, ' ')) + .ToArray(); + } +} + /// /// Indicates the state of a given cell in the simulation. /// From 6a3f0b3259112a3fd8589c66ad249805cbae68f9 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 16:09:10 -0300 Subject: [PATCH 290/331] Fix various indexing problems that caused drifting. Now, the application behaves exactly like the original, even in "invalid" generations. --- 55_Life/csharp/Program.cs | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 3aeb088e..a6fb0d98 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -117,10 +117,10 @@ void ProcessSimulation() } // refreshes the matrix and updates search area - for (var x = minX; x < maxX; x++) + for (var x = minX; x <= maxX; x++) { var printedLine = Enumerable.Repeat(' ', maxWidth).ToList(); - for (var y = minY; y < maxY; y++) + for (var y = minY; y <= maxY; y++) { if (matrix[x, y] == CellState.Dying) { @@ -139,9 +139,9 @@ void ProcessSimulation() printedLine[y] = '*'; nextMinX = Math.Min(x, nextMinX); - nextMaxX = Math.Max(x + 1, nextMaxX); + nextMaxX = Math.Max(x, nextMaxX); nextMinY = Math.Min(y, nextMinY); - nextMaxY = Math.Max(y + 1, nextMaxY); + nextMaxY = Math.Max(y, nextMaxY); } matrixOutput.AppendLine(string.Join(separator: null, values: printedLine)); @@ -162,42 +162,45 @@ void ProcessSimulation() minY = nextMinY; maxY = nextMaxY; - if (minX < 3) + if (minX < 2) // was 3 { - minX = 3; + minX = 2; // was 3 isInvalid = true; } - if (maxX > 22) + const int limitX = 22; //maxHeight - 2; // was 22 + const int limitY = 68; //maxWidth - 2; // was 68 + + if (maxX > limitX) // was 22 { - maxX = 22; + maxX = limitX; // was 22 isInvalid = true; } - if (minY < 3) + if (minY < 2) // was 3 { - minY = 3; + minY = 2; // was 3 isInvalid = true; } - if (maxY > 68) + if (maxY > limitY) // was 68 { - maxY = 68; + maxY = limitY; // was 68 isInvalid = true; } } UpdateSearchArea(); - for (var x = minX - 1; x < maxX + 2; x++) + for (var x = minX - 1; x <= maxX + 1; x++) { - for (var y = minY - 1; y < maxY + 2; y++) + for (var y = minY - 1; y <= maxY + 1; y++) { int CountNeighbors() { var neighbors = 0; - for (var i = x - 1; i < x + 2; i++) + for (var i = x - 1; i <= x + 1; i++) { - for (var j = y - 1; j < y + 2; j++) + for (var j = y - 1; j <= y + 1; j++) { if (matrix[i, j] == CellState.Stable || matrix[i, j] == CellState.Dying) neighbors++; @@ -208,7 +211,7 @@ void ProcessSimulation() } var neighbors = CountNeighbors(); - if (matrix[x, y] == 0) + if (matrix[x, y] == CellState.Empty) { if (neighbors == 3) { From eaa20ba52bf76ea8bac49f901ba341b0d9126dd3 Mon Sep 17 00:00:00 2001 From: Alex Gomez Date: Wed, 12 Jan 2022 16:47:45 -0600 Subject: [PATCH 291/331] Carriage return removed --- 62_Mugwump/perl/mugwump.pl | 192 ++++++++++++++++++------------------- 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/62_Mugwump/perl/mugwump.pl b/62_Mugwump/perl/mugwump.pl index d02a9036..33835b77 100755 --- a/62_Mugwump/perl/mugwump.pl +++ b/62_Mugwump/perl/mugwump.pl @@ -1,96 +1,96 @@ -#!/usr/bin/perl - -use strict; -use warnings; - -# global variables defined here -my(@MUGWUMP) = (); - -# subroutines defined here - -# init_mugwump: pick the random places for the Mugwumps -sub init_mugwump() { - @MUGWUMP = (); - for (1 .. 4) { - push @MUGWUMP, [ int(rand 10), int(rand 10) ]; - } -} - - -# main code starts here - -# print introductory text -print <); - my($M,$N) = split(/,/,$in); - $M = int($M); - $N = int($N); - - for my $i (0 .. $#MUGWUMP) { - # -1 indicates a Mugwump that was already found - next if $MUGWUMP[$i]->[0] == -1; - - if ($MUGWUMP[$i]->[0] == $M && $MUGWUMP[$i]->[1] == $N) { - $MUGWUMP[$i]->[0] = -1; - printf("You have found Mugwump %d\n", $i+1); - } else { - my $d = sqrt(($MUGWUMP[$i]->[0] - $M) ** 2 + ($MUGWUMP[$i]->[1] - $N) ** 2); - printf("You are %.1f units away from Mugwump %d\n", $d, $i+1); - } - } - - # If a Mugwump still has not been found, - # go to the next turn - for my $j (0 .. $#MUGWUMP) { - if ($MUGWUMP[$j]->[0] != -1) { - next TURN; - } - } - # You win! - printf("You got all of them in %d %s!\n\n", $turn, ($turn == 1 ? 'turn' : 'turns')); - # Pass execution down to the continue block - next PLAY; - - } # end of TURN loop - - print "\nSorry, that's 10 tries. Here's where they're hiding:\n"; - for my $i (0 .. $#MUGWUMP) { - printf("Mugwump %d is at (%d, %d)\n", $i+1, $MUGWUMP[$i]->[0], $MUGWUMP[$i]->[1]) - if $MUGWUMP[$i]->[0] != -1; - } -} -continue { - print "\nThat was fun! Let's play again.......\n"; - print "Four more Mugwumps are now in hiding.\n\n"; -} - +#!/usr/bin/perl + +use strict; +use warnings; + +# global variables defined here +my(@MUGWUMP) = (); + +# subroutines defined here + +# init_mugwump: pick the random places for the Mugwumps +sub init_mugwump() { + @MUGWUMP = (); + for (1 .. 4) { + push @MUGWUMP, [ int(rand 10), int(rand 10) ]; + } +} + + +# main code starts here + +# print introductory text +print <); + my($M,$N) = split(/,/,$in); + $M = int($M); + $N = int($N); + + for my $i (0 .. $#MUGWUMP) { + # -1 indicates a Mugwump that was already found + next if $MUGWUMP[$i]->[0] == -1; + + if ($MUGWUMP[$i]->[0] == $M && $MUGWUMP[$i]->[1] == $N) { + $MUGWUMP[$i]->[0] = -1; + printf("You have found Mugwump %d\n", $i+1); + } else { + my $d = sqrt(($MUGWUMP[$i]->[0] - $M) ** 2 + ($MUGWUMP[$i]->[1] - $N) ** 2); + printf("You are %.1f units away from Mugwump %d\n", $d, $i+1); + } + } + + # If a Mugwump still has not been found, + # go to the next turn + for my $j (0 .. $#MUGWUMP) { + if ($MUGWUMP[$j]->[0] != -1) { + next TURN; + } + } + # You win! + printf("You got all of them in %d %s!\n\n", $turn, ($turn == 1 ? 'turn' : 'turns')); + # Pass execution down to the continue block + next PLAY; + + } # end of TURN loop + + print "\nSorry, that's 10 tries. Here's where they're hiding:\n"; + for my $i (0 .. $#MUGWUMP) { + printf("Mugwump %d is at (%d, %d)\n", $i+1, $MUGWUMP[$i]->[0], $MUGWUMP[$i]->[1]) + if $MUGWUMP[$i]->[0] != -1; + } +} +continue { + print "\nThat was fun! Let's play again.......\n"; + print "Four more Mugwumps are now in hiding.\n\n"; +} + From fd8c02371a272d3d64777c6c1e5de8fdd6af462d Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 19:49:30 -0300 Subject: [PATCH 292/331] Adjusting indexes. --- 55_Life/csharp/Program.cs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index a6fb0d98..d2cf8c1c 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -162,30 +162,30 @@ void ProcessSimulation() minY = nextMinY; maxY = nextMaxY; - if (minX < 2) // was 3 - { - minX = 2; // was 3 - isInvalid = true; - } - - const int limitX = 22; //maxHeight - 2; // was 22 - const int limitY = 68; //maxWidth - 2; // was 68 + const int limitX = 21; + const int limitY = 67; - if (maxX > limitX) // was 22 + if (minX < 2) { - maxX = limitX; // was 22 + minX = 2; + isInvalid = true; + } + + if (maxX > limitX) + { + maxX = limitX; isInvalid = true; } - if (minY < 2) // was 3 + if (minY < 2) { - minY = 2; // was 3 + minY = 2; isInvalid = true; } - if (maxY > limitY) // was 68 + if (maxY > limitY) { - maxY = limitY; // was 68 + maxY = limitY; isInvalid = true; } } From 5731a4df0823a6cc7d5337325d49f0b4ebf03ed0 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 19:50:32 -0300 Subject: [PATCH 293/331] Temporary compensation for error calculating (possibly related to rounding) that caused misplacement of the initial pattern by 2 in the y axis. --- 55_Life/csharp/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index d2cf8c1c..bb0463b4 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -66,7 +66,7 @@ Simulation InitializeSimulation(Pattern pattern, Matrix matrixToInitialize) { if (pattern.Content[x][y] == ' ') continue; - matrixToInitialize[minX + x, minY + y] = CellState.Stable; + matrixToInitialize[minX + x, minY + y + 2] = CellState.Stable; newSimulation.IncreasePopulation(); } } From 7a7d92ce2448517329eed7c62891415e9ffa4a35 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 20:07:52 -0300 Subject: [PATCH 294/331] Compensated for the displacement that was occurring in the y axis by adjusting the "middle" to a valid value when working with zero based indexes. --- 55_Life/csharp/Program.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index bb0463b4..32514c75 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -6,8 +6,8 @@ const int maxHeight = 24; Console.WriteLine("ENTER YOUR PATTERN:"); var pattern = new Pattern(ReadPattern(limitHeight: maxHeight).ToArray()); -var minX = 10 - pattern.Height / 2; // was 11 -var minY = 32 - pattern.Width / 2; // was 33 +var minX = 10 - pattern.Height / 2; +var minY = 34 - pattern.Width / 2; var maxX = maxHeight - 1; var maxY = maxWidth - 1; @@ -66,7 +66,7 @@ Simulation InitializeSimulation(Pattern pattern, Matrix matrixToInitialize) { if (pattern.Content[x][y] == ' ') continue; - matrixToInitialize[minX + x, minY + y + 2] = CellState.Stable; + matrixToInitialize[minX + x, minY + y] = CellState.Stable; newSimulation.IncreasePopulation(); } } From f70b6d42ddac55660817f0357849bebcd016623d Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 20:08:53 -0300 Subject: [PATCH 295/331] Refactoring. --- 55_Life/csharp/Program.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 32514c75..8da15360 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -251,8 +251,12 @@ public class Pattern { Height = patternLines.Count; Width = patternLines.Max(x => x.Length); - - Content = patternLines + Content = NormalizeWidth(patternLines); + } + + private string[] NormalizeWidth(IReadOnlyCollection patternLines) + { + return patternLines .Select(x => x.PadRight(Width, ' ')) .ToArray(); } From d52981de7313a81ecca15e8d7176623bba266fdb Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 20:21:30 -0300 Subject: [PATCH 296/331] Refactoring. --- 55_Life/csharp/Program.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 8da15360..879b16be 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -76,15 +76,14 @@ Simulation InitializeSimulation(Pattern pattern, Matrix matrixToInitialize) { TimeSpan GetPauseBetweenIterations() { - if (args.Length == 2) + if (args.Length != 2) return TimeSpan.Zero; + + var parameter = args[0].ToLower(); + if (parameter.Contains("wait")) { - var parameter = args[0].ToLower(); - if (parameter.Contains("wait")) - { - var value = args[1]; - if (int.TryParse(value, out var sleepMilliseconds)) - return TimeSpan.FromMilliseconds(sleepMilliseconds); - } + var value = args[1]; + if (int.TryParse(value, out var sleepMilliseconds)) + return TimeSpan.FromMilliseconds(sleepMilliseconds); } return TimeSpan.Zero; From b93cc409e204f5f96d496364416a4c49fec9e04a Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 20:22:26 -0300 Subject: [PATCH 297/331] Adjusted message of "invalid" generations, matching the original. --- 55_Life/csharp/Program.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index 879b16be..bcfc22f4 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -96,9 +96,8 @@ void ProcessSimulation() while (true) { - Console.WriteLine($"GENERATION: {simulation.Generation}\tPOPULATION: {simulation.Population}"); - if (isInvalid) - Console.WriteLine("INVALID!"); + var invalidText = isInvalid ? "INVALID!" : ""; + Console.WriteLine($"GENERATION: {simulation.Generation}\tPOPULATION: {simulation.Population} {invalidText}"); simulation.StartNewGeneration(); From 2ac28191511259a6a9f3056a8766eb6b95c1ab61 Mon Sep 17 00:00:00 2001 From: Dyego Maas Date: Wed, 12 Jan 2022 20:23:17 -0300 Subject: [PATCH 298/331] Removed extra line printed after each generation, to better match the original's visuals. --- 55_Life/csharp/Program.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/55_Life/csharp/Program.cs b/55_Life/csharp/Program.cs index bcfc22f4..eeb00465 100644 --- a/55_Life/csharp/Program.cs +++ b/55_Life/csharp/Program.cs @@ -150,8 +150,7 @@ void ProcessSimulation() { matrixOutput.AppendLine(); } - Console.WriteLine(matrixOutput); - Console.WriteLine(); + Console.Write(matrixOutput); void UpdateSearchArea() { From 0c91432e5a096b421eebb39efc44b0d84b7b41c8 Mon Sep 17 00:00:00 2001 From: Jackson Brouwer Date: Wed, 12 Jan 2022 22:47:27 -0600 Subject: [PATCH 299/331] Added Basketball Java Version --- 07_Basketball/java/Basketball.java | 469 +++++++++++++++++++++++++++++ 1 file changed, 469 insertions(+) create mode 100644 07_Basketball/java/Basketball.java diff --git a/07_Basketball/java/Basketball.java b/07_Basketball/java/Basketball.java new file mode 100644 index 00000000..3ff9e7ab --- /dev/null +++ b/07_Basketball/java/Basketball.java @@ -0,0 +1,469 @@ +import java.lang.Math; +import java.util.*; +import java.util.Scanner; + +/* The basketball class is a computer game that allows you to play as + Dartmouth College's captain and playmaker + The game uses set probabilites to simulate outcomes of each posession + You are able to choose your shot types as well as defensive formations */ + +public class Basketball { + int time = 0; + int[] score = {0, 0}; + double defense = -1; + List defense_choices = Arrays.asList(6.0, 6.5, 7.0, 7.5); + int shot = -1; + List shot_choices = Arrays.asList(0, 1, 2, 3, 4); + double opponent_chance = 0; + String opponent = null; + + public Basketball() { + + // Explains the keyboard inputs + System.out.println("\t\t\t Basketball"); + System.out.println("\t Creative Computing Morristown, New Jersey\n\n\n"); + System.out.println("This is Dartmouth College basketball. "); + System.out.println("Υou will be Dartmouth captain and playmaker."); + System.out.println("Call shots as follows:"); + System.out.println("1. Long (30ft.) Jump Shot; 2. Short (15 ft.) Jump Shot; " + + "3. Lay up; 4. Set Shot"); + System.out.println("Both teams will use the same defense. Call Defense as follows:"); + System.out.println("6. Press; 6.5 Man-to-Man; 7. Zone; 7.5 None."); + System.out.println("To change defense, just type 0 as your next shot."); + System.out.print("Your starting defense will be? "); + + Scanner scanner = new Scanner(System.in); // creates a scanner + + // takes input for a defense + if (scanner.hasNextDouble()) { + defense = scanner.nextDouble(); + } + else { + scanner.next(); + } + + // makes sure that input is legal + while (!defense_choices.contains(defense)) { + System.out.print("Your new defensive allignment is? "); + if (scanner.hasNextDouble()) { + defense = scanner.nextDouble(); + } + else { + scanner.next(); + continue; + } + } + + // takes input for opponent's name + System.out.print("\nChoose your opponent? "); + + opponent = scanner.next(); + start_of_period(); + } + + // adds points to the score + // team can take 0 or 1, for opponent or Dartmouth, respectively + private void add_points(int team, int points) { + score[team] += points; + print_score(); + } + + + private void ball_passed_back() { + System.out.print("Ball passed back to you. "); + dartmouth_ball(); + } + + // change defense, called when the user enters 0 for their shot + private void change_defense() { + defense = -1; + Scanner scanner = new Scanner(System.in); // creates a scanner + + while (!defense_choices.contains(defense)) { + System.out.println("Your new defensive allignment is? "); + if (scanner.hasNextDouble()) { + defense = (double)(scanner.nextDouble()); + } + else { + continue; + } + } + + dartmouth_ball(); + } + + // simulates two foul shots for a player and adds the points + private void foul_shots(int team) { + System.out.println("Shooter fouled. Two shots."); + + if (Math.random() > .49) { + if (Math.random() > .75) { + System.out.println("Both shots missed."); + } + else { + System.out.println("Shooter makes one shot and misses one."); + score[team] += 1; + } + } + else { + System.out.println("Shooter makes both shots."); + score[team] += 2; + } + + print_score(); + } + + // called when time = 50, starts a new period + private void halftime() { + System.out.println("\n ***** End of first half *****\n"); + print_score(); + start_of_period(); + } + + // prints the current score + private void print_score() { + System.out.println("Score: " + score[1] + " to " + score[0] + "\n"); + } + + // simulates a center jump for posession at the beginning of a period + private void start_of_period() { + System.out.println("Center jump"); + if (Math.random() > .6) { + System.out.println("Dartmouth controls the tap.\n"); + dartmouth_ball(); + } + else { + System.out.println(opponent + " controls the tap.\n"); + opponent_ball(); + } + } + + // called when t = 92 + private void two_minute_warning() { + System.out.println(" *** Two minutes left in the game ***"); + } + + // called when the user enters 1 or 2 for their shot + private void dartmouth_jump_shot() { + time ++; + if (time == 50) { + halftime(); + } + else if (time == 92) { + two_minute_warning(); + } + + System.out.println("Jump Shot."); + // simulates chances of different possible outcomes + if (Math.random() > .341 * defense / 8) { + if (Math.random() > .682 * defense / 8) { + if (Math.random() > .782 * defense / 8) { + if (Math.random() > .843 * defense / 8) { + System.out.println("Charging foul. Dartmouth loses ball.\n"); + opponent_ball(); + } + else { + // player is fouled + foul_shots(1); + opponent_ball(); + } + } + else { + if (Math.random() > .5) { + System.out.println("Shot is blocked. Ball controlled by " + + opponent + ".\n"); + opponent_ball(); + } + else { + System.out.println("Shot is blocked. Ball controlled by Dartmouth."); + dartmouth_ball(); + } + } + } + else { + System.out.println("Shot is off target."); + if (defense / 6 * Math.random() > .45) { + System.out.println("Rebound to " + opponent + "\n"); + opponent_ball(); + } + else { + System.out.println("Dartmouth controls the rebound."); + if (Math.random() > .4) { + if (defense == 6 && Math.random() > .6) { + System.out.println("Pass stolen by " + opponent + + ", easy lay up"); + add_points(0, 2); + dartmouth_ball(); + } + else { + // ball is passed back to you + ball_passed_back(); + } + } + else { + System.out.println(""); + dartmouth_non_jump_shot(); + } + } + } + } + else { + System.out.println("Shot is good."); + add_points(1, 2); + opponent_ball(); + } + } + + // called when the user enters 0, 3, or 4 + // lay up, set shot, or defense change + private void dartmouth_non_jump_shot() { + time ++; + if (time == 50) { + halftime(); + } + else if (time == 92) { + two_minute_warning(); + } + + if (shot == 4) { + System.out.println("Set shot."); + } + else if (shot == 3) { + System.out.println("Lay up."); + } + else if (shot == 0) { + change_defense(); + } + + // simulates different outcomes after a lay up or set shot + if (7/defense*Math.random() > .4) { + if (7/defense*Math.random() > .7) { + if (7/defense*Math.random() > .875) { + if (7/defense*Math.random() > .925) { + System.out.println("Charging foul. Dartmouth loses the ball.\n"); + opponent_ball(); + } + else { + System.out.println("Shot blocked. " + opponent + "'s ball.\n"); + opponent_ball(); + } + } + else { + foul_shots(1); + opponent_ball(); + } + } + else { + System.out.println("Shot is off the rim."); + if (Math.random() > 2/3) { + System.out.println("Dartmouth controls the rebound."); + if (Math.random() > .4) { + System.out.println("Ball passed back to you.\n"); + dartmouth_ball(); + } + else { + dartmouth_non_jump_shot(); + } + } + else { + System.out.println(opponent + " controls the rebound.\n"); + opponent_ball(); + } + } + } + else { + System.out.println("Shot is good. Two points."); + add_points(1, 2); + opponent_ball(); + } + } + + + // plays out a Dartmouth posession, starting with your choice of shot + private void dartmouth_ball() { + Scanner scanner = new Scanner(System.in); // creates a scanner + System.out.print("Your shot? "); + shot = -1; + if (scanner.hasNextInt()) { + shot = scanner.nextInt(); + } + else { + System.out.println(""); + scanner.next(); + } + + while (!shot_choices.contains(shot)) { + System.out.print("Incorrect answer. Retype it. Your shot?"); + if (scanner.hasNextInt()) { + shot = scanner.nextInt(); + } + else { + System.out.println(""); + scanner.next(); + } + } + + if (time < 100 || Math.random() < .5) { + if (shot == 1 || shot == 2) { + dartmouth_jump_shot(); + } + else { + dartmouth_non_jump_shot(); + } + } + else { + if (score[0] != score[1]) { + System.out.println("\n ***** End Of Game *****"); + System.out.println("Final Score: Dartmouth: " + score[1] + " " + + opponent + ": " + score[0]); + System.exit(0); + } + else { + System.out.println("\n ***** End Of Second Half *****"); + System.out.println("Score at end of regulation time:"); + System.out.println(" Dartmouth: " + score[1] + " " + + opponent + ": " + score[0]); + System.out.println("Begin two minute overtime period"); + time = 93; + start_of_period(); + } + } + } + + // simulates the opponents jumpshot + private void opponent_jumpshot() { + System.out.println("Jump Shot."); + if (8/defense*Math.random() > .35) { + if (8/defense*Math.random() > .75) { + if (8/defense*Math.random() > .9) { + System.out.println("Offensive foul. Dartmouth's ball.\n"); + dartmouth_ball(); + } + else { + foul_shots(0); + dartmouth_ball(); + } + } + else { + System.out.println("Shot is off the rim."); + if (defense/6*Math.random() > .5) { + System.out.println(opponent + " controls the rebound."); + if (defense == 6) { + if (Math.random() > .75) { + System.out.println("Ball stolen. Easy lay up for Dartmouth."); + add_points(1, 2); + opponent_ball(); + } + else { + if (Math.random() > .5) { + System.out.println(""); + opponent_non_jumpshot(); + } + else { + System.out.println("Pass back to " + opponent + + " guard.\n"); + opponent_ball(); + } + } + } + else { + if (Math.random() > .5) { + opponent_non_jumpshot(); + } + else { + System.out.println("Pass back to " + opponent + + " guard.\n"); + opponent_ball(); + } + } + } + else { + System.out.println("Dartmouth controls the rebound.\n"); + dartmouth_ball(); + } + } + } + else { + System.out.println("Shot is good."); + add_points(0, 2); + dartmouth_ball(); + } + } + + // simulates opponents lay up or set shot + private void opponent_non_jumpshot() { + if (opponent_chance > 3) { + System.out.println("Set shot."); + } + else { + System.out.println("Lay up"); + } + if (7/defense*Math.random() > .413) { + System.out.println("Shot is missed."); + if (defense/6*Math.random() > .5) { + System.out.println(opponent + " controls the rebound."); + if (defense == 6) { + if (Math.random() > .75) { + System.out.println("Ball stolen. Easy lay up for Dartmouth."); + add_points(1, 2); + opponent_ball(); + } + else { + if (Math.random() > .5) { + System.out.println(""); + opponent_non_jumpshot(); + } + else { + System.out.println("Pass back to " + opponent + + " guard.\n"); + opponent_ball(); + } + } + } + else { + if (Math.random() > .5) { + System.out.println(""); + opponent_non_jumpshot(); + } + else { + System.out.println("Pass back to " + opponent + " guard\n"); + opponent_ball(); + } + } + } + else { + System.out.println("Dartmouth controls the rebound.\n"); + dartmouth_ball(); + } + } + else { + System.out.println("Shot is good."); + add_points(0, 2); + dartmouth_ball(); + } + } + + // simulates an opponents possesion + // #randomly picks jump shot or lay up / set shot. + private void opponent_ball() { + time ++; + if (time == 50) { + halftime(); + } + opponent_chance = 10/4*Math.random()+1; + if (opponent_chance > 2) { + opponent_non_jumpshot(); + } + else { + opponent_jumpshot(); + } + } + + public static void main(String[] args) { + Basketball new_game = new Basketball(); + } +} + + + + From 75cca25c386017eff5d9e5e2c926f703804f9d51 Mon Sep 17 00:00:00 2001 From: Jackson Brouwer Date: Wed, 12 Jan 2022 22:50:00 -0600 Subject: [PATCH 300/331] Bug fix on defense change --- 07_Basketball/python/basketball.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/07_Basketball/python/basketball.py b/07_Basketball/python/basketball.py index 5ba88188..20a6cd94 100644 --- a/07_Basketball/python/basketball.py +++ b/07_Basketball/python/basketball.py @@ -13,7 +13,7 @@ class Basketball(): self.defense = None self.defense_choices = [6, 6.5, 7, 7.5] self.shot = None - self.shot_choices = [1, 2, 3, 4] + self.shot_choices = [0, 1, 2, 3, 4] self.z1 = None # Explains the keyboard inputs From 08ea76d111770671a0935c44d930619150e394d5 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Thu, 13 Jan 2022 16:28:08 +0800 Subject: [PATCH 301/331] Update display --- 73_Reverse/csharp/Reverse/Reverse/Program.cs | 24 ++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/73_Reverse/csharp/Reverse/Reverse/Program.cs b/73_Reverse/csharp/Reverse/Reverse/Program.cs index 2f95cc55..82e78131 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Program.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Program.cs @@ -21,7 +21,8 @@ namespace Reverse { var reverser = new Reverser(arrayLength); - Console.WriteLine("HERE WE GO ... THE LIST IS:\n"); + Console.WriteLine("HERE WE GO ... THE LIST IS:"); + Console.WriteLine(); PrintList(reverser.GetArrayString()); var arrayIsNotInAscendingOrder = true; var numberOfMoves = 0; @@ -41,14 +42,17 @@ namespace Reverse { arrayIsNotInAscendingOrder = false; Console.WriteLine($"YOU WON IT IN {numberOfMoves} MOVES!!!"); + Console.WriteLine(); + Console.WriteLine(); } numberOfMoves++; } - Console.Write("TRY AGAIN (YES OR NO)"); + Console.Write("TRY AGAIN (YES OR NO) "); tryAgain = Console.ReadLine(); } + Console.WriteLine(); Console.WriteLine("OK HOPE YOU HAD FUN"); } @@ -90,31 +94,37 @@ namespace Reverse private static void PrintTitle() { - Console.WriteLine("REVERSE"); - Console.WriteLine("CREATIVE COMPUTING MORRISTON, NEW JERSEY"); + Console.WriteLine("\t\t REVERSE"); + Console.WriteLine(" CREATIVE COMPUTING MORRISTON, NEW JERSEY"); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine("REVERSE -- A GAME OF SKILL"); + Console.WriteLine(); } private static void DisplayRules() { + Console.WriteLine(); Console.WriteLine("THIS IS THE GAME OF 'REVERSE'. TO WIN, ALL YOU HAVE"); Console.WriteLine("TO DO IS ARRANGE A LIST OF NUMBERS (1 THOUGH 9 )"); Console.WriteLine("IN NUMBERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU"); Console.WriteLine("TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO"); Console.WriteLine("REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:"); Console.WriteLine(); - Console.WriteLine(" 2 3 4 5 1 6 7 8 9"); + Console.WriteLine("2 3 4 5 1 6 7 8 9"); Console.WriteLine(); Console.WriteLine("AND YOU REVERSE 4, THE RESULT WILL BE:"); Console.WriteLine(); - Console.WriteLine(" 5 4 3 2 1 6 7 8 9"); + Console.WriteLine("5 4 3 2 1 6 7 8 9"); Console.WriteLine(); Console.WriteLine("NOW IF YOU REVERSE 5, YOU WIN!"); Console.WriteLine(); - Console.WriteLine(" 1 2 3 4 5 6 7 8 9"); + Console.WriteLine("1 2 3 4 5 6 7 8 9"); Console.WriteLine(); Console.WriteLine("NO DOUBT YOU WILL LIKE THIS GAME, BUT "); Console.WriteLine("IF YOU WANT TO QUIT, REVERSE 0 (ZERO)"); Console.WriteLine(); + Console.WriteLine(); } } } From ed50c3e24b817e27a482ed0949d422c6a99b32c7 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Thu, 13 Jan 2022 16:28:54 +0800 Subject: [PATCH 302/331] fix typo. --- 73_Reverse/csharp/Reverse/Reverse/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/73_Reverse/csharp/Reverse/Reverse/Program.cs b/73_Reverse/csharp/Reverse/Reverse/Program.cs index 82e78131..8454a58c 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Program.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Program.cs @@ -107,7 +107,7 @@ namespace Reverse Console.WriteLine(); Console.WriteLine("THIS IS THE GAME OF 'REVERSE'. TO WIN, ALL YOU HAVE"); Console.WriteLine("TO DO IS ARRANGE A LIST OF NUMBERS (1 THOUGH 9 )"); - Console.WriteLine("IN NUMBERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU"); + Console.WriteLine("IN NUMERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU"); Console.WriteLine("TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO"); Console.WriteLine("REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:"); Console.WriteLine(); From 4f2bc6f98c97465e02da335d7bcb416d892ec194 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Thu, 13 Jan 2022 16:32:55 +0800 Subject: [PATCH 303/331] Add test showing that reverse handles numbers less than zero. --- .../csharp/Reverse/Reverse.Tests/ReverserTests.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs index bd00436f..4e57a05a 100644 --- a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs @@ -87,6 +87,19 @@ namespace Reverse.Tests Assert.True(sut.GetArray().SequenceEqual(output)); } + [Fact] + public void Reverse_WithIndexLessThanZero_DoesNothing() + { + var input = new int[] { 1, 2 }; + var output = new int[] { 1, 2 }; + var sut = new TestReverser(1); + sut.SetArray(input); + + sut.Reverse(-1); + + Assert.True(sut.GetArray().SequenceEqual(output)); + } + [Theory] [InlineData(new int[] { 1 })] [InlineData(new int[] { 1, 2 })] From 7d14c37aaad85ac4c487ac247768a285fa8cc427 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Thu, 13 Jan 2022 16:41:24 +0800 Subject: [PATCH 304/331] Handle array size inputs less than 1. --- 73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs | 9 +++++++++ 73_Reverse/csharp/Reverse/Reverse/Reverser.cs | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs index 4e57a05a..6fe3bb77 100644 --- a/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs +++ b/73_Reverse/csharp/Reverse/Reverse.Tests/ReverserTests.cs @@ -1,5 +1,6 @@ using FsCheck.Xunit; using Reverse.Tests.Generators; +using System; using System.Linq; using Xunit; @@ -7,6 +8,14 @@ namespace Reverse.Tests { public class ReverserTests { + [Fact] + public void Constructor_CannotAcceptNumberLessThanZero() + { + Action action = () => new Reverser(0); + + Assert.Throws(action); + } + [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })] public void Constructor_CreatesRandomArrayOfSpecifiedLength(int size) { diff --git a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs index 2d2ea700..fdab5e96 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Reverser.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Reverser.cs @@ -43,6 +43,11 @@ namespace Reverse private int[] CreateRandomArray(int size) { + if (size < 1) + { + throw new ArgumentOutOfRangeException(nameof(size), "Array size must be a positive integer"); + } + var array = new int[size]; for (int i = 1; i <= size; i++) { From ead374e8b5935ab49e4b7ad497de7d871aeee0b6 Mon Sep 17 00:00:00 2001 From: Kristian Stolen Date: Thu, 13 Jan 2022 16:53:09 +0800 Subject: [PATCH 305/331] refactor and reformat output. --- 73_Reverse/csharp/Reverse/Reverse/Program.cs | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/73_Reverse/csharp/Reverse/Reverse/Program.cs b/73_Reverse/csharp/Reverse/Reverse/Program.cs index 8454a58c..5f8c5967 100644 --- a/73_Reverse/csharp/Reverse/Reverse/Program.cs +++ b/73_Reverse/csharp/Reverse/Reverse/Program.cs @@ -22,11 +22,10 @@ namespace Reverse var reverser = new Reverser(arrayLength); Console.WriteLine("HERE WE GO ... THE LIST IS:"); - Console.WriteLine(); PrintList(reverser.GetArrayString()); - var arrayIsNotInAscendingOrder = true; + var arrayIsInAscendingOrder = false; var numberOfMoves = 0; - while (arrayIsNotInAscendingOrder) + while (arrayIsInAscendingOrder == false) { int index = ReadNextInput(); @@ -37,23 +36,24 @@ namespace Reverse reverser.Reverse(index); PrintList(reverser.GetArrayString()); - - if (reverser.IsArrayInAscendingOrder()) - { - arrayIsNotInAscendingOrder = false; - Console.WriteLine($"YOU WON IT IN {numberOfMoves} MOVES!!!"); - Console.WriteLine(); - Console.WriteLine(); - } + arrayIsInAscendingOrder = reverser.IsArrayInAscendingOrder(); numberOfMoves++; } + if (arrayIsInAscendingOrder) + { + Console.WriteLine($"YOU WON IT IN {numberOfMoves} MOVES!!!"); + + } + + Console.WriteLine(); + Console.WriteLine(); Console.Write("TRY AGAIN (YES OR NO) "); tryAgain = Console.ReadLine(); } Console.WriteLine(); - Console.WriteLine("OK HOPE YOU HAD FUN"); + Console.WriteLine("OK HOPE YOU HAD FUN!!"); } private static int ReadNextInput() From b887d2993052ee26b649496d7500021908d1e6e2 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 13 Jan 2022 08:36:27 -0500 Subject: [PATCH 306/331] Finished Move script (if it is correct) --- 48_High_IQ/python/High_IQ.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index b2e71b6c..548d984d 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -67,10 +67,15 @@ def move(board): if difference != 2 and difference != 18: return False center = (end + start) / 2 + if not board[center] == '!': + return False + board[start] = 'O' + board[center] = 'O' + board[end] = '!' + return True except: return False - return True def main(): # if input("Do you want instrunctions?\n").lower().startswith("y"): From 679481ea233b43ff55e19ff8d321cc00b31697bc Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 13 Jan 2022 08:41:13 -0500 Subject: [PATCH 307/331] Simplified / Shortened move script --- 48_High_IQ/python/High_IQ.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 548d984d..0f39b9d4 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -61,19 +61,14 @@ def move(board): return False end = int(input("TO WHERE? ")) - if not (board[end] == 'O'): - return False difference = abs(end - start) - if difference != 2 and difference != 18: - return False center = (end + start) / 2 - if not board[center] == '!': - return False - board[start] = 'O' - board[center] = 'O' - board[end] = '!' - return True + if (difference == 2 or difference == 18) and board[end] == 'O' and board[center] == '!': + board[start] = 'O' + board[center] = 'O' + board[end] == '!' + return True except: return False From 633c0137c7d3bdfb6b943f1535765e76b6d83fca Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 13 Jan 2022 08:45:48 -0500 Subject: [PATCH 308/331] Added Post-Game prints --- 48_High_IQ/python/High_IQ.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 0f39b9d4..57473922 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -53,6 +53,17 @@ def play_game(): print_board(board) while not move(board): print("ILLEGAL MOVE! TRY AGAIN") + + 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): try: From 212cc1d8bd54f717e794ed5b006d51f67cf92a1a Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 13 Jan 2022 08:47:41 -0500 Subject: [PATCH 309/331] Removed Commented Line --- 48_High_IQ/python/High_IQ.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 57473922..1c69abda 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -84,7 +84,6 @@ def move(board): return False def main(): -# if input("Do you want instrunctions?\n").lower().startswith("y"): print(" " * 33 + "H-I-Q") print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") print_instructions() @@ -94,8 +93,8 @@ def is_game_finished(board): for pos in board.keys(): if board[pos] == "X": for space in [1,9]: - nextToPeg = ((pos + space) in board) and board[pos + space] == "X" - hasMovableSpace = (not ((pos - space) in board and board[pos - space] == "X")) or (not ((pos + space * 2) in board and board[pos + space * 2] == "X")) + nextToPeg = ((pos + space) in board) and board[pos + space] == "!" + hasMovableSpace = (not ((pos - space) in board and board[pos - space] == "!")) or (not ((pos + space * 2) in board and board[pos + space * 2] == "!")) if nextToPeg and hasMovableSpace: return False From 351530faed6ae8173b9b8e506970908a135b747d Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 13 Jan 2022 09:07:33 -0500 Subject: [PATCH 310/331] Removed extra quotation mark --- 48_High_IQ/python/High_IQ.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 1c69abda..e8cca71d 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -68,7 +68,7 @@ def play_game(): def move(board): try: start = int(input("MOVE WHICH PIECE? ")) - if not (board[start] == "'!'): + if not (board[start] == '!'): return False end = int(input("TO WHERE? ")) @@ -97,7 +97,6 @@ def is_game_finished(board): hasMovableSpace = (not ((pos - space) in board and board[pos - space] == "!")) or (not ((pos + space * 2) in board and board[pos + space * 2] == "!")) if nextToPeg and hasMovableSpace: return False - return True From d041d2f92a4031dd9805d5200ffc77ddad554cf1 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 13 Jan 2022 09:14:39 -0500 Subject: [PATCH 311/331] Replaced double quotes with single quotes --- 48_High_IQ/python/High_IQ.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index e8cca71d..69cc6210 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -2,8 +2,8 @@ def new_board(): 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" + board[i] = '!' + board[41] = 'O' return board @@ -91,10 +91,10 @@ def main(): def is_game_finished(board): for pos in board.keys(): - if board[pos] == "X": + if board[pos] == 'X': for space in [1,9]: - nextToPeg = ((pos + space) in board) and board[pos + space] == "!" - hasMovableSpace = (not ((pos - space) in board and board[pos - space] == "!")) or (not ((pos + space * 2) in board and board[pos + space * 2] == "!")) + nextToPeg = ((pos + space) in board) and board[pos + space] == '!' + hasMovableSpace = (not ((pos - space) in board and board[pos - space] == '!')) or (not ((pos + space * 2) in board and board[pos + space * 2] == '!')) if nextToPeg and hasMovableSpace: return False return True From baf5d3750aeca07214747177522fcb84780ebce4 Mon Sep 17 00:00:00 2001 From: Zev Spitz Date: Thu, 13 Jan 2022 16:24:46 +0200 Subject: [PATCH 312/331] Some utility scripts for C# and VB.NET ports --- 00_Utilities/DotnetUtils/.editorconfig | 168 ++++++++++++++++++ 00_Utilities/DotnetUtils/DotnetUtils.sln | 25 +++ .../DotnetUtils/DotnetUtils.csproj | 10 ++ .../DotnetUtils/DotnetUtils/Extensions.cs | 27 +++ .../DotnetUtils/DotnetUtils/Globals.cs | 8 + .../DotnetUtils/DotnetUtils/PortInfo.cs | 51 ++++++ .../DotnetUtils/DotnetUtils/PortInfos.cs | 22 +++ .../DotnetUtils/DotnetUtils/Program.cs | 163 +++++++++++++++++ 8 files changed, 474 insertions(+) create mode 100644 00_Utilities/DotnetUtils/.editorconfig create mode 100644 00_Utilities/DotnetUtils/DotnetUtils.sln create mode 100644 00_Utilities/DotnetUtils/DotnetUtils/DotnetUtils.csproj create mode 100644 00_Utilities/DotnetUtils/DotnetUtils/Extensions.cs create mode 100644 00_Utilities/DotnetUtils/DotnetUtils/Globals.cs create mode 100644 00_Utilities/DotnetUtils/DotnetUtils/PortInfo.cs create mode 100644 00_Utilities/DotnetUtils/DotnetUtils/PortInfos.cs create mode 100644 00_Utilities/DotnetUtils/DotnetUtils/Program.cs diff --git a/00_Utilities/DotnetUtils/.editorconfig b/00_Utilities/DotnetUtils/.editorconfig new file mode 100644 index 00000000..9e7a90d5 --- /dev/null +++ b/00_Utilities/DotnetUtils/.editorconfig @@ -0,0 +1,168 @@ +root = true + + +[*.{cs,vb}] +indent_size = 4 +indent_style = space +end_of_line = crlf +insert_final_newline = true + +dotnet_separate_import_directive_groups = false +dotnet_sort_system_directives_first = false + +dotnet_style_qualification_for_event = false:suggestion +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_property = false:suggestion + +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:silent + +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_operator_placement_when_wrapping = end_of_line +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion + + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_private_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_private_members_should_be_pascal_case.symbols = non_private_members +dotnet_naming_rule.non_private_members_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.private_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.private_members_should_be_pascal_case.symbols = private_members +dotnet_naming_rule.private_members_should_be_pascal_case.style = camel_case + + +# Symbols for use with naming rules + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum, delegate +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_private_members.applicable_kinds = property, method, field, event +dotnet_naming_symbols.non_private_members.applicable_accessibilities = public, internal, protected, protected_internal, private_protected + +dotnet_naming_symbols.private_members.applicable_kinds = property, method, field, event +dotnet_naming_symbols.private_members.applicable_accessibilities = private + + +# Naming styles + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.camel_case.required_prefix = +dotnet_naming_style.camel_case.required_suffix = +dotnet_naming_style.camel_case.word_separator = +dotnet_naming_style.camel_case.capitalization = camel_case + + +[*.cs] +csharp_new_line_before_catch = false +csharp_new_line_before_else = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_open_brace = none +csharp_new_line_between_query_expression_clauses = true + +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_labels = one_less_than_current +csharp_indent_switch_labels = true + +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +csharp_prefer_braces = true:warning + +csharp_style_expression_bodied_constructors = true:suggestion +csharp_style_expression_bodied_methods = true:suggestion +csharp_style_expression_bodied_properties = true:suggestion + +csharp_prefer_simple_default_expression = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion + +csharp_style_var_elsewhere = true:suggestion +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion + +csharp_preferred_modifier_order = internal,protected,public,private,static,readonly,abstract,override,sealed,virtual:suggestion + +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + + +[*.vb] +visual_basic_preferred_modifier_order = partial,default,private,protected,public,friend,notoverridable,overridable,mustoverride,overloads,overrides,mustinherit,notinheritable,static,shared,shadows,readonly,writeonly,dim,const,withevents,widening,narrowing,custom,async,iterator:silent +visual_basic_style_unused_value_assignment_preference = unused_local_variable:suggestion +visual_basic_style_unused_value_expression_statement_preference = unused_local_variable:silent diff --git a/00_Utilities/DotnetUtils/DotnetUtils.sln b/00_Utilities/DotnetUtils/DotnetUtils.sln new file mode 100644 index 00000000..ecf9588c --- /dev/null +++ b/00_Utilities/DotnetUtils/DotnetUtils.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32014.148 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotnetUtils", "DotnetUtils\DotnetUtils.csproj", "{BFDF93C2-4FB7-4838-AFDF-E7B5F83C3F00}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BFDF93C2-4FB7-4838-AFDF-E7B5F83C3F00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BFDF93C2-4FB7-4838-AFDF-E7B5F83C3F00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BFDF93C2-4FB7-4838-AFDF-E7B5F83C3F00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BFDF93C2-4FB7-4838-AFDF-E7B5F83C3F00}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {30FCF56E-4E83-42F8-AB43-A52C86C7C9B4} + EndGlobalSection +EndGlobal diff --git a/00_Utilities/DotnetUtils/DotnetUtils/DotnetUtils.csproj b/00_Utilities/DotnetUtils/DotnetUtils/DotnetUtils.csproj new file mode 100644 index 00000000..74abf5c9 --- /dev/null +++ b/00_Utilities/DotnetUtils/DotnetUtils/DotnetUtils.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/00_Utilities/DotnetUtils/DotnetUtils/Extensions.cs b/00_Utilities/DotnetUtils/DotnetUtils/Extensions.cs new file mode 100644 index 00000000..82ff9532 --- /dev/null +++ b/00_Utilities/DotnetUtils/DotnetUtils/Extensions.cs @@ -0,0 +1,27 @@ +using System.Diagnostics.CodeAnalysis; + +namespace DotnetUtils; + +public static class Extensions { + public static IEnumerable SelectT(this IEnumerable<(T1, T2)> src, Func selector) => + src.Select(x => selector(x.Item1, x.Item2)); + public static IEnumerable SelectT(this IEnumerable<(T1, T2, T3)> src, Func selector) => + src.Select(x => selector(x.Item1, x.Item2, x.Item3)); + public static IEnumerable<(T1, T2, int)> WithIndex(this IEnumerable<(T1, T2)> src) => src.Select((x, index) => (x.Item1, x.Item2, index)); + + public static bool IsNullOrWhitespace([NotNullWhen(false)] this string? s) => string.IsNullOrWhiteSpace(s); + + [return: NotNullIfNotNull("path")] + public static string? RelativePath(this string? path, string? rootPath) { + if ( + path.IsNullOrWhitespace() || + rootPath.IsNullOrWhitespace() + ) { return path; } + + var path1 = path.TrimEnd('\\'); + rootPath = rootPath.TrimEnd('\\'); + if (!path1.StartsWith(rootPath, StringComparison.InvariantCultureIgnoreCase)) { return path; } + + return path1[(rootPath.Length + 1)..]; // ignore the initial / + } +} diff --git a/00_Utilities/DotnetUtils/DotnetUtils/Globals.cs b/00_Utilities/DotnetUtils/DotnetUtils/Globals.cs new file mode 100644 index 00000000..1ff7c09d --- /dev/null +++ b/00_Utilities/DotnetUtils/DotnetUtils/Globals.cs @@ -0,0 +1,8 @@ +namespace DotnetUtils; + +public static class Globals { + public static readonly Dictionary LangData = new() { + { "csharp", ("cs", "csproj") }, + { "vbnet", ("vb", "vbproj") } + }; +} diff --git a/00_Utilities/DotnetUtils/DotnetUtils/PortInfo.cs b/00_Utilities/DotnetUtils/DotnetUtils/PortInfo.cs new file mode 100644 index 00000000..894c8834 --- /dev/null +++ b/00_Utilities/DotnetUtils/DotnetUtils/PortInfo.cs @@ -0,0 +1,51 @@ +using System.Reflection; +using static System.IO.Directory; +using static System.IO.Path; +using static DotnetUtils.Globals; + +namespace DotnetUtils; + +public record PortInfo( + string FullPath, string FolderName, int Index, string GameName, + string LangPath, string Lang, string Ext, string ProjExt, + string[] CodeFiles, string[] Slns, string[] Projs +) { + + private static readonly EnumerationOptions enumerationOptions = new() { + RecurseSubdirectories = true, + MatchType = MatchType.Simple, + MatchCasing = MatchCasing.CaseInsensitive + }; + + public static PortInfo? Create(string fullPath, string langKeyword) { + var folderName = GetFileName(fullPath); + var parts = folderName.Split('_', 2); + + var index = + parts.Length > 0 && int.TryParse(parts[0], out var n) ? + n : + (int?)null; + + var gameName = + parts.Length > 1 ? + parts[1].Replace("_", "") : + null; + + if (index is 0 or null || gameName is null) { return null; } + + var (ext, projExt) = LangData[langKeyword]; + var langPath = Combine(fullPath, langKeyword); + var codeFiles = + GetFiles(langPath, $"*.{ext}", enumerationOptions) + .Where(x => !x.Contains("\\bin\\") && !x.Contains("\\obj\\")) + .ToArray(); + + return new PortInfo( + fullPath, folderName, index.Value, gameName, + langPath, langKeyword, ext, projExt, + codeFiles, + GetFiles(langPath, "*.sln", enumerationOptions), + GetFiles(langPath, $"*.{projExt}", enumerationOptions) + ); + } +} diff --git a/00_Utilities/DotnetUtils/DotnetUtils/PortInfos.cs b/00_Utilities/DotnetUtils/DotnetUtils/PortInfos.cs new file mode 100644 index 00000000..b8c1afd3 --- /dev/null +++ b/00_Utilities/DotnetUtils/DotnetUtils/PortInfos.cs @@ -0,0 +1,22 @@ +using System.Reflection; +using static System.IO.Directory; +using static DotnetUtils.Globals; + +namespace DotnetUtils; + +public static class PortInfos { + public static readonly string Root; + + static PortInfos() { + Root = GetParent(Assembly.GetEntryAssembly()!.Location)!.FullName; + Root = Root[..Root.IndexOf(@"\00_Utilities")]; + + Get = GetDirectories(Root) + .SelectMany(fullPath => LangData.Keys.Select(keyword => (fullPath, keyword))) + .SelectT((fullPath, keyword) => PortInfo.Create(fullPath, keyword)) + .Where(x => x is not null) + .ToArray()!; + } + + public static readonly PortInfo[] Get; +} diff --git a/00_Utilities/DotnetUtils/DotnetUtils/Program.cs b/00_Utilities/DotnetUtils/DotnetUtils/Program.cs new file mode 100644 index 00000000..9bf36f4f --- /dev/null +++ b/00_Utilities/DotnetUtils/DotnetUtils/Program.cs @@ -0,0 +1,163 @@ +using DotnetUtils; +using static System.Console; +using static System.IO.Path; + +var infos = PortInfos.Get; + +var actions = new (Action action, string description)[] { + (printInfos, "Output information -- solution, project, and code files"), + (missingSln, "Output missing sln"), + (unexpectedSlnName, "Output misnamed sln"), + (multipleSlns, "Output multiple sln files"), + (missingProj, "Output missing project file"), + (unexpectedProjName, "Output misnamed project files"), + (multipleProjs, "Output multiple project files") +}; + +foreach (var (_, description, index) in actions.WithIndex()) { + WriteLine($"{index}: {description}"); +} + +WriteLine(); + +actions[getChoice(actions.Length - 1)].action(); + +int getChoice(int maxValue) { + int result; + do { + Write("? "); + } while (!int.TryParse(ReadLine(), out result) || result < 0 || result > maxValue); + WriteLine(); + return result; +} + +void printSlns(PortInfo pi) { + switch (pi.Slns.Length) { + case 0: + WriteLine("No sln"); + break; + case 1: + WriteLine($"Solution: {pi.Slns[0].RelativePath(pi.LangPath)}"); + break; + case > 1: + WriteLine("Solutions:"); + foreach (var sln in pi.Slns) { + Write(sln.RelativePath(pi.LangPath)); + WriteLine(); + } + break; + } +} + +void printProjs(PortInfo pi) { + switch (pi.Projs.Length) { + case 0: + WriteLine("No project"); + break; + case 1: + WriteLine($"Project: {pi.Projs[0].RelativePath(pi.LangPath)}"); + break; + case > 1: + WriteLine("Projects:"); + foreach (var proj in pi.Projs) { + Write(proj.RelativePath(pi.LangPath)); + WriteLine(); + } + break; + } + WriteLine(); +} + +void printInfos() { + foreach (var item in infos) { + WriteLine(item.LangPath); + WriteLine(); + + printSlns(item); + WriteLine(); + + printProjs(item); + WriteLine(); + + // get code files + foreach (var file in item.CodeFiles) { + WriteLine(file.RelativePath(item.LangPath)); + } + WriteLine(new string('-', 50)); + } +} + +void missingSln() { + var data = infos.Where(x => !x.Slns.Any()).ToArray(); + foreach (var item in data) { + WriteLine(item.LangPath); + } + WriteLine(); + WriteLine($"Count: {data.Length}"); +} + +void unexpectedSlnName() { + var counter = 0; + foreach (var item in infos) { + if (!item.Slns.Any()) { continue; } + + var expectedSlnName = $"{item.GameName}.sln"; + if (item.Slns.Contains(Combine(item.LangPath, expectedSlnName))) { continue; } + + counter += 1; + WriteLine(item.LangPath); + WriteLine($"Expected: {expectedSlnName}"); + + printSlns(item); + + WriteLine(); + } + WriteLine($"Count: {counter}"); +} + +void multipleSlns() { + var data = infos.Where(x => x.Slns.Length > 1).ToArray(); + foreach (var item in data) { + WriteLine(item.LangPath); + printSlns(item); + } + WriteLine(); + WriteLine($"Count: {data.Length}"); +} + +void missingProj() { + var data = infos.Where(x => !x.Projs.Any()).ToArray(); + foreach (var item in data) { + WriteLine(item.LangPath); + } + WriteLine(); + WriteLine($"Count: {data.Length}"); +} + +void unexpectedProjName() { + var counter = 0; + foreach (var item in infos) { + if (!item.Projs.Any()) { continue; } + + var expectedProjName = $"{item.GameName}.{item.ProjExt}"; + if (item.Projs.Contains(Combine(item.LangPath, expectedProjName))) { continue; } + + counter += 1; + WriteLine(item.LangPath); + WriteLine($"Expected: {expectedProjName}"); + + printProjs(item); + + WriteLine(); + } + WriteLine($"Count: {counter}"); +} + +void multipleProjs() { + var data = infos.Where(x => x.Projs.Length > 1).ToArray(); + foreach (var item in data) { + WriteLine(item.LangPath); + } + WriteLine(); + WriteLine($"Count: {data.Length}"); +} From db5face44a80f8f30c01e8e917aca8fc30b176ad Mon Sep 17 00:00:00 2001 From: Zev Spitz Date: Thu, 13 Jan 2022 16:32:13 +0200 Subject: [PATCH 313/331] Fix: print projects for multiproject script --- 00_Utilities/DotnetUtils/DotnetUtils/Program.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/00_Utilities/DotnetUtils/DotnetUtils/Program.cs b/00_Utilities/DotnetUtils/DotnetUtils/Program.cs index 9bf36f4f..6d4594b7 100644 --- a/00_Utilities/DotnetUtils/DotnetUtils/Program.cs +++ b/00_Utilities/DotnetUtils/DotnetUtils/Program.cs @@ -157,6 +157,9 @@ void multipleProjs() { var data = infos.Where(x => x.Projs.Length > 1).ToArray(); foreach (var item in data) { WriteLine(item.LangPath); + WriteLine(); + printProjs(item); + } WriteLine(); WriteLine($"Count: {data.Length}"); From 6c1adde2056151fafe330ef9970403db5d372ce0 Mon Sep 17 00:00:00 2001 From: Stephen Childs Date: Thu, 13 Jan 2022 10:56:50 -0500 Subject: [PATCH 314/331] Move harvest calculation outside rat condition. This fixes an error where the harvest was only added to the total bushels if rats ate some. Note in the BASIC file, we check to see if rats eat the grain in line 522 and if not, go to line 530, which is where the `S=S-E+H` calculation is done. --- 43_Hammurabi/python/hamurabi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/43_Hammurabi/python/hamurabi.py b/43_Hammurabi/python/hamurabi.py index 7c18f892..17c61982 100644 --- a/43_Hammurabi/python/hamurabi.py +++ b/43_Hammurabi/python/hamurabi.py @@ -154,7 +154,8 @@ while Z < 11: # line 270. main loop. while the year is less than 11 if int(C / 2) == C / 2: # even number. 50/50 chance # REM *** RATS ARE RUNNING WILD!! E = int(S / C) # calc losses due to rats, based on previous random number - S = S - E + H # deduct losses from stores + + S = S - E + H # deduct losses from stores C = gen_random() # REM *** LET'S HAVE SOME BABIES From 94a65239d5f6acd9b0817ad77bfb26622e82b676 Mon Sep 17 00:00:00 2001 From: Stephen Childs Date: Thu, 13 Jan 2022 11:04:43 -0500 Subject: [PATCH 315/331] Allow max fields to be worked in python Hamurabi. In the BASIC version the calculation is on line 455: `455 IF D<10*P THEN 510` Which skips over the not enough people message. In the Python version the logic is reversed, and we check to see if there is too few people and then run the message: `elif D >= 10 * P` (in the current code). However, this means that the case where you want to plant the maximum number of acres won't work. e.g. You have 100 people (P) and want to plant 1000 acres (D). `1000 >= 10 * 100` `1000 >= 1000` Which triggers the "not enough people code". Maybe this is a bug in the original program. --- 43_Hammurabi/python/hamurabi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/43_Hammurabi/python/hamurabi.py b/43_Hammurabi/python/hamurabi.py index 17c61982..e7310fc7 100644 --- a/43_Hammurabi/python/hamurabi.py +++ b/43_Hammurabi/python/hamurabi.py @@ -137,7 +137,7 @@ while Z < 11: # line 270. main loop. while the year is less than 11 # REM *** ENOUGH GRAIN FOR SEED? bad_input_710(S) D = -99 - elif D >= 10 * P: + elif D > 10 * P: # REM *** ENOUGH PEOPLE TO TEND THE CROPS? print("BUT YOU HAVE ONLY", P, "PEOPLE TO TEND THE FIELDS! NOW THEN,") D = -99 From 37791fe915067b256285a3e3d1ffcb9f0528e683 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 13 Jan 2022 11:29:05 -0500 Subject: [PATCH 316/331] Commented and fixed error --- 48_High_IQ/python/High_IQ.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 69cc6210..a91f3699 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -1,5 +1,6 @@ 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] = '!' @@ -38,6 +39,7 @@ NUMBERS. OK, LET'S BEGIN. """) def print_board(board): + """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]) print(board[29] + board[30] + board[31] + board[32] + board[33] + board[34] + board[35]) @@ -47,13 +49,16 @@ def print_board(board): print(" " * 2 + board[67] + board[68] + board[69]) def play_game(): + # Create new board board = new_board() + # Main game loop while not is_game_finished(board): print_board(board) while not move(board): print("ILLEGAL MOVE! TRY AGAIN") + # Check peg count and print the user's score peg_count = 0 for key in board.keys(): if board[key] == '!': @@ -66,20 +71,29 @@ def play_game(): print("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!") 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""" try: + # Ask for the "start" location start = int(input("MOVE WHICH PIECE? ")) + # Verify that the location has a peg if not (board[start] == '!'): return False + # Ask for the "end" location end = int(input("TO WHERE? ")) + + # difference and center difference = abs(end - start) center = (end + start) / 2 + # Execute the move if the difference is correct, there is a peg in the center and no peg at the end if (difference == 2 or difference == 18) and board[end] == 'O' and board[center] == '!': board[start] = 'O' board[center] = 'O' board[end] == '!' return True + else: + return False except: return False @@ -90,10 +104,13 @@ def main(): play_game() 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] == 'X': for space in [1,9]: + # Checks if the next location has a peg nextToPeg = ((pos + space) in board) and board[pos + space] == '!' + # Checks both going forward (+ location) or backwards (-location) hasMovableSpace = (not ((pos - space) in board and board[pos - space] == '!')) or (not ((pos + space * 2) in board and board[pos + space * 2] == '!')) if nextToPeg and hasMovableSpace: return False From dc0ceba48ae791079c61f7bab540f67230b1836c Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 13 Jan 2022 12:27:53 -0500 Subject: [PATCH 317/331] Using tests instead of try catches --- 48_High_IQ/python/High_IQ.py | 70 +++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index a91f3699..2455049f 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -72,30 +72,60 @@ def play_game(): 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""" - try: - # Ask for the "start" location - start = int(input("MOVE WHICH PIECE? ")) - # Verify that the location has a peg - if not (board[start] == '!'): - return False + # try: + # # Ask for the "start" location + # start = int(input("MOVE WHICH PIECE? ")) + # # Verify that the location has a peg + # if not (board[start] == '!'): + # return False - # Ask for the "end" location - end = int(input("TO WHERE? ")) + # # Ask for the "end" location + # end = int(input("TO WHERE? ")) - # difference and center - difference = abs(end - start) - center = (end + start) / 2 + # # difference and center + # difference = abs(end - start) + # center = (end + start) / 2 - # Execute the move if the difference is correct, there is a peg in the center and no peg at the end - if (difference == 2 or difference == 18) and board[end] == 'O' and board[center] == '!': - board[start] = 'O' - board[center] = 'O' - board[end] == '!' - return True - else: - return False - except: + # # Execute the move if the difference is correct, there is a peg in the center and no peg at the end + # if (difference == 2 or difference == 18) and board[end] == 'O' and board[center] == '!': + # board[start] = 'O' + # board[center] = 'O' + # board[end] == '!' + # return True + # else: + # return False + # except: + # return False + start_input = input("MOVE WHICH PIECE? ") + + if not start_input.isdigit(): return False + + start = int(start_input) + + if start not in board or board[start] != '!': + return False + + end_input = input("TO WHERE? ") + + if not end_input.isdigit(): + return False + + end = int(end_input) + + if end not in board or board[end] != '0': + return False + + difference = abs(start - end) + 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] == '!' + return True + else: + return False + def main(): print(" " * 33 + "H-I-Q") From e107e885095820ade482a836155747f5a8f4d8c2 Mon Sep 17 00:00:00 2001 From: = Date: Thu, 13 Jan 2022 16:59:25 -0500 Subject: [PATCH 318/331] Fixed Bug --- 48_High_IQ/python/High_IQ.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index 2455049f..cd5a996d 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -136,7 +136,7 @@ def main(): 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] == 'X': + if board[pos] == '!': for space in [1,9]: # Checks if the next location has a peg nextToPeg = ((pos + space) in board) and board[pos + space] == '!' From e7e16eb9498201c755a0d839917072b2106ac454 Mon Sep 17 00:00:00 2001 From: = Date: Thu, 13 Jan 2022 17:01:43 -0500 Subject: [PATCH 319/331] Move code now properly works --- 48_High_IQ/python/High_IQ.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index cd5a996d..fe61e9ba 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -113,7 +113,7 @@ def move(board): end = int(end_input) - if end not in board or board[end] != '0': + if end not in board or board[end] != 'O': return False difference = abs(start - end) @@ -121,7 +121,7 @@ def move(board): if (difference == 2 or difference == 18) and board[end] == 'O' and board[center] == '!': board[start] = 'O' board[center] = 'O' - board[end] == '!' + board[end] = '!' return True else: return False From 33b5da4b1fb85b9073d83b38a56465358ce49b92 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 13 Jan 2022 17:16:45 -0500 Subject: [PATCH 320/331] Misc final steps Removed commented code Added to README.md --- 48_High_IQ/python/High_IQ.py | 24 ------------------------ 48_High_IQ/python/README.md | 2 ++ 2 files changed, 2 insertions(+), 24 deletions(-) diff --git a/48_High_IQ/python/High_IQ.py b/48_High_IQ/python/High_IQ.py index fe61e9ba..4e14ddc1 100644 --- a/48_High_IQ/python/High_IQ.py +++ b/48_High_IQ/python/High_IQ.py @@ -72,30 +72,6 @@ def play_game(): 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""" - # try: - # # Ask for the "start" location - # start = int(input("MOVE WHICH PIECE? ")) - # # Verify that the location has a peg - # if not (board[start] == '!'): - # return False - - # # Ask for the "end" location - # end = int(input("TO WHERE? ")) - - # # difference and center - # difference = abs(end - start) - # center = (end + start) / 2 - - # # Execute the move if the difference is correct, there is a peg in the center and no peg at the end - # if (difference == 2 or difference == 18) and board[end] == 'O' and board[center] == '!': - # board[start] = 'O' - # board[center] = 'O' - # board[end] == '!' - # return True - # else: - # return False - # except: - # return False start_input = input("MOVE WHICH PIECE? ") if not start_input.isdigit(): diff --git a/48_High_IQ/python/README.md b/48_High_IQ/python/README.md index 781945ec..a0738c90 100644 --- a/48_High_IQ/python/README.md +++ b/48_High_IQ/python/README.md @@ -1,3 +1,5 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Python](https://www.python.org/about/) + +[Implementation](./High_IQ.py) by [Thomas Kwashnak](https://github.com/LittleTealeaf) \ No newline at end of file From cf55a5f63756691ce3145636cbaf43606fc61831 Mon Sep 17 00:00:00 2001 From: Bernard Cooke Date: Fri, 14 Jan 2022 01:28:30 +0000 Subject: [PATCH 321/331] 12. Port Bombs Away to Python --- 12_Bombs_Away/python/bombs_away.py | 177 +++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 12_Bombs_Away/python/bombs_away.py diff --git a/12_Bombs_Away/python/bombs_away.py b/12_Bombs_Away/python/bombs_away.py new file mode 100644 index 00000000..894f968c --- /dev/null +++ b/12_Bombs_Away/python/bombs_away.py @@ -0,0 +1,177 @@ +""" +Bombs away + +Ported from BASIC to Python3 by Bernard Cooke (bernardcooke53) +Tested with Python 3.8.10, formatted with Black and type checked with mypy. +""" +import random +from typing import Iterable + + +def _stdin_choice(*, prompt: str, choices: Iterable[str]) -> str: + ret = input(prompt) + while ret not in choices: + print("TRY AGAIN...") + ret = input(prompt) + return ret + + +def player_survived() -> None: + print("YOU MADE IT THROUGH TREMENDOUS FLAK!!") + + +def player_death() -> None: + print("* * * * BOOM * * * *") + print("YOU HAVE BEEN SHOT DOWN.....") + print("DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR") + print("LAST TRIBUTE...") + + +def mission_success() -> None: + print(f"DIRECT HIT!!!! {int(100 * random.random())} KILLED.") + print("MISSION SUCCESSFUL.") + + +def death_with_chance(p_death: float) -> bool: + """ + 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 + """ + return p_death > random.random() + + +def commence_non_kamikazi_attack() -> None: + nmissions = int(input("HOW MANY MISSIONS HAVE YOU FLOWN? ")) + + while nmissions >= 160: + print("MISSIONS, NOT MILES...") + print("150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS") + nmissions = int(input("NOW THEN, HOW MANY MISSIONS HAVE YOU FLOWN? ")) + + if nmissions >= 100: + print("THAT'S PUSHING THE ODDS!") + + if nmissions < 25: + print("FRESH OUT OF TRAINING, EH?") + + print() + return ( + mission_success() if nmissions >= 160 * random.random() else mission_failure() + ) + + +def mission_failure() -> None: + weapons_choices = { + "1": "GUNS", + "2": "MISSILES", + "3": "BOTH", + } + print(f"MISSED TARGET BY {int(2 + 30 * random.random())} MILES!") + print("NOW YOU'RE REALLY IN FOR IT !!") + print() + enemy_weapons = _stdin_choice( + prompt="DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? ", + choices=weapons_choices.keys(), + ) + + # 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 + + enemy_gunner_accuracy = 0.0 + if enemy_weapons != "2": + # If the enemy has guns, how accurate are the gunners? + enemy_gunner_accuracy = float( + input("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? ") + ) + + if enemy_gunner_accuracy < 10: + print("YOU LIE, BUT YOU'LL PAY...") + return player_death() + + missile_threat_weighting = 0 if enemy_weapons == "1" else 35 + + death = death_with_chance( + p_death=(enemy_gunner_accuracy + missile_threat_weighting) / 100 + ) + + return player_survived() if not death else player_death() + + +def play_italy() -> None: + targets_to_messages = { + # 1 - ALBANIA, 2 - GREECE, 3 - NORTH AFRICA + "1": "SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.", + "2": "BE CAREFUL!!!", + "3": "YOU'RE GOING FOR THE OIL, EH?", + } + target = _stdin_choice( + prompt="YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)", + choices=targets_to_messages.keys(), + ) + + print(targets_to_messages[target]) + return commence_non_kamikazi_attack() + + +def play_allies() -> None: + 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 = _stdin_choice( + prompt="AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4): ", + choices=aircraft_to_message.keys(), + ) + + print(aircraft_to_message[aircraft]) + return commence_non_kamikazi_attack() + + +def play_japan() -> None: + print("YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.") + first_mission = input("YOUR FIRST KAMIKAZE MISSION? (Y OR N): ") + if first_mission.lower() == "n": + return player_death() + + if random.random() > 0.65: + return mission_success() + return player_death() + + +def play_germany() -> None: + targets_to_messages = { + # 1 - RUSSIA, 2 - ENGLAND, 3 - FRANCE + "1": "YOU'RE NEARING STALINGRAD.", + "2": "NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR.", + "3": "NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.", + } + target = _stdin_choice( + prompt="A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\nENGLAND(2), OR FRANCE(3)? ", + choices=targets_to_messages.keys(), + ) + + print(targets_to_messages[target]) + + return commence_non_kamikazi_attack() + + +def play_game() -> None: + print("YOU ARE A PILOT IN A WORLD WAR II BOMBER.") + sides = {"1": play_italy, "2": play_allies, "3": play_japan, "4": play_germany} + side = _stdin_choice( + prompt="WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4): ", + choices=sides.keys(), + ) + return sides[side]() + + +if __name__ == "__main__": + again = True + while again: + play_game() + again = True if input("ANOTHER MISSION (Y OR N)").upper() == "Y" else False From 11ffe9cf90d7b7f61c7fe576b1ad7b61f451daee Mon Sep 17 00:00:00 2001 From: Bernard Cooke Date: Fri, 14 Jan 2022 01:31:27 +0000 Subject: [PATCH 322/331] Tidy up 'Another mission?' message --- 12_Bombs_Away/python/bombs_away.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/12_Bombs_Away/python/bombs_away.py b/12_Bombs_Away/python/bombs_away.py index 894f968c..a7c4ccd5 100644 --- a/12_Bombs_Away/python/bombs_away.py +++ b/12_Bombs_Away/python/bombs_away.py @@ -174,4 +174,4 @@ if __name__ == "__main__": again = True while again: play_game() - again = True if input("ANOTHER MISSION (Y OR N)").upper() == "Y" else False + again = True if input("ANOTHER MISSION? (Y OR N): ").upper() == "Y" else False From f29fa1792ce2dc0b7f161ae631a3cd63854cdf3f Mon Sep 17 00:00:00 2001 From: Bernard Cooke Date: Fri, 14 Jan 2022 01:53:41 +0000 Subject: [PATCH 323/331] Tidy logic with inline conditionals for clarity --- 12_Bombs_Away/python/bombs_away.py | 52 +++++++++++++++++++----------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/12_Bombs_Away/python/bombs_away.py b/12_Bombs_Away/python/bombs_away.py index a7c4ccd5..b3133ae3 100644 --- a/12_Bombs_Away/python/bombs_away.py +++ b/12_Bombs_Away/python/bombs_away.py @@ -8,7 +8,7 @@ import random from typing import Iterable -def _stdin_choice(*, prompt: str, choices: Iterable[str]) -> str: +def _stdin_choice(prompt: str, *, choices: Iterable[str]) -> str: ret = input(prompt) while ret not in choices: print("TRY AGAIN...") @@ -43,12 +43,22 @@ def death_with_chance(p_death: float) -> bool: def commence_non_kamikazi_attack() -> None: - nmissions = int(input("HOW MANY MISSIONS HAVE YOU FLOWN? ")) + while True: + try: + nmissions = int(input("HOW MANY MISSIONS HAVE YOU FLOWN? ")) - while nmissions >= 160: - print("MISSIONS, NOT MILES...") - print("150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS") - nmissions = int(input("NOW THEN, HOW MANY MISSIONS HAVE YOU FLOWN? ")) + while nmissions >= 160: + print("MISSIONS, NOT MILES...") + print("150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS") + nmissions = int(input("NOW THEN, HOW MANY MISSIONS HAVE YOU FLOWN? ")) + break + except ValueError: + # In the BASIC implementation this + # wasn't accounted for + print("TRY AGAIN...") + continue + else: + break if nmissions >= 100: print("THAT'S PUSHING THE ODDS!") @@ -73,7 +83,7 @@ def mission_failure() -> None: print() enemy_weapons = _stdin_choice( prompt="DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)? ", - choices=weapons_choices.keys(), + choices=weapons_choices, ) # If there are no gunners (i.e. weapon choice 2) then @@ -83,9 +93,17 @@ def mission_failure() -> None: enemy_gunner_accuracy = 0.0 if enemy_weapons != "2": # If the enemy has guns, how accurate are the gunners? - enemy_gunner_accuracy = float( - input("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? ") - ) + while True: + try: + enemy_gunner_accuracy = float( + input("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? ") + ) + break + except ValueError: + # In the BASIC implementation this + # wasn't accounted for + print("TRY AGAIN...") + continue if enemy_gunner_accuracy < 10: print("YOU LIE, BUT YOU'LL PAY...") @@ -109,7 +127,7 @@ def play_italy() -> None: } target = _stdin_choice( prompt="YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)", - choices=targets_to_messages.keys(), + choices=targets_to_messages, ) print(targets_to_messages[target]) @@ -125,7 +143,7 @@ def play_allies() -> None: } aircraft = _stdin_choice( prompt="AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4): ", - choices=aircraft_to_message.keys(), + choices=aircraft_to_message, ) print(aircraft_to_message[aircraft]) @@ -137,10 +155,7 @@ def play_japan() -> None: first_mission = input("YOUR FIRST KAMIKAZE MISSION? (Y OR N): ") if first_mission.lower() == "n": return player_death() - - if random.random() > 0.65: - return mission_success() - return player_death() + return mission_success() if random.random() > 0.65 else player_death() def play_germany() -> None: @@ -152,7 +167,7 @@ def play_germany() -> None: } target = _stdin_choice( prompt="A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\nENGLAND(2), OR FRANCE(3)? ", - choices=targets_to_messages.keys(), + choices=targets_to_messages, ) print(targets_to_messages[target]) @@ -164,8 +179,7 @@ def play_game() -> None: print("YOU ARE A PILOT IN A WORLD WAR II BOMBER.") sides = {"1": play_italy, "2": play_allies, "3": play_japan, "4": play_germany} side = _stdin_choice( - prompt="WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4): ", - choices=sides.keys(), + prompt="WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4): ", choices=sides ) return sides[side]() From 62af4c0ab2a4c64633ec39e4f7da6ec5971392a0 Mon Sep 17 00:00:00 2001 From: Bernard Cooke Date: Fri, 14 Jan 2022 08:47:21 +0000 Subject: [PATCH 324/331] Correct looping/breaking in number of missions dialogue --- 12_Bombs_Away/python/bombs_away.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/12_Bombs_Away/python/bombs_away.py b/12_Bombs_Away/python/bombs_away.py index b3133ae3..5c591f44 100644 --- a/12_Bombs_Away/python/bombs_away.py +++ b/12_Bombs_Away/python/bombs_away.py @@ -51,14 +51,12 @@ def commence_non_kamikazi_attack() -> None: print("MISSIONS, NOT MILES...") print("150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS") nmissions = int(input("NOW THEN, HOW MANY MISSIONS HAVE YOU FLOWN? ")) - break + break except ValueError: # In the BASIC implementation this # wasn't accounted for print("TRY AGAIN...") continue - else: - break if nmissions >= 100: print("THAT'S PUSHING THE ODDS!") From 8245d7badba8fdf3fe5c0123759a9e9220315238 Mon Sep 17 00:00:00 2001 From: Joe Nellis Date: Fri, 14 Jan 2022 01:42:44 -0800 Subject: [PATCH 325/331] Breakdown of the original BASIC code for re-implementers of this game. Sample code in BASIC showing distribution of right and wrong dice rolls. --- 29_Craps/README.md | 208 +++++++++++++++++++++++++++++++++++++ 29_Craps/distributions.bas | 24 +++++ 2 files changed, 232 insertions(+) create mode 100644 29_Craps/distributions.bas diff --git a/29_Craps/README.md b/29_Craps/README.md index 7372b99f..3c45c62b 100644 --- a/29_Craps/README.md +++ b/29_Craps/README.md @@ -17,3 +17,211 @@ As published in Basic Computer Games (1978): Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html + +### Comments on the BASIC code for re-implementers. + + 15 LET R=0 +`R` is a variable that tracks winnings and losings. Unlike other games that +start out with a lump sum of cash to spend this game assumes the user has as +much money as they want and we only track how much they lost or won. + + 21 LET T=1 + 22 PRINT "PICK A NUMBER AND INPUT TO ROLL DICE"; + 23 INPUT Z + 24 LET X=(RND(0)) + 25 LET T =T+1 + 26 IF T<=Z THEN 24 +This block of code does nothing other than try to scramble the random number +generator. Random number generation is not random, they are generated from the +previous generated number. Because of the slow speed of these systems back then, +gaming random number generators was a concern, mostly for gameplay quality. +If you could know the "seed value" to the generator then you could effectively +know how to get the exact same dice rolls to happen and change your bet to +maximize your winnings and minimize your losses. + +The first reason this is an example of bad coding practice is the user is asked +to input a number but no clue is given as to the use of this number. This number +has no bearing on the game and as we'll see only has bearing on the internal +implementation of somehow trying to get an un-game-able seed for the random number +generator (since all future random numbers generated are based off this seed value.) + +The `RND(1)` command generates a number from a seed value that is always +the same, everytime, from when the machine is booted up (old C64 behavior). In +order to avoid the same dice rolls being generated, a special call to `RND(-TI)` +would initialize the random generator with something else. But RND(-TI) is not +a valid command on all systems. So `RND(0)`, which generates a random number +from the system clock is used. But technically this could be gamed because the +system clock was driven by the bootup time, there wasn't a BIOS battery on these +systems that kept an internal real time clock going even when the system was +turned off, unlike your regular PC. Therefore, in order to ensure as true +randomness as possible, insert human reaction time by asking for human input. + +But a human could just be holding down the enter key on bootup and that would +just skip any kind of multi-millisecond variance assigned by a natural human +reaction time. So, paranoia being a great motivator, a number is asked of the +user to avoid just holding down the enter key which negates the timing variance +of a human reaction. + +What comes next is a bit of nonsense. The block of code loops a counter, recalling +the `RND(0)` function (and thus reseeding it with the system clock value) +and then comparing the counter to the user's number input +in order to bail out of the loop. Because the `RND(0)` function is based off the +system clock and the loop of code has no branching other than the bailout +condition, the loop also takes a fixed amount of time to execute, thus making +repeated calls to `RND(0)` predictive and this scheming to get a better random +number is pointless. Furthermore, the loop is based on the number the user inputs +so a huge number like ten million causes a very noticable delay and leaves the +user wondering if the program has errored. The author could have simply called +`RND(0)` once and used a prompt that made more sense like asking for the users +name and then using that name in the game's replies. + +It is advised that you use whatever your languages' random number generator +provides and simply skip trying to recreate this bit of nonsense including +the user input. + + 27 PRINT"INPUT THE AMOUNT OF YOUR WAGER."; + 28 INPUT F + 30 PRINT "I WILL NOW THROW THE DICE" + 40 LET E=INT(7*RND(1)) + 41 LET S=INT(7*RND(1)) + 42 LET X=E+S + .... a bit later .... + 60 IF X=1 THEN 40 + 65 IF X=0 THEN 40 + + +`F` is a variable that represents the users wager for this betting round. +`E` and `S` represent the two individual and random dice being rolled. +This code is actually wrong because it returns a value between 0 and 6. +`X` is the sum of these dice rolls. As you'll see though further down in the +code, if `X` is zero or one it re-rolls the dice to maintain a potential +outcome of the sum of two dice between 2 and 12. This skews the normal distribution +of dice values to favor lower numbers because it does not consider that `E` +could be zero and `S` could be 2 or higher. To show this skewing of values +you can run the `distribution.bas` program which creates a histogram of the +distribution of the bad dice throw code and proper dice throw code. + +Here are the results: + + DISTRIBUTION OF DICE ROLLS WITH INT(7*RND(1)) VS INT(6*RND(1)+1) + THE INT(7*RND(1)) DISTRIBUTION: + 2 3 4 5 6 7 8 9 10 11 12 + 6483 8662 10772 13232 15254 13007 10746 8878 6486 4357 2123 + THE INT(6*RND(1)+1) DISTRIBUTION + 2 3 4 5 6 7 8 9 10 11 12 + 2788 5466 8363 11072 13947 16656 13884 11149 8324 5561 2790 +If the dice rolls are fair then we should see the largest occurrence be a 7 and +the smallest should be 2 and 12. Furthermore the occurrences should be +symetrical meaning there should be roughly the same amount of 2's as 12's, the +same amount of 3's as 11's, 4's as 10's and so on until you reach the middle, 7. +But notice in the skewed dice roll, 6 is the most rolled number not 7, and the +rest of the numbers are not symetrical, there are many more 2's than 12's. +So the lesson is test your code. + +The proper way to model a dice throw, in almost every language is + `INT(6*RND(1)+1)` or `INT(6*RND(1))+1` + +SideNote: `X` was used already in the +previous code block discussed but its value was never used. This is another +poor coding practice: **Don't reuse variable names for different purposes.** + + 50 IF X=7 THEN 180 + 55 IF X=11 THEN 180 + 60 IF X=1 THEN 40 + 62 IF X=2 THEN 195 + 65 IF X=0 THEN 40 + 70 IF X=2 THEN 200 + 80 IF X=3 THEN 200 + 90 IF X=12 THEN 200 + 125 IF X=5 THEN 220 + 130 IF X =6 THEN 220 + 140 IF X=8 THEN 220 + 150 IF X=9 THEN 220 + 160 IF X =10 THEN 220 + 170 IF X=4 THEN 220 + +This bit of code determines the routing of where to go for payout, or loss. +Of course, line 60 and 65 are pointless as we've just shown and should be removed +as long as the correct dice algorithm is also changed. + + 62 IF X=2 THEN 195 + .... + 70 IF X=2 THEN 200 +The check for a 2 has already been made and the jump is done. Line 70 is +therefore redundant and can be left out. The purpose of line 62 is only to +print a special output, "SNAKE EYES!" which we'll see in the next block creates +duplicate code. + +Lines 125-170 are also pointlessly checked because we know previous values have +been ruled out, only these last values must remain, and they are all going to +the same place, line 220. Line 125-170 could have simply been replaced with +`GOTO 220` + + + + 180 PRINT X "- NATURAL....A WINNER!!!!" + 185 PRINT X"PAYS EVEN MONEY, YOU WIN"F"DOLLARS" + 190 GOTO 210 + 195 PRINT X"- SNAKE EYES....YOU LOSE." + 196 PRINT "YOU LOSE"F "DOLLARS." + 197 LET F=0-F + 198 GOTO 210 + 200 PRINT X " - CRAPS...YOU LOSE." + 205 PRINT "YOU LOSE"F"DOLLARS." + 206 LET F=0-F + 210 LET R= R+F + 211 GOTO 320 + +This bit of code manages instant wins or losses due to 7,11 or 2,3,12. As +mentioned previously, lines 196 and 197 are essentially the same as lines +205 and 206. A simpler code would be just to jump after printing the special +message of "SNAKE EYES!" to line 205. + +Lines 197 and 206 just negate the wager by subtracting it from zero. Just saying +`F = -F` would have sufficed. Line 210 updates your running total of winnings +or losses with this bet. + + 220 PRINT X "IS THE POINT. I WILL ROLL AGAIN" + 230 LET H=INT(7*RND(1)) + 231 LET Q=INT(7*RND(1)) + 232 LET O=H+Q + 240 IF O=1 THEN 230 + 250 IF O=7 THEN 290 + 255 IF O=0 THEN 230 + +This code sets the point, the number you must re-roll to win without rolling +a 7, the most probable number to roll. Except in this case again, it has the +same incorrect dice rolling code and therefore 6 is the most probable number +to roll. The concept of DRY (don't repeat yourself) is a coding practice which +encourages non-duplication of code because if there is an error in the code, it +can be fixed in one place and not multiple places like in this code. The scenario +might be that a programmer sees some wrong code, fixes it, but neglects to +consider that there might be duplicates of the same wrong code elsewhere. If +you practice DRY then you never worry much about behaviors in your code diverging +due to duplicate code snippets. + + 260 IF O=X THEN 310 + 270 PRINT O " - NO POINT. I WILL ROLL AGAIN" + 280 GOTO 230 + 290 PRINT O "- CRAPS. YOU LOSE." + 291 PRINT "YOU LOSE $"F + 292 F=0-F + 293 GOTO 210 + 300 GOTO 320 + 310 PRINT X"- A WINNER.........CONGRATS!!!!!!!!" + 311 PRINT X "AT 2 TO 1 ODDS PAYS YOU...LET ME SEE..."2*F"DOLLARS" + 312 LET F=2*F + 313 GOTO 210 + +This is the code to keep rolling until the point is made or a seven is rolled. +Again we see the negated `F` wager and lose message duplicated. This code could +have been reorganized using a subroutine, or in BASIC, the GOSUB command, but +in your language its most likely just known as a function or method. You can +do a `grep -r 'GOSUB'` from the root directory to see other BASIC programs in +this set that use GOSUB. + +The rest of the code if fairly straight forward, replay the game or end with +a report of your winnings or losings. + + + diff --git a/29_Craps/distributions.bas b/29_Craps/distributions.bas new file mode 100644 index 00000000..a963b228 --- /dev/null +++ b/29_Craps/distributions.bas @@ -0,0 +1,24 @@ +10 PRINT "DISTRIBUTION OF DICE ROLLS WITH INT(7*RND(1)) VS INT(6*RND(1)+1)" +20 DIM A(12) +30 DIM B(12) +100 FOR X = 1 TO 100000 : REM CHOOSE A LARGE NUMBER TO GET A FINER GRAINED HISTOGRAM +140 REM GET A NUMBER FROM 0 TO 6 INCLUSIVE WITH THE INTENT TO THROW AWAY ZEROES. +150 LET D1 = INT(7*RND(1)) +155 LET D2 = INT(7*RND(1)) +160 LET S1 = D1+D2 +165 REM IF THIS SUM IS LESS THAN TWO THEN TRY AGAIN. +170 IF S1<2 THEN 150 +199 REM GET A NUMBER FROM 0 TO 5 THEN ADD 1 TO IT TO MAKE IT 1 TO 6 +200 LET D3 = INT(6*RND(1))+1 +210 LET D4 = INT(6*RND(1))+1 +220 LET S2 = D3+D4 +245 REM USE OUR ARRAY AS A HISTOGRAM, COUNTING EACH OCCURRENCE OF DICE ROLL +250 A(S1) = A(S1) + 1 +260 B(S2) = B(S2) + 1 +290 NEXT X +300 PRINT "THE INT(7*RND(1)) DISTRIBUTION:" +310 FOR I = 2 TO 12 :PRINT I,:NEXT:PRINT +320 FOR I = 2 TO 12 :PRINT A(I),:NEXT:PRINT +325 PRINT "THE INT(6*RND(1)+1) DISTRIBUTION" +330 FOR I = 2 TO 12 :PRINT I,:NEXT:PRINT +340 FOR I = 2 TO 12 :PRINT B(I),:NEXT:PRINT From b4c8bfc9c8ae609713bdfa0c6024bcf6908e9ce8 Mon Sep 17 00:00:00 2001 From: Joe Nellis Date: Fri, 14 Jan 2022 01:43:24 -0800 Subject: [PATCH 326/331] Java port of BASIC Craps --- 29_Craps/java/src/Craps.java | 125 +++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 29_Craps/java/src/Craps.java diff --git a/29_Craps/java/src/Craps.java b/29_Craps/java/src/Craps.java new file mode 100644 index 00000000..483c16a9 --- /dev/null +++ b/29_Craps/java/src/Craps.java @@ -0,0 +1,125 @@ +import java.util.Random; +import java.util.Scanner; + +/** + * Port of Craps from BASIC to Java 17. + */ +public class Craps { + public static final Random random = new Random(); + + public static void main(String[] args) { + System.out.println(""" + CRAPS + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + 2,3,12 ARE LOSERS; 4,5,6,8,9,10 ARE POINTS; 7,11 ARE NATURAL WINNERS. + """); + double winnings = 0.0; + do { + winnings = playCraps(winnings); + } while (stillInterested(winnings)); + winningsReport(winnings); + } + + public static double playCraps(double winnings) { + double wager = getWager(); + System.out.println("I WILL NOW THROW THE DICE"); + int roll = rollDice(); + double payout = switch (roll) { + case 7, 11 -> naturalWin(roll, wager); + case 2, 3, 12 -> lose(roll, wager); + default -> setPoint(roll, wager); + }; + return winnings + payout; + } + + public static int rollDice() { + return random.nextInt(1, 7) + random.nextInt(1, 7); + } + + private static double setPoint(int point, double wager) { + System.out.printf("%1$ d IS THE POINT. I WILL ROLL AGAIN%n",point); + return makePoint(point, wager); + } + + private static double makePoint(int point, double wager) { + int roll = rollDice(); + if (roll == 7) + return lose(roll, wager); + if (roll == point) + return win(roll, wager); + System.out.printf("%1$ d - NO POINT. I WILL ROLL AGAIN%n", roll); + return makePoint(point, wager); // recursive + } + + private static double win(int roll, double wager) { + double payout = 2 * wager; + System.out.printf("%1$ d - A WINNER.........CONGRATS!!!!!!!!%n", roll); + System.out.printf("%1$ d AT 2 TO 1 ODDS PAYS YOU...LET ME SEE...$%2$3.2f%n", + roll, payout); + return payout; + } + + private static double lose(int roll, double wager) { + String msg = roll == 2 ? "SNAKE EYES.":"CRAPS"; + System.out.printf("%1$ d - %2$s...YOU LOSE.%n", roll, msg); + System.out.printf("YOU LOSE $%3.2f%n", wager); + return -wager; + } + + public static double naturalWin(int roll, double wager) { + System.out.printf("%1$ d - NATURAL....A WINNER!!!!%n", roll); + System.out.printf("%1$ d PAYS EVEN MONEY, YOU WIN $%2$3.2f%n", roll, wager); + return wager; + } + + public static void winningsUpdate(double winnings) { + System.out.println(switch ((int) Math.signum(winnings)) { + case 1 -> "YOU ARE NOW AHEAD $%3.2f".formatted(winnings); + case 0 -> "YOU ARE NOW EVEN AT 0"; + default -> "YOU ARE NOW UNDER $%3.2f".formatted(-winnings); + }); + } + + public static void winningsReport(double winnings) { + System.out.println( + switch ((int) Math.signum(winnings)) { + case 1 -> "CONGRATULATIONS---YOU CAME OUT A WINNER. COME AGAIN!"; + case 0 -> "CONGRATULATIONS---YOU CAME OUT EVEN, NOT BAD FOR AN AMATEUR"; + default -> "TOO BAD, YOU ARE IN THE HOLE. COME AGAIN."; + } + ); + } + + public static boolean stillInterested(double winnings) { + System.out.print(" IF YOU WANT TO PLAY AGAIN PRINT 5 IF NOT PRINT 2 "); + int fiveOrTwo = (int)getInput(); + winningsUpdate(winnings); + return fiveOrTwo == 5; + } + + public static double getWager() { + System.out.print("INPUT THE AMOUNT OF YOUR WAGER. "); + return getInput(); + } + + public static double getInput() { + Scanner scanner = new Scanner(System.in); + System.out.print("> "); + while (true) { + try { + return scanner.nextDouble(); + } catch (Exception ex) { + try { + scanner.nextLine(); // flush whatever this non number stuff is. + } catch (Exception ns_ex) { // received EOF (ctrl-d or ctrl-z if windows) + System.out.println("END OF INPUT, STOPPING PROGRAM."); + System.exit(1); + } + } + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); + System.out.print("> "); + } + } +} From 3b082b4db98b178f5db65c4e97dc66b35f451779 Mon Sep 17 00:00:00 2001 From: Alessandro Tegner Date: Fri, 14 Jan 2022 09:32:16 -0300 Subject: [PATCH 327/331] Chief in Ruby --- 25_Chief/ruby/chief.rb | 98 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 25_Chief/ruby/chief.rb diff --git a/25_Chief/ruby/chief.rb b/25_Chief/ruby/chief.rb new file mode 100644 index 00000000..c60b2519 --- /dev/null +++ b/25_Chief/ruby/chief.rb @@ -0,0 +1,98 @@ +def tab(size) + str = '' + size.times do + str += ' ' + end + + str +end + +def input + gets.chomp +end + +def bye + print "BYE!!!\n" +end + +def main + print tab(30), "CHIEF\n" + print tab(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n" + print "\n" + print "\n" + print "\n" + print "I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD.\n" + print "ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR\n" + + a = input + if a != 'YES' + print "SHUT UP, PALE FACE WITH WISE TONGUE.\n" + end + + print " TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND\n" + print "MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1.\n" + print " WHAT DO YOU HAVE\n" + + b = input.to_f + c = ((b + 1 - 5) * 5 / 8 * 5 -3).to_f + print "I BET YOUR NUMBER WAS #{c}. AM I RIGHT\n" + + d = input + if d == 'YES' + return bye + end + + print "WHAT WAS YOUR ORIGINAL NUMBER\n" + + k = input.to_f + 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?\n" + print "NOW WATCH.\n" + print k, " PLUS 3 EQUALS ", f, ". THIS DIVIDED BY 5 EQUALS ", g, ";\n" + print "THIS TIMES 8 EQUALS ", h, ". IF WE DIVIDE BY 5 AND ADD 5,\n" + print "WE GET ", i, ", WHICH, MINUS 1, EQUALS ", j, ".\n" + print "NOW DO YOU BELIEVE ME\n" + + z = input + if z == 'YES' + return bye + end + + print "YOU HAVE MADE ME MAD!!!\n" + print "THERE MUST BE A GREAT LIGHTNING BOLT!\n" + print "\n" + print "\n" + + x = 30 + while x >= 22 + print tab(x), "X X\n" + x -= 1 + end + + print tab(21), "X XXX\n" + print tab(20), "X X\n" + print tab(19), "XX X\n" + + y = 20 + while y >= 13 + print tab(y), "X X\n" + y -= 1 + end + + print tab(12), "XX\n" + print tab(11), "X\n" + print tab(10), "*\n" + + print "\n" + print "#########################\n" + print "\n" + print "I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!\n" + return bye +end + +main From f9a9a791e2e82f576cea7ef7dedb9845bfd902c5 Mon Sep 17 00:00:00 2001 From: markbernard Date: Fri, 14 Jan 2022 09:54:49 -0500 Subject: [PATCH 328/331] Add Notepad++ syntax colouring for Vintage BASIC. --- 00_Utilities/VintageBASIC.xml | 64 +++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 00_Utilities/VintageBASIC.xml diff --git a/00_Utilities/VintageBASIC.xml b/00_Utilities/VintageBASIC.xml new file mode 100644 index 00000000..4b49b888 --- /dev/null +++ b/00_Utilities/VintageBASIC.xml @@ -0,0 +1,64 @@ + + + + + + + + 00REM 01 02 03 04 + + + + + + + + - + ^ * / = <> < > <= >= + + + + + + + + + + + DATA DEF FN DIM END FOR GOSUB GOTO IF THEN INPUT LET NEXT ON PRINT RANDOMIZE REM RESTORE RETURN STOP TO + ABS ASC ATN CHR$ COS EXP INT LEFT$ LEN LOG MID$ RIGHT$ RND SGN SIN SPC SQR STR TAB TAN VAL + NOT AND OR + + + + + + 00" 01 02" 03( 04 05) 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From f6c6065bdd51f4ebbbc8222b9b02f083aa15be64 Mon Sep 17 00:00:00 2001 From: Nezumi Ronin Date: Fri, 14 Jan 2022 11:31:02 -0600 Subject: [PATCH 329/331] Create gomoko.pl Original "intelligent move" it's awful. Seems it only move below user. --- 40_Gomoko/perl/gomoko.pl | 121 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 40_Gomoko/perl/gomoko.pl diff --git a/40_Gomoko/perl/gomoko.pl b/40_Gomoko/perl/gomoko.pl new file mode 100644 index 00000000..9bd2f3db --- /dev/null +++ b/40_Gomoko/perl/gomoko.pl @@ -0,0 +1,121 @@ +#!/usr/bin/perl +use strict; + + +print ' 'x 33 . "GOMOKO\n"; +print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n"; print "\n"; print "\n"; +#my @A; +print "WELCOME TO THE ORIENTAL GAME OF GOMOKO.\n"; +print "\n"; print "THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE\n"; +print "THAT YOU SPECIFY. DURING YOUR PLAY, YOU MAY COVER ONE GRID\n"; +print "INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET\n"; +print "5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR\n"; +print "DIAGONALLY. ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED\n"; +print "WITH A '1' AND THE COMPUTER MOVES WITH A '2'.\n"; +print "\n"; print "THE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON.\n"; +print "TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\n"; print "\n"; + + +my $Ret; +my $I; +my $J; + +my @Board; +my $Size= 0; + + +while (1) { + + do { + $Size= 0; + print "WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)"; print "? "; chomp($Size = uc()); + if ($Size<7 || $Size>19) { + $Size=0; + print "I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.\n"; + } + } until ($Size); + + #==> Reset Board to zeroes... + for (my $I=1; $I<=$Size; $I++) { + for (my $J=1; $J<=$Size; $J++) { + $Board[$I][$J]= 0; + } + } + + print "\n"; print "WE ALTERNATE MOVES. YOU GO FIRST...\n"; print "\n"; + + while (1) { + do { + print "YOUR PLAY (I,J)"; print "? "; chomp(my $Inp = uc()); + ($I, $J)= split(",", $Inp); + print "\n"; + if ($I==-1) { last; } + $Ret= &ValidMove($I, $J, 1); + } until ($Ret==1); + if ($I==-1) { last; } + $Board[$I][$J]= 1; + + my $X; + my $Y; + my $Found=0; + # REM *** COMPUTER TRIES AN INTELLIGENT MOVE *** + #==> Too complex, original basic code seems only move below user. + $Ret= &ValidMove($I+1, $J); + if ($Ret==1) { + $Found=1; + $X= $I+1; + $Y= $J; + } + + while($Found==0) { + # REM *** COMPUTER TRIES A RANDOM MOVE *** + $X= int($Size*rand(1)+1); + $Y= int($Size*rand(1)+1); + $Ret= &ValidMove($X, $Y, 2); + if ($Ret==1) { $Found= 1; } + }; + $Board[$X][$Y]=2; + + &ShowBoard(); + } + + print "\n"; print "THANKS FOR THE GAME!!\n"; + print "PLAY AGAIN (1 FOR YES, 0 FOR NO)"; print "? "; chomp(my $Q = uc()); + if ($Q==0) { last; } + } + + + +exit; + + +sub ShowBoard { + for (my $I=1; $I<=$Size; $I++) { + print " "; + for (my $J=1; $J<=$Size; $J++) { + print "$Board[$I][$J] "; + } + print "\n"; + } + print "\n"; + return; + } + + +sub ValidMove { + my ($X, $Y, $Val)= @_; + if ($X<1 || $X>$Size || $Y<1 || $Y>$Size) { + if ($Val==1) { print "ILLEGAL MOVE. TRY AGAIN...\n"; } + return 0; + } + if ($Board[$X][$Y]!=0) { + if ($Val==1) { print "SQUARE OCCUPIED. TRY AGAIN...\n"; } + return 0; + } + + #$Board[$X][$Y]= $Val; + return 1; + } + + From 697697228d38520bec7bb71993d8272a4793283b Mon Sep 17 00:00:00 2001 From: imiro Date: Fri, 14 Jan 2022 12:41:42 -0600 Subject: [PATCH 330/331] 67-One Check on Python --- 67_One_Check/python/onecheck.py | 115 ++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 67_One_Check/python/onecheck.py diff --git a/67_One_Check/python/onecheck.py b/67_One_Check/python/onecheck.py new file mode 100644 index 00000000..b3d828b1 --- /dev/null +++ b/67_One_Check/python/onecheck.py @@ -0,0 +1,115 @@ +# ONE CHECK + +# Port to python by imiro + +def tab(x): + return ' '*x + +def main(): + + # Initial instructions + 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"); + 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(); + 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() + print("AND HERE IS THE OPENING POSITION OF THE CHECKERS.") + print() + + (jumps, left) = play_game() + + print() + print("YOU MADE " + jumps + " JUMPS AND HAD " + left + " PIECES") + print("REMAINING ON THE BOARD.") + print() + + if not(try_again()): + break + + print() + print("O.K. HOPE YOU HAD FUN!!") + +def play_game(): + # Initialize board + # Give more than 64 elements to accomodate 1-based indexing + board = [1]*70 + for j in range(19,44,8): + for i in range(j,j+4): + board[i] = 0 + jumps = 0 + while True: + # print board + for j in range(1,64,8): + for i in range(j,j+7): + print(board[i], end=' ') + print(board[j+7]) + print() + + while True: + print("JUMP FROM", end=' ') + f = input() + f = int(f) + if f == 0: + break + print("TO", end=' ') + t = input() + t = int(t) + print() + + # Check legality of move + f1 = ((f-1) // 8) + f2 = f - 8 * f1 + t1 = ((t-1) // 8) + t2 = t - 8 * t1 + if (f1 > 7 or t1 > 7 or f2 > 8 or t2 > 8 or abs(f1 - t1) != 2 or + abs(f2 - t2) != 2 or board[(t + f) // 2] == 0 or + board[f] == 0 or board[t] == 1): + print("ILLEGAL MOVE. TRY AGAIN...") + continue + break + + if(f == 0): + break + board[t] = 1 + board[f] = 0 + board[(t+f) // 2] = 0 + jumps = jumps + 1 + + left = 0 + for i in range(1,64+1): + left = left + board[i] + return (str(jumps), str(left)) + +def try_again(): + print("TRY AGAIN", end=' ') + answer = input() + if (answer.upper() == "YES"): + return True + elif (answer.upper() == "NO"): + return False + print("PLEASE ANSWER 'YES' OR 'NO'.") + try_again() + +if __name__ == '__main__': + main() From cb2aeed07cef61000fc5d15234666241bcd40e1c Mon Sep 17 00:00:00 2001 From: Joe Nellis Date: Fri, 14 Jan 2022 12:36:11 -0800 Subject: [PATCH 331/331] Fix dice roll computation. Remove obscure input prompt for random number generation scrambling. --- 29_Craps/javascript/craps.js | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/29_Craps/javascript/craps.js b/29_Craps/javascript/craps.js index 93351011..108f6067 100644 --- a/29_Craps/javascript/craps.js +++ b/29_Craps/javascript/craps.js @@ -42,6 +42,11 @@ function tab(space) return str; } +function roll() +{ + return Math.floor(6 * Math.random())+1 + Math.floor(6 * Math.random())+1; +} + // Main program async function main() { @@ -52,22 +57,11 @@ async function main() print("\n"); r = 0; print("2,3,12 ARE LOSERS: 4,5,6,8,9,10 ARE POINTS: 7,11 ARE NATURAL WINNERS.\n"); - t = 1; - print("PICK A NUMBER AND INPUT TO ROLL DICE"); - z = parseInt(await input()); - do { - x = Math.random(); - t++; - } while (t <= z) ; while (1) { print("INPUT THE AMOUNT OF YOUR WAGER."); f = parseInt(await input()); print("I WILL NOW THROW THE DICE\n"); - do { - e = Math.floor(7 * Math.random()); - s = Math.floor(7 * Math.random()); - x = e + s; - } while (x == 0 || x == 1) ; + x = roll(); if (x == 7 || x == 11) { print(x + " - NATURAL....A WINNER!!!!\n"); print(x + " PAYS EVEN MONEY, YOU WIN " + f + " DOLLARS\n"); @@ -83,11 +77,7 @@ async function main() } else { print(x + " IS THE POINT. I WILL ROLL AGAIN\n"); while (1) { - do { - h = Math.floor(7 * Math.random()); - q = Math.floor(7 * Math.random()); - o = h + q; - } while (o == 0 || o == 1) ; + o = roll(); if (o == 7) { print(o + " - CRAPS, YOU LOSE.\n"); print("YOU LOSE $" + f + "\n");

+ * Based on game of Cube at: + * https://github.com/coding-horror/basic-computer-games/blob/main/30_Cube/cube.bas + * + * + */ public class Cube { + //Current player location private Location playerLocation; + + //Current list of mines private Set mines; + + //System input / output objects private PrintStream out; private Scanner scanner; + //Player's current money private int money; - + /** + * Entry point, creates a new Cube object and calls the play method + * @param args Java execution arguments, not used in application + */ public static void main(String[] args) { new Cube().play(); } @@ -22,9 +39,12 @@ public class Cube { out = System.out; scanner = new Scanner(System.in); money = 500; - mines = new HashSet<>(); + mines = new HashSet<>(5); } + /** + * Clears mines and places 5 new mines on the board + */ private void placeMines() { mines.clear(); Random random = new Random(); @@ -36,6 +56,9 @@ public class Cube { } } + /** + * Runs the entire game until the player runs out of money or chooses to stop + */ public void play() { out.println("DO YOU WANT TO SEE INSTRUCTIONS? (YES--1,NO--0)"); if(readParsedBoolean()) { @@ -99,6 +122,11 @@ public class Cube { out.println("\nGOODBYE."); } + /** + * Queries the user whether they want to play another round + * @return True if the player decides to play another round, + * False if the player would not like to play again + */ private boolean doAnotherRound() { if(money > 0) { out.println("DO YOU WANT TO TRY AGAIN?"); @@ -108,6 +136,9 @@ public class Cube { } } + /** + * Prints the instructions to the game, copied from the original code. + */ public void printInstructions() { out.println("THIS IS A GAME IN WHICH YOU WILL BE PLAYING AGAINST THE"); out.println("RANDOM DECISION OF THE COMPUTER. THE FIELD OF PLAY IS A"); @@ -133,6 +164,11 @@ public class Cube { out.println("GOOD LUCK!"); } + /** + * Waits for the user to input a boolean value. This could either be (true,false), (1,0), (y,n), (yes,no), etc. + * By default, it will return false + * @return Parsed boolean value of the user input + */ private boolean readParsedBoolean() { String in = scanner.nextLine(); try { @@ -155,6 +191,9 @@ public class Cube { this.z = z; } + /* + For use in HashSet and checking if two Locations are the same + */ @Override public boolean equals(Object o) { if (this == o) return true; @@ -167,6 +206,9 @@ public class Cube { return z == location.z; } + /* + For use in the HashSet to accordingly index the set + */ @Override public int hashCode() { int result = x; From d2495a55aad12e1cad51b0497bf2eac74c5ab9c0 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 16:12:04 -0500 Subject: [PATCH 148/331] Added Comments --- 30_Cube/java/src/Cube.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/30_Cube/java/src/Cube.java b/30_Cube/java/src/Cube.java index 1237a49d..0100682a 100644 --- a/30_Cube/java/src/Cube.java +++ b/30_Cube/java/src/Cube.java @@ -178,6 +178,12 @@ public class Cube { } } + /** + * Checks if a move is valid + * @param from The point that the player is at + * @param to The point that the player wishes to move to + * @return True if the player is only moving, at most, 1 location in any direction, False if the move is invalid + */ private boolean isMoveValid(Location from, Location to) { return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) + Math.abs(from.z - to.z) <= 1; } From d2bf2e2e3b476d1c200cecc7f2d523bc4a92393d Mon Sep 17 00:00:00 2001 From: Pat Ludwig Date: Thu, 6 Jan 2022 17:17:39 -0600 Subject: [PATCH 149/331] Fix issues with spacing in intro section And bug with justification of the first two lines --- 11_Bombardment/perl/bombardment.pl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/11_Bombardment/perl/bombardment.pl b/11_Bombardment/perl/bombardment.pl index 593bd9fa..0641102e 100644 --- a/11_Bombardment/perl/bombardment.pl +++ b/11_Bombardment/perl/bombardment.pl @@ -112,8 +112,8 @@ sub populate_computer_bases { } sub print_intro { - print "" * 33 + "BOMBARDMENT\n"; - print "" * 15 + " CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; + print " " x 33, "BOMBARDMENT\n"; + print " " x 15, " CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; print "\n\n"; print "YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\n"; print "HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\n"; @@ -122,8 +122,8 @@ sub print_intro { print "THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\n"; print "OUTPOSTS OF THE COMPUTER. IT WILL DO THE SAME TO YOU.\n"; print "THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\n"; - print "FIRST IS THE WINNER.\n"; - print "GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\n"; + print "FIRST IS THE WINNER.\n\n"; + print "GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\n\n"; print "TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\n"; print "\n\n\n\n"; } From dd7def55f3c637cd25629c1b810935a9ade97303 Mon Sep 17 00:00:00 2001 From: Flavio Poletti Date: Fri, 7 Jan 2022 03:11:52 +0100 Subject: [PATCH 150/331] Add 12_Bombs_Away in Perl --- 12_Bombs_Away/perl/bombsaway.pl | 140 ++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 12_Bombs_Away/perl/bombsaway.pl diff --git a/12_Bombs_Away/perl/bombsaway.pl b/12_Bombs_Away/perl/bombsaway.pl new file mode 100644 index 00000000..dd4c4674 --- /dev/null +++ b/12_Bombs_Away/perl/bombsaway.pl @@ -0,0 +1,140 @@ +#!/usr/bin/env perl +use v5.24; +use warnings; +use experimental 'signatures'; +no warnings 'experimental::signatures'; + +exit main(@ARGV); + +sub main { + $|++; + my $mission = 'y'; + + my @choices = ( + { # 1 - Italy + ask => 'YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)', + comments => [ + q{SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.}, + 'BE CAREFUL!!!', + q{YOU'RE GOING FOR THE OIL, EH?}, + ], + }, + { # 2 - Allies + ask => 'AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)', + comments => [ + q{YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.}, + q{YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.}, + q{YOU'RE CHASING THE BISMARK IN THE NORTH SEA.}, + q{YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.}, + ], + }, + \&japan, + { # 4 - Germany + ask => "A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\n" + . 'ENGLAND(2), OR FRANCE(3)', + comments => [ + q{YOU'RE NEARING STALINGRAD.}, + q{NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR.}, + q{NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.}, + ], + }, + ); + + while (fc($mission // 'n') eq fc('y')) { + say 'YOU ARE A PILOT IN A WORLD WAR II BOMBER.'; + + my $side = choose( + 'WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)? ', 4); + my $choice = $choices[$side - 1]; + ref($choice) eq 'HASH' ? multiple($choice) : $choice->(); + + print "\n\n\nANOTHER MISSION (Y OR N)? "; + chomp($mission = ); + } + say "CHICKEN !!!\n"; + return 0; +} + +sub choose ($prompt, $n_max) { + while ('necessary') { + print "$prompt? "; + chomp(my $side = ); + return $side if $side =~ m{\A [1-9]\d* \z}mxs && $side <= $n_max; + say 'TRY AGAIN...'; + } +} + +sub multiple ($spec) { + my $target = choose("$spec->{ask}? ", scalar $spec->{comments}->@*); + say $spec->{comments}->[$target - 1]; + say ''; + + my $missions; + while ('necessary') { + print 'HOW MANY MISSIONS HAVE YOU FLOWN? '; + chomp($missions = ); + last if $missions < 160; + print 'MISSIONS, NOT MILES... +150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS. +NOW THEN, '; + } + if ($missions < 25) { say 'FRESH OUT OF TRANING, EH?' } + elsif ($missions >= 100) { say q{THAT'S PUSHING THE ODDS!} } + + return direct_hit() if $missions >= rand(160); + + my $miss = 2 + int rand(30); + say "MISSED TARGET BY $miss MILES!"; + say "NOW YOU'RE REALLY IN FOR IT !!\n"; + our $double_fire = 0; + my $response = choose( + 'DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)', 3); + if ($response < 2) { + print q{WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? }; + chomp (our $hit_rate = ); + if ($hit_rate < 10) { + say q{YOU LIE, BUT YOU'LL PAY...}; + return endgame('fail'); # sure failure + } + say ''; + } + else { + $double_fire = 35; + } + return endgame(); +} + +sub direct_hit { + my $killed = int rand(100); + say "DIRECT HIT!!!! $killed KILLED.\nMISSION SUCCESSFUL"; + return; +} + +sub endgame ($fail = 0) { + our $double_fire //= 0; + our $hit_rate //= 0; + $fail ||= ($double_fire + $hit_rate) > rand(100); + if ($fail) { + say '* * * * BOOM * * * * +YOU HAVE BEEN SHOT DOWN..... +DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR +LAST TRIBUTE...'; + } + else { + say 'YOU MADE IT THROUGH TREMENDOUS FLAK!!'; + } + return; +} + +sub japan { + say q{YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.}; + print q{YOUR FIRST KAMIKAZE MISSION(Y OR N)? }; + chomp(my $is_first_kamikaze = ); + if (fc($is_first_kamikaze) eq fc('n')) { + our $hit_rate = 0; + say ''; + return endgame(); + } + return direct_hit() if rand(1) > 0.65; + return endgame('fail'); +} From 5b0d5e1221490818c433e4a19d97f450f2a61e58 Mon Sep 17 00:00:00 2001 From: Pat Ludwig Date: Thu, 6 Jan 2022 19:49:26 -0600 Subject: [PATCH 151/331] Fix misspelling General code cleanup, including * Address code indendation * Condense print statments * Add spaces before = signs * Add spaces around operators * Simplify a few things * Use full variable names instead of single letters --- 54_Letter/perl/letter.pl | 41 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/54_Letter/perl/letter.pl b/54_Letter/perl/letter.pl index 54fb5fe0..56acf533 100755 --- a/54_Letter/perl/letter.pl +++ b/54_Letter/perl/letter.pl @@ -5,40 +5,37 @@ print ' 'x33 . "LETTER\n"; print ' 'x15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; print "\n\n\n"; -print "LETTER GUESSING GAME\n"; print "\n"; +print "LETTER GUESSING GAME\n\n"; print "I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\n"; print "TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\n"; print "AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\n"; -my $A; while (1) { - my $L= 65+int(rand(1)*26); - my $G= 0; - print "\n"; print "O.K., I HAVE A LETTER. START GUESSING.\n"; + my $letter = 65 + int(rand(26)); + my $guesses = 0; + print "\nO.K., I HAVE A LETTER. START GUESSING.\n"; + my $answer; do { - print "\n"; print "WHAT IS YOUR GUESS? "; - $G=$G+1; - chomp($A= ); - $A= ord($A); + print "\nWHAT IS YOUR GUESS? "; + $guesses++; + chomp($answer = ); + $answer = ord($answer); print "\n"; - if ($A<$L) { print "TOO LOW. TRY A HIGHER LETTER.\n"; } - if ($A>$L) { print "TOO HIGH. TRY A LOWER LETTER.\n"; } - } until($A eq $L); + print "TOO LOW. TRY A HIGHER LETTER.\n" if $answer < $letter; + print "TOO HIGH. TRY A LOWER LETTER.\n" if $answer > $letter; + } until($answer eq $letter); - print "\n"; print "YOU GOT IT IN $G GUESSES!!\n"; + print "\nYOU GOT IT IN $guesses GUESSES!!\n"; - if ($G<=5) { + if ($guesses <= 5) { print "GOOD JOB !!!!!\n"; - for (my $N=1; $N<=15; $N++) { print chr(7); } #ASCII Bell. - } else { + print chr(7) x 15; # ASCII Bell + } else { print "BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\n"; - } - - print "\n"; - print "LET'S PLAN AGAIN.....\n"; } + print "\nLET'S PLAY AGAIN.....\n"; +} + exit; - - From c2358069574050e33ee4fbb101594d246828099f Mon Sep 17 00:00:00 2001 From: James Allenspach Date: Thu, 6 Jan 2022 20:23:53 -0600 Subject: [PATCH 152/331] Initial commit --- 62_Mugwump/perl/mugwump.pl | 96 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100755 62_Mugwump/perl/mugwump.pl diff --git a/62_Mugwump/perl/mugwump.pl b/62_Mugwump/perl/mugwump.pl new file mode 100755 index 00000000..356c9983 --- /dev/null +++ b/62_Mugwump/perl/mugwump.pl @@ -0,0 +1,96 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +# global variables defined here +my(@MUGWUMP) = (); + +# subroutines defined here + +# init_mugwump: pick the random places for the Mugwumps +sub init_mugwump() { + @MUGWUMP = (); + for (1 .. 4) { + push @MUGWUMP, [ int(rand 10), int(rand 10) ]; + } +} + + +# main code starts here + +# print introductory text +print <); + my($M,$N) = split(/,/,$in); + $M = int($M); + $N = int($N); + + for my $i (0 .. $#MUGWUMP) { + # -1 indicates a Mugwump that was already found + next if $MUGWUMP[$i]->[0] == -1; + + if ($MUGWUMP[$i]->[0] == $M && $MUGWUMP[$i]->[1] == $N) { + $MUGWUMP[$i]->[0] = -1; + printf("You have found Mugwump %d\n", $i+1); + } else { + my $d = sqrt(($MUGWUMP[$i]->[0] - $M) ** 2 + ($MUGWUMP[$i]->[1] - $N) ** 2); + printf("You are %.1f units away from Mugwump %d\n", $d, $i+1); + } + } + + # If a Mugwump still has not been found, + # go to the next turn + for my $j (0 .. $#MUGWUMP) { + if ($MUGWUMP[$j]->[0] != -1) { + next TURN; + } + } + # You win! + printf("You got all of them in %d %s!\n\n", $turn, ($turn == 1 ? 'turn' : 'turns')); + # Pass execution down to the continue block + next PLAY; + + } # end of TURN loop + + print "\nSorry, that's 10 tries. Here's where they're hiding:\n"; + for my $i (0 .. $#MUGWUMP) { + printf("Mugwump %d is at (%d, %d)\n", $i+1, $MUGWUMP[$i]->[0], $MUGWUMP[$i]->[1]) + if $MUGWUMP[$i]->[0] != -1; + } +} +continue { + print "\nThat was fun! Let's play again.......\n"; + print "Four more Mugwumps are now in hiding.\n\n"; +} + From dbc02ecf611f001fe434a7b343be61d8d76e19ae Mon Sep 17 00:00:00 2001 From: James Allenspach Date: Thu, 6 Jan 2022 20:25:06 -0600 Subject: [PATCH 153/331] typo --- 62_Mugwump/perl/mugwump.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/62_Mugwump/perl/mugwump.pl b/62_Mugwump/perl/mugwump.pl index 356c9983..d02a9036 100755 --- a/62_Mugwump/perl/mugwump.pl +++ b/62_Mugwump/perl/mugwump.pl @@ -33,7 +33,7 @@ number between 0 and 9, inclusive. First number is distance to right of homebase and second number is distance above homebase. -You get 10 tries. After each try, i will tell +You get 10 tries. After each try, I will tell you how far you are from each Mugwump. HERE From 03a18e473ab64753262d9099569534edf64775f3 Mon Sep 17 00:00:00 2001 From: Pat Ludwig Date: Thu, 6 Jan 2022 22:09:04 -0600 Subject: [PATCH 154/331] Fix enemy fire Choice 3, both should apply both $double_fire and $hit_rate --- 12_Bombs_Away/perl/bombsaway.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/12_Bombs_Away/perl/bombsaway.pl b/12_Bombs_Away/perl/bombsaway.pl index dd4c4674..478d01a7 100644 --- a/12_Bombs_Away/perl/bombsaway.pl +++ b/12_Bombs_Away/perl/bombsaway.pl @@ -89,7 +89,7 @@ NOW THEN, '; our $double_fire = 0; my $response = choose( 'DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)', 3); - if ($response < 2) { + if ($response != 2) { print q{WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? }; chomp (our $hit_rate = ); if ($hit_rate < 10) { @@ -98,7 +98,7 @@ NOW THEN, '; } say ''; } - else { + if ($response > 1) { $double_fire = 35; } return endgame(); From 6dda7ce25a7311af6acca01554249a5074f77588 Mon Sep 17 00:00:00 2001 From: RibTips <36372030+ribtips@users.noreply.github.com> Date: Fri, 7 Jan 2022 02:46:39 -0500 Subject: [PATCH 155/331] 89_TicTacToe in perl --- 89_Tic-Tac-Toe/perl/tictactoe2.pl | 197 ++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 89_Tic-Tac-Toe/perl/tictactoe2.pl diff --git a/89_Tic-Tac-Toe/perl/tictactoe2.pl b/89_Tic-Tac-Toe/perl/tictactoe2.pl new file mode 100644 index 00000000..4bd12cf7 --- /dev/null +++ b/89_Tic-Tac-Toe/perl/tictactoe2.pl @@ -0,0 +1,197 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +#GLOBALs +my %board = ( + 1 => 0, + 2 => 0, + 3 => 0, + 4 => 0, + 5 => 0, + 6 => 0, + 7 => 0, + 8 => 0, + 9 => 0, +); + +my %winning_combos = ( + 1 => [1,2,3], + 2 => [4,5,6], + 3 => [7,8,9], + 4 => [1,4,7], + 5 => [2,5,8], + 6 => [3,6,9], + 7 => [1,5,9], + 8 => [7,5,3], +); + +my $player=100; +my $player_goal=0; +my $computer=100; +my $computer_goal=0; +my $count=0; + +&main; + +sub main { + &print_intro; + print "DO YOU WANT 'X' OR 'O'\n"; + chomp(my $ans = ); + &assign_X_and_O($ans); + if ($ans eq "X") { + until ($count >= 9) { + &player_choice; + $count++; + &print_board; + &check_for_winners; + &computer_choice; + $count++; + &print_board; + &check_for_winners; + } + } + else { + until ($count >= 9) { + &computer_choice; + $count++; + &print_board; + &check_for_winners; + &player_choice; + $count++; + &print_board; + &check_for_winners; + } + } + print "IT'S A DRAW. THANK YOU.\n"; +} + +sub check_for_winners { + my %tally; + foreach my $key (keys %winning_combos) { + foreach my $val (@{$winning_combos{$key}}) { + $tally{$key}+=$board{$val}; + } + } + foreach my $key (keys %tally) { + if ($tally{$key} == $player_goal) { + print "YOU BEAT ME!! GOOD GAME.\n"; + exit; + } + if ($tally{$key} == $computer_goal) { + print "I WIN, TURKEY!!!\n"; + exit; + } + } +} + +sub computer_choice { + my $move; + $move=&check_for_blocks_or_wins;; + if ($move > 9) { + $move=&check_for_corners; + } + print "THE COMPUTER MOVES TO...\n"; + $board{$move}=$computer; +} + +sub check_for_corners { + my @precedence; + if ($count == 0) { + @precedence=(1,9,7,3,5,2,4,6,8); + } + else { + @precedence=(5,1,9,7,3,2,4,6,8); + } + foreach my $move (@precedence) { + my $validity=&check_occupation($move); + if ($validity eq "valid") { + return $move; + } + } +} + +sub check_for_blocks_or_wins { + my %tally; + my $validity = "invalid"; + my $move = 10; + foreach my $key (keys %winning_combos) { + foreach my $val (@{$winning_combos{$key}}) { + $tally{$key}+=$board{$val}; + } + } + foreach my $key (keys %tally) { + if (abs($tally{$key}) == 2) { + until ($validity eq "valid") { + foreach my $val (@{$winning_combos{$key}}) { + $validity=&check_occupation($val); + if ($validity eq "valid") { + $move = $val; + last; + } + } + } + return $move; + } + } + return $move; +} + +sub player_choice { + my $validity = "invalid"; + my $ans = ""; + until ($validity eq "valid") { + print "WHERE DO YOU MOVE? "; + chomp($ans = ); + $validity=&check_occupation($ans); + if ($validity eq "invalid") {print "THAT SQUARE IS OCCUPIED.\n\n"} + } + $board{$ans}=$player; +} + +sub check_occupation { + my $space = shift; + if ($board{$space}==0) { return "valid" } + else {return "invalid"}; +} + +sub print_board { + foreach my $num (1..9) { + my $char = &which_char($board{$num}); + if ($num == 4 || $num == 7) { print "\n---+---+---\n";} + print "$char"; + if ($num % 3 > 0) { print "!" } + } + print "\n"; +} + +sub which_char { + my $val=shift; + if ($val == 0) {return " ";} + elsif ($val == 1) {return " X ";} + else {return " O ";} +} + +sub assign_X_and_O { + my $ans = shift; + if ($ans eq "X") { + $player = 1; + $computer = -1; + $player_goal=3; + $computer_goal=-3; + } + else { + $player = -1; + $computer = 1; + $player_goal=-3; + $computer_goal=3; + } +} + +sub print_intro { + print ' ' x 30 . "TIC-TAC-TOE\n"; + print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"; + print "THE BOARD IS NUMBERED:\n"; + print "1 2 3\n4 5 6\n7 8 9\n\n\n"; +} From 8c8a00df0f94d5b7f1d3e315eef0381ce051af93 Mon Sep 17 00:00:00 2001 From: RibTips <36372030+ribtips@users.noreply.github.com> Date: Fri, 7 Jan 2022 02:58:35 -0500 Subject: [PATCH 156/331] 89_TicTacToe2 in perl --- 89_Tic-Tac-Toe/perl/tictactoe2.pl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/89_Tic-Tac-Toe/perl/tictactoe2.pl b/89_Tic-Tac-Toe/perl/tictactoe2.pl index 4bd12cf7..e7448e3e 100644 --- a/89_Tic-Tac-Toe/perl/tictactoe2.pl +++ b/89_Tic-Tac-Toe/perl/tictactoe2.pl @@ -67,6 +67,7 @@ sub main { print "IT'S A DRAW. THANK YOU.\n"; } +# This will check to see if anyone has won by adding up the various 3-in-a-row lines. sub check_for_winners { my %tally; foreach my $key (keys %winning_combos) { @@ -86,6 +87,8 @@ sub check_for_winners { } } +#On the computer's turn it will first check to see if it should block the player. If it finds it isn't going to win or need to block a player, the it will choose a spot to place it's X or O. + sub computer_choice { my $move; $move=&check_for_blocks_or_wins;; From 1348086a12806a12caacfcc958909f21b8b91e09 Mon Sep 17 00:00:00 2001 From: Flavio Poletti Date: Fri, 7 Jan 2022 09:34:08 +0100 Subject: [PATCH 157/331] Commented and fixed code --- 12_Bombs_Away/perl/bombsaway.pl | 225 ++++++++++++++++++++++---------- 1 file changed, 156 insertions(+), 69 deletions(-) diff --git a/12_Bombs_Away/perl/bombsaway.pl b/12_Bombs_Away/perl/bombsaway.pl index 478d01a7..70d8850e 100644 --- a/12_Bombs_Away/perl/bombsaway.pl +++ b/12_Bombs_Away/perl/bombsaway.pl @@ -10,97 +10,192 @@ sub main { $|++; my $mission = 'y'; - my @choices = ( - { # 1 - Italy - ask => 'YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)', - comments => [ - q{SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.}, - 'BE CAREFUL!!!', - q{YOU'RE GOING FOR THE OIL, EH?}, - ], - }, - { # 2 - Allies - ask => 'AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)', - comments => [ - q{YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.}, - q{YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.}, - q{YOU'RE CHASING THE BISMARK IN THE NORTH SEA.}, - q{YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.}, - ], - }, - \&japan, - { # 4 - Germany - ask => "A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\n" - . 'ENGLAND(2), OR FRANCE(3)', - comments => [ - q{YOU'RE NEARING STALINGRAD.}, - q{NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR.}, - q{NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.}, - ], - }, - ); + # first-level choices will allow us to select the "right" callback + # function to start each mission + my @choices = (\&italy, \&allies, \&japan, \&germany); + # to support being case-insensitive "the right way" we apply the fc() + # function (i.e. "fold case"). This is slightly overkill in this case + # but it's better to stick to good habits. while (fc($mission // 'n') eq fc('y')) { say 'YOU ARE A PILOT IN A WORLD WAR II BOMBER.'; my $side = choose( - 'WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)? ', 4); - my $choice = $choices[$side - 1]; - ref($choice) eq 'HASH' ? multiple($choice) : $choice->(); + 'WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)', 4); - print "\n\n\nANOTHER MISSION (Y OR N)? "; - chomp($mission = ); + # arrays start from 0 in Perl, so our starting-from-1 side value + # has to be offset by 1. + $choices[$side - 1]->(); + + $mission = get_input("\n\n\nANOTHER MISSION (Y OR N)"); } - say "CHICKEN !!!\n"; - return 0; + __exit(); } +# unified exit function, make sure to shame the desertor! +sub __exit ($prefix = '') { + say $prefix, "CHICKEN !!!\n"; + exit 0; +} + +# unified input gathering. Checks if the input is closed (e.g. because the +# player hit CTRL-D) and __exit()s in case. Gets a prompt for asking a +# question, returns whatever is input (except spaces). +sub get_input ($prompt) { + print "$prompt? "; + defined(my $input = ) or __exit("\n"); + + # remove spaces from the input (including newlines), they are not used + + $input =~ s{\s+}{}gmxs; + return $input; +} + +# structured choosing function, gets a $prompt for asking a question and +# will iterate asking until the input is a number between 1 and $n_max. sub choose ($prompt, $n_max) { while ('necessary') { - print "$prompt? "; - chomp(my $side = ); + my $side = get_input($prompt); return $side if $side =~ m{\A [1-9]\d* \z}mxs && $side <= $n_max; say 'TRY AGAIN...'; } } -sub multiple ($spec) { - my $target = choose("$spec->{ask}? ", scalar $spec->{comments}->@*); - say $spec->{comments}->[$target - 1]; - say ''; +# Italy mission has the same structure as Allies and Germany, so it's been +# refactored into a single "multiple()" (pun intended) function, providing +# the right messaging. +sub italy { + return multiple( + 'YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)', + q{SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.}, + 'BE CAREFUL!!!', + q{YOU'RE GOING FOR THE OIL, EH?}, + ); +} + +# Allies mission has the same structure as Italy and Germany, so it's been +# refactored into a single "multiple()" (pun intended) function, providing +# the right messaging. +sub allies { + return multiple( + 'AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)', + q{YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.}, + q{YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.}, + q{YOU'RE CHASING THE BISMARK IN THE NORTH SEA.}, + q{YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.}, + ); +} + +# Japan mission is different from the other three and is coded... +# differently. The end game phases are the same as other missions though, +# hence the calls to "direct_hit()" and "endgame()" functions. +sub japan { + say q{YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.}; + my $is_first_kamikaze = get_input(q{YOUR FIRST KAMIKAZE MISSION(Y OR N)}); + if (fc($is_first_kamikaze) eq fc('n')) { + our $guns_hit_rate = 0; + say ''; + return endgame(); + } + return direct_hit() if rand(1) > 0.65; + return endgame('fail'); +} + +# Germany mission has the same structure as Italy and Allies, so it's been +# refactored into a single "multiple()" (pun intended) function, providing +# the right messaging. +sub germany { + return multiple( + "A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\n" + . 'ENGLAND(2), OR FRANCE(3)', + q{YOU'RE NEARING STALINGRAD.}, + q{NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR.}, + q{NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.} + ); +} + +# This function implements the workhorse for Italy, Allies and Germany +# missions, which all have the same structure. It starts with a $question +# and a few @comments, each commenting every different answer to the +# $question. +sub multiple ($question, @comments) { + my $target = choose($question, scalar @comments); + say "\n", $comments[$target - 1], "\n"; + + # we gather the number of missions flown so far so that we can + # use it to figure out if *this* mission will be successful. The more + # the missions flown, the higher the probability of success. my $missions; while ('necessary') { - print 'HOW MANY MISSIONS HAVE YOU FLOWN? '; - chomp($missions = ); + $missions = get_input('HOW MANY MISSIONS HAVE YOU FLOWN'); last if $missions < 160; print 'MISSIONS, NOT MILES... 150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS. NOW THEN, '; } - if ($missions < 25) { say 'FRESH OUT OF TRANING, EH?' } - elsif ($missions >= 100) { say q{THAT'S PUSHING THE ODDS!} } + say ''; + # a little intermediate comment based on the value of $missions + if ($missions < 25) { say "FRESH OUT OF TRANING, EH?\n" } + elsif ($missions >= 100) { say "THAT'S PUSHING THE ODDS!\n" } + + # let's roll a 160-faced die and compare to the missions flown so far, + # player might not even have to engage in combat! return direct_hit() if $missions >= rand(160); + # player didn't get a direct hit on the target, so we provide a + # feedback about how much it was apart. This is part of the story. my $miss = 2 + int rand(30); say "MISSED TARGET BY $miss MILES!"; say "NOW YOU'RE REALLY IN FOR IT !!\n"; - our $double_fire = 0; + + # here is where the game shows a little "weakness", although it might + # have been done on purpose. We use "our" variables $missiles_hit_rate + # and $guns_hit_rate here because the original BASIC code did not reset + # the associated variables (respectively T and S) at every mission, thus + # leaking state from one mission to the following ones. + # + # In particular, both are leaked to the Japan mission(s), and + # $guns_hit_rate is leaked to future "multiple()" missions that have + # missiles only. + # + # This is what you get when your language only has global variables. + # + # Of course, this might have been done on purpose, and we'll replicate + # this behaviour here because it adds some randomness to the game. + our $missiles_hit_rate = 0; my $response = choose( 'DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)', 3); - if ($response != 2) { - print q{WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? }; - chomp (our $hit_rate = ); - if ($hit_rate < 10) { + + if ($response != 2) { # there's some guns involved, ask more + say ''; + + # see comment above as to why we have a "our" variable here + our $guns_hit_rate = + get_input(q{WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)}); + + # let's normalize the input a bit + $guns_hit_rate = 0 unless $guns_hit_rate =~ m{\A [1-9]\d* \z}mxs; + + # a hit rate this low is not reasonable and is immediately punished! + if ($guns_hit_rate < 10) { say q{YOU LIE, BUT YOU'LL PAY...}; + + # function endgame() provides the... end game messaging, which is + # also used by the Japan mission, so it's been factored out. + # Passing 'fail' (or any true value) makes sure that is' a + # failure. return endgame('fail'); # sure failure } say ''; } - if ($response > 1) { - $double_fire = 35; + else { + $missiles_hit_rate = 35; # remember... this is a global variable } + + # hand control over to the "endgame()" refactored function (also shared + # by the Japan mission). return endgame(); } @@ -110,10 +205,15 @@ sub direct_hit { return; } +# This function provides the end game randomization and messages, shared +# across all missions. If passed a true value $fail, it will make sure that +# the outcome is... a failure. This allows coping with a few ad-hoc +# GOTO:s in the original BASIC code, while still preserving a refactored +# code. sub endgame ($fail = 0) { - our $double_fire //= 0; - our $hit_rate //= 0; - $fail ||= ($double_fire + $hit_rate) > rand(100); + our $missiles_hit_rate //= 0; + our $guns_hit_rate //= 0; + $fail ||= ($missiles_hit_rate + $guns_hit_rate) > rand(100); if ($fail) { say '* * * * BOOM * * * * YOU HAVE BEEN SHOT DOWN..... @@ -125,16 +225,3 @@ LAST TRIBUTE...'; } return; } - -sub japan { - say q{YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.}; - print q{YOUR FIRST KAMIKAZE MISSION(Y OR N)? }; - chomp(my $is_first_kamikaze = ); - if (fc($is_first_kamikaze) eq fc('n')) { - our $hit_rate = 0; - say ''; - return endgame(); - } - return direct_hit() if rand(1) > 0.65; - return endgame('fail'); -} From 74326a5c08320a72e8782b6672d9a5b9b546a178 Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Fri, 7 Jan 2022 07:07:33 -0500 Subject: [PATCH 158/331] Port of 81_Splat to Perl. Pretty much a straight port -- just straightened out the spaghetti in the original BASIC. --- 81_Splat/perl/splat.pl | 597 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 597 insertions(+) create mode 100755 81_Splat/perl/splat.pl diff --git a/81_Splat/perl/splat.pl b/81_Splat/perl/splat.pl new file mode 100755 index 00000000..459bc790 --- /dev/null +++ b/81_Splat/perl/splat.pl @@ -0,0 +1,597 @@ +#!/usr/bin/env perl + +use 5.010; # To get 'state' and 'say' + +use strict; # Require explicit declaration of variables +use warnings; # Enable optional compiler warnings + +use English; # Use more friendly names for Perl's magic variables +use List::Util qw{ shuffle }; # Shuffle an array. +use Scalar::Util qw{ looks_like_number }; +use Term::ReadLine; # Prompt and return user input + +our $VERSION = '0.000_01'; + +use constant ROW_TPLT => ( '%4d' x 8 ) . "\n"; + +print <<'EOD'; + SPLAT + Creative Computing Morristown, New Jersey + + + +Welcome to 'Splat' -- the game that simulates a parachute +jump. Try to open your chute at the last possible +moment without going splat. +EOD + +while ( 1 ) { + say ''; + my $initial_altitude = int( 9001 * rand() + 1000 ); + + my $nominal_terminal_velocity; + if ( get_yes_no( 'Select your own terminal velocity' ) ) { + $nominal_terminal_velocity = get_input( + 'What terminal velocity (mi/hr)? ', + sub { looks_like_number( $ARG ) && $ARG > 0 }, + 'Please enter a positive number', + ); + # Convert miles per hour to feet per second + $nominal_terminal_velocity = $nominal_terminal_velocity * 5280 / 3600; + } else { + $nominal_terminal_velocity = int( 1000 * rand() ); + say "OK. Terminal velocity = $nominal_terminal_velocity mi/hr" + } + my $terminal_velocity = dither( $nominal_terminal_velocity ); + + my $nominal_gravity; # Acceleration due to gravity + if ( get_yes_no( 'Want to select acceleration due to gravity' ) ) { + } else { + state $body = [ + [ q, + 12.2 ], + [ q, + 28.3 ], + [ q, + 32.16 ], + [ q, + 5.15 ], + [ q, + 12.5 ], + [ q, + 85.2 ], + [ q, + 37.6 ], + [ q, + 33.8 ], + [ q, + 39.6 ], + [ q, + 896 ], + ]; + my $pick = $body->[ rand scalar @{ $body } ]; + say $pick->[0]; + $nominal_gravity = $pick->[1]; + } + my $gravity = dither( $nominal_gravity ); + + print <<"EOD"; + + Altitude = $initial_altitude ft + Term. velocity = $nominal_terminal_velocity ft/sec +/- 5% + Acceleration = $nominal_gravity ft/sec/sec +/- 5% +Set the timer for your freefall +EOD + + my $drop_time = get_input( + 'How many seconds? ', + sub { m/ \A [0-9]+ \z /smx }, + "Please enter an unsigned integer\n", + ); + + print <<'EOD'; +Here we go. + +Time (sec) Dist to fall (ft) +========== ================= +EOD + + if ( defined( my $altitude = make_jump( + $initial_altitude, + $gravity, + $terminal_velocity, + $drop_time ) ) + ) { + # Successful jump + state $succesful = []; + state $ordinal = [ qw{ 1st 2nd 3rd } ]; + if ( defined( my $ord = $ordinal->[ @{ $succesful } ] ) ) { + say "Amazing!!! Not nad for your $ord successful jump!!!"; + } else { + my $jumps = @{ $succesful }; + my $worse = grep { $_ > $altitude } @{ $succesful }; + my $fractile = 1 - $worse / $jumps; + my $better = $jumps - $worse; + if ( $fractile <= 0.1 ) { + print <<"EOD"; +Wow! That's some jumping. Of the $jumps successful jumps +before yours, only $better opened their chutes lower than +you did. +EOD + } elsif ( $fractile <= 0.25 ) { + print <<"EOD"; +Pretty good! $jumps successful jumps preceded yours and only +$better of them got lower than you did before their chutes +opened. +EOD + } elsif ( $fractile <= 0.5 ) { + print <<"EOD"; +Not bad. There have been $jumps successful jumps before yours. +You were beaten out by $better of them. +EOD + } elsif ( $fractile <= 0.75 ) { + print <<"EOD"; +Conservative, aren't you? You ranked only $better in the +$jumps successful jumps before yours. +EOD + } elsif ( $fractile <= 0.9 ) { + print <<"EOD"; +Humph! Don't you have any sporting blood? There were +$jumps successful jumps before yours and you came in $worse jumps +better than the worst. Shape up!!! +EOD + } else { + print <<"EOD"; +Hey! You pulled the rip cord much too soon. $jumps successful +jumps before yours and you came in number $better! Get with it! +EOD + } + } + push @{ $succesful }, $altitude; + } else { + # Splat + + say q; + } + + next if get_yes_no( 'Do you want to play again' ); + next if get_yes_no( 'Please' ); + + print <<'EOD'; +Ssssssssss. + +EOD + last; + +} + +# Return the first argument modified by up to plus or minus some +# fraction specified by the second argument (default 0.05) +sub dither { + my ( $arg, $fract ) = @_; + $fract //= 1 / 20; + return $arg + ( $arg * rand() * $fract ) - ( $arg * rand() * $fract ); +} + +use constant FORMAT_FALL => "%10.1f %10d\n"; +use constant FORMAT_SPLAT => "%10.1f %s\n"; +sub make_jump { + my ( $initial_altitude, $gravity, $terminal_velocity, $drop_time ) = @_; + my $altitude; + foreach my $step ( 0 .. 8 ) { + my $time = $step * $drop_time / 8; + if ( $time > $terminal_velocity / $gravity ) { + # Terminal velocity reached + printf "Terminal velocity reached at T plus %.2f seconds.\n", + $terminal_velocity / $gravity; + for my $step ( $step .. 8 ) { + my $time = $step * $drop_time / 8; + $altitude = $initial_altitude - ( + $terminal_velocity * $terminal_velocity / + ( 2 * $gravity ) + $terminal_velocity * ( + $time - $terminal_velocity / $gravity ) ); + if ( $altitude > 0 ) { + printf FORMAT_FALL, $time, $altitude; + } else { + splat( + $terminal_velocity / $gravity + ( + $initial_altitude - + $terminal_velocity * $terminal_velocity / + ( 2 * $gravity ) ) / $terminal_velocity, + ); + return; + } + } + last; + } else { + $altitude = $initial_altitude - $gravity / 2 * $time * $time; + if ( $altitude > 0 ) { + printf FORMAT_FALL, $time, $altitude; + } else { + splat( sqrt( 2 * $initial_altitude / $gravity ) ); + return; + } + } + } + + say 'Chute open.'; + return $altitude; +} + +sub splat { + my ( $time ) = @_; + printf FORMAT_SPLAT, $time, 'Splat!'; + state $rip = [ + q, + q, + q, + q, + q<#$%&&%!$>, + q, + q, + q, + q, + q, + ]; + say $rip->[ rand scalar @{ $rip } ]; + return; +} + +# Get input from the user. The arguments are: +# * The prompt +# * A reference to validation code. This code receives the response in +# $ARG and returns true for a valid response. +# * A warning to print if the response is not valid. This must end in a +# return. +# The first valid response is returned. An end-of-file terminates the +# script. +sub get_input { + my ( $prompt, $validate, $warning ) = @ARG; + + # If no validator is passed, default to one that always returns + # true. + $validate ||= sub { 1 }; + + # Create the readline object. The 'state' causes the variable to be + # initialized only once, no matter how many times this subroutine is + # called. The do { ... } is a compound statement used because we + # need to tweak the created object before we store it. + state $term = do { + my $obj = Term::ReadLine->new( 'reverse' ); + $obj->ornaments( 0 ); + $obj; + }; + + while ( 1 ) { # Iterate indefinitely + + # Read the input into the topic variable, localized to prevent + # Spooky Action at a Distance. We exit on undef, which signals + # end-of-file. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Return the input if it is valid. + return $ARG if $validate->(); + + # Issue the warning, and go around the merry-go-round again. + warn $warning; + } +} + +# Get a yes-or-no answer. The argument is the prompt, which will have +# '? [y/n]: ' appended. The donkey work is done by get_input(), which is +# requested to validate the response as beginning with 'y' or 'n', +# case-insensitive. The return is a true value for 'y' and a false value +# for 'n'. +sub get_yes_no { + my ( $prompt ) = @ARG; + state $map_answer = { + n => 0, + y => 1, + }; + my $resp = lc get_input( + "$prompt? [y/n]: ", + sub { m/ \A [yn] /smxi }, + "Please respond 'y' or 'n'\n", + ); + return $map_answer->{ substr $resp, 0, 1 }; +} + +__END__ + +print <<'EOD' if get_yes_no( 'Do you want instructions' ); +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. + + +EOD + +while ( 1 ) { + + say ''; + + foreach my $row ( 0 .. 7 ) { + printf ROW_TPLT, map { ( $_ + $row ) * 10 + $row + 1 } reverse 1 .. 8; + } + +} + +# Get input from the user. The arguments are: +# * The prompt +# * A reference to validation code. This code receives the response in +# $ARG and returns true for a valid response. +# * A warning to print if the response is not valid. This must end in a +# return. +# The first valid response is returned. An end-of-file terminates the +# script. +sub get_input { + my ( $prompt, $validate, $warning ) = @ARG; + + # If no validator is passed, default to one that always returns + # true. + $validate ||= sub { 1 }; + + # Create the readline object. The 'state' causes the variable to be + # initialized only once, no matter how many times this subroutine is + # called. The do { ... } is a compound statement used because we + # need to tweak the created object before we store it. + state $term = do { + my $obj = Term::ReadLine->new( 'reverse' ); + $obj->ornaments( 0 ); + $obj; + }; + + while ( 1 ) { # Iterate indefinitely + + # Read the input into the topic variable, localized to prevent + # Spooky Action at a Distance. We exit on undef, which signals + # end-of-file. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Return the input if it is valid. + return $ARG if $validate->(); + + # Issue the warning, and go around the merry-go-round again. + warn $warning; + } +} + +# Get a yes-or-no answer. The argument is the prompt, which will have +# '? [y/n]: ' appended. The donkey work is done by get_input(), which is +# requested to validate the response as beginning with 'y' or 'n', +# case-insensitive. The return is a true value for 'y' and a false value +# for 'n'. +sub get_yes_no { + my ( $prompt ) = @ARG; + state $map_answer = { + n => 0, + y => 1, + }; + my $resp = lc get_input( + "$prompt? [y/n]: ", + sub { m/ \A [yn] /smxi }, + "Please respond 'y' or 'n'\n", + ); + return $map_answer->{ substr $resp, 0, 1 }; +} + +__END__ +# Display the rules if desired. There is no straightforward way to +# interpolate a manifest constant into a string, but @{[ ... ]} will +# interpolate any expression. +print <<"EOD" if get_yes_no( 'Do you want the rules' ); + +This is the game of 'Reverse'. To win, all you have +to do is arrange a list of numbers (1 through @{[ NUMBER_OF_NUMBERS ]}) +in numerical order from left to right. To move, you +tell me how many numbers (counting from the left) to +reverse. For example, if the current list is: + +2 3 4 5 1 6 7 8 9 + +and you reverse 4, the result will be: + +5 4 3 2 1 6 7 8 9 + +Now if you reverse 5, you win! + +1 2 3 4 5 6 7 8 9 + +No doubt you will like this game, but +if you want to quit, reverse 0 (zero). + +EOD + +while ( 1 ) { # Iterate until something interrupts us. + + # Populate the list with the integers from 1, shuffled. If we + # accidentally generate a winning list, just redo the loop. + my @list = shuffle( 1 .. NUMBER_OF_NUMBERS ); + redo if is_win( \@list ); + + print <<"EOD"; + +Here we go ... The list is: +EOD + + my $moves = 0; # Move counter + + while ( 1 ) { # Iterate until something interrupts us. + print <<"EOD"; + +@list + +EOD + + # Read the number of values to reverse. Zero is special-cased to + # take us out of this loop. + last unless my $max_index = get_input( + 'How many shall I reverse (0 to quit)? ', + sub { + return m/ \A [0-9]+ \z /smx && + $ARG <= NUMBER_OF_NUMBERS; + }, + "Oops! Too many! I can reverse at most " . + NUMBER_OF_NUMBERS, + ); + + --$max_index; # Convert number to reverse to upper index + + # Use a Perl array slice and the reverse() built-in to reverse + # the beginning of the list. + @list[ 0 .. $max_index ] = reverse @list[ 0 .. $max_index ]; + + $moves++; # Count a move + + # If we have not won, iterate again. + next unless is_win( \@list ); + + # Announce the win, and drop out of the loop. + print <<"EOD"; + +You won it in $moves moves!!! +EOD + last; + } + + # Drop out of this loop unless the player wants to play again. + say ''; + last unless get_yes_no( 'Try again' ); +} + +print <<'EOD'; + +O.K. Hope you had fun!! +EOD + +# Get input from the user. The arguments are: +# * The prompt +# * A reference to validation code. This code receives the response in +# $ARG and returns true for a valid response. +# * A warning to print if the response is not valid. This must end in a +# return. +# The first valid response is returned. An end-of-file terminates the +# script. +sub get_input { + my ( $prompt, $validate, $warning ) = @ARG; + + # If no validator is passed, default to one that always returns + # true. + $validate ||= sub { 1 }; + + # Create the readline object. The 'state' causes the variable to be + # initialized only once, no matter how many times this subroutine is + # called. The do { ... } is a compound statement used because we + # need to tweak the created object before we store it. + state $term = do { + my $obj = Term::ReadLine->new( 'reverse' ); + $obj->ornaments( 0 ); + $obj; + }; + + while ( 1 ) { # Iterate indefinitely + + # Read the input into the topic variable, localized to prevent + # Spooky Action at a Distance. We exit on undef, which signals + # end-of-file. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Return the input if it is valid. + return $ARG if $validate->(); + + # Issue the warning, and go around the merry-go-round again. + warn $warning; + } +} + +# Get a yes-or-no answer. The argument is the prompt, which will have +# '? [y/n]: ' appended. The donkey work is done by get_input(), which is +# requested to validate the response as beginning with 'y' or 'n', +# case-insensitive. The return is a true value for 'y' and a false value +# for 'n'. +sub get_yes_no { + my ( $prompt ) = @ARG; + state $map_answer = { + n => 0, + y => 1, + }; + my $resp = lc get_input( + "$prompt? [y/n]: ", + sub { m/ \A [yn] /smxi }, + "Please respond 'y' or 'n'\n", + ); + return $map_answer->{ substr $resp, 0, 1 }; +} + +# Determine if a given list represents a win. The argument is a +# reference to the array containing the list. We return a true value for +# a win, or a false value otherwise. +sub is_win { + my ( $list ) = @_; + my $expect = 1; # We expect the first element to be 1; + + # Iterate over the array. + foreach my $element ( @{ $list } ) { + + # If the element does not have the expected value, we return + # false. We post-increment the expected value en passant. + $element == $expect++ + or return 0; + } + + # All elements had the expected value, so we won. Return a true + # value. + return 1; +} + +__END__ + +=head1 TITLE + +reverse.pl - Play the game 'reverse' from Basic Computer Games + +=head1 SYNOPSIS + + reverse.pl + +=head1 DETAILS + +This Perl script is a port of C, which is the 73rd entry in +Basic Computer Games. + +The cool thing about this port is the fact that, in a language with +array slices, list assignments, and a C built-in, the +reversal is a single assignment statement. + +=head1 PORTED BY + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set expandtab tabstop=4 textwidth=72 : From b473fffc4a3720d78c79abc1d1763c85321f2328 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Sat, 8 Jan 2022 00:44:18 +1100 Subject: [PATCH 159/331] formatted version of battle.bas --- 09_Battle/battle_formatted.bas | 223 +++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 09_Battle/battle_formatted.bas diff --git a/09_Battle/battle_formatted.bas b/09_Battle/battle_formatted.bas new file mode 100644 index 00000000..9c292bd9 --- /dev/null +++ b/09_Battle/battle_formatted.bas @@ -0,0 +1,223 @@ +5 PRINT TAB(33);"BATTLE" +7 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +10 REM -- BATTLE WRITTEN BY RAY WESTERGARD 10/70 +20 REM COPYRIGHT 1971 BY THE REGENTS OF THE UNIV. OF CALIF. +30 REM PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY +40 DIM PLAYFIELD(6,6),HITS(6,6),ROW(4),COLUMN(4),SHIP_HITS(6),LOSSES(3) + +50 FOR X=1 TO 6 + 51 FOR Y=1 TO 6 + 52 PLAYFIELD(X,Y)=0 + 53 NEXT Y +54 NEXT X + +60 FOR I=1 TO 3 + 70 N=4-I + 80 FOR J=1 TO 2 + + 90 A=INT(6*RND(1)+1) + 100 B=INT(6*RND(1)+1) + 110 D=INT(4*RND(1)+1) + + 120 IF PLAYFIELD(A,B)>0 THEN 90 + 130 M=0 + 140 ON D GOTO 150,340,550,740 + + 150 COLUMN(1)=B + 160 COLUMN(2)=7:COLUMN(3)=7 + 170 FOR K=1 TO N + 180 IF M>1 THEN 240 + 190 IF COLUMN(K)=6 THEN 230 + 200 IF PLAYFIELD(A,COLUMN(K)+1)>0 THEN 230 + 210 COLUMN(K+1)=COLUMN(K)+1 + 220 GOTO 280 + 230 M=2 + 240 IF COLUMN(1)0 THEN 90 + 270 COLUMN(K+1)=Z-1 + 280 NEXT K + 290 PLAYFIELD(A,B)=9-2*I-J + 300 FOR K=1 TO N + 310 PLAYFIELD(A,COLUMN(K+1))=PLAYFIELD(A,B) + 320 NEXT K + 330 GOTO 990 + + 340 ROW(1)=A + 350 COLUMN(1)=B + 360 ROW(2)=0:ROW(3)=0:COLUMN(2)=0:COLUMN(3)=0 + 370 FOR K=1 TO N + 380 IF M>1 THEN 460 + 390 IF ROW(K)=1 OR COLUMN(K)=1 THEN 450 + 400 IF PLAYFIELD(ROW(K)-1,COLUMN(K)-1)>0 THEN 450 + 410 IF PLAYFIELD(ROW(K)-1,COLUMN(K))>0 AND PLAYFIELD(ROW(K)-1,COLUMN(K))=PLAYFIELD(ROW(K),COLUMN(K)-1) THEN 450 + 420 ROW(K+1)=ROW(K)-1 + 430 COLUMN(K+1)=COLUMN(K)-1 + 440 GOTO 530 + 450 M=2 + 460 IF ROW(1)>ROW(2) AND ROW(1)>ROW(3) THEN Z1=ROW(1) + 462 IF ROW(2)>ROW(1) AND ROW(2)>ROW(3) THEN Z1=ROW(2) + 464 IF ROW(3)>ROW(1) AND ROW(3)>ROW(2) THEN Z1=ROW(3) + 470 IF COLUMN(1)>COLUMN(2) AND COLUMN(1)>COLUMN(3) THEN Z2=COLUMN(1) + 474 IF COLUMN(2)>COLUMN(1) AND COLUMN(2)>COLUMN(3) THEN Z2=COLUMN(2) + 476 IF COLUMN(3)>COLUMN(1) AND COLUMN(3)>COLUMN(2) THEN Z2=COLUMN(3) + + 480 IF Z1=6 OR Z2=6 THEN 90 + 490 IF PLAYFIELD(Z1+1,Z2+1)>0 THEN 90 + 500 IF PLAYFIELD(Z1,Z2+1)>0 AND PLAYFIELD(Z1,Z2+1)=PLAYFIELD(Z1+1,Z2) THEN 90 + + 510 ROW(K+1)=Z1+1 + 520 COLUMN(K+1)=Z2+1 + 530 NEXT K + 540 GOTO 950 + + 550 ROW(1)=A + 560 ROW(2)=7:ROW(3)=7 + 570 FOR K=1 TO N + 580 IF M>1 THEN 640 + 590 IF ROW(K)=6 THEN 630 + 600 IF PLAYFIELD(ROW(K)+1,B)>0 THEN 630 + 610 ROW(K+1)=ROW(K)+1 + 620 GOTO 680 + 630 M=2 + 640 IF ROW(1)0 THEN 90 + + 670 ROW(K+1)=Z-1 + 680 NEXT K + 690 PLAYFIELD(A,B)=9-2*I-J + 700 FOR K=1 TO N + 710 PLAYFIELD(ROW(K+1),B)=PLAYFIELD(A,B) + 720 NEXT K + 730 GOTO 990 + + 740 ROW(1)=A + 750 COLUMN(1)=B + 760 ROW(2)=7:ROW(3)=7 + 770 COLUMN(2)=0:COLUMN(3)=0 + 780 FOR K=1 TO N + 790 IF M>1 THEN 870 + 800 IF ROW(K)=6 OR COLUMN(K)=1 THEN 860 + 810 IF PLAYFIELD(ROW(K)+1,COLUMN(K)-1)>0 THEN 860 + 820 IF PLAYFIELD(ROW(K)+1,COLUMN(K))>0 AND PLAYFIELD(ROW(K)+1,COLUMN(K))=PLAYFIELD(ROW(K),COLUMN(K)-1) THEN 860 + 830 ROW(K+1)=ROW(K)+1 + 840 COLUMN(K+1)=COLUMN(K)-1 + 850 GOTO 940 + 860 M=2 + 870 IF ROW(1)COLUMN(2) AND COLUMN(1)>COLUMN(3) THEN Z2=COLUMN(1) + 882 IF COLUMN(2)>COLUMN(1) AND COLUMN(2)>COLUMN(3) THEN Z2=COLUMN(2) + 884 IF COLUMN(3)>COLUMN(1) AND COLUMN(3)>COLUMN(2) THEN Z2=COLUMN(3) + + 890 IF Z1=1 OR Z2=6 THEN 90 + 900 IF PLAYFIELD(Z1-1,Z2+1)>0 THEN 90 + 910 IF PLAYFIELD(Z1,Z2+1)>0 AND PLAYFIELD(Z1,Z2+1)=PLAYFIELD(Z1-1,Z2) THEN 90 + + 920 ROW(K+1)=Z1-1 + 930 COLUMN(K+1)=Z2+1 + 940 NEXT K + + 950 PLAYFIELD(A,B)=9-2*I-J + 960 FOR K=1 TO N + 970 PLAYFIELD(ROW(K+1),COLUMN(K+1))=PLAYFIELD(A,B) + 980 NEXT K + + 990 NEXT J +1000 NEXT I + +1010 PRINT +1020 PRINT "THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION" +1030 PRINT "HAS BEEN CAPTURED BUT NOT DECODED:" +1040 PRINT +1050 FOR I=1 TO 6 + 1051 FOR J=1 TO 6 + 1052 HITS(I,J)=PLAYFIELD(J,I) + 1053 NEXT J +1054 NEXT I +1060 FOR I=1 TO 6 + 1061 FOR J=1 TO 6 + 1062 PRINT HITS(I,J); + 1063 NEXT J + 1064 PRINT +1065 NEXT I +1070 PRINT +1080 PRINT "DE-CODE IT AND USE IT IF YOU CAN" +1090 PRINT "BUT KEEP THE DE-CODING METHOD A SECRET." +1100 PRINT +1110 FOR I=1 TO 6 + 1111 FOR J=1 TO 6 + 1112 HITS(I,J)=0 + 1113 NEXT J +1114 NEXT I +1120 FOR I=1 TO 3 + 1121 LOSSES(I)=0 +1122 NEXT I + +1130 SHIP_HITS(1)=2:SHIP_HITS(2)=2 +1140 SHIP_HITS(3)=1:SHIP_HITS(4)=1 +1150 SHIP_HITS(5)=0:SHIP_HITS(6)=0 +1160 S=0:HITS=0 + +1170 PRINT "START GAME" + +1180 INPUT X,Y +1190 IF X<1 OR X>6 OR INT(X)<>ABS(X) THEN 1210 +1200 IF Y>0 AND Y<7 AND INT(Y)=ABS(Y) THEN 1230 +1210 PRINT "INVALID INPUT. TRY AGAIN." +1220 GOTO 1180 + +1230 R=7-Y +1240 C=X +1250 IF PLAYFIELD(R,C)>0 THEN 1290 +1260 S=S+1 +1270 PRINT "SPLASH! TRY AGAIN." +1280 GOTO 1180 + +1290 IF SHIP_HITS(PLAYFIELD(R,C))<4 THEN 1340 +1300 PRINT "THERE USED TO BE A SHIP AT THAT POINT, BUT YOU SUNK IT." +1310 PRINT "SPLASH! TRY AGAIN." +1320 S=S+1 +1330 GOTO 1180 + +1340 IF HITS(R,C)>0 THEN 1420 +1350 HITS=HITS+1 +1360 HITS(R,C)=PLAYFIELD(R,C) +1370 PRINT "A DIRECT HIT ON SHIP NUMBER";PLAYFIELD(R,C) +1380 SHIP_HITS(PLAYFIELD(R,C))=SHIP_HITS(PLAYFIELD(R,C))+1 +1390 IF SHIP_HITS(PLAYFIELD(R,C))>=4 THEN 1470 +1400 PRINT "TRY AGAIN." +1410 GOTO 1180 + +1420 PRINT "YOU ALREADY PUT A HOLE IN SHIP NUMBER";PLAYFIELD(R,C); +1430 PRINT "AT THAT POINT." +1440 PRINT "SPLASH! TRY AGAIN." +1450 S=S+1 +1460 GOTO 1180 + +1470 LOSSES((INT(PLAYFIELD(R,C)-1)/2)+1)=LOSSES((INT(PLAYFIELD(R,C)-1)/2)+1)+1 + +1480 PRINT "AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS." +1490 PRINT "SO FAR, THE BAD GUYS HAVE LOST" +1500 PRINT LOSSES(1);"DESTROYER(S),";LOSSES(2);"CRUISER(S), AND"; +1510 PRINT LOSSES(3);"AIRCRAFT CARRIER(S)." +1520 PRINT "YOUR CURRENT SPLASH/HIT RATIO IS";S/HITS +1530 IF (LOSSES(1)+LOSSES(2)+LOSSES(3))<6 THEN 1180 + +1540 PRINT +1550 PRINT "YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET" +1560 PRINT "WITH A FINAL SPLASH/HIT RATIO OF";S/HITS +1570 IF S/HITS>0 THEN 1590 +1580 PRINT "CONGRATULATIONS -- A DIRECT HIT EVERY TIME." +1590 PRINT +1600 PRINT "****************************" +1610 PRINT +1620 GOTO 50 +1630 END From d7b8976a20e5243f776efdf730790e204dbe3713 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Sat, 8 Jan 2022 01:45:49 +1100 Subject: [PATCH 160/331] All games now have the correct gameMain defined in gradle.properties --- 89_Tic-Tac-Toe/java/src/{TicTacToe2.java => TicTacToe.java} | 2 +- 89_Tic-Tac-Toe/kotlin/{TicTacToe2.kt => TicTacToe.kt} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename 89_Tic-Tac-Toe/java/src/{TicTacToe2.java => TicTacToe.java} (99%) rename 89_Tic-Tac-Toe/kotlin/{TicTacToe2.kt => TicTacToe.kt} (100%) diff --git a/89_Tic-Tac-Toe/java/src/TicTacToe2.java b/89_Tic-Tac-Toe/java/src/TicTacToe.java similarity index 99% rename from 89_Tic-Tac-Toe/java/src/TicTacToe2.java rename to 89_Tic-Tac-Toe/java/src/TicTacToe.java index bda3793c..c8fa2d03 100644 --- a/89_Tic-Tac-Toe/java/src/TicTacToe2.java +++ b/89_Tic-Tac-Toe/java/src/TicTacToe.java @@ -4,7 +4,7 @@ import java.util.Random; /** * @author Ollie Hensman-Crook */ -public class TicTacToe2 { +public class TicTacToe { public static void main(String[] args) { Board gameBoard = new Board(); Random compChoice = new Random(); diff --git a/89_Tic-Tac-Toe/kotlin/TicTacToe2.kt b/89_Tic-Tac-Toe/kotlin/TicTacToe.kt similarity index 100% rename from 89_Tic-Tac-Toe/kotlin/TicTacToe2.kt rename to 89_Tic-Tac-Toe/kotlin/TicTacToe.kt From a1bc1b4fd9841cad7c2ebbb4c74e184ddd263e20 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Sat, 8 Jan 2022 01:57:12 +1100 Subject: [PATCH 161/331] oops revert renaming TicTacToe2 --- 89_Tic-Tac-Toe/java/src/{TicTacToe.java => TicTacToe2.java} | 2 +- 89_Tic-Tac-Toe/kotlin/{TicTacToe.kt => TicTacToe2.kt} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename 89_Tic-Tac-Toe/java/src/{TicTacToe.java => TicTacToe2.java} (99%) rename 89_Tic-Tac-Toe/kotlin/{TicTacToe.kt => TicTacToe2.kt} (100%) diff --git a/89_Tic-Tac-Toe/java/src/TicTacToe.java b/89_Tic-Tac-Toe/java/src/TicTacToe2.java similarity index 99% rename from 89_Tic-Tac-Toe/java/src/TicTacToe.java rename to 89_Tic-Tac-Toe/java/src/TicTacToe2.java index c8fa2d03..bda3793c 100644 --- a/89_Tic-Tac-Toe/java/src/TicTacToe.java +++ b/89_Tic-Tac-Toe/java/src/TicTacToe2.java @@ -4,7 +4,7 @@ import java.util.Random; /** * @author Ollie Hensman-Crook */ -public class TicTacToe { +public class TicTacToe2 { public static void main(String[] args) { Board gameBoard = new Board(); Random compChoice = new Random(); diff --git a/89_Tic-Tac-Toe/kotlin/TicTacToe.kt b/89_Tic-Tac-Toe/kotlin/TicTacToe2.kt similarity index 100% rename from 89_Tic-Tac-Toe/kotlin/TicTacToe.kt rename to 89_Tic-Tac-Toe/kotlin/TicTacToe2.kt From a7f05d150183fb35e890b3d53aa70381e873e9d2 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Sat, 8 Jan 2022 02:15:40 +1100 Subject: [PATCH 162/331] README.md --- buildJvm/README.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 buildJvm/README.md diff --git a/buildJvm/README.md b/buildJvm/README.md new file mode 100644 index 00000000..f0046ab3 --- /dev/null +++ b/buildJvm/README.md @@ -0,0 +1,63 @@ +# JVM gradle scripts + +## Quickstart + +Build all the games: + + cd buildJvm + ./gradlew -q assemble installDist distributeBin distributeLib + +Then, run a game + +### Mac or linux: + + build/distrib/bin/build_53_King_kotlin + +### Windows +[not tested yet] + + build\distrib\bin\build_53_King_kotlin.bat + +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. + +--- +## Adding a new game + +These are build scripts for all JVM games contributed so far. +New games can be added by: +- Creating a `build_NUMBER_NAME_[java/kotlin]` directory +- Adding a `build.gradle` file to that directory. +All `build.gradle` files under `build_NUMBER_*` should be nearly identical, unless +there is some special requirement. +- Adding 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. + +The `build.gradle` file will normally be identical to this: + + plugins { + id 'application' + } + + sourceSets { + main { + java { + srcDirs "../../$gameSource" + } + } + } + + repositories { + mavenCentral() + } + + application { + mainClass = gameMain + } + +And 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. From 9f1b12d61cb883247efc021659778c9921b07527 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Sat, 8 Jan 2022 02:26:18 +1100 Subject: [PATCH 163/331] Delete old and experimental code --- 09_Battle/battle_formatted.bas | 223 --------------------------------- 1 file changed, 223 deletions(-) delete mode 100644 09_Battle/battle_formatted.bas diff --git a/09_Battle/battle_formatted.bas b/09_Battle/battle_formatted.bas deleted file mode 100644 index 9c292bd9..00000000 --- a/09_Battle/battle_formatted.bas +++ /dev/null @@ -1,223 +0,0 @@ -5 PRINT TAB(33);"BATTLE" -7 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" -10 REM -- BATTLE WRITTEN BY RAY WESTERGARD 10/70 -20 REM COPYRIGHT 1971 BY THE REGENTS OF THE UNIV. OF CALIF. -30 REM PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY -40 DIM PLAYFIELD(6,6),HITS(6,6),ROW(4),COLUMN(4),SHIP_HITS(6),LOSSES(3) - -50 FOR X=1 TO 6 - 51 FOR Y=1 TO 6 - 52 PLAYFIELD(X,Y)=0 - 53 NEXT Y -54 NEXT X - -60 FOR I=1 TO 3 - 70 N=4-I - 80 FOR J=1 TO 2 - - 90 A=INT(6*RND(1)+1) - 100 B=INT(6*RND(1)+1) - 110 D=INT(4*RND(1)+1) - - 120 IF PLAYFIELD(A,B)>0 THEN 90 - 130 M=0 - 140 ON D GOTO 150,340,550,740 - - 150 COLUMN(1)=B - 160 COLUMN(2)=7:COLUMN(3)=7 - 170 FOR K=1 TO N - 180 IF M>1 THEN 240 - 190 IF COLUMN(K)=6 THEN 230 - 200 IF PLAYFIELD(A,COLUMN(K)+1)>0 THEN 230 - 210 COLUMN(K+1)=COLUMN(K)+1 - 220 GOTO 280 - 230 M=2 - 240 IF COLUMN(1)0 THEN 90 - 270 COLUMN(K+1)=Z-1 - 280 NEXT K - 290 PLAYFIELD(A,B)=9-2*I-J - 300 FOR K=1 TO N - 310 PLAYFIELD(A,COLUMN(K+1))=PLAYFIELD(A,B) - 320 NEXT K - 330 GOTO 990 - - 340 ROW(1)=A - 350 COLUMN(1)=B - 360 ROW(2)=0:ROW(3)=0:COLUMN(2)=0:COLUMN(3)=0 - 370 FOR K=1 TO N - 380 IF M>1 THEN 460 - 390 IF ROW(K)=1 OR COLUMN(K)=1 THEN 450 - 400 IF PLAYFIELD(ROW(K)-1,COLUMN(K)-1)>0 THEN 450 - 410 IF PLAYFIELD(ROW(K)-1,COLUMN(K))>0 AND PLAYFIELD(ROW(K)-1,COLUMN(K))=PLAYFIELD(ROW(K),COLUMN(K)-1) THEN 450 - 420 ROW(K+1)=ROW(K)-1 - 430 COLUMN(K+1)=COLUMN(K)-1 - 440 GOTO 530 - 450 M=2 - 460 IF ROW(1)>ROW(2) AND ROW(1)>ROW(3) THEN Z1=ROW(1) - 462 IF ROW(2)>ROW(1) AND ROW(2)>ROW(3) THEN Z1=ROW(2) - 464 IF ROW(3)>ROW(1) AND ROW(3)>ROW(2) THEN Z1=ROW(3) - 470 IF COLUMN(1)>COLUMN(2) AND COLUMN(1)>COLUMN(3) THEN Z2=COLUMN(1) - 474 IF COLUMN(2)>COLUMN(1) AND COLUMN(2)>COLUMN(3) THEN Z2=COLUMN(2) - 476 IF COLUMN(3)>COLUMN(1) AND COLUMN(3)>COLUMN(2) THEN Z2=COLUMN(3) - - 480 IF Z1=6 OR Z2=6 THEN 90 - 490 IF PLAYFIELD(Z1+1,Z2+1)>0 THEN 90 - 500 IF PLAYFIELD(Z1,Z2+1)>0 AND PLAYFIELD(Z1,Z2+1)=PLAYFIELD(Z1+1,Z2) THEN 90 - - 510 ROW(K+1)=Z1+1 - 520 COLUMN(K+1)=Z2+1 - 530 NEXT K - 540 GOTO 950 - - 550 ROW(1)=A - 560 ROW(2)=7:ROW(3)=7 - 570 FOR K=1 TO N - 580 IF M>1 THEN 640 - 590 IF ROW(K)=6 THEN 630 - 600 IF PLAYFIELD(ROW(K)+1,B)>0 THEN 630 - 610 ROW(K+1)=ROW(K)+1 - 620 GOTO 680 - 630 M=2 - 640 IF ROW(1)0 THEN 90 - - 670 ROW(K+1)=Z-1 - 680 NEXT K - 690 PLAYFIELD(A,B)=9-2*I-J - 700 FOR K=1 TO N - 710 PLAYFIELD(ROW(K+1),B)=PLAYFIELD(A,B) - 720 NEXT K - 730 GOTO 990 - - 740 ROW(1)=A - 750 COLUMN(1)=B - 760 ROW(2)=7:ROW(3)=7 - 770 COLUMN(2)=0:COLUMN(3)=0 - 780 FOR K=1 TO N - 790 IF M>1 THEN 870 - 800 IF ROW(K)=6 OR COLUMN(K)=1 THEN 860 - 810 IF PLAYFIELD(ROW(K)+1,COLUMN(K)-1)>0 THEN 860 - 820 IF PLAYFIELD(ROW(K)+1,COLUMN(K))>0 AND PLAYFIELD(ROW(K)+1,COLUMN(K))=PLAYFIELD(ROW(K),COLUMN(K)-1) THEN 860 - 830 ROW(K+1)=ROW(K)+1 - 840 COLUMN(K+1)=COLUMN(K)-1 - 850 GOTO 940 - 860 M=2 - 870 IF ROW(1)COLUMN(2) AND COLUMN(1)>COLUMN(3) THEN Z2=COLUMN(1) - 882 IF COLUMN(2)>COLUMN(1) AND COLUMN(2)>COLUMN(3) THEN Z2=COLUMN(2) - 884 IF COLUMN(3)>COLUMN(1) AND COLUMN(3)>COLUMN(2) THEN Z2=COLUMN(3) - - 890 IF Z1=1 OR Z2=6 THEN 90 - 900 IF PLAYFIELD(Z1-1,Z2+1)>0 THEN 90 - 910 IF PLAYFIELD(Z1,Z2+1)>0 AND PLAYFIELD(Z1,Z2+1)=PLAYFIELD(Z1-1,Z2) THEN 90 - - 920 ROW(K+1)=Z1-1 - 930 COLUMN(K+1)=Z2+1 - 940 NEXT K - - 950 PLAYFIELD(A,B)=9-2*I-J - 960 FOR K=1 TO N - 970 PLAYFIELD(ROW(K+1),COLUMN(K+1))=PLAYFIELD(A,B) - 980 NEXT K - - 990 NEXT J -1000 NEXT I - -1010 PRINT -1020 PRINT "THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION" -1030 PRINT "HAS BEEN CAPTURED BUT NOT DECODED:" -1040 PRINT -1050 FOR I=1 TO 6 - 1051 FOR J=1 TO 6 - 1052 HITS(I,J)=PLAYFIELD(J,I) - 1053 NEXT J -1054 NEXT I -1060 FOR I=1 TO 6 - 1061 FOR J=1 TO 6 - 1062 PRINT HITS(I,J); - 1063 NEXT J - 1064 PRINT -1065 NEXT I -1070 PRINT -1080 PRINT "DE-CODE IT AND USE IT IF YOU CAN" -1090 PRINT "BUT KEEP THE DE-CODING METHOD A SECRET." -1100 PRINT -1110 FOR I=1 TO 6 - 1111 FOR J=1 TO 6 - 1112 HITS(I,J)=0 - 1113 NEXT J -1114 NEXT I -1120 FOR I=1 TO 3 - 1121 LOSSES(I)=0 -1122 NEXT I - -1130 SHIP_HITS(1)=2:SHIP_HITS(2)=2 -1140 SHIP_HITS(3)=1:SHIP_HITS(4)=1 -1150 SHIP_HITS(5)=0:SHIP_HITS(6)=0 -1160 S=0:HITS=0 - -1170 PRINT "START GAME" - -1180 INPUT X,Y -1190 IF X<1 OR X>6 OR INT(X)<>ABS(X) THEN 1210 -1200 IF Y>0 AND Y<7 AND INT(Y)=ABS(Y) THEN 1230 -1210 PRINT "INVALID INPUT. TRY AGAIN." -1220 GOTO 1180 - -1230 R=7-Y -1240 C=X -1250 IF PLAYFIELD(R,C)>0 THEN 1290 -1260 S=S+1 -1270 PRINT "SPLASH! TRY AGAIN." -1280 GOTO 1180 - -1290 IF SHIP_HITS(PLAYFIELD(R,C))<4 THEN 1340 -1300 PRINT "THERE USED TO BE A SHIP AT THAT POINT, BUT YOU SUNK IT." -1310 PRINT "SPLASH! TRY AGAIN." -1320 S=S+1 -1330 GOTO 1180 - -1340 IF HITS(R,C)>0 THEN 1420 -1350 HITS=HITS+1 -1360 HITS(R,C)=PLAYFIELD(R,C) -1370 PRINT "A DIRECT HIT ON SHIP NUMBER";PLAYFIELD(R,C) -1380 SHIP_HITS(PLAYFIELD(R,C))=SHIP_HITS(PLAYFIELD(R,C))+1 -1390 IF SHIP_HITS(PLAYFIELD(R,C))>=4 THEN 1470 -1400 PRINT "TRY AGAIN." -1410 GOTO 1180 - -1420 PRINT "YOU ALREADY PUT A HOLE IN SHIP NUMBER";PLAYFIELD(R,C); -1430 PRINT "AT THAT POINT." -1440 PRINT "SPLASH! TRY AGAIN." -1450 S=S+1 -1460 GOTO 1180 - -1470 LOSSES((INT(PLAYFIELD(R,C)-1)/2)+1)=LOSSES((INT(PLAYFIELD(R,C)-1)/2)+1)+1 - -1480 PRINT "AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS." -1490 PRINT "SO FAR, THE BAD GUYS HAVE LOST" -1500 PRINT LOSSES(1);"DESTROYER(S),";LOSSES(2);"CRUISER(S), AND"; -1510 PRINT LOSSES(3);"AIRCRAFT CARRIER(S)." -1520 PRINT "YOUR CURRENT SPLASH/HIT RATIO IS";S/HITS -1530 IF (LOSSES(1)+LOSSES(2)+LOSSES(3))<6 THEN 1180 - -1540 PRINT -1550 PRINT "YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET" -1560 PRINT "WITH A FINAL SPLASH/HIT RATIO OF";S/HITS -1570 IF S/HITS>0 THEN 1590 -1580 PRINT "CONGRATULATIONS -- A DIRECT HIT EVERY TIME." -1590 PRINT -1600 PRINT "****************************" -1610 PRINT -1620 GOTO 50 -1630 END From e666dcfbdcca28040ed96f89560720b4d597d0a9 Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Sat, 8 Jan 2022 02:26:18 +1100 Subject: [PATCH 164/331] Delete old and experimental code --- 09_Battle/battle_formatted.bas | 223 --------------------------------- 1 file changed, 223 deletions(-) delete mode 100644 09_Battle/battle_formatted.bas diff --git a/09_Battle/battle_formatted.bas b/09_Battle/battle_formatted.bas deleted file mode 100644 index 9c292bd9..00000000 --- a/09_Battle/battle_formatted.bas +++ /dev/null @@ -1,223 +0,0 @@ -5 PRINT TAB(33);"BATTLE" -7 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" -10 REM -- BATTLE WRITTEN BY RAY WESTERGARD 10/70 -20 REM COPYRIGHT 1971 BY THE REGENTS OF THE UNIV. OF CALIF. -30 REM PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY -40 DIM PLAYFIELD(6,6),HITS(6,6),ROW(4),COLUMN(4),SHIP_HITS(6),LOSSES(3) - -50 FOR X=1 TO 6 - 51 FOR Y=1 TO 6 - 52 PLAYFIELD(X,Y)=0 - 53 NEXT Y -54 NEXT X - -60 FOR I=1 TO 3 - 70 N=4-I - 80 FOR J=1 TO 2 - - 90 A=INT(6*RND(1)+1) - 100 B=INT(6*RND(1)+1) - 110 D=INT(4*RND(1)+1) - - 120 IF PLAYFIELD(A,B)>0 THEN 90 - 130 M=0 - 140 ON D GOTO 150,340,550,740 - - 150 COLUMN(1)=B - 160 COLUMN(2)=7:COLUMN(3)=7 - 170 FOR K=1 TO N - 180 IF M>1 THEN 240 - 190 IF COLUMN(K)=6 THEN 230 - 200 IF PLAYFIELD(A,COLUMN(K)+1)>0 THEN 230 - 210 COLUMN(K+1)=COLUMN(K)+1 - 220 GOTO 280 - 230 M=2 - 240 IF COLUMN(1)0 THEN 90 - 270 COLUMN(K+1)=Z-1 - 280 NEXT K - 290 PLAYFIELD(A,B)=9-2*I-J - 300 FOR K=1 TO N - 310 PLAYFIELD(A,COLUMN(K+1))=PLAYFIELD(A,B) - 320 NEXT K - 330 GOTO 990 - - 340 ROW(1)=A - 350 COLUMN(1)=B - 360 ROW(2)=0:ROW(3)=0:COLUMN(2)=0:COLUMN(3)=0 - 370 FOR K=1 TO N - 380 IF M>1 THEN 460 - 390 IF ROW(K)=1 OR COLUMN(K)=1 THEN 450 - 400 IF PLAYFIELD(ROW(K)-1,COLUMN(K)-1)>0 THEN 450 - 410 IF PLAYFIELD(ROW(K)-1,COLUMN(K))>0 AND PLAYFIELD(ROW(K)-1,COLUMN(K))=PLAYFIELD(ROW(K),COLUMN(K)-1) THEN 450 - 420 ROW(K+1)=ROW(K)-1 - 430 COLUMN(K+1)=COLUMN(K)-1 - 440 GOTO 530 - 450 M=2 - 460 IF ROW(1)>ROW(2) AND ROW(1)>ROW(3) THEN Z1=ROW(1) - 462 IF ROW(2)>ROW(1) AND ROW(2)>ROW(3) THEN Z1=ROW(2) - 464 IF ROW(3)>ROW(1) AND ROW(3)>ROW(2) THEN Z1=ROW(3) - 470 IF COLUMN(1)>COLUMN(2) AND COLUMN(1)>COLUMN(3) THEN Z2=COLUMN(1) - 474 IF COLUMN(2)>COLUMN(1) AND COLUMN(2)>COLUMN(3) THEN Z2=COLUMN(2) - 476 IF COLUMN(3)>COLUMN(1) AND COLUMN(3)>COLUMN(2) THEN Z2=COLUMN(3) - - 480 IF Z1=6 OR Z2=6 THEN 90 - 490 IF PLAYFIELD(Z1+1,Z2+1)>0 THEN 90 - 500 IF PLAYFIELD(Z1,Z2+1)>0 AND PLAYFIELD(Z1,Z2+1)=PLAYFIELD(Z1+1,Z2) THEN 90 - - 510 ROW(K+1)=Z1+1 - 520 COLUMN(K+1)=Z2+1 - 530 NEXT K - 540 GOTO 950 - - 550 ROW(1)=A - 560 ROW(2)=7:ROW(3)=7 - 570 FOR K=1 TO N - 580 IF M>1 THEN 640 - 590 IF ROW(K)=6 THEN 630 - 600 IF PLAYFIELD(ROW(K)+1,B)>0 THEN 630 - 610 ROW(K+1)=ROW(K)+1 - 620 GOTO 680 - 630 M=2 - 640 IF ROW(1)0 THEN 90 - - 670 ROW(K+1)=Z-1 - 680 NEXT K - 690 PLAYFIELD(A,B)=9-2*I-J - 700 FOR K=1 TO N - 710 PLAYFIELD(ROW(K+1),B)=PLAYFIELD(A,B) - 720 NEXT K - 730 GOTO 990 - - 740 ROW(1)=A - 750 COLUMN(1)=B - 760 ROW(2)=7:ROW(3)=7 - 770 COLUMN(2)=0:COLUMN(3)=0 - 780 FOR K=1 TO N - 790 IF M>1 THEN 870 - 800 IF ROW(K)=6 OR COLUMN(K)=1 THEN 860 - 810 IF PLAYFIELD(ROW(K)+1,COLUMN(K)-1)>0 THEN 860 - 820 IF PLAYFIELD(ROW(K)+1,COLUMN(K))>0 AND PLAYFIELD(ROW(K)+1,COLUMN(K))=PLAYFIELD(ROW(K),COLUMN(K)-1) THEN 860 - 830 ROW(K+1)=ROW(K)+1 - 840 COLUMN(K+1)=COLUMN(K)-1 - 850 GOTO 940 - 860 M=2 - 870 IF ROW(1)COLUMN(2) AND COLUMN(1)>COLUMN(3) THEN Z2=COLUMN(1) - 882 IF COLUMN(2)>COLUMN(1) AND COLUMN(2)>COLUMN(3) THEN Z2=COLUMN(2) - 884 IF COLUMN(3)>COLUMN(1) AND COLUMN(3)>COLUMN(2) THEN Z2=COLUMN(3) - - 890 IF Z1=1 OR Z2=6 THEN 90 - 900 IF PLAYFIELD(Z1-1,Z2+1)>0 THEN 90 - 910 IF PLAYFIELD(Z1,Z2+1)>0 AND PLAYFIELD(Z1,Z2+1)=PLAYFIELD(Z1-1,Z2) THEN 90 - - 920 ROW(K+1)=Z1-1 - 930 COLUMN(K+1)=Z2+1 - 940 NEXT K - - 950 PLAYFIELD(A,B)=9-2*I-J - 960 FOR K=1 TO N - 970 PLAYFIELD(ROW(K+1),COLUMN(K+1))=PLAYFIELD(A,B) - 980 NEXT K - - 990 NEXT J -1000 NEXT I - -1010 PRINT -1020 PRINT "THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION" -1030 PRINT "HAS BEEN CAPTURED BUT NOT DECODED:" -1040 PRINT -1050 FOR I=1 TO 6 - 1051 FOR J=1 TO 6 - 1052 HITS(I,J)=PLAYFIELD(J,I) - 1053 NEXT J -1054 NEXT I -1060 FOR I=1 TO 6 - 1061 FOR J=1 TO 6 - 1062 PRINT HITS(I,J); - 1063 NEXT J - 1064 PRINT -1065 NEXT I -1070 PRINT -1080 PRINT "DE-CODE IT AND USE IT IF YOU CAN" -1090 PRINT "BUT KEEP THE DE-CODING METHOD A SECRET." -1100 PRINT -1110 FOR I=1 TO 6 - 1111 FOR J=1 TO 6 - 1112 HITS(I,J)=0 - 1113 NEXT J -1114 NEXT I -1120 FOR I=1 TO 3 - 1121 LOSSES(I)=0 -1122 NEXT I - -1130 SHIP_HITS(1)=2:SHIP_HITS(2)=2 -1140 SHIP_HITS(3)=1:SHIP_HITS(4)=1 -1150 SHIP_HITS(5)=0:SHIP_HITS(6)=0 -1160 S=0:HITS=0 - -1170 PRINT "START GAME" - -1180 INPUT X,Y -1190 IF X<1 OR X>6 OR INT(X)<>ABS(X) THEN 1210 -1200 IF Y>0 AND Y<7 AND INT(Y)=ABS(Y) THEN 1230 -1210 PRINT "INVALID INPUT. TRY AGAIN." -1220 GOTO 1180 - -1230 R=7-Y -1240 C=X -1250 IF PLAYFIELD(R,C)>0 THEN 1290 -1260 S=S+1 -1270 PRINT "SPLASH! TRY AGAIN." -1280 GOTO 1180 - -1290 IF SHIP_HITS(PLAYFIELD(R,C))<4 THEN 1340 -1300 PRINT "THERE USED TO BE A SHIP AT THAT POINT, BUT YOU SUNK IT." -1310 PRINT "SPLASH! TRY AGAIN." -1320 S=S+1 -1330 GOTO 1180 - -1340 IF HITS(R,C)>0 THEN 1420 -1350 HITS=HITS+1 -1360 HITS(R,C)=PLAYFIELD(R,C) -1370 PRINT "A DIRECT HIT ON SHIP NUMBER";PLAYFIELD(R,C) -1380 SHIP_HITS(PLAYFIELD(R,C))=SHIP_HITS(PLAYFIELD(R,C))+1 -1390 IF SHIP_HITS(PLAYFIELD(R,C))>=4 THEN 1470 -1400 PRINT "TRY AGAIN." -1410 GOTO 1180 - -1420 PRINT "YOU ALREADY PUT A HOLE IN SHIP NUMBER";PLAYFIELD(R,C); -1430 PRINT "AT THAT POINT." -1440 PRINT "SPLASH! TRY AGAIN." -1450 S=S+1 -1460 GOTO 1180 - -1470 LOSSES((INT(PLAYFIELD(R,C)-1)/2)+1)=LOSSES((INT(PLAYFIELD(R,C)-1)/2)+1)+1 - -1480 PRINT "AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS." -1490 PRINT "SO FAR, THE BAD GUYS HAVE LOST" -1500 PRINT LOSSES(1);"DESTROYER(S),";LOSSES(2);"CRUISER(S), AND"; -1510 PRINT LOSSES(3);"AIRCRAFT CARRIER(S)." -1520 PRINT "YOUR CURRENT SPLASH/HIT RATIO IS";S/HITS -1530 IF (LOSSES(1)+LOSSES(2)+LOSSES(3))<6 THEN 1180 - -1540 PRINT -1550 PRINT "YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET" -1560 PRINT "WITH A FINAL SPLASH/HIT RATIO OF";S/HITS -1570 IF S/HITS>0 THEN 1590 -1580 PRINT "CONGRATULATIONS -- A DIRECT HIT EVERY TIME." -1590 PRINT -1600 PRINT "****************************" -1610 PRINT -1620 GOTO 50 -1630 END From 016ad4f825fd69c1b7a1bc4056f1b7a05aa79490 Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Fri, 7 Jan 2022 10:49:49 -0500 Subject: [PATCH 165/331] Clean up dead code left over from cut-and-paste development. --- 81_Splat/perl/splat.pl | 269 +---------------------------------------- 1 file changed, 4 insertions(+), 265 deletions(-) diff --git a/81_Splat/perl/splat.pl b/81_Splat/perl/splat.pl index 459bc790..eebfcb6b 100755 --- a/81_Splat/perl/splat.pl +++ b/81_Splat/perl/splat.pl @@ -298,281 +298,20 @@ sub get_yes_no { __END__ -print <<'EOD' if get_yes_no( 'Do you want instructions' ); -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. - - -EOD - -while ( 1 ) { - - say ''; - - foreach my $row ( 0 .. 7 ) { - printf ROW_TPLT, map { ( $_ + $row ) * 10 + $row + 1 } reverse 1 .. 8; - } - -} - -# Get input from the user. The arguments are: -# * The prompt -# * A reference to validation code. This code receives the response in -# $ARG and returns true for a valid response. -# * A warning to print if the response is not valid. This must end in a -# return. -# The first valid response is returned. An end-of-file terminates the -# script. -sub get_input { - my ( $prompt, $validate, $warning ) = @ARG; - - # If no validator is passed, default to one that always returns - # true. - $validate ||= sub { 1 }; - - # Create the readline object. The 'state' causes the variable to be - # initialized only once, no matter how many times this subroutine is - # called. The do { ... } is a compound statement used because we - # need to tweak the created object before we store it. - state $term = do { - my $obj = Term::ReadLine->new( 'reverse' ); - $obj->ornaments( 0 ); - $obj; - }; - - while ( 1 ) { # Iterate indefinitely - - # Read the input into the topic variable, localized to prevent - # Spooky Action at a Distance. We exit on undef, which signals - # end-of-file. - exit unless defined( local $ARG = $term->readline( $prompt ) ); - - # Return the input if it is valid. - return $ARG if $validate->(); - - # Issue the warning, and go around the merry-go-round again. - warn $warning; - } -} - -# Get a yes-or-no answer. The argument is the prompt, which will have -# '? [y/n]: ' appended. The donkey work is done by get_input(), which is -# requested to validate the response as beginning with 'y' or 'n', -# case-insensitive. The return is a true value for 'y' and a false value -# for 'n'. -sub get_yes_no { - my ( $prompt ) = @ARG; - state $map_answer = { - n => 0, - y => 1, - }; - my $resp = lc get_input( - "$prompt? [y/n]: ", - sub { m/ \A [yn] /smxi }, - "Please respond 'y' or 'n'\n", - ); - return $map_answer->{ substr $resp, 0, 1 }; -} - -__END__ -# Display the rules if desired. There is no straightforward way to -# interpolate a manifest constant into a string, but @{[ ... ]} will -# interpolate any expression. -print <<"EOD" if get_yes_no( 'Do you want the rules' ); - -This is the game of 'Reverse'. To win, all you have -to do is arrange a list of numbers (1 through @{[ NUMBER_OF_NUMBERS ]}) -in numerical order from left to right. To move, you -tell me how many numbers (counting from the left) to -reverse. For example, if the current list is: - -2 3 4 5 1 6 7 8 9 - -and you reverse 4, the result will be: - -5 4 3 2 1 6 7 8 9 - -Now if you reverse 5, you win! - -1 2 3 4 5 6 7 8 9 - -No doubt you will like this game, but -if you want to quit, reverse 0 (zero). - -EOD - -while ( 1 ) { # Iterate until something interrupts us. - - # Populate the list with the integers from 1, shuffled. If we - # accidentally generate a winning list, just redo the loop. - my @list = shuffle( 1 .. NUMBER_OF_NUMBERS ); - redo if is_win( \@list ); - - print <<"EOD"; - -Here we go ... The list is: -EOD - - my $moves = 0; # Move counter - - while ( 1 ) { # Iterate until something interrupts us. - print <<"EOD"; - -@list - -EOD - - # Read the number of values to reverse. Zero is special-cased to - # take us out of this loop. - last unless my $max_index = get_input( - 'How many shall I reverse (0 to quit)? ', - sub { - return m/ \A [0-9]+ \z /smx && - $ARG <= NUMBER_OF_NUMBERS; - }, - "Oops! Too many! I can reverse at most " . - NUMBER_OF_NUMBERS, - ); - - --$max_index; # Convert number to reverse to upper index - - # Use a Perl array slice and the reverse() built-in to reverse - # the beginning of the list. - @list[ 0 .. $max_index ] = reverse @list[ 0 .. $max_index ]; - - $moves++; # Count a move - - # If we have not won, iterate again. - next unless is_win( \@list ); - - # Announce the win, and drop out of the loop. - print <<"EOD"; - -You won it in $moves moves!!! -EOD - last; - } - - # Drop out of this loop unless the player wants to play again. - say ''; - last unless get_yes_no( 'Try again' ); -} - -print <<'EOD'; - -O.K. Hope you had fun!! -EOD - -# Get input from the user. The arguments are: -# * The prompt -# * A reference to validation code. This code receives the response in -# $ARG and returns true for a valid response. -# * A warning to print if the response is not valid. This must end in a -# return. -# The first valid response is returned. An end-of-file terminates the -# script. -sub get_input { - my ( $prompt, $validate, $warning ) = @ARG; - - # If no validator is passed, default to one that always returns - # true. - $validate ||= sub { 1 }; - - # Create the readline object. The 'state' causes the variable to be - # initialized only once, no matter how many times this subroutine is - # called. The do { ... } is a compound statement used because we - # need to tweak the created object before we store it. - state $term = do { - my $obj = Term::ReadLine->new( 'reverse' ); - $obj->ornaments( 0 ); - $obj; - }; - - while ( 1 ) { # Iterate indefinitely - - # Read the input into the topic variable, localized to prevent - # Spooky Action at a Distance. We exit on undef, which signals - # end-of-file. - exit unless defined( local $ARG = $term->readline( $prompt ) ); - - # Return the input if it is valid. - return $ARG if $validate->(); - - # Issue the warning, and go around the merry-go-round again. - warn $warning; - } -} - -# Get a yes-or-no answer. The argument is the prompt, which will have -# '? [y/n]: ' appended. The donkey work is done by get_input(), which is -# requested to validate the response as beginning with 'y' or 'n', -# case-insensitive. The return is a true value for 'y' and a false value -# for 'n'. -sub get_yes_no { - my ( $prompt ) = @ARG; - state $map_answer = { - n => 0, - y => 1, - }; - my $resp = lc get_input( - "$prompt? [y/n]: ", - sub { m/ \A [yn] /smxi }, - "Please respond 'y' or 'n'\n", - ); - return $map_answer->{ substr $resp, 0, 1 }; -} - -# Determine if a given list represents a win. The argument is a -# reference to the array containing the list. We return a true value for -# a win, or a false value otherwise. -sub is_win { - my ( $list ) = @_; - my $expect = 1; # We expect the first element to be 1; - - # Iterate over the array. - foreach my $element ( @{ $list } ) { - - # If the element does not have the expected value, we return - # false. We post-increment the expected value en passant. - $element == $expect++ - or return 0; - } - - # All elements had the expected value, so we won. Return a true - # value. - return 1; -} - -__END__ - =head1 TITLE -reverse.pl - Play the game 'reverse' from Basic Computer Games +splat.pl - Play the game 'splat' from Basic Computer Games =head1 SYNOPSIS - reverse.pl + splat.pl =head1 DETAILS -This Perl script is a port of C, which is the 73rd entry in +This Perl script is a port of C, which is the 73rd entry in Basic Computer Games. -The cool thing about this port is the fact that, in a language with -array slices, list assignments, and a C built-in, the -reversal is a single assignment statement. +This is a very basic port. All I really did was untangle the spaghetti. =head1 PORTED BY From 501deb035ce5f759deedd6d4d992299f7b12634c Mon Sep 17 00:00:00 2001 From: RibTips <36372030+ribtips@users.noreply.github.com> Date: Fri, 7 Jan 2022 10:59:03 -0500 Subject: [PATCH 166/331] Fixed game termination bug Fixed issue where the game wouldn't terminate properly if the computer goes first. --- 89_Tic-Tac-Toe/perl/tictactoe2.pl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/89_Tic-Tac-Toe/perl/tictactoe2.pl b/89_Tic-Tac-Toe/perl/tictactoe2.pl index e7448e3e..0cbf4c10 100644 --- a/89_Tic-Tac-Toe/perl/tictactoe2.pl +++ b/89_Tic-Tac-Toe/perl/tictactoe2.pl @@ -58,6 +58,10 @@ sub main { $count++; &print_board; &check_for_winners; + if ($count >= 9) { + print "IT'S A DRAW. THANK YOU.\n"; + exit; + } &player_choice; $count++; &print_board; @@ -65,6 +69,7 @@ sub main { } } print "IT'S A DRAW. THANK YOU.\n"; + exit; } # This will check to see if anyone has won by adding up the various 3-in-a-row lines. From e8c2638b98ffb8de51075c7418c46973c99d4dc9 Mon Sep 17 00:00:00 2001 From: jcoehoorn Date: Fri, 7 Jan 2022 09:59:29 -0600 Subject: [PATCH 167/331] Create program.vb --- 33_Dice/vbnet/program.vb | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 33_Dice/vbnet/program.vb diff --git a/33_Dice/vbnet/program.vb b/33_Dice/vbnet/program.vb new file mode 100644 index 00000000..977a5344 --- /dev/null +++ b/33_Dice/vbnet/program.vb @@ -0,0 +1,38 @@ +Imports System + +Module Program + Sub Main(args As String()) + Const header As String = +" DICE +CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + +THIS PROGRAM SIMULATES THE ROLLING OF A +PAIR OF DICE. +YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO +/ROLL/ THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE +A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000." + + Console.WriteLine(header) + + Dim D6 As New Random() + Dim continuePrompt As String = "YES" + While continuePrompt = "YES" + Console.Write($"{vbCrLf}HOW MANY ROLLS? ") + Dim x As Integer = Convert.ToInt32(Console.ReadLine()) + Dim F = Enumerable.Repeat(0, 11).ToList() + For s As Integer = 0 To x - 1 + F(D6.Next(6) + D6.Next(6)) += 1 + Next + + Console.WriteLine($"{vbCrLf}TOTAL SPOTS NUMBER OF TIMES") + For V As Integer = 0 To 10 + Console.WriteLine($" {V + 2}{vbTab,-8}{F(V)}") + Next + + Console.Write($"{vbCrLf}TRY AGAIN ") + continuePrompt = Console.ReadLine().ToUpper() + End While + End Sub +End Module From 96ef2628668db806928d6709ff934b1aafc1c44e Mon Sep 17 00:00:00 2001 From: Flavio Poletti Date: Fri, 7 Jan 2022 18:41:41 +0100 Subject: [PATCH 168/331] Update AI for Awari --- 04_Awari/perl/awari.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/04_Awari/perl/awari.pl b/04_Awari/perl/awari.pl index 3d70452c..b3e30b54 100644 --- a/04_Awari/perl/awari.pl +++ b/04_Awari/perl/awari.pl @@ -190,7 +190,8 @@ sub computer_move ($board, $failures, $moves) { # be obtained by setting the ORIGINAL environment variable to a # "true" value (in Perl terms). Otherwise it is calculated # according to the real rules for the game. - my $p_score = $ENV{ORIGINAL} ? $landing > 13 : int(($landing - 5) / 14); + my $p_score = $ENV{ORIGINAL} ? $landing > 13 + : ($landing + 1) % 14 > 6; # whatever, the landing position must be within the bounds $landing %= 14; From 1dbd2704553224f232bee1a4f9d40233ea37eb5f Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Fri, 7 Jan 2022 14:42:32 -0500 Subject: [PATCH 169/331] Port 88_Slots to Perl. I have made a change in the payout table versus the BASIC, since I presume the failure to pay a double on LEMON CHERRY LEMON is a bug. See the documentation in the module for why. --- 80_Slots/perl/slots.pl | 238 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100755 80_Slots/perl/slots.pl diff --git a/80_Slots/perl/slots.pl b/80_Slots/perl/slots.pl new file mode 100755 index 00000000..b5c1ee39 --- /dev/null +++ b/80_Slots/perl/slots.pl @@ -0,0 +1,238 @@ +#!/usr/bin/env perl + +use 5.010; # To get 'state' and 'say' + +use strict; # Require explicit declaration of variables +use warnings; # Enable optional compiler warnings + +use English; # Use more friendly names for Perl's magic variables +use List::Util qw{ shuffle }; # Shuffle an array. +use Scalar::Util qw{ looks_like_number }; +use Term::ReadLine; # Prompt and return user input + +our $VERSION = '0.000_01'; + +print <<'EOD'; + SLOTS + Creative Computing Morristown, New Jersey + + + +You are in the H&M casino, in front of one of our +one-arm bandits. Bet from $1 to $100. +To pull the arm, punch the return key after making your bet. +EOD + +my $winnings = 0; # Winnings + +while ( 1 ) { # Iterate indefinitely + + say ''; + + my $bet = get_input( 'Your bet? ', + sub { m/ \A [0-9]+ \z /smx }, + 'Please enter a whole number between 0 and 100', + ); + if ( $bet > 100 ) { + say 'The house limit is $100'; + next; + } + if ( $bet < 1 ) { + say 'The minimum bet is $1'; + next; + } + + say "\a" x 10; + my $reel_x = int( 6 * rand() ); + my $reel_y = int( 6 * rand() ); + my $reel_z = int( 6 * rand() ); + foreach my $column ( $reel_x, $reel_y, $reel_z ) { + state $symbol = [ qw{ Bar Bell Orange Lemon Plum Cherry } ]; + print $symbol->[$column], "\a" x 5, ' '; + } + + use constant YOU_WON => 'You won!'; + use constant YOU_LOST => 'You lost.'; + + say ''; + if ( $reel_x == $reel_y ) { + if ( $reel_y == $reel_z ) { + if ( $reel_z ) { + say '** TOP DOLLAR **'; + $winnings += 11 * $bet; + } else { + say '*** JACKPOT ***'; + $winnings += 101 * $bet; + } + say YOU_WON; + } elsif ( $reel_y ) { + $winnings += double( $bet ); + } else { + $winnings += double_bar( $bet ); + } + } elsif ( $reel_x == $reel_z ) { + if ( $reel_z ) { + $winnings += double( $bet ); + # NOTE that the below code is what is actually implemented + # in the basic, but it is implemented strangely enough (a + # GOTO a line that contains a test that, if I understand the + # control flow, must fail) that I wonder if it is an error. + # I know nothing about slot machines, but research suggests + # the payoff table is fairly arbitrary. The code above makes + # code above makes the game orthogonal. + # $winnings += you_lost( $bet ); + } else { + $winnings += double_bar( $bet ); + } + } elsif ( $reel_y == $reel_z ) { + if ( $reel_z ) { + $winnings += double( $bet ); + } else { + $winnings += double_bar( $bet ); + } + } else { + $winnings += you_lost( $bet ); + } + + say 'Your standings are $', $winnings; + + last unless get_yes_no( 'Again' ); + +} + +if ( $winnings < 0 ) { + say 'Pay up! Please leave your money on the terminal.'; +} elsif ( $winnings > 0 ) { + say 'Collect your winnings from the H&M cashier.'; +} else { + say 'Hey, you broke even.'; +} + +sub double { + my ( $bet ) = @_; + say 'DOUBLE!'; + say YOU_WON; + return 3 * $bet; +} + +sub double_bar { + my ( $bet ) = @_; + say '* DOUBLE BAR *'; + say YOU_WON; + return 6 * $bet; +} + +sub you_lost { + my ( $bet ) = @_; + say YOU_LOST; + return -$bet; +} + +# Get input from the user. The arguments are: +# * The prompt +# * A reference to validation code. This code receives the response in +# $ARG and returns true for a valid response. +# * A warning to print if the response is not valid. This must end in a +# return. +# The first valid response is returned. An end-of-file terminates the +# script. +sub get_input { + my ( $prompt, $validate, $warning ) = @ARG; + + # If no validator is passed, default to one that always returns + # true. + $validate ||= sub { 1 }; + + # Create the readline object. The 'state' causes the variable to be + # initialized only once, no matter how many times this subroutine is + # called. The do { ... } is a compound statement used because we + # need to tweak the created object before we store it. + state $term = do { + my $obj = Term::ReadLine->new( 'reverse' ); + $obj->ornaments( 0 ); + $obj; + }; + + while ( 1 ) { # Iterate indefinitely + + # Read the input into the topic variable, localized to prevent + # Spooky Action at a Distance. We exit on undef, which signals + # end-of-file. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Return the input if it is valid. + return $ARG if $validate->(); + + # Issue the warning, and go around the merry-go-round again. + warn $warning; + } +} + +# Get a yes-or-no answer. The argument is the prompt, which will have +# '? [y/n]: ' appended. The donkey work is done by get_input(), which is +# requested to validate the response as beginning with 'y' or 'n', +# case-insensitive. The return is a true value for 'y' and a false value +# for 'n'. +sub get_yes_no { + my ( $prompt ) = @ARG; + state $map_answer = { + n => 0, + y => 1, + }; + my $resp = lc get_input( + "$prompt? [y/n]: ", + sub { m/ \A [yn] /smxi }, + "Please respond 'y' or 'n'\n", + ); + return $map_answer->{ substr $resp, 0, 1 }; +} + +__END__ + +=head1 TITLE + +slots - Play the game 'Slots' from Basic Computer Games + +=head1 SYNOPSIS + + slots.pl + +=head1 DETAILS + +This Perl script is a port of C, which is the 80th entry in Basic +Computer Games. + +I know nothing about slot machines, and my research into them says to me +that the payout tables can be fairly arbitrary. But I have taken the +liberty of deeming the BASIC program's refusal to pay on LEMON CHERRY +LEMON a bug, and made that case a double. + +My justification for this is that at the point where the BASIC has +detected the double in the first and third reels it has already detected +that there is no double in the first and second reels. After the check +for a bar (and therefore a double bar) fails it goes back and checks for +a double on the second and third reels. But we know this check will +fail, since the check for a double on the first and second reels failed. +So if a loss was intended at this point, why not just call it a loss? + +=head1 PORTED BY + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set expandtab tabstop=4 textwidth=72 : From ae903a3b62dec4ef5f3bf2cda6e22e32cb885958 Mon Sep 17 00:00:00 2001 From: Pat Ludwig Date: Fri, 7 Jan 2022 14:03:15 -0600 Subject: [PATCH 170/331] Apply Both damage correctly Choices 2 and 3 should both have missile damage applied. --- 12_Bombs_Away/perl/bombsaway.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/12_Bombs_Away/perl/bombsaway.pl b/12_Bombs_Away/perl/bombsaway.pl index 70d8850e..1b4989f6 100644 --- a/12_Bombs_Away/perl/bombsaway.pl +++ b/12_Bombs_Away/perl/bombsaway.pl @@ -168,6 +168,7 @@ NOW THEN, '; my $response = choose( 'DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)', 3); + # Apply Gun damage for responses 1 and 3 if ($response != 2) { # there's some guns involved, ask more say ''; @@ -190,7 +191,8 @@ NOW THEN, '; } say ''; } - else { + # Apply missile damage for responses 2 and 3 + if ($response > 1 ) { $missiles_hit_rate = 35; # remember... this is a global variable } From d88d3b298785c41537ac225b612d0ac457bca446 Mon Sep 17 00:00:00 2001 From: Bill Cruise Date: Fri, 7 Jan 2022 15:48:09 -0500 Subject: [PATCH 171/331] Fixed bug in acey-ducey range. --- 01_Acey_Ducey/python/acey_ducey_oo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01_Acey_Ducey/python/acey_ducey_oo.py b/01_Acey_Ducey/python/acey_ducey_oo.py index 325af4b4..3e05387f 100644 --- a/01_Acey_Ducey/python/acey_ducey_oo.py +++ b/01_Acey_Ducey/python/acey_ducey_oo.py @@ -36,7 +36,7 @@ class Deck: def build(self): for suit in ['\u2665', '\u2666', '\u2663', '\u2660']: - for rank in range(1, 14): + for rank in range(2, 15): self.cards.append(Card(suit, rank)) def shuffle(self): From c9f9f9bcdd36e1faaa59807cfbf01dd51bc394b5 Mon Sep 17 00:00:00 2001 From: zoot661 Date: Fri, 7 Jan 2022 21:40:42 +0000 Subject: [PATCH 172/331] Create Program.cs Add initial implementation Working version but requires commenting and maybe some better error handling --- 92_Trap/csharp/Program.cs | 119 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 92_Trap/csharp/Program.cs diff --git a/92_Trap/csharp/Program.cs b/92_Trap/csharp/Program.cs new file mode 100644 index 00000000..6cd74d10 --- /dev/null +++ b/92_Trap/csharp/Program.cs @@ -0,0 +1,119 @@ +using System; + +namespace trap_cs +{ + class Program + { + const int maxGuesses = 6; + const int maxNumber = 100; + static void Main(string[] args) + { + int lowGuess = 0; + int highGuess = 0; + + Random randomNumberGenerator = new (); + + Print("TRAP"); + Print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + Print(); + Print(); + Print(); + + PrintInstructions(); + + int numberToGuess = randomNumberGenerator.Next(1, maxNumber); + + for (int nGuess = 1; nGuess <= maxGuesses + 1; nGuess++) + { + if (nGuess > maxGuesses) + { + Print(string.Format("SORRY, THAT'S {0} GUESSES. THE NUMBER WAS {1}", maxGuesses, numberToGuess)); + Print(); + break; + } + + GetGuesses(nGuess, ref lowGuess, ref highGuess); + + if(lowGuess == highGuess && lowGuess == numberToGuess) + { + Print("YOU GOT IT!!!"); + Print(); + Print("TRY AGAIN."); + Print(); + break; + } + if (highGuess < numberToGuess) + { + Print("MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS."); + } + else if (lowGuess > numberToGuess) + { + Print("MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS."); + } + else + { + Print("YOU HAVE TRAPPED MY NUMBER."); + } + } + } + +// TRAP +// REM - STEVE ULLMAN, 8 - 1 - 72 + static void PrintInstructions() + { + Print("INSTRUCTIONS ?"); + + char response = Console.ReadKey().KeyChar; + if (response == 'Y') + { + Print(string.Format("I AM THINKING OF A NUMBER BETWEEN 1 AND {0}", maxNumber)); + 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(string.Format("YOU GET {0} GUESSES TO GET MY NUMBER.", maxGuesses)); + } + } + static void Print(string stringToPrint) + { + Console.WriteLine(stringToPrint); + } + static void Print() + { + Console.WriteLine(); + } + static void GetGuesses(int nGuess, ref int lowGuess, ref int highGuess) + { + Print(); + Print(string.Format("GUESS #{0}", nGuess)); + + lowGuess = GetIntFromConsole("Type low guess"); + highGuess = GetIntFromConsole("Type high guess"); + + if(lowGuess > highGuess) + { + int tempGuess = lowGuess; + + lowGuess = highGuess; + highGuess = tempGuess; + } + } + static int GetIntFromConsole(string prompt) + { + + Console.Write( prompt + " > "); + string intAsString = Console.ReadLine(); + + if(int.TryParse(intAsString, out int intValue) ==false) + { + intValue = 1; + } + + return intValue; + } + } +} From ab5301151e064a395410efc0f198f1406f94ca37 Mon Sep 17 00:00:00 2001 From: Robert Flach Date: Fri, 7 Jan 2022 16:38:29 -0600 Subject: [PATCH 173/331] Fixed 2 bugs. 1 yes and no both restarted the game 2. zero is supposed to skip the third card but was treated as an invalid bet. 1. In trying as keep as close to the spirit of the original game as possible, there is no handling for an invalidly low number. A zero input prints "chicken" and skips the third card and starts over with 2 new initial cards. 2. After the wad is blown, anything but a yes answer to the "Try again" question ends the game --- 01_Acey_Ducey/javascript/aceyducey.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/01_Acey_Ducey/javascript/aceyducey.js b/01_Acey_Ducey/javascript/aceyducey.js index 8bf5e9e1..9969ebbf 100644 --- a/01_Acey_Ducey/javascript/aceyducey.js +++ b/01_Acey_Ducey/javascript/aceyducey.js @@ -90,19 +90,23 @@ async function main() { print('\nWHAT IS YOUR BET? '); bet = parseInt(await input(), 10); let minimumRequiredBet = 0; - if (bet > minimumRequiredBet) { + if (bet >= minimumRequiredBet) { if (bet > availableDollars) { print('SORRY, MY FRIEND, BUT YOU BET TOO MUCH.'); print(`YOU HAVE ONLY ${availableDollars} DOLLARS TO BET.`); } else { validBet = true; } - } else { - // Does not meet minimum required bet - print('CHICKEN!!'); - print(''); } } + if (bet == 0) + { + // User chose not to bet. + print('CHICKEN!!'); + print(''); + // Don't draw a third card, draw a new set of 2 cards. + continue; + } print('\n\nHERE IS THE CARD WE DREW: '); print(getCardValue(cardThree)); @@ -127,7 +131,7 @@ async function main() { print(''); print(''); - if (isValidYesNoString(tryAgainInput)) { + if (isValidYesString(tryAgainInput)) { availableDollars = 100; } else { print('O.K., HOPE YOU HAD FUN!'); From a14a7bea3cfe411f1ce704cd12f911aa93b240d7 Mon Sep 17 00:00:00 2001 From: simonskrede Date: Sat, 8 Jan 2022 00:42:53 +0100 Subject: [PATCH 174/331] Initial port of Poker to plain Java --- 71_Poker/java/Poker.java | 851 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 851 insertions(+) create mode 100644 71_Poker/java/Poker.java diff --git a/71_Poker/java/Poker.java b/71_Poker/java/Poker.java new file mode 100644 index 00000000..426a71fd --- /dev/null +++ b/71_Poker/java/Poker.java @@ -0,0 +1,851 @@ +import java.util.Random; +import java.util.Scanner; + +import static java.lang.System.out; + +/** + * Port of CREATIVE COMPUTING Poker written in Commodore 64 Basic to plain Java + * + * Original source scanned from magazine: https://www.atariarchives.org/basicgames/showpage.php?page=129 + * + * I based my port on the OCR'ed source code here: https://github.com/coding-horror/basic-computer-games/blob/main/71_Poker/poker.bas + * + * Why? Because I remember typing this into my C64 when I was a tiny little developer and having great fun playing it! + * + * Goal: Keep the algorithms and UX more or less as-is; Improve the control flow a bit (no goto in Java!) and rename some stuff to be easier to follow. + * + * Result: There are probably bugs, please let me know. + */ +public class Poker { + + public static void main(String[] args) { + new Poker().run(); + } + + float[] cards = new float[50]; // Index 1-5 = Human hand, index 6-10 = Computer hand + float[] B = new float[15]; + + float playerValuables = 1; + float computerMoney = 200; + float humanMoney = 200; + float pot = 0; + + String J$ = ""; + float computerHandValue = 0; + + int K = 0; + float G = 0; + float T = 0; + int M = 0; + int D = 0; + + int U = 0; + float N = 1; + + float I = 0; + + float X = 0; + + int Z = 0; + + String handDescription = ""; + + float V; + + void run() { + printWelcome(); + playRound(); + startAgain(); + } + + void printWelcome() { + tab(33); + out.println("POKER"); + tab(15); + out.print("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + out.println(); + out.println(); + out.println(); + out.println("WELCOME TO THE CASINO. WE EACH HAVE $200."); + out.println("I WILL OPEN THE BETTING BEFORE THE DRAW; YOU OPEN AFTER."); + out.println("TO FOLD BET 0; TO CHECK BET .5."); + out.println("ENOUGH TALK -- LET'S GET DOWN TO BUSINESS."); + out.println(); + } + + void tab(int number) { + System.out.print("\t".repeat(number)); + } + + int random0to10() { + return new Random().nextInt(10); + } + + int removeHundreds(long x) { + return _int(x - (100F * _int(x / 100F))); + } + + void startAgain() { + pot = 0; + playRound(); + } + + void playRound() { + if (computerMoney <= 5) { + computerBroke(); + } + + out.println("THE ANTE IS $5. I WILL DEAL:"); + out.println(); + + if (humanMoney <= 5) { + playerBroke(); + } + + pot = pot + 10; + humanMoney = humanMoney - 5; + computerMoney = computerMoney - 5; + for (int Z = 1; Z < 10; Z++) { + generateCards(Z); + } + out.println("YOUR HAND:"); + N = 1; + showHand(); + N = 6; + I = 2; + + describeHand(); + + out.println(); + + if (I != 6) { + if (U >= 13) { + if (U <= 16) { + Z = 35; + } else { + Z = 2; + if (random0to10() < 1) { + Z = 35; + } + } + computerOpens(); + playerMoves(); + } else if (random0to10() >= 2) { + computerChecks(); + } else { + I = 7; + Z = 23; + computerOpens(); + playerMoves(); + } + } else if (random0to10() <= 7) { + if (random0to10() <= 7) { + if (random0to10() >= 1) { + Z = 1; + K = 0; + out.print("I CHECK. "); + playerMoves(); + } else { + X = 11111; + I = 7; + Z = 23; + computerOpens(); + playerMoves(); + } + } else { + X = 11110; + I = 7; + Z = 23; + computerOpens(); + playerMoves(); + } + } else { + X = 11100; + I = 7; + Z = 23; + computerOpens(); + playerMoves(); + } + } + + void playerMoves() { + playersTurn(); + checkWinnerAfterFirstBet(); + promptPlayerDrawCards(); + } + + void computerOpens() { + V = Z + random0to10(); + computerMoves(); + out.print("I'LL OPEN WITH $" + V); + K = _int(V); + } + + @SuppressWarnings("StatementWithEmptyBody") + void computerMoves() { + if (computerMoney - G - V >= 0) { + } else if (G != 0) { + if (computerMoney - G >= 0) { + computerSees(); + } else { + computerBroke(); + } + } else { + V = computerMoney; + } + } + + void promptPlayerDrawCards() { + out.println(); + out.println("NOW WE DRAW -- HOW MANY CARDS DO YOU WANT"); + inputPlayerDrawCards(); + } + + void inputPlayerDrawCards() { + T = Integer.parseInt(readString()); + if (T == 0) { + computerDrawing(); + } else { + Z = 10; + if (T < 4) { + playerDrawsCards(); + } else { + out.println("YOU CAN'T DRAW MORE THAN THREE CARDS."); + inputPlayerDrawCards(); + } + } + } + + // line # 980 + void computerDrawing() { + Z = _int(10 + T); + for (U = 6; U <= 10; U++) { + if (_int((float) (X / Math.pow(10F, (U - 6F)))) == (10 * (_int((float) (X / Math.pow(10, (U - 5))))))) { + drawNextCard(); + } + } + out.print("I AM TAKING " + _int(Z - 10 - T) + " CARD"); + if (Z == 11 + T) { + out.println(); + } else { + out.println("S"); + } + + N = 6; + V = I; + I = 1; + describeHand(); + startPlayerBettingAndReaction(); + } + + void drawNextCard() { + Z = Z + 1; + drawCard(); + } + + @SuppressWarnings("StatementWithEmptyBody") + void drawCard() { + cards[Z] = 100 * new Random().nextInt(4) + new Random().nextInt(100); + if (_int(cards[Z] / 100) > 3) { + drawCard(); + } else if (cards[Z] - 100 * _int(cards[Z] / 100) > 12) { + drawCard(); + } else if (Z == 1) { + } else { + for (K = 1; K <= Z - 1; K++) { + if (cards[Z] == cards[K]) { + drawCard(); + } + } + if (Z <= 10) { + } else { + N = cards[U]; + cards[U] = cards[Z]; + cards[Z] = N; + } + } + } + + void playerDrawsCards() { + out.println("WHAT ARE THEIR NUMBERS:"); + for (int Q = 1; Q <= T; Q++) { + U = Integer.parseInt(readString()); + drawNextCard(); + } + + out.println("YOUR NEW HAND:"); + N = 1; + showHand(); + computerDrawing(); + } + + void startPlayerBettingAndReaction() { + computerHandValue = U; + M = D; + + if (V != 7) { + if (I != 6) { + if (U >= 13) { + if (U >= 16) { + Z = 2; + playerBetsAndComputerReacts(); + } else { + Z = 19; + if (random0to10() == 8) { + Z = 11; + } + playerBetsAndComputerReacts(); + } + } else { + Z = 2; + if (random0to10() == 6) { + Z = 19; + } + playerBetsAndComputerReacts(); + } + } else { + Z = 1; + playerBetsAndComputerReacts(); + } + } else { + Z = 28; + playerBetsAndComputerReacts(); + } + } + + void playerBetsAndComputerReacts() { + K = 0; + playersTurn(); + if (T != .5) { + checkWinnerAfterFirstBetAndCompareHands(); + } else if (V == 7 || I != 6) { + computerOpens(); + promptAndInputPlayerBet(); + checkWinnerAfterFirstBetAndCompareHands(); + } else { + out.println("I'LL CHECK"); + compareHands(); + } + } + + void checkWinnerAfterFirstBetAndCompareHands() { + checkWinnerAfterFirstBet(); + compareHands(); + } + + void compareHands() { + out.println("NOW WE COMPARE HANDS:"); + J$ = handDescription; + out.println("MY HAND:"); + N = 6; + showHand(); + N = 1; + describeHand(); + out.print("YOU HAVE "); + K = D; + printHandDescriptionResult(); + handDescription = J$; + K = M; + out.print(" AND I HAVE "); + printHandDescriptionResult(); + out.print(". "); + if (computerHandValue > U) { + computerWins(); + } else if (U > computerHandValue) { + humanWins(); + } else if (handDescription.contains("A FLUS")) { + someoneWinsWithFlush(); + } else if (removeHundreds(M) < removeHundreds(D)) { + humanWins(); + } else if (removeHundreds(M) > removeHundreds(D)) { + computerWins(); + } else { + handIsDrawn(); + } + } + + void printHandDescriptionResult() { + out.print(handDescription); + if (!handDescription.contains("A FLUS")) { + K = removeHundreds(K); + printCardValue(); + if (handDescription.contains("SCHMAL")) { + out.print(" HIGH"); + } else if (!handDescription.contains("STRAIG")) { + out.print("'S"); + } else { + out.print(" HIGH"); + } + } else { + K = K / 100; + printCardColor(); + out.println(); + } + } + + void handIsDrawn() { + out.print("THE HAND IS DRAWN."); + out.print("ALL $" + pot + " REMAINS IN THE POT."); + playRound(); + } + + void someoneWinsWithFlush() { + if (removeHundreds(M) > removeHundreds(D)) { + computerWins(); + } else if (removeHundreds(D) > removeHundreds(M)) { + humanWins(); + } else { + handIsDrawn(); + } + } + + @SuppressWarnings("StatementWithEmptyBody") + void checkWinnerAfterFirstBet() { + if (I != 3) { + if (I != 4) { + } else { + humanWins(); + } + } else { + out.println(); + computerWins(); + } + } + + void computerWins() { + out.print(". I WIN. "); + computerMoney = computerMoney + pot; + potStatusAndNextRoundPrompt(); + } + + void potStatusAndNextRoundPrompt() { + out.println("NOW I HAVE $" + computerMoney + " AND YOU HAVE $" + humanMoney); + out.print("DO YOU WISH TO CONTINUE"); + + if (yesFromPrompt()) { + startAgain(); + } else { + System.exit(0); + } + } + + private boolean yesFromPrompt() { + String h = readString(); + if (h != null) { + if (h.toLowerCase().matches("y|yes|yep|affirmative|yay")) { + return true; + } else if (h.toLowerCase().matches("n|no|nope|fuck off|nay")) { + return false; + } + } + out.println("ANSWER YES OR NO, PLEASE."); + return yesFromPrompt(); + } + + void computerChecks() { + Z = 0; + K = 0; + out.print("I CHECK. "); + playerMoves(); + } + + void humanWins() { + out.println("YOU WIN."); + humanMoney = humanMoney + pot; + potStatusAndNextRoundPrompt(); + } + + // line # 1740 + void generateCards(int Z) { + cards[Z] = (100 * new Random().nextInt(4)) + new Random().nextInt(100); + if (_int(cards[Z] / 100) > 3) { + generateCards(Z); + return; + } + if (cards[Z] - 100 * (_int(cards[Z] / 100)) > 12) { + generateCards(Z); + return; + } + if (Z == 1) {return;} + for (int K = 1; K <= Z - 1; K++) {// TO Z-1 + if (cards[Z] == cards[K]) { + generateCards(Z); + return; + } + } + if (Z <= 10) {return;} + float N = cards[U]; + cards[U] = cards[Z]; + cards[Z] = N; + } + + // line # 1850 + void showHand() { + for (int cardNumber = _int(N); cardNumber <= N + 4; cardNumber++) { + out.print(cardNumber + "-- "); + printCardValueAtIndex(cardNumber); + out.print(" OF"); + printCardColorAtIndex(cardNumber); + if (cardNumber / 2 == (cardNumber / 2)) { + out.println(); + } + } + } + + // line # 1950 + void printCardValueAtIndex(int Z) { + K = removeHundreds(_int(cards[Z])); + printCardValue(); + } + + void printCardValue() { + if (K == 9) { + out.print("JACK"); + } else if (K == 10) { + out.print("QUEEN"); + } else if (K == 11) { + out.print("KING"); + } else if (K == 12) { + out.print("ACE"); + } else if (K < 9) { + out.print(K + 2); + } + } + + // line # 2070 + void printCardColorAtIndex(int Z) { + K = _int(cards[Z] / 100); + printCardColor(); + } + + void printCardColor() { + if (K == 0) { + out.print(" CLUBS"); + } else if (K == 1) { + out.print(" DIAMONDS"); + } else if (K == 2) { + out.print(" HEARTS"); + } else if (K == 3) { + out.print(" SPADES"); + } + } + + // line # 2170 + void describeHand() { + U = 0; + for (Z = _int(N); Z <= N + 4; Z++) { + B[Z] = removeHundreds(_int(cards[Z])); + if (Z == N + 4) {continue;} + if (_int(cards[Z] / 100) != _int(cards[Z + 1] / 100)) {continue;} + U = U + 1; + } + if (U != 4) { + for (Z = _int(N); Z <= N + 3; Z++) { + for (K = Z + 1; K <= N + 4; K++) { + if (B[Z] <= B[K]) {continue;} + X = cards[Z]; + cards[Z] = cards[K]; + B[Z] = B[K]; + cards[K] = X; + B[K] = cards[K] - 100 * _int(cards[K] / 100); + } + } + X = 0; + for (Z = _int(N); Z <= N + 3; Z++) { + if (B[Z] != B[Z + 1]) {continue;} + X = (float) (X + 11 * Math.pow(10, (Z - N))); + D = _int(cards[Z]); + + if (U >= 11) { + if (U != 11) { + if (U > 12) { + if (B[Z] != B[Z - 1]) { + fullHouse(); + } else { + U = 17; + handDescription = "FOUR "; + } + } else { + fullHouse(); + } + } else if (B[Z] != B[Z - 1]) { + handDescription = "TWO PAIR, "; + U = 12; + } else { + handDescription = "THREE "; + U = 13; + } + } else { + U = 11; + handDescription = "A PAIR OF "; + } + } + + if (X != 0) { + schmaltzHand(); + } else { + if (B[_int(N)] + 3 == B[_int(N + 3)]) { + X = 1111; + U = 10; + } + if (B[_int(N + 1)] + 3 != B[_int(N + 4)]) { + schmaltzHand(); + } else if (U != 10) { + U = 10; + X = 11110; + schmaltzHand(); + } else { + U = 14; + handDescription = "STRAIGHT"; + X = 11111; + D = _int(cards[_int(N + 4)]); + } + } + } else { + X = 11111; + D = _int(cards[_int(N)]); + handDescription = "A FLUSH IN"; + U = 15; + } + } + + void schmaltzHand() { + if (U >= 10) { + if (U != 10) { + if (U > 12) {return;} + if (removeHundreds(D) <= 6) { + I = 6; + } + } else { + if (I == 1) { + I = 6; + } + } + } else { + D = _int(cards[_int(N + 4)]); + handDescription = "SCHMALTZ, "; + U = 9; + X = 11000; + I = 6; + } + } + + void fullHouse() { + U = 16; + handDescription = "FULL HOUSE, "; + } + + void playersTurn() { + G = 0; + promptAndInputPlayerBet(); + } + + String readString() { + Scanner sc = new Scanner(System.in); + return sc.nextLine(); + } + + @SuppressWarnings("StatementWithEmptyBody") + void promptAndInputPlayerBet() { + out.println("WHAT IS YOUR BET"); + T = readFloat(); + if (T - _int(T) == 0) { + processPlayerBet(); + } else if (K != 0) { + playerBetInvalidAmount(); + } else if (G != 0) { + playerBetInvalidAmount(); + } else if (T == .5) { + } else { + playerBetInvalidAmount(); + } + } + + private float readFloat() { + try { + return Float.parseFloat(readString()); + } catch (Exception ex) { + System.out.println("INVALID INPUT, PLEASE TYPE A FLOAT. "); + return readFloat(); + } + } + + void playerBetInvalidAmount() { + out.println("NO SMALL CHANGE, PLEASE."); + promptAndInputPlayerBet(); + } + + void processPlayerBet() { + if (humanMoney - G - T >= 0) { + humanCanAffordBet(); + } else { + playerBroke(); + promptAndInputPlayerBet(); + } + } + + void humanCanAffordBet() { + if (T != 0) { + if (G + T >= K) { + processComputerMove(); + } else { + out.println("IF YOU CAN'T SEE MY BET, THEN FOLD."); + promptAndInputPlayerBet(); + } + } else { + I = 3; + moveMoneyToPot(); + } + } + + void processComputerMove() { + G = G + T; + if (G == K) { + moveMoneyToPot(); + } else if (Z != 1) { + if (G > 3 * Z) { + computerRaisesOrSees(); + } else { + computerRaises(); + } + } else if (G > 5) { + if (T <= 25) { + computerRaisesOrSees(); + } else { + computerFolds(); + } + } else { + V = 5; + if (G > 3 * Z) { + computerRaisesOrSees(); + } else { + computerRaises(); + } + } + } + + void computerRaises() { + V = G - K + random0to10(); + computerMoves(); + out.println("I'LL SEE YOU, AND RAISE YOU" + V); + K = _int(G + V); + promptAndInputPlayerBet(); + } + + void computerFolds() { + I = 4; + out.println("I FOLD."); + } + + void computerRaisesOrSees() { + if (Z == 2) { + computerRaises(); + } else { + computerSees(); + } + } + + void computerSees() { + out.println("I'LL SEE YOU."); + K = _int(G); + moveMoneyToPot(); + } + + void moveMoneyToPot() { + humanMoney = humanMoney - G; + computerMoney = computerMoney - K; + pot = pot + G + K; + } + + void computerBusted() { + out.println("I'M BUSTED. CONGRATULATIONS!"); + System.exit(0); + } + + @SuppressWarnings("StatementWithEmptyBody") + private void computerBroke() { + if ((playerValuables / 2) == _int(playerValuables / 2) && playerBuyBackWatch()) { + } else if (playerValuables / 3 == _int(playerValuables / 3) && playerBuyBackTieRack()) { + } else { + computerBusted(); + } + } + + private int _int(float v) { + return (int) Math.floor(v); + } + + private boolean playerBuyBackWatch() { + out.println("WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50"); + if (yesFromPrompt()) { + computerMoney = computerMoney + 50; + playerValuables = playerValuables / 2; + return true; + } else { + return false; + } + } + + private boolean playerBuyBackTieRack() { + out.println("WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50"); + if (yesFromPrompt()) { + computerMoney = computerMoney + 50; + playerValuables = playerValuables / 3; + return true; + } else { + return false; + } + } + + // line # 3830 + @SuppressWarnings("StatementWithEmptyBody") + void playerBroke() { + out.println("YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT."); + if (playerValuables / 2 != _int(playerValuables / 2) && playerSellWatch()) { + } else if (playerValuables / 3 != _int(playerValuables / 3) && playerSellTieTack()) { + } else { + playerBusted(); + } + } + + private void playerBusted() { + out.println("YOUR WAD IS SHOT. SO LONG, SUCKER!"); + System.exit(0); + } + + private boolean playerSellWatch() { + out.println("WOULD YOU LIKE TO SELL YOUR WATCH"); + if (yesFromPrompt()) { + if (random0to10() < 7) { + out.println("I'LL GIVE YOU $75 FOR IT."); + humanMoney = humanMoney + 75; + } else { + out.println("THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25."); + humanMoney = humanMoney + 25; + } + playerValuables = playerValuables * 2; + return true; + } else { + return false; + } + } + + private boolean playerSellTieTack() { + out.println("WILL YOU PART WITH THAT DIAMOND TIE TACK"); + + if (yesFromPrompt()) { + if (random0to10() < 6) { + out.println("YOU ARE NOW $100 RICHER."); + humanMoney = humanMoney + 100; + } else { + out.println("IT'S PASTE. $25."); + humanMoney = humanMoney + 25; + } + playerValuables = playerValuables * 3; + return true; + } else { + return false; + } + } + +} From 8db8272d0b088749867350f1674ec8369d0ae259 Mon Sep 17 00:00:00 2001 From: Flavio Poletti Date: Sat, 8 Jan 2022 02:14:33 +0100 Subject: [PATCH 175/331] Add 72_Queen in Perl --- 72_Queen/perl/queen.pl | 209 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 72_Queen/perl/queen.pl diff --git a/72_Queen/perl/queen.pl b/72_Queen/perl/queen.pl new file mode 100644 index 00000000..62682210 --- /dev/null +++ b/72_Queen/perl/queen.pl @@ -0,0 +1,209 @@ +#!/usr/bin/env perl +use v5.24; +use warnings; +use experimental 'signatures'; +no warnings 'experimental::signatures'; + +use constant TARGET => 158; + +main(@ARGV); + +sub main (@args) { + welcome(); + help() if ask_yes_no('DO YOU WANT INSTRUCTIONS'); + do { one_match() } while ask_yes_no('ANYONE ELSE CARE TO TRY'); + __exit(); +} + +sub one_match { + print_board(); + + # the player can choose the starting position in the top row or the + # right column + my $move = ask_first_move() or return forfeit(); + + # we alternate moves between computer or player from now on + while ('playing') { + $move = computer_move($move); + say "COMPUTER MOVES TO SQUARE $move"; + return print_computer_victory() if $move == TARGET; + + $move = ask_player_move($move) or return forfeit(); + return print_player_victory() if $move == TARGET; + } +} + +sub is_valid_move ($move, $current, $skip_prevalidation = 0) { + + # pre-validation is needed for moves coming from the user + if (! $skip_prevalidation) { + state $valid_position = { map { $_ => 1 } board_identifiers() }; + return 0 unless $move =~ m{\A [1-9]\d+ \z}mxs; + return 1 if $move == 0; + return 0 unless $valid_position->{$move}; + return 0 if $move <= $current; + } + + # the move might be valid in general, let's check from $current + my $delta = $move - $current; + + # a valid move differs from the current position by a multiple of 10, + # or 11, or 21. If dividing by all of them yields a remainder, then + # the move is not valid + return 0 if $delta % 10 && $delta % 11 && $delta % 21; + + # otherwise it is + return 1; +} + +sub ask_player_move ($current) { + while ('necessary') { + my $move = ask_input('WHAT IS YOUR MOVE'); + return $move if is_valid_move($move, $current); + say "\nY O U C H E A T . . . TRY AGAIN"; + } +} + +sub computer_move ($current) { + + # this game has some optimal/safe positions from where it's possible + # to win with the right strategy. We will aim for them, if possible + state $optimals = [ 158, 127, 126, 75, 73 ]; + for my $optimal ($optimals->@*) { + + # moves can only increase, if we did not find any optimal move so far + # then there's no point going on + last if $optimal <= $current; + + # computer moves are "syntactically" valid, skip pre-validation + return $optimal if is_valid_move($optimal, $current, 'skip'); + + } + + # cannot reach an optimal position... resort to randomness + my $z = rand(); + return $current + 11 if $z > 0.6; # move down + return $current + 21 if $z > 0.3; # move diagonally + return $current + 10; ; # move horizontally +} + +sub board_identifiers { + return ( + 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, + ); +} + +sub print_player_victory { + print <<'END'; + +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. + +END +} + +sub print_computer_victory { + print <<'END'; + +NICE TRY, BUT IT LOOKS LIKE I HAVE WON. +THANKS FOR PLAYING. + +END +} + +sub forfeit { say "\nIT LOOKS LIKE I HAVE WON BY FORFEIT.\n" } + +sub ask_input ($prompt) { + print "$prompt? "; + defined(my $input = ) or __exit(); + + # remove spaces from the input (including newlines), they are not used + $input =~ s{\s+}{}gmxs; + + return $input; +} + +sub ask_yes_no ($prompt) { + while ('necessary') { + my $input = ask_input($prompt); + return 1 if $input =~ m{\A (?: yes | y) \z}imxs; + return 0 if $input =~ m{\A (?: no | n) \z}imxs; + say q{PLEASE ANSWER 'YES' OR 'NO'.}; + } +} + +sub ask_first_move { + while ('necessary') { + my $input = ask_input('WHERE WOULD YOU LIKE TO START'); + if ($input =~ m{\A (?: 0 | [1-9]\d+) \z}mxs) { + return 0 unless $input; + my $diagonal = int($input / 10); + my $row = $input % 10; + return $input if $row == 1 || $row == $diagonal; + } + say <<'END' +PLEASE READ THE DIRECTIONS AGAIN. +YOU HAVE BEGUN ILLEGALLY. + +END + } +} + +sub __exit { + say "\nOK --- THANKS AGAIN."; + exit 0; +} + +sub welcome { + print <<'END' + QUEEN + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + +END +} + +sub help { + print <<'END'; +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. + + +END +} + +sub print_board { + say ''; + my @ids = board_identifiers(); + my $row_template = join ' ', ($ENV{ORIGINAL} ? '%d' : '%3d') x 8; + for my $A (0 .. 7) { + my $start = $A * 8; + my @range = $start .. $start + 7; + say ' ', sprintf $row_template, @ids[@range]; + say "\n"; + } + say ''; +} From 9f636574a41084dd4284f0c4b4066611f96d3a65 Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Fri, 7 Jan 2022 22:49:51 -0300 Subject: [PATCH 176/331] Added ruby version of russian roulette --- 76_Russian_Roulette/ruby/russianroulette.rb | 73 +++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 76_Russian_Roulette/ruby/russianroulette.rb diff --git a/76_Russian_Roulette/ruby/russianroulette.rb b/76_Russian_Roulette/ruby/russianroulette.rb new file mode 100644 index 00000000..abb3ad35 --- /dev/null +++ b/76_Russian_Roulette/ruby/russianroulette.rb @@ -0,0 +1,73 @@ +puts <<~INSTRUCTIONS + RUSSIAN ROULETTE + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + +THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE. + +HERE IS A REVOLVER. + +INSTRUCTIONS + +NUMBER_OF_ROUNDS = 9 + +def parse_input + correct_input = false + + while not correct_input + puts " ?" + inp = gets.chomp + if inp == "1" or inp == "2" + correct_input = true + end + end + + inp +end + +while true + + dead = false + n = 0 + + puts "TYPE \'1\' TO SPIN CHAMBER AND PULL TRIGGER" + puts "TYPE \'2\' TO GIVE UP" + puts "GO" + + while not dead + + inp = parse_input + + if inp == "2" + break + end + + if rand > 0.8333333333333334 + dead = true + else + puts "- CLICK -" + n += 1 + end + + if n > NUMBER_OF_ROUNDS + break + end + + end + + if dead + puts "BANG!!!!! You're Dead!" + puts "Condolences will be sent to your relatives.\n\n\n" + puts "...Next victim..." + else + if n > NUMBER_OF_ROUNDS + puts "You win!!!!!" + puts "Let someone else blow his brain out.\n" + else + puts " Chicken!!!!!\n\n\n" + puts "...Next victim...." + end + end + +end From 32eee996546c66d3b21004b535da4abd01837c4a Mon Sep 17 00:00:00 2001 From: Pat Ludwig Date: Fri, 7 Jan 2022 21:26:46 -0600 Subject: [PATCH 177/331] Fix exception if choice 2 for damage is selected Initialize the variables. --- 12_Bombs_Away/javascript/bombsaway.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/12_Bombs_Away/javascript/bombsaway.js b/12_Bombs_Away/javascript/bombsaway.js index 835a2608..84831856 100644 --- a/12_Bombs_Away/javascript/bombsaway.js +++ b/12_Bombs_Away/javascript/bombsaway.js @@ -45,6 +45,8 @@ function tab(space) // Main program async function main() { + s = 0; + t = 0; while (1) { print("YOU ARE A PILOT IN A WORLD WAR II BOMBER.\n"); while (1) { From ab2b9d0c3425e5d14fd6cbed4f8be1e71741ada7 Mon Sep 17 00:00:00 2001 From: James Allenspach Date: Fri, 7 Jan 2022 21:51:00 -0600 Subject: [PATCH 178/331] Initial commit --- 51_Hurkle/perl/hurkle.pl | 84 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100755 51_Hurkle/perl/hurkle.pl diff --git a/51_Hurkle/perl/hurkle.pl b/51_Hurkle/perl/hurkle.pl new file mode 100755 index 00000000..abb42d5a --- /dev/null +++ b/51_Hurkle/perl/hurkle.pl @@ -0,0 +1,84 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +# global variables + +my($GRID) = 10; +my($TRIES) = 5; + + +# main program starts here + +# print instructions +print <); + # Use a regex to attempt to parse out + # two integers separated by a comma. + if ($in =~ m{(\d+)\s*,\s*(\d+)}) { + $G1 = $1; $G2 = $2; + last CHECK; + } + # Input not accepted, please try again + print "Please enter two numbers separated by a comma ? "; + } + + if (abs($H1 - $G1) + abs($H2 - $G2) != 0) { + + # print directional info + printf("Go %s%s\n\n", + ($G2 == $H2 ? '' : $G2 < $H2 ? 'north' : 'south'), + ($G1 == $H1 ? '' : $G1 < $H1 ? 'east' : 'west' ), + ); + } else { + # win! + printf("\nYou found him in %d tries!\n", $i); + # move to the continue block + next PLAY; + } + } # tries loop + + # No more guesses + printf("Sorry, that's %d gueses.\n", $TRIES); + printf("The Hurkle is at %d, %d\n", $H1, $H2); +} + +# Execution comes here either from the "next PLAY" +# statement, or by the PLAY block naturally ending +# after the player has lost. +continue { + print "\nLet's play again. Hurkle is hiding.\n\n"; +} \ No newline at end of file From 4d66d18e714e08384395a03775d6f1756ef43bc8 Mon Sep 17 00:00:00 2001 From: James Allenspach Date: Fri, 7 Jan 2022 21:51:56 -0600 Subject: [PATCH 179/331] typo --- 51_Hurkle/perl/hurkle.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/51_Hurkle/perl/hurkle.pl b/51_Hurkle/perl/hurkle.pl index abb42d5a..52d7e853 100755 --- a/51_Hurkle/perl/hurkle.pl +++ b/51_Hurkle/perl/hurkle.pl @@ -72,7 +72,7 @@ PLAY: while (1) { } # tries loop # No more guesses - printf("Sorry, that's %d gueses.\n", $TRIES); + printf("Sorry, that's %d guesses.\n", $TRIES); printf("The Hurkle is at %d, %d\n", $H1, $H2); } From 83a9d95fc43f65233719434f2af5f4039aec50ab Mon Sep 17 00:00:00 2001 From: James Allenspach Date: Fri, 7 Jan 2022 21:52:30 -0600 Subject: [PATCH 180/331] add line break at eof --- 51_Hurkle/perl/hurkle.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/51_Hurkle/perl/hurkle.pl b/51_Hurkle/perl/hurkle.pl index 52d7e853..1497e50c 100755 --- a/51_Hurkle/perl/hurkle.pl +++ b/51_Hurkle/perl/hurkle.pl @@ -81,4 +81,4 @@ PLAY: while (1) { # after the player has lost. continue { print "\nLet's play again. Hurkle is hiding.\n\n"; -} \ No newline at end of file +} From 42ed63d175cd387e5505485d7c80b9bd78e32766 Mon Sep 17 00:00:00 2001 From: Pat Ludwig Date: Fri, 7 Jan 2022 22:03:14 -0600 Subject: [PATCH 181/331] Add *.class to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4707e8fb..d2115efc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.class */.vs *.suo From bc6580f2098dce0f215e0821ed87c68dd2ec951d Mon Sep 17 00:00:00 2001 From: Tim Buchalka <70119791+journich@users.noreply.github.com> Date: Sat, 8 Jan 2022 17:28:18 +1030 Subject: [PATCH 182/331] Fix for gunner rate being incorrectly asked for when missiles selected - see issue #457. Add test for player entering an amount for the percentage hit rate of gunners less than the minimum. It now shoots down the player as per the original game. --- 12_Bombs_Away/java/src/BombsAway.java | 51 +++++++++++++++++---------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/12_Bombs_Away/java/src/BombsAway.java b/12_Bombs_Away/java/src/BombsAway.java index e156ea73..b084ddcb 100644 --- a/12_Bombs_Away/java/src/BombsAway.java +++ b/12_Bombs_Away/java/src/BombsAway.java @@ -4,10 +4,16 @@ import java.util.Scanner; * Game of Bombs Away * * Based on the Basic game of Bombs Away here - * https://github.com/coding-horror/basic-computer-games/blob/main/12%20Bombs%20Away/bombsaway.bas + * https://github.com/coding-horror/basic-computer-games/blob/main/12_Bombs_Away/bombsaway.bas + * + * Note: The idea was to create a version of the 1970's Basic game in Java, without adding new features. + * Obvious bugs where found have been fixed, but the playability and overlook and feel + * of the game have been faithfully reproduced. + * + * Modern Java coding conventions have been employed and JDK 11 used for maximum compatibility. + * + * Java port by https://github.com/journich * - * Note: The idea was to create a version of the 1970's Basic game in Java, without introducing - * new features - no additional text, error checking, etc has been added. */ public class BombsAway { @@ -116,8 +122,9 @@ public class BombsAway { private int missions; - private int chanceToHit; + private int chanceToBeHit; private int percentageHitRateOfGunners; + private boolean liar; public BombsAway() { @@ -139,8 +146,9 @@ public class BombsAway { // Show an introduction the first time the game is played. case START: intro(); - chanceToHit = 0; + chanceToBeHit = 0; percentageHitRateOfGunners = 0; + liar = false; gameState = GAME_STATE.CHOOSE_SIDE; break; @@ -267,7 +275,7 @@ public class BombsAway { break; case CHOOSE_ENEMY_DEFENCES: - boolean bothWeapons = true; + percentageHitRateOfGunners = 0; ENEMY_DEFENCES enemyDefences = getEnemyDefences("DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3) ? "); if(enemyDefences == null) { @@ -275,31 +283,38 @@ public class BombsAway { } else { switch(enemyDefences) { case MISSILES: - case GUNS: - bothWeapons = false; + chanceToBeHit = 35; + break; - // fall through on purpose to BOTH since its pretty much identical code other than the chance to hit - // increasing if both weapons are part of the defence. + case GUNS: + + // fall through (no break) on purpose to case BOTH + // since it's identical code for GUNS or BOTH weapons case BOTH: + chanceToBeHit = 0; percentageHitRateOfGunners = getNumberFromKeyboard("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? "); if(percentageHitRateOfGunners < 10) { System.out.println("YOU LIE, BUT YOU'LL PAY..."); - } - if(bothWeapons) { - chanceToHit = 35; - + liar = true; } break; } } - gameState = GAME_STATE.PROCESS_FLAK; + // If player didn't lie when entering percentage hit rate of gunners continue with game + // Otherwise shoot down the player. + if(!liar) { + gameState = GAME_STATE.PROCESS_FLAK; + } else { + gameState = GAME_STATE.SHOT_DOWN; + } + break; - // Determine if the players airplan makes it through the Flak. + // Determine if the player's airplane makes it through the Flak. case PROCESS_FLAK: double calc = (CHANCE_OF_BEING_SHOT_DOWN_BASE * randomNumber(1)); - if ((chanceToHit + percentageHitRateOfGunners) > calc) { + if ((chanceToBeHit + percentageHitRateOfGunners) > calc) { gameState = GAME_STATE.SHOT_DOWN; } else { gameState = GAME_STATE.MADE_IT_THROUGH_FLAK; @@ -462,7 +477,7 @@ public class BombsAway { /** * Check whether a string equals one of a variable number of values * Useful to check for Y or YES for example - * Comparison is case insensitive. + * Comparison is case-insensitive. * * @param text source string * @param values a range of values to compare against the source string From 5caa02958ef28d925406a024a4ab87e84987c003 Mon Sep 17 00:00:00 2001 From: Yash Chauhan <68198489+ITrustNumbers@users.noreply.github.com> Date: Sat, 8 Jan 2022 15:11:02 +0530 Subject: [PATCH 183/331] Ported 83_Stock_Market to Python I've used an Object-Oriented Approach. The code's a little messy, We'll clean it up later. --- 83_Stock_Market/python/Stock_Market.py | 208 +++++++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 83_Stock_Market/python/Stock_Market.py diff --git a/83_Stock_Market/python/Stock_Market.py b/83_Stock_Market/python/Stock_Market.py new file mode 100644 index 00000000..98386cc1 --- /dev/null +++ b/83_Stock_Market/python/Stock_Market.py @@ -0,0 +1,208 @@ +import random + +#Stock_Market +class Stock_Market(): + + def __init__(self): + + #Hard Coded Names + short_names = ['IBM', 'RCA', 'LBJ', 'ABC', 'CBS'] + full_names = ['INT. BALLISTIC MISSLES', 'RED CROSS OF AMERICA', + 'LICHTENSTEIN, BUMRAP & JOKE', 'AMERICAN BANKRUPT CO.', + 'CENSURED BOOKS STORE'] + + #Initializing Dictionary to hold all the information systematically + self.data = {} + for sn, fn in zip(short_names, full_names): + #A dictionary for each stock + temp = {'Name' : fn, 'Price' : None, 'Holdings' : 0} + #Nested outer dictionary for all stocks + self.data[sn] = temp + + #Initializing Randomly generated initial prices + for stock in self.data.values(): + stock['Price'] = round(random.uniform(80,120),2) #Price b/w 60 and 120 + + #Initialize Assets + self.cash_assets = 10000 + self.stock_assets = 0 + + def total_assets(self): + + return self.cash_assets + self.stock_assets + + 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): + + self._generate_day_change() + for stock, change in zip(self.data.values(), self.changes): + stock['Price'] = round(stock['Price'] + (change/100)*stock['Price'], 2) + + def print_exchange_average(self): + + sum = 0 + for stock in self.data.values(): + sum += stock['Price'] + + print('\nNEW YORK STOCK EXCHANGE AVERAGE: ${:.2f}'.format(sum/5)) + + def get_average_change(self): + + sum = 0 + for change in self.changes: + sum += change + + return round(sum/5,2) + + def print_first_day(self): + + print('\nSTOCK\t\t\t\t\tINITIALS\tPRICE/SHARE($)') + for stock, data in self.data.items(): + if stock != 'LBJ': + print('{}\t\t\t{}\t\t{}'.format(data['Name'], stock, data['Price'])) + else: + print('{}\t\t{}\t\t{}'.format(data['Name'], stock, data['Price'])) + + self.print_exchange_average() + self.print_assets() + + def take_inputs(self): + + print('\nWHAT IS YOUR TRANSACTION IN') + flag = False + while flag != True: + new_holdings = [] + for stock in self.data.keys(): + try: + new_holdings.append(int(input('{}? '.format(stock)))) + except: + print('\nINVALID ENTRY, TRY AGAIN\n') + break + if len(new_holdings) == 5: + flag = self._check_transaction(new_holdings) + + return new_holdings + + def print_trading_day(self): + + print("STOCK\tPRICE/SHARE\tHOLDINGS\tNET. Value\tPRICE CHANGE") + for stock, data, change in zip(self.data.keys(), self.data.values(),self.changes): + value = data['Price'] * data['Holdings'] + print('{}\t{}\t\t{}\t\t{:.2f}\t\t{}'.format(stock, data['Price'], data['Holdings'], value, change)) + + def update_cash_assets(self, new_holdings): + + sell=0 + buy=0 + for stock, holding in zip(self.data.values(), new_holdings): + if holding > 0: + buy += stock['Price']*holding + + elif holding < 0: + sell += stock['Price']*abs(holding) + + self.cash_assets = self.cash_assets + sell - buy + + def update_stock_assets(self): + + sum=0 + for data in self.data.values(): + sum += data['Price']*data['Holdings'] + + self.stock_assets = round(sum,2) + + def print_assets(self): + + print('\nTOTAL STOCK ASSETS ARE: ${:.2f}'.format(self.stock_assets)) + print('TOTAL CASH ASSETS ARE: ${:.2f}'.format(self.cash_assets)) + print('TOTAL ASSETS ARE: ${:.2f}'.format(self.total_assets())) + + def _check_transaction(self, new_holdings): + + sum = 0 + for stock, holding in zip(self.data.values(), new_holdings): + if holding > 0: + sum += stock['Price']*holding + + elif holding < 0: + if abs(holding) > stock['Holdings']: + print('\nYOU HAVE OVERSOLD SOME STOCKS, TRY AGAIN\n') + return False + + if sum > self.cash_assets: + print('\nYOU HAVE USED ${:.2f} MORE THAN YOU HAVE, TRY AGAIN\n'.format(sum - self.cash_assets)) + return False + + return True + + def update_holdings(self, new_holdings): + + for stock, new_holding in zip(self.data.values(), new_holdings): + stock['Holdings'] += new_holding + +def print_instruction(): + + print(''' +THIS PROGRAM PLAYS THE STOCK MARKET. YOU WILL BE GIVEN +$10,000 AND MAY BUY OR SELL STOCKS. THE STOCK PRICES WILL +BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT +REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE. A TABLE +OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES +IN YOUR PORTFOLIO WILL BE PRINTED. FOLLOWING THIS, THE +INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION +MARK. HERE YOU INDICATE A TRANSACTION. TO BUY A STOCK +TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE +NUMBER OF SHARES. A BROKERAGE FEE OF 1% WILL BE CHARGED +ON ALL TRANSACTIONS. NOTE THAT IF A STOCK'S VALUE DROPS +TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN. YOU +HAVE $10,000 TO INVEST. USE INTEGERS FOR ALL YOUR INPUTS. +(NOTE: TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST +10 DAYS) + ------------GOOD LUCK!------------\n + ''') + +if __name__ == "__main__": + + print('\t\t STOCK MARKET') + help = input('\nDO YOU WANT INSTRUCTIONS(YES OR NO)? ') + + #Printing Instruction + if help == 'YES' or help == 'yes' or help == 'Yes': + print_instruction() + + #Initialize Game + Game = Stock_Market() + + #Do first day + Game.print_first_day() + new_holdings = Game.take_inputs() + Game.update_holdings(new_holdings) + Game.update_cash_assets(new_holdings) + print('\n------------END OF TRADING DAY--------------\n') + + response = 1 + while response == 1: + + #Simulate a DAY + Game.update_prices() + Game.print_trading_day() + Game.print_exchange_average() + Game.update_stock_assets() + Game.print_assets() + + response = int(input('\nDO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)? ')) + if response == 0: + break + + new_holdings = Game.take_inputs() + Game.update_holdings(new_holdings) + Game.update_cash_assets(new_holdings) + print('\n------------END OF TRADING DAY--------------\n') + + print('\nHOPE YOU HAD FUN!!!!') + input('') From d5a226079606527aeca533b1de9a49f03bdea739 Mon Sep 17 00:00:00 2001 From: Bill Cruise Date: Sat, 8 Jan 2022 12:56:44 -0500 Subject: [PATCH 184/331] Reformat to make code more Pythonic and (hopefully) readable. --- 43_Hammurabi/python/hamurabi.py | 369 +++++++++++++++++--------------- 1 file changed, 194 insertions(+), 175 deletions(-) diff --git a/43_Hammurabi/python/hamurabi.py b/43_Hammurabi/python/hamurabi.py index 24ebe581..39ac4cd1 100644 --- a/43_Hammurabi/python/hamurabi.py +++ b/43_Hammurabi/python/hamurabi.py @@ -1,183 +1,202 @@ -def GenRandom(C): - C=int(random()*5)+1 -def BadInput850(): - print ( "\nHAMURABI: I CANNOT DO WHAT YOU WISH.") - print ( "GET YOURSELF ANOTHER STEWARD!!!!!") - Z=99 -def BadInput710(S): - print ( "HAMURABI: THINK AGAIN. YOU HAVE ONLY") - print ( S,"BUSHELS OF GRAIN. NOW THEN,") -def BadInput720(A): - print ( "HAMURABI: THINK AGAIN. YOU OWN ONLY",A,"ACRES. NOW THEN,") -def BadInput710(S): - print ( "HAMURABI: THINK AGAIN. YOU HAVE ONLY") - print ( S,"BUSHELS OF GRAIN. NOW THEN,") -def NationalFink(): - 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): #emulate BASIC input. It rejects non-numeric values - x=input(promptstring) - while x.isalpha(): - x=input("?REDO FROM START\n? ") - return int(x) - from random import random from random import seed + + +def gen_random(C): + C = int(random() * 5) + 1 + + +def bad_input_850(): + print("\nHAMURABI: I CANNOT DO WHAT YOU WISH.") + print("GET YOURSELF ANOTHER STEWARD!!!!!") + Z = 99 + + +def bad_input_710(S): + print("HAMURABI: THINK AGAIN. YOU HAVE ONLY") + print(S, "BUSHELS OF GRAIN. NOW THEN,") + + +def bad_input_720(A): + print("HAMURABI: THINK AGAIN. YOU OWN ONLY", A, "ACRES. NOW THEN,") + + +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): # emulate BASIC input. It rejects non-numeric values + x = input(promptstring) + while x.isalpha(): + x = input("?REDO FROM START\n? ") + return int(x) + + seed() title = "HAMURABI" -title = title.rjust(32,' ') -print (title) +title = title.rjust(32, ' ') +print(title) attribution = "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" -attribution = attribution.rjust(15," ") -print (attribution) -print ('\n\n\n') -print ("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA") -print ("FOR A TEN-YEAR TERM OF OFFICE.\n") -D1=0 -P1=0 -Z=0 #year -P=95 #population -S=2800 #grain stores -H=3000 -E=H-S #rats eaten -Y=3 #yield (amount of production from land). Reused as price per acre -A=H/Y #acres of land -I=5 #immigrants -Q=1 #boolean for plague, also input for buy/sell land -D=0 # people -while (Z<11): #line 270. main loop. while the year is less than 11 - print ("\n\n\nHAMURABI: I BEG TO REPORT TO YOU") - Z=Z+1 #year - print ( "IN YEAR",Z,",",D,"PEOPLE STARVED,",I,"CAME TO THE CITY,") - P=P+I - if Q==0: - P=int(P/2) - print ("A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED.") - print ("POPULATION IS NOW",P) - print ("THE CITY NOW OWNS",A,"ACRES.") - print ("YOU HARVESTED",Y,"BUSHELS PER ACRE.") - print ("THE RATS ATE",E,"BUSHELS.") - print ("YOU NOW HAVE ",S,"BUSHELS IN STORE.\n") - C=int(10*random()) #random number between 1 and 10 - Y=C+17 - print ("LAND IS TRADING AT",Y,"BUSHELS PER ACRE.") - Q=-99 #dummy value to track status - while Q==-99: #always run the loop once - Q = B_input("HOW MANY ACRES DO YOU WISH TO BUY? ") - if Q<0: - Q = -1 #to avoid the corner case of Q=-99 - BadInput850() - Z=99 #jump out of main loop and exit - elif Y*Q>S: #can't afford it - BadInput710(S) - Q=-99 # give'm a second change to get it right - elif Y*Q<=S: #normal case, can afford it - A=A+Q #increase the number of acres by Q - S=S-Y*Q #decrease the amount of grain in store to pay for it - C=0 #WTF is C for? - if Q ==0 and Z!=99: #maybe you want to sell some land? +attribution = attribution.rjust(15, " ") +print(attribution) +print('\n\n\n') +print("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA") +print("FOR A TEN-YEAR TERM OF OFFICE.\n") + +D1 = 0 +P1 = 0 +Z = 0 # year +P = 95 # population +S = 2800 # grain stores +H = 3000 +E = H - S # rats eaten +Y = 3 # yield (amount of production from land). Reused as price per acre +A = H / Y # acres of land +I = 5 # immigrants +Q = 1 # boolean for plague, also input for buy/sell land +D = 0 # people + +while Z < 11: # line 270. main loop. while the year is less than 11 + print("\n\n\nHAMURABI: I BEG TO REPORT TO YOU") + Z = Z + 1 # year + print("IN YEAR", Z, ",", D, "PEOPLE STARVED,", I, "CAME TO THE CITY,") + P = P + I + + if Q == 0: + P = int(P / 2) + print("A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED.") + + print("POPULATION IS NOW", P) + print("THE CITY NOW OWNS", A, "ACRES.") + print("YOU HARVESTED", Y, "BUSHELS PER ACRE.") + print("THE RATS ATE", E, "BUSHELS.") + print("YOU NOW HAVE ", S, "BUSHELS IN STORE.\n") + C = int(10 * random()) # random number between 1 and 10 + Y = C + 17 + print("LAND IS TRADING AT", Y, "BUSHELS PER ACRE.") + + Q = -99 # dummy value to track status + while Q == -99: # always run the loop once + Q = b_input("HOW MANY ACRES DO YOU WISH TO BUY? ") + if Q < 0: + Q = -1 # to avoid the corner case of Q=-99 + bad_input_850() + Z = 99 # jump out of main loop and exit + elif Y * Q > S: # can't afford it + bad_input_710(S) + Q = -99 # give'm a second change to get it right + elif Y * Q <= S: # normal case, can afford it + A = A + Q # increase the number of acres by Q + S = S - Y * Q # decrease the amount of grain in store to pay for it + C = 0 # WTF is C for? + + if Q == 0 and Z != 99: # maybe you want to sell some land? Q = -99 - while Q==-99: - Q = B_input( "HOW MANY ACRES DO YOU WISH TO SELL? ") - if Q<0: - BadInput850() - Z=99 #jump out of main loop and exit - elif Q<=A:#normal case - A=A-Q # reduce the acres - S=S+Y*Q #add to grain stores - C=0 #still don't know what C is for - else: #Q>A error! - BadInput720() - Q=-99 #reloop - print ("\n") - Q=-99 - while Q==-99 and Z!=99: - Q = B_input("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? ") - if Q<0: - BadInput850() - #REM *** TRYING TO USE MORE GRAIN THAN IS IN SILOS? - elif Q>S: - BadInput710 - Q=-99 #try again! - else: #we're good. do the transaction - S=S-Q #remove the grain from the stores - C=1 #set the speed of light to 1. jk - print ("\n") - D=-99 #dummy value to force at least one loop - while D == -99 and Z!=99: - D = B_input("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? ") - if D<0: - BadInput850() - Z=99 - elif D>0: - if D>A: - #REM *** TRYING TO PLANT MORE ACRES THAN YOU OWN? - BadInput720(A) - D = -99 - elif int(D/2)>S: - #REM *** ENOUGH GRAIN FOR SEED? - BadInput710(S) + while Q == -99: + Q = b_input("HOW MANY ACRES DO YOU WISH TO SELL? ") + if Q < 0: + bad_input_850() + Z = 99 # jump out of main loop and exit + elif Q <= A: # normal case + A = A - Q # reduce the acres + S = S + Y * Q # add to grain stores + C = 0 # still don't know what C is for + else: # Q>A error! + bad_input_720(A) + Q = -99 # reloop + print("\n") + + Q = -99 + while Q == -99 and Z != 99: + Q = b_input("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? ") + if Q < 0: + bad_input_850() + # REM *** TRYING TO USE MORE GRAIN THAN IS IN SILOS? + elif Q > S: + bad_input_710(S) + Q = -99 # try again! + else: # we're good. do the transaction + S = S - Q # remove the grain from the stores + C = 1 # set the speed of light to 1. jk + + print("\n") + D = -99 # dummy value to force at least one loop + while D == -99 and Z != 99: + D = b_input("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? ") + if D < 0: + bad_input_850() + Z = 99 + elif D > 0: + if D > A: + # REM *** TRYING TO PLANT MORE ACRES THAN YOU OWN? + bad_input_720(A) D = -99 - elif D>=10*P: - #REM *** ENOUGH PEOPLE TO TEND THE CROPS? - print ("BUT YOU HAVE ONLY",P,"PEOPLE TO TEND THE FIELDS! NOW THEN,") - D=-99 - else: #we're good. decrement the grain store - S=S-int(D/2) - GenRandom(C) - #REM *** A BOUNTIFUL HARVEST! - Y=C - H=D*Y - E=0 - GenRandom(C) - if int(C/2)==C/2: #even number. 50/50 chance - #REM *** RATS ARE RUNNING WILD!! - E=int(S/C) #calc losses due to rats, based on previous random number - S=S-E+H #deduct losses from stores - GenRandom(C) - #REM *** LET'S HAVE SOME BABIES - I=int(C*(20*A+S)/P/100+1) - #REM *** HOW MANY PEOPLE HAD FULL TUMMIES? - C=int(Q/20) - #REM *** HORROS, A 15% CHANCE OF PLAGUE - #yeah, should be HORRORS, but left it - Q=int(10*(2*random()-.3)) - if P>=C and Z!=99: #if there are some people without full bellies... - #REM *** STARVE ENOUGH FOR IMPEACHMENT? - D=P-C - if D>.45*P: - print ("\nYOU STARVED",D,"PEOPLE IN ONE YEAR!!!") - NationalFink() - Z=99 #exit the loop - P1=((Z-1)*P1+D*100/P)/Z - P=C - D1=D1+D -if Z!=99: - print ( "IN YOUR 10-YEAR TERM OF OFFICE,",P1,"PERCENT OF THE") - print ( "POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF") - print ( D1,"PEOPLE DIED!!") - L=A/P - print ( "YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH") - print ( L,"ACRES PER PERSON.\n") - if (P1>33 or L<7): - NationalFink() - elif (P1>10 or L<9): - print ( "YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.") - 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") - print ( "REALLY WASN'T TOO BAD AT ALL. ",int(P*.8*random()),"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!\n") - for N in range(1,10): - print ( '\a') + elif int(D / 2) > S: + # REM *** ENOUGH GRAIN FOR SEED? + bad_input_710(S) + D = -99 + elif D >= 10 * P: + # REM *** ENOUGH PEOPLE TO TEND THE CROPS? + print("BUT YOU HAVE ONLY", P, "PEOPLE TO TEND THE FIELDS! NOW THEN,") + D = -99 + else: # we're good. decrement the grain store + S = S - int(D / 2) + + gen_random(C) + # REM *** A BOUNTIFUL HARVEST! + Y = C + H = D * Y + E = 0 + + gen_random(C) + if int(C / 2) == C / 2: # even number. 50/50 chance + # REM *** RATS ARE RUNNING WILD!! + E = int(S / C) # calc losses due to rats, based on previous random number + S = S - E + H # deduct losses from stores + + gen_random(C) + # REM *** LET'S HAVE SOME BABIES + I = int(C * (20 * A + S) / P / 100 + 1) + # REM *** HOW MANY PEOPLE HAD FULL TUMMIES? + C = int(Q / 20) + # REM *** HORROS, A 15% CHANCE OF PLAGUE + # yeah, should be HORRORS, but left it + Q = int(10 * (2 * random() - .3)) + if P >= C and Z != 99: # if there are some people without full bellies... + # REM *** STARVE ENOUGH FOR IMPEACHMENT? + D = P - C + if D > .45 * P: + print("\nYOU STARVED", D, "PEOPLE IN ONE YEAR!!!") + national_fink() + Z = 99 # exit the loop + P1 = ((Z - 1) * P1 + D * 100 / P) / Z + P = C + D1 = D1 + D + +if Z != 99: + print("IN YOUR 10-YEAR TERM OF OFFICE,", P1, "PERCENT OF THE") + print("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF") + print(D1, "PEOPLE DIED!!") + L = A / P + print("YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH") + print(L, "ACRES PER PERSON.\n") + if P1 > 33 or L < 7: + national_fink() + elif P1 > 10 or L < 9: + print("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.") + 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") + print("REALLY WASN'T TOO BAD AT ALL. ", int(P * .8 * random()), "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!\n") + for N in range(1, 10): + print('\a') + print("\nSO LONG FOR NOW.\n") - - - From a360ca17ca8315b28ee40a4829f786cf88c55529 Mon Sep 17 00:00:00 2001 From: Bill Cruise Date: Sat, 8 Jan 2022 13:18:09 -0500 Subject: [PATCH 185/331] Return a value from gen_random function. --- 43_Hammurabi/python/hamurabi.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/43_Hammurabi/python/hamurabi.py b/43_Hammurabi/python/hamurabi.py index 39ac4cd1..7c18f892 100644 --- a/43_Hammurabi/python/hamurabi.py +++ b/43_Hammurabi/python/hamurabi.py @@ -2,8 +2,8 @@ from random import random from random import seed -def gen_random(C): - C = int(random() * 5) + 1 +def gen_random(): + return int(random() * 5) + 1 def bad_input_850(): @@ -144,19 +144,19 @@ while Z < 11: # line 270. main loop. while the year is less than 11 else: # we're good. decrement the grain store S = S - int(D / 2) - gen_random(C) + C = gen_random() # REM *** A BOUNTIFUL HARVEST! Y = C H = D * Y E = 0 - gen_random(C) + C = gen_random() if int(C / 2) == C / 2: # even number. 50/50 chance # REM *** RATS ARE RUNNING WILD!! E = int(S / C) # calc losses due to rats, based on previous random number S = S - E + H # deduct losses from stores - gen_random(C) + C = gen_random() # REM *** LET'S HAVE SOME BABIES I = int(C * (20 * A + S) / P / 100 + 1) # REM *** HOW MANY PEOPLE HAD FULL TUMMIES? From a78c1e812209d2a5f6f20afb0207725a4aba0442 Mon Sep 17 00:00:00 2001 From: Tim Buchalka <70119791+journich@users.noreply.github.com> Date: Sun, 9 Jan 2022 06:50:24 +1030 Subject: [PATCH 186/331] Another issue #457 bugfix. Player selecting enemy weapons option BOTH (GUNS and MISSILES) now calculates amount correctly resulting in a higher likelyhood of being shot down. Added comments to make it clearer how the calculation worked for all enemy weapons. --- 12_Bombs_Away/java/src/BombsAway.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/12_Bombs_Away/java/src/BombsAway.java b/12_Bombs_Away/java/src/BombsAway.java index b084ddcb..290b2c6d 100644 --- a/12_Bombs_Away/java/src/BombsAway.java +++ b/12_Bombs_Away/java/src/BombsAway.java @@ -281,18 +281,20 @@ public class BombsAway { if(enemyDefences == null) { System.out.println("TRY AGAIN..."); } else { + chanceToBeHit = 35; switch(enemyDefences) { case MISSILES: - chanceToBeHit = 35; + // MISSILES... An extra 35 but cannot specify percentage hit rate for gunners break; case GUNS: - - // fall through (no break) on purpose to case BOTH - // since it's identical code for GUNS or BOTH weapons + // GUNS... No extra 35 but can specify percentage hit rate for gunners + chanceToBeHit = 0; + // fall through (no break) on purpose because remaining code is applicable + // for both GUNS and BOTH options. case BOTH: - chanceToBeHit = 0; + // BOTH... An extra 35 and percentage hit rate for gunners can be specified. percentageHitRateOfGunners = getNumberFromKeyboard("WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? "); if(percentageHitRateOfGunners < 10) { System.out.println("YOU LIE, BUT YOU'LL PAY..."); From 7274cf82dd2835b681884e873f969ed10315e1c8 Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Sat, 8 Jan 2022 15:42:01 -0500 Subject: [PATCH 187/331] Port 67_One_Check to Perl. This is pretty much a straight port to idiomatic Perl. --- 67_One_Check/perl/onecheck.pl | 252 ++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100755 67_One_Check/perl/onecheck.pl diff --git a/67_One_Check/perl/onecheck.pl b/67_One_Check/perl/onecheck.pl new file mode 100755 index 00000000..62f1f0be --- /dev/null +++ b/67_One_Check/perl/onecheck.pl @@ -0,0 +1,252 @@ +#!/usr/bin/env perl + +use 5.010; # To get 'state' and 'say' + +use strict; # Require explicit declaration of variables +use warnings; # Enable optional compiler warnings + +use English; # Use more friendly names for Perl's magic variables +use List::Util qw{ sum }; # Add all its arguments +use Term::ReadLine; # Prompt and return user input + +our $VERSION = '0.000_01'; + +print <<'EOD'; + ONE CHECK + Creative Computing Morristown, New Jersey + + + +Solitaire checker puzzle by David Ahl + +48 checkers are 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?' +EOD + +while ( 1 ) { # Iterate indefinitely + + board_num(); # Display the numerical board. + + # Initialize the board, which is a two-dimensional array. + my @board = map { [ ( 1 ) x 8 ] } 0 .. 7; # Initialize to all 1. + for my $row ( 2 .. 5 ) { # Set the center section to 0 + for my $col ( 2 .. 5 ) { + $board[$row][$col] = 0; + } + } + + print <<'EOD'; +And here is the opening position of the checkers. + +EOD + board_pos( \@board ); + + my $moves = 0; # Number of moves made. + + # A game proceeds while 'Jump from' is a true value. We make use of + # the fact that of the possible returns, only 0 evaluates false. + while ( my $jump_from = get_input( + 'Jump from? ', + sub { + $ARG = lc; # The caller sees this. + return 1 if $ARG eq 'b'; + return unless m/ \A [0-9]+ \z /smx; + $ARG += 0; # Numify, because string '00' is true. + return $ARG < 65; + }, + "Please enter a number from 0 to 64, or 'b' to re-display the numeric board\n" + ) + ) { + if ( $jump_from eq 'b' ) { + board_num(); + board_pos( \@board ); + next; + } + + my $jump_to = get_input( + ' to? ', + sub { m/ \A [0-9]+ \z /smx }, + "Please enter a number from 1 to 64\n", + ); + + if ( make_move( \@board, $jump_from, $jump_to ) ) { + $moves++; + board_pos( \@board ); + } else { + say 'Illegal move. Try again.'; + } + } + + my $checkers_left = sum( map { sum( @{ $board[$_] } ) } 0 .. 7 ); + print <<"EOD"; + +You made $moves jumps and had $checkers_left pieces +remaining on the board. + +EOD + + last unless get_yes_no( 'Try again' ); + +} + +print <<'EOD'; + +O.K. Hope you had fun!! +EOD + +# Print the numerical board +sub board_num { + print <<'EOD'; + +Here is the numerical board: + +EOD + foreach my $row ( 0 .. 7 ) { + state $tplt = ( '%3d' x 8 ) . "\n"; + my $inx = $row * 8; + printf $tplt, map { $inx + $_ } 1 .. 8; + } + say ''; + return; +} + +# Print the board position +sub board_pos { + my ( $board ) = @_; + for my $row ( 0 .. 7 ) { + state $tplt = ( '%2d' x 8 ) . "\n"; + printf $tplt, @{ $board->[$row] }; + } + say ''; + return; +} + +# Make the move. This is a subroutine for convenience in control flow. +# We return a true value for success, and false for failure. +sub make_move { + my ( $board, $jump_from, $jump_to ) = @_; + $jump_from -= 1; + $jump_to -= 1; + my $from_row = int( $jump_from / 8 ); # Truncates toward 0 + my $from_col = $jump_from % 8; + my $to_row = int( $jump_to / 8 ); # Truncates toward 0 + my $to_col = $jump_to % 8; + return unless $board->[$from_row][$from_col]; # From must be occupied + return if $board->[$to_row][$to_col]; # To must be vacant + return unless abs( $from_row - $to_row ) == 2; # Must cross two rows + return unless abs( $from_col - $to_col ) == 2; # Must cross two cols + my $over_row = ( $from_row + $to_row ) / 2; # The row jumped over + my $over_col = ( $from_col + $to_col ) / 2; # The col jumped over + $board->[$from_row][$from_col] = # Clear the from cell + $board->[$over_row][$over_col] = 0; # and the jumped cell + $board->[$to_row][$to_col] = 1; # Occupy the to cell + return 1; +} + +# Get input from the user. The arguments are: +# * The prompt +# * A reference to validation code. This code receives the response in +# $ARG and returns true for a valid response. +# * A warning to print if the response is not valid. This must end in a +# return. +# The first valid response is returned. An end-of-file terminates the +# script. +sub get_input { + my ( $prompt, $validate, $warning ) = @ARG; + + # If no validator is passed, default to one that always returns + # true. + $validate ||= sub { 1 }; + + # Create the readline object. The 'state' causes the variable to be + # initialized only once, no matter how many times this subroutine is + # called. The do { ... } is a compound statement used because we + # need to tweak the created object before we store it. + state $term = do { + my $obj = Term::ReadLine->new( 'reverse' ); + $obj->ornaments( 0 ); + $obj; + }; + + while ( 1 ) { # Iterate indefinitely + + # Read the input into the topic variable, localized to prevent + # Spooky Action at a Distance. We exit on undef, which signals + # end-of-file. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Return the input if it is valid. + return $ARG if $validate->(); + + # Issue the warning, and go around the merry-go-round again. + warn $warning; + } +} + +# Get a yes-or-no answer. The argument is the prompt, which will have +# '? [y/n]: ' appended. The donkey work is done by get_input(), which is +# requested to validate the response as beginning with 'y' or 'n', +# case-insensitive. The return is a true value for 'y' and a false value +# for 'n'. +sub get_yes_no { + my ( $prompt ) = @ARG; + state $map_answer = { + n => 0, + y => 1, + }; + my $resp = lc get_input( + "$prompt? [y/n]: ", + sub { m/ \A [yn] /smxi }, + "Please respond 'y' or 'n'\n", + ); + return $map_answer->{ substr $resp, 0, 1 }; +} + +__END__ + +=head1 TITLE + +one check - Play the game 'One Check' from Basic Computer Games + +=head1 SYNOPSIS + + one check.pl + +=head1 DETAILS + +This Perl script is a port of onecheck. + +This is a solitaire game played on a checker board, where the object is +to eliminate as many checkers as possible by making diagonal jumps and +removing the jumped checkers. + +It is pretty much a straight port of the BASIC original. + +=head1 PORTED BY + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set expandtab tabstop=4 textwidth=72 : From c8fccde8892305549e689e4eb353ee86a57dd0f5 Mon Sep 17 00:00:00 2001 From: Yuriy Lyeshchenko Date: Sat, 8 Jan 2022 19:00:19 -0600 Subject: [PATCH 188/331] Implementing https://github.com/coding-horror/basic-computer-games/blob/main/15_Boxing/boxing.bas in C# --- 15_Boxing/csharp/AttackStrategy.cs | 48 ++++++++ 15_Boxing/csharp/Boxer.cs | 45 ++++++++ 15_Boxing/csharp/Boxing.csproj | 10 ++ 15_Boxing/csharp/Boxing.sln | 22 ++++ 15_Boxing/csharp/OpponentAttackStrategy.cs | 115 ++++++++++++++++++++ 15_Boxing/csharp/PlayerAttackStrategy.cs | 121 +++++++++++++++++++++ 15_Boxing/csharp/Program.cs | 29 +++++ 15_Boxing/csharp/Punch.cs | 9 ++ 15_Boxing/csharp/Round.cs | 96 ++++++++++++++++ 15_Boxing/csharp/Utils.cs | 35 ++++++ 10 files changed, 530 insertions(+) create mode 100644 15_Boxing/csharp/AttackStrategy.cs create mode 100644 15_Boxing/csharp/Boxer.cs create mode 100644 15_Boxing/csharp/Boxing.csproj create mode 100644 15_Boxing/csharp/Boxing.sln create mode 100644 15_Boxing/csharp/OpponentAttackStrategy.cs create mode 100644 15_Boxing/csharp/PlayerAttackStrategy.cs create mode 100644 15_Boxing/csharp/Program.cs create mode 100644 15_Boxing/csharp/Punch.cs create mode 100644 15_Boxing/csharp/Round.cs create mode 100644 15_Boxing/csharp/Utils.cs diff --git a/15_Boxing/csharp/AttackStrategy.cs b/15_Boxing/csharp/AttackStrategy.cs new file mode 100644 index 00000000..5ffdb2cc --- /dev/null +++ b/15_Boxing/csharp/AttackStrategy.cs @@ -0,0 +1,48 @@ +namespace Boxing; + +public abstract class AttackStrategy +{ + protected const int KnockoutDamageThreshold = 35; + protected readonly Boxer Other; + protected readonly Stack Work; + private readonly Action _notifyGameEnded; + + public AttackStrategy(Boxer other, Stack work, Action notifyGameEnded) + { + Other = other; + Work = work; + _notifyGameEnded = notifyGameEnded; + } + + public void Attack() + { + var punch = GetPunch(); + if (punch.IsBestPunch) + { + Other.DamageTaken += 2; + } + + Work.Push(punch.Punch switch + { + Punch.FullSwing => FullSwing, + Punch.Hook => Hook, + Punch.Uppercut => Uppercut, + _ => Jab + }); + } + + protected abstract AttackPunch GetPunch(); + protected abstract void FullSwing(); + protected abstract void Hook(); + protected abstract void Uppercut(); + protected abstract void Jab(); + + protected void RegisterKnockout(string knockoutMessage) + { + Work.Clear(); + _notifyGameEnded(); + Console.WriteLine(knockoutMessage); + } + + protected record AttackPunch(Punch Punch, bool IsBestPunch); +} \ No newline at end of file diff --git a/15_Boxing/csharp/Boxer.cs b/15_Boxing/csharp/Boxer.cs new file mode 100644 index 00000000..3f5fdd26 --- /dev/null +++ b/15_Boxing/csharp/Boxer.cs @@ -0,0 +1,45 @@ +namespace Boxing; + +public class Boxer +{ + private int _wins; + + private string Name { get; set; } = string.Empty; + + public Punch BestPunch { get; set; } + + public Punch Vulnerability { get; set; } + + public void SetName(string prompt) + { + Console.WriteLine(prompt); + string? name; + do + { + name = Console.ReadLine(); + } while (string.IsNullOrWhiteSpace(name)); + Name = name; + } + + public int DamageTaken { get; set; } + + public void ResetForNewRound() => DamageTaken = 0; + + public void RecordWin() => _wins += 1; + + public bool IsWinner => _wins >= 2; + + public override string ToString() => Name; +} + +public class Opponent : Boxer +{ + public void SetRandomPunches() + { + do + { + BestPunch = (Punch) GameUtils.Roll(4); // B1 + Vulnerability = (Punch) GameUtils.Roll(4); // D1 + } while (BestPunch == Vulnerability); + } +} \ No newline at end of file diff --git a/15_Boxing/csharp/Boxing.csproj b/15_Boxing/csharp/Boxing.csproj new file mode 100644 index 00000000..74abf5c9 --- /dev/null +++ b/15_Boxing/csharp/Boxing.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/15_Boxing/csharp/Boxing.sln b/15_Boxing/csharp/Boxing.sln new file mode 100644 index 00000000..6202b593 --- /dev/null +++ b/15_Boxing/csharp/Boxing.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Boxing", "Boxing.csproj", "{52A7BDE5-3085-4F58-AC57-2BA4E65212D8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {52A7BDE5-3085-4F58-AC57-2BA4E65212D8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/15_Boxing/csharp/OpponentAttackStrategy.cs b/15_Boxing/csharp/OpponentAttackStrategy.cs new file mode 100644 index 00000000..c5bf3e38 --- /dev/null +++ b/15_Boxing/csharp/OpponentAttackStrategy.cs @@ -0,0 +1,115 @@ +using static Boxing.GameUtils; +using static System.Console; + +namespace Boxing; + +public class OpponentAttackStrategy : AttackStrategy +{ + private readonly Opponent _opponent; + + public OpponentAttackStrategy(Opponent opponent, Boxer player, Action notifyGameEnded, Stack work) : base(player, work, notifyGameEnded) + { + _opponent = opponent; + } + + protected override AttackPunch GetPunch() + { + var punch = (Punch)Roll(4); + return new AttackPunch(punch, punch == _opponent.BestPunch); + } + + protected override void FullSwing() // 720 + { + Write($"{_opponent} TAKES A FULL SWING AND"); + if (Other.Vulnerability == Punch.FullSwing) + { + ScoreFullSwing(); + } + else + { + if (RollSatisfies(60, x => x < 30)) + { + WriteLine(" IT'S BLOCKED!"); + } + else + { + ScoreFullSwing(); + } + } + + void ScoreFullSwing() + { + WriteLine(" POW!!!!! HE HITS HIM RIGHT IN THE FACE!"); + if (Other.DamageTaken > KnockoutDamageThreshold) + { + Work.Push(RegisterOtherKnockedOut); + } + Other.DamageTaken += 15; + } + } + + protected override void Hook() // 810 + { + Write($"{_opponent} GETS {Other} IN THE JAW (OUCH!)"); + Other.DamageTaken += 7; + WriteLine("....AND AGAIN!"); + Other.DamageTaken += 5; + if (Other.DamageTaken > KnockoutDamageThreshold) + { + Work.Push(RegisterOtherKnockedOut); + } + } + + protected override void Uppercut() // 860 + { + Write($"{Other} IS ATTACKED BY AN UPPERCUT (OH,OH)..."); + if (Other.Vulnerability == Punch.Uppercut) + { + ScoreUppercut(); + } + else + { + if (RollSatisfies(200, x => x > 75)) + { + WriteLine($" BLOCKS AND HITS {_opponent} WITH A HOOK."); + _opponent.DamageTaken += 5; + } + else + { + ScoreUppercut(); + } + } + + void ScoreUppercut() + { + WriteLine($"AND {_opponent} CONNECTS..."); + Other.DamageTaken += 8; + } + } + + protected override void Jab() // 640 + { + Write($"{_opponent} JABS AND "); + if (Other.Vulnerability == Punch.Jab) + { + ScoreJab(); + } + else + { + if (RollSatisfies(7, x => x > 4)) + { + WriteLine("BLOOD SPILLS !!!"); + ScoreJab(); + } + else + { + WriteLine("IT'S BLOCKED!"); + } + } + + void ScoreJab() => Other.DamageTaken += 5; + } + + private void RegisterOtherKnockedOut() + => RegisterKnockout($"{Other} IS KNOCKED COLD AND {_opponent} IS THE WINNER AND CHAMP!"); +} \ No newline at end of file diff --git a/15_Boxing/csharp/PlayerAttackStrategy.cs b/15_Boxing/csharp/PlayerAttackStrategy.cs new file mode 100644 index 00000000..fd43c0ed --- /dev/null +++ b/15_Boxing/csharp/PlayerAttackStrategy.cs @@ -0,0 +1,121 @@ +using static Boxing.GameUtils; +using static System.Console; +namespace Boxing; + +public class PlayerAttackStrategy : AttackStrategy +{ + private readonly Boxer _player; + + public PlayerAttackStrategy(Boxer player, Opponent opponent, Action notifyGameEnded, Stack work) + : base(opponent, work, notifyGameEnded) => _player = player; + + protected override AttackPunch GetPunch() + { + var punch = GameUtils.GetPunch($"{_player}'S PUNCH"); + return new AttackPunch(punch, punch == _player.BestPunch); + } + + protected override void FullSwing() // 340 + { + Write($"{_player} SWINGS AND "); + if (Other.Vulnerability == Punch.FullSwing) + { + ScoreFullSwing(); + } + else + { + if (RollSatisfies(30, x => x < 10)) + { + ScoreFullSwing(); + } + else + { + WriteLine("HE MISSES"); + } + } + + void ScoreFullSwing() + { + WriteLine("HE CONNECTS!"); + if (Other.DamageTaken > KnockoutDamageThreshold) + { + Work.Push(() => RegisterKnockout($"{Other} IS KNOCKED COLD AND {_player} IS THE WINNER AND CHAMP!")); + } + Other.DamageTaken += 15; + } + } + + protected override void Uppercut() // 520 + { + Write($"{_player} TRIES AN UPPERCUT "); + if (Other.Vulnerability == Punch.Uppercut) + { + ScoreUpperCut(); + } + else + { + if (RollSatisfies(100, x => x < 51)) + { + ScoreUpperCut(); + } + else + { + WriteLine("AND IT'S BLOCKED (LUCKY BLOCK!)"); + } + } + + void ScoreUpperCut() + { + WriteLine("AND HE CONNECTS!"); + Other.DamageTaken += 4; + } + } + + protected override void Hook() // 450 + { + Write($"{_player} GIVES THE HOOK... "); + if (Other.Vulnerability == Punch.Hook) + { + ScoreHookOnOpponent(); + } + else + { + if (RollSatisfies(2, x => x == 1)) + { + WriteLine("BUT IT'S BLOCKED!!!!!!!!!!!!!"); + } + else + { + ScoreHookOnOpponent(); + } + } + + void ScoreHookOnOpponent() + { + WriteLine("CONNECTS..."); + Other.DamageTaken += 7; + } + } + + protected override void Jab() + { + WriteLine($"{_player} JABS AT {Other}'S HEAD"); + if (Other.Vulnerability == Punch.Jab) + { + ScoreJabOnOpponent(); + } + else + { + if (RollSatisfies(8, x => x < 4)) + { + WriteLine("IT'S BLOCKED."); + } + else + { + ScoreJabOnOpponent(); + } + } + + void ScoreJabOnOpponent() => Other.DamageTaken += 3; + } +} \ No newline at end of file diff --git a/15_Boxing/csharp/Program.cs b/15_Boxing/csharp/Program.cs new file mode 100644 index 00000000..57923de0 --- /dev/null +++ b/15_Boxing/csharp/Program.cs @@ -0,0 +1,29 @@ +using Boxing; +using static Boxing.GameUtils; +using static System.Console; + +WriteLine(new string('\t', 33) + "BOXING"); +WriteLine(new string('\t', 15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); +WriteLine("{0}{0}{0}BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS){0}", Environment.NewLine); + +var opponent = new Opponent(); +opponent.SetName("WHAT IS YOUR OPPONENT'S NAME"); // J$ +var player = new Boxer(); +player.SetName("INPUT YOUR MAN'S NAME"); // L$ + +PrintPunchDescription(); +player.BestPunch = GetPunch("WHAT IS YOUR MANS BEST"); // B +player.Vulnerability = GetPunch("WHAT IS HIS VULNERABILITY"); // D +opponent.SetRandomPunches(); +WriteLine($"{opponent}'S ADVANTAGE IS {opponent.BestPunch.ToFriendlyString()} AND VULNERABILITY IS SECRET."); + + +for (var i = 1; i <= 3; i ++) // R +{ + var round = new Round(player, opponent, i); + round.Start(); + round.CheckOpponentWin(); + round.CheckPlayerWin(); + if (round.GameEnded) break; +} +WriteLine("{0}{0}AND NOW GOODBYE FROM THE OLYMPIC ARENA.{0}", Environment.NewLine); \ No newline at end of file diff --git a/15_Boxing/csharp/Punch.cs b/15_Boxing/csharp/Punch.cs new file mode 100644 index 00000000..add2003a --- /dev/null +++ b/15_Boxing/csharp/Punch.cs @@ -0,0 +1,9 @@ +namespace Boxing; + +public enum Punch +{ + FullSwing = 1, + Hook = 2, + Uppercut = 3, + Jab = 4 +} \ No newline at end of file diff --git a/15_Boxing/csharp/Round.cs b/15_Boxing/csharp/Round.cs new file mode 100644 index 00000000..dfa1e26b --- /dev/null +++ b/15_Boxing/csharp/Round.cs @@ -0,0 +1,96 @@ +namespace Boxing; + +class Round +{ + + private readonly Boxer _player; + private readonly Boxer _opponent; + private readonly int _round; + private Stack _work = new(); + private readonly PlayerAttackStrategy _playerAttackStrategy; + private readonly OpponentAttackStrategy _opponentAttackStrategy; + + public bool GameEnded { get; private set; } + + public Round(Boxer player, Opponent opponent, int round) + { + _player = player; + _opponent = opponent; + _round = round; + _work.Push(ResetPlayers); + _work.Push(CheckOpponentWin); + _work.Push(CheckPlayerWin); + + void NotifyGameEnded() => GameEnded = true; + _playerAttackStrategy = new PlayerAttackStrategy(player, opponent, NotifyGameEnded, _work); + _opponentAttackStrategy = new OpponentAttackStrategy(opponent, player, NotifyGameEnded, _work); + } + + public void Start() + { + while (_work.Count > 0) + { + var action = _work.Pop(); + // This delay does not exist in the VB code but it makes a bit easier to follow the game. + // I assume the computers at the time were slow enough + // so that they did not need this delay... + Thread.Sleep(300); + action(); + } + } + + public void CheckOpponentWin() + { + if (_opponent.IsWinner) + { + Console.WriteLine($"{_opponent} WINS (NICE GOING, {_opponent})."); + GameEnded = true; + } + } + + public void CheckPlayerWin() + { + if (_player.IsWinner) + { + Console.WriteLine($"{_player} AMAZINGLY WINS!!"); + GameEnded = true; + } + } + + private void ResetPlayers() + { + _player.ResetForNewRound(); + _opponent.ResetForNewRound(); + _work.Push(RoundBegins); + } + + private void RoundBegins() + { + Console.WriteLine(); + Console.WriteLine($"ROUND {_round} BEGINS..."); + _work.Push(CheckRoundWinner); + for (var i = 0; i < 7; i++) + { + _work.Push(DecideWhoAttacks); + } + } + + private void CheckRoundWinner() + { + if (_opponent.DamageTaken > _player.DamageTaken) + { + Console.WriteLine($"{_player} WINS ROUND {_round}"); + _player.RecordWin(); + } + else + { + Console.WriteLine($"{_opponent} WINS ROUND {_round}"); + _opponent.RecordWin(); + } + } + + private void DecideWhoAttacks() + { + _work.Push( GameUtils.RollSatisfies(10, x => x > 5) ? _opponentAttackStrategy.Attack : _playerAttackStrategy.Attack ); + } +} \ No newline at end of file diff --git a/15_Boxing/csharp/Utils.cs b/15_Boxing/csharp/Utils.cs new file mode 100644 index 00000000..1ada516c --- /dev/null +++ b/15_Boxing/csharp/Utils.cs @@ -0,0 +1,35 @@ +namespace Boxing; +public static class GameUtils +{ + private static readonly Random Rnd = new((int) DateTime.UtcNow.Ticks); + public static void PrintPunchDescription() => + Console.WriteLine($"DIFFERENT PUNCHES ARE: {PunchDesc(Punch.FullSwing)}; {PunchDesc(Punch.Hook)}; {PunchDesc(Punch.Uppercut)}; {PunchDesc(Punch.Jab)}."); + + private static string PunchDesc(Punch punch) => $"({(int)punch}) {punch.ToFriendlyString()}"; + + public static Punch GetPunch(string prompt) + { + Console.WriteLine(prompt); + Punch result; + while (!Enum.TryParse(Console.ReadLine(), out result) || !Enum.IsDefined(typeof(Punch), result)) + { + PrintPunchDescription(); + } + return result; + } + + public static Func Roll { get; } = upperLimit => (int) (upperLimit * Rnd.NextSingle()) + 1; + + public static bool RollSatisfies(int upperLimit, Predicate predicate) => predicate(Roll(upperLimit)); + + public static string ToFriendlyString(this Punch punch) + => punch switch + { + Punch.FullSwing => "FULL SWING", + Punch.Hook => "HOOK", + Punch.Uppercut => "UPPERCUT", + Punch.Jab => "JAB", + _ => throw new ArgumentOutOfRangeException(nameof(punch), punch, null) + }; + +} \ No newline at end of file From 40617fa4fc357a94b58141e15980efd50382105f Mon Sep 17 00:00:00 2001 From: Mark Wieder Date: Sat, 8 Jan 2022 17:20:53 -0800 Subject: [PATCH 189/331] implementation of game 73 (Reverse) in ruby --- 73_Reverse/ruby/reverse.rb | 111 +++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 73_Reverse/ruby/reverse.rb diff --git a/73_Reverse/ruby/reverse.rb b/73_Reverse/ruby/reverse.rb new file mode 100644 index 00000000..0e2f7934 --- /dev/null +++ b/73_Reverse/ruby/reverse.rb @@ -0,0 +1,111 @@ +ARRAYSIZE = 9 +$digitArray = Array.new(ARRAYSIZE) +$winningArray = Array.new(ARRAYSIZE) + +# Method to print the rules +def displayTheRules + puts "This is the game of 'Reverse'. to win, all you have" + puts "to do is arrange a list of numbers (1 through " + ARRAYSIZE.to_s + ")" + puts "in numerical order from left to right. to move, you" + puts "tell me how many numbers (counting from the left) to" + puts "reverse. For example, if the current list is:" + puts "2 3 4 5 1 6 7 8 9" + puts "and you reverse 4, the result will be:" + puts "5 4 3 2 1 6 7 8 9" + puts "Now if you reverse 5, you win!" + puts "1 2 3 4 5 6 7 8 9" + puts "No doubt you will like this game, but" + puts "if you want to quit, reverse 0 (zero)." +end + +# Method to print the list +def printList + puts "\n" + $digitArray.join(" ") + "\n\n" +end + +# Zero-based arrays contain digits 1-9 +# Make a random array and an ordered winning answer array A[0] to A[N] +def makeRandomList + for kIndex in 0..ARRAYSIZE-1 do + $digitArray[kIndex] = kIndex+1 + $winningArray[kIndex] = kIndex+1 + end + # now randomize the digit array order + $digitArray.shuffle! +end + +def checkForWin? (triesSoFar) + # Check for a win (all array elements in order) + if $digitArray == $winningArray then + puts "You won it in " + triesSoFar.to_s + " moves!!!\n\n" + puts "try again (yes or no)?" + tryAgain = gets.strip.upcase + if tryAgain == "YES" then + return true + end + puts "\nO.K. Hope you had fun!!" + exit + end + return false +end + +def reverseIt (howManyToReverse, triesSoFar) + # REVERSE R NUMBERS AND PRINT NEW LIST + + # extract and reverse the first howManyToReverse elements of the array + subArray = $digitArray.take(howManyToReverse) + subArray.reverse! + + # get the remaining elements of the original array + endArray = $digitArray.slice(howManyToReverse, ARRAYSIZE) + # append those elements to the reversed elements + $digitArray = subArray.concat(endArray) + + # if we got all in order, randomize again + isWinner = checkForWin?(triesSoFar) + if isWinner == true then + makeRandomList + end + printList # always print the newly ordered list + return isWinner +end + +def askHowManyToReverse + puts "How many shall I reverse?"; + rNumber = gets.to_i + if rNumber > 0 then + if rNumber > ARRAYSIZE then + puts "Oops! Too many! I can reverse at most " + ARRAYSIZE.to_s + end + else + rNumber = 0 # zero or negative values end the game + end + return rNumber +end + +puts "REVERSE" +puts "Creative Computing Morristown, New Jersey\n\n\n" +puts "REVERSE -- A game of skill\n\n" + +puts "Do you want the rules?" +wantRules = gets.strip.upcase +if wantRules == "YES" then + displayTheRules +end + +makeRandomList +howManyTries = 0 +puts "\nHere we go ... the list is:" +printList # display the initial list +# start the game loop +r = askHowManyToReverse +while r != 0 do # zero will end the game + if r <= ARRAYSIZE then + howManyTries = howManyTries+1 + if reverseIt(r, howManyTries) then + howManyTries = 0 + end + end + r = askHowManyToReverse +end + From ccb2e5a7c422b61572d1f6b9b22a70a38442add0 Mon Sep 17 00:00:00 2001 From: "Eric S. Weilnau" Date: Sat, 8 Jan 2022 20:51:33 -0500 Subject: [PATCH 190/331] Add link to PowerShell implementation --- 01_Acey_Ducey/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/01_Acey_Ducey/README.md b/01_Acey_Ducey/README.md index 77ff8621..f8e16312 100644 --- a/01_Acey_Ducey/README.md +++ b/01_Acey_Ducey/README.md @@ -17,3 +17,4 @@ http://www.vintage-basic.net/games.html #### External Links - Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp + - PowerShell: https://github.com/eweilnau/basic-computer-games-powershell/blob/main/AceyDucey.ps1 From 52cbd74d19496d7bf33ea5627690b52082b87f13 Mon Sep 17 00:00:00 2001 From: Kanykei Akmatova Date: Sat, 8 Jan 2022 21:55:47 -0500 Subject: [PATCH 191/331] FlipFlop port to csharp --- 36_Flip_Flop/csharp/FlipFlop.cs | 197 ++++++++++++++++++++++++++++ 36_Flip_Flop/csharp/FlipFlop.csproj | 10 ++ 36_Flip_Flop/csharp/FlipFlop.sln | 25 ++++ 3 files changed, 232 insertions(+) create mode 100644 36_Flip_Flop/csharp/FlipFlop.cs create mode 100644 36_Flip_Flop/csharp/FlipFlop.csproj create mode 100644 36_Flip_Flop/csharp/FlipFlop.sln diff --git a/36_Flip_Flop/csharp/FlipFlop.cs b/36_Flip_Flop/csharp/FlipFlop.cs new file mode 100644 index 00000000..53c613e8 --- /dev/null +++ b/36_Flip_Flop/csharp/FlipFlop.cs @@ -0,0 +1,197 @@ +// Flip Flop Game + +PrintGameInfo(); + +bool startNewGame = true; + +string[] board = new string[] { "X", "X", "X", "X", "X", "X", "X", "X", "X", "X" }; + +do +{ + int stepsCount = 0; + int lastMove = -1; + int moveIndex; + int gameSum; + double gameEntropyRate = Rnd(); + bool toPlay = false; + bool setNewBoard = true; + + Print(); + Print("HERE IS THE STARTING LINE OF X'S."); + Print(); + + do + { + bool illegalEntry; + bool equalToLastMove; + + if (setNewBoard) + { + PrintNewBoard(); + board = new string[] { "X", "X", "X", "X", "X", "X", "X", "X", "X", "X" }; + setNewBoard = false; + toPlay = true; + } + + stepsCount++; + gameSum = 0; + + // Read User's move + do + { + Write("INPUT THE NUMBER? "); + var input = Console.ReadLine(); + illegalEntry = !int.TryParse(input, out moveIndex); + + if (illegalEntry || moveIndex > 11) + { + illegalEntry = true; + Print("ILLEGAL ENTRY--TRY AGAIN."); + } + } + while (illegalEntry); + + if (moveIndex == 11) + { + // Run new game, To start a new game at any point + toPlay = false; + stepsCount = 12; + startNewGame = true; + } + + + if (moveIndex == 0) + { + // To reset the line to all X, same game + setNewBoard = true; + toPlay = false; + } + + if (toPlay) + { + board[moveIndex - 1] = board[moveIndex - 1] == "O" ? "X" : "O"; + + if (lastMove == moveIndex) + { + equalToLastMove = true; + } + else + { + equalToLastMove = false; + lastMove = moveIndex; + } + + do + { + moveIndex = equalToLastMove + ? GetMoveIndexWhenEqualeLastMove(moveIndex, gameEntropyRate) + : GetMoveIndex(moveIndex, gameEntropyRate); + + board[moveIndex] = board[moveIndex] == "O" ? "X" : "O"; + } + while (lastMove == moveIndex && board[moveIndex] == "X"); + + PrintGameBoard(board); + + foreach (var item in board) + { + if (item == "O") + { + gameSum++; + } + } + } + } + while (stepsCount < 12 && gameSum < 10); + + if (toPlay) + { + PrintGameResult(gameSum, stepsCount); + + Write("DO YOU WANT TO TRY ANOTHER PUZZLE "); + + var toContinue = Console.ReadLine(); + + if (!string.IsNullOrEmpty(toContinue) && toContinue?.ToUpper()[0] == 'N') + { + startNewGame = false; + } + + Print(); + } +} +while (startNewGame); + +void Print(string str = "") => Console.WriteLine(str); + +void Write(string value) => Console.Write(value); + +string Tab(int pos) => new(' ', pos); + +double Rnd() => new Random().NextDouble(); + +int GetMoveIndex(int moveIndex, double gameEntropyRate) +{ + double rate = Math.Tan(gameEntropyRate + moveIndex / gameEntropyRate - moveIndex) - Math.Sin(gameEntropyRate / moveIndex) + 336 * Math.Sin(8 * moveIndex); + return Convert.ToInt32(Math.Floor(10 * (rate - Math.Floor(rate)))); +} + +int GetMoveIndexWhenEqualeLastMove(int moveIndex, double gameEntropyRate) +{ + double rate = 0.592 * (1 / Math.Tan(gameEntropyRate / moveIndex + gameEntropyRate)) / Math.Sin(moveIndex * 2 + gameEntropyRate) - Math.Cos(moveIndex); + return Convert.ToInt32(Math.Floor(10 * (rate - Math.Floor(rate)))); +} + +void PrintNewBoard() +{ + Print("1 2 3 4 5 6 7 8 9 10"); + Print("X X X X X X X X X X"); + Print(); +} + +void PrintGameBoard(string[] board) +{ + Print("1 2 3 4 5 6 7 8 9 10"); + + foreach (var item in board) + { + Write($"{item} "); + } + + Print(); + Print(); +} + +void PrintGameResult(int gameSum, int stepsCount) +{ + if (gameSum == 10) + { + Print($"VERY GOOD. YOU GUESSED IT IN ONLY {stepsCount} GUESSES."); + } + else + { + Print($"TRY HARDER NEXT TIME. IT TOOK YOU {stepsCount} GUESSES."); + } +} + +void PrintGameInfo() +{ + Print(Tab(32) + "FLIPFLOP"); + Print(Tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + Print(); + 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)."); +} \ No newline at end of file diff --git a/36_Flip_Flop/csharp/FlipFlop.csproj b/36_Flip_Flop/csharp/FlipFlop.csproj new file mode 100644 index 00000000..74abf5c9 --- /dev/null +++ b/36_Flip_Flop/csharp/FlipFlop.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + diff --git a/36_Flip_Flop/csharp/FlipFlop.sln b/36_Flip_Flop/csharp/FlipFlop.sln new file mode 100644 index 00000000..a26f312e --- /dev/null +++ b/36_Flip_Flop/csharp/FlipFlop.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32014.148 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlipFlop", "FlipFlop.csproj", "{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {108E5099-D7AA-4260-B587-1B1FE1AF6B54} + EndGlobalSection +EndGlobal From 68e278095d8168d821eb91fafa8a714240a7708c Mon Sep 17 00:00:00 2001 From: Joseph Nellis Date: Sat, 8 Jan 2022 20:24:12 -0800 Subject: [PATCH 192/331] Add files via upload --- 01_Acey_Ducey/java/src/AceyDucey17.java | 196 ++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 01_Acey_Ducey/java/src/AceyDucey17.java diff --git a/01_Acey_Ducey/java/src/AceyDucey17.java b/01_Acey_Ducey/java/src/AceyDucey17.java new file mode 100644 index 00000000..9b229f0b --- /dev/null +++ b/01_Acey_Ducey/java/src/AceyDucey17.java @@ -0,0 +1,196 @@ +import java.util.Random; +import java.util.Scanner; + +/** + * A modern version (JDK17) of ACEY DUCEY using post Java 8 features. Notes + * regarding new java features or differences in the original basic + * implementation are numbered and at the bottom of this code. + * The goal is to recreate the exact look and feel of the original program + * minus a large glaring bug in the original code that lets you cheat. + */ +public class AceyDucey17 { + + public static void main(String[] args) { + // notes [1] + System.out.println(""" + ACEY DUCEY CARD GAME + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + 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"""); + + do { + playGame(); + } while (stillInterested()); + System.out.println("O.K., HOPE YOU HAD FUN!"); + } + + public static void playGame() { + int cashOnHand = 100; // our only mutable variable note [11] + System.out.println("YOU NOW HAVE "+ cashOnHand +" DOLLARS.");// note [6] + while (cashOnHand > 0) { + System.out.println(); + System.out.println("HERE ARE YOUR NEXT TWO CARDS:"); + + final Card lowCard = Card.getRandomCard(2, Card.KING); //note [3] + System.out.println(lowCard); + final Card highCard = Card.getRandomCard(lowCard.rank() + 1, Card.ACE); + System.out.println(highCard); + + final int bet = getBet(cashOnHand); + final int winnings = determineWinnings(lowCard,highCard,bet); + cashOnHand += winnings; + if(winnings != 0){ //note [2] + System.out.println("YOU NOW HAVE "+ cashOnHand +" DOLLARS.");//note [6] + } + } + } + + public static int determineWinnings(Card lowCard, Card highCard, int bet){ + if (bet <= 0) { // note [5] + System.out.println("CHICKEN!!"); + return 0; + } + Card nextCard = Card.getRandomCard(2, Card.ACE); + System.out.println(nextCard); + if(nextCard.between(lowCard,highCard)){ + System.out.println("YOU WIN!!!"); + return bet; + } + System.out.println("SORRY, YOU LOSE"); + return -bet; + } + + public static boolean stillInterested(){ + System.out.println(); + System.out.println(); + System.out.println("SORRY, FRIEND, BUT YOU BLEW YOUR WAD."); + System.out.println(); + System.out.println(); + System.out.println("TRY AGAIN (YES OR NO)"); + Scanner input = new Scanner(System.in); + return input.nextLine() + .toUpperCase() + .startsWith("Y"); // note [9] + } + + public static int getBet(int cashOnHand){ + int bet; + do{ + System.out.println(); + System.out.print("WHAT IS YOUR BET? "); + bet = inputNumber(); + if (bet > cashOnHand) { + System.out.println("SORRY, MY FRIEND, BUT YOU BET TOO MUCH."); + System.out.println("YOU HAVE ONLY "+cashOnHand+" DOLLARS TO BET."); + } + }while(bet > cashOnHand); + return bet; + } + + public static int inputNumber() { + final Scanner input = new Scanner(System.in); + // set to negative to mark as not entered yet in case of input error. + int number = -1; + while (number < 0) { + try { + number = input.nextInt(); + } catch(Exception ex) { // note [7] + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); + System.out.print("? "); + try{ + input.nextLine(); + } + catch(Exception ns_ex){ // received EOF (ctrl-d or ctrl-z if windows) + System.out.println("END OF INPUT, STOPPING PROGRAM."); + System.exit(1); + } + } + } + return number; + } + + record Card(int rank){ + // Some constants to describe face cards. + public static final int JACK = 11, QUEEN = 12, KING = 13, ACE = 14; + private static final Random random = new Random(); + + public static Card getRandomCard(int from, int to){ + return new Card(random.nextInt(from, to+1)); // note [4] + } + + public boolean between(Card lower, Card higher){ + return lower.rank() < this.rank() && this.rank() < higher.rank(); + } + + @Override + public String toString() { // note [13] + return switch (rank) { + case JACK -> "JACK"; + case QUEEN -> "QUEEN"; + case KING -> "KING"; + case ACE -> "ACE\n"; // note [10] + default -> " "+rank+" "; // note [6] + }; + } + } + + /* + Notes: + 1. Multiline strings, a.k.a. text blocks, were added in JDK15. + 2. The original game only displays the players balance if it changed, + which it does not when the player chickens out and bets zero. + 3. To pick two cards to show, the original BASIC implementation has a + bug that could cause a race condition if the RND function never chose + a lower number first and higher number second. It loops infinitely + re-choosing random numbers until the condition is met of the first + one being lower. The logic is changed a bit here so that the first + card picked is anything but an ACE, the highest possible card, + and then the second card is between the just picked first card upto + and including the ACE. + 4. Random.nextInt(origin, bound) was added in JDK17, and allows to + directly pick a range for a random integer to be generated. The second + parameter is exclusive of the range and thus why they are stated with + +1's to the face card. + 5. The original BASIC implementation has a bug that allows negative value + bets. Since you can't bet MORE cash than you have you can always bet + less including a very, very large negative value. You would do this when + the chances of winning are slim or zero since losing a hand SUBTRACTS + your bet from your cash; subtracting a negative number actually ADDS + to your cash, potentially making you an instant billionaire. + This loophole is now closed. + 6. The subtle behavior of the BASIC PRINT command causes a space to be + printed before all positive numbers as well as a trailing space. Any + place a non-face card or the players balance is printed has extra space + to mimic this behavior. + 7. Errors on input were probably specific to the interpreter. This program + tries to match the Vintage Basic interpreter's error messages. The final + input.nextLine() command exists to clear the blockage of whatever + non-number input was entered. But even that could fail if the user + types Ctrl-D (windows Ctrl-Z), signifying an EOF (end of file) and thus + the closing of STDIN channel. The original program on an EOF signal prints + "END OF INPUT IN LINE 660" and thus we cover it roughly the same way. + All of this is necessary to avoid a messy stack trace from being + printed as the program crashes. + 9. The original game only accepted a full upper case "YES" to continue + playing if bankrupted. This program is more lenient and will accept + any input that starts with the letter 'y', uppercase or not. + 10. The original game prints an extra blank line if the card is an ACE. There + is seemingly no rationale for this. + 11. Modern java best practices are edging toward a more functional paradigm + and as such, mutating state is discouraged. All other variables besides + the cashOnHand are final and initialized only once. + 12. Refactoring of the concept of a card is done with a record. Records were + introduced in JDK14. Card functionality is encapsulated in this example + of a record. An enum could be a better alternative since there are + technically only 13 cards possible. + 13. Switch expressions were introduced as far back as JDK12 but continue to + be refined for clarity, exhaustiveness. As of JDK17 pattern matching + for switch expressions can be accessed by enabling preview features. + */ +} From f9a884e22a20edfcfe4753f4bc25d398f44a1ba4 Mon Sep 17 00:00:00 2001 From: xl-c7b3 Date: Sun, 9 Jan 2022 02:49:50 -0500 Subject: [PATCH 193/331] added non-source code exclusions to .gitignore --- .gitignore | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.gitignore b/.gitignore index d2115efc..9dda64ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,18 @@ +.local/ +.vscode/ +.gradle/ +node_modules/ +buildJvm/ + +build.gradle + +.classpath +.project +.settings +.metadata +*.iml +*.ipr + *.class */.vs *.suo @@ -12,6 +27,7 @@ obj/ out/ *.py[co] + Pipfile .DS_Store From 00d6881194180555073ad75736673631b920f1ba Mon Sep 17 00:00:00 2001 From: Joe Nellis Date: Sun, 9 Jan 2022 00:48:55 -0800 Subject: [PATCH 194/331] Only display player balance if balance isn't zero. Small formatting change with replay text. --- 01_Acey_Ducey/java/src/AceyDucey17.java | 397 ++++++++++++------------ 1 file changed, 201 insertions(+), 196 deletions(-) diff --git a/01_Acey_Ducey/java/src/AceyDucey17.java b/01_Acey_Ducey/java/src/AceyDucey17.java index 9b229f0b..6192fc14 100644 --- a/01_Acey_Ducey/java/src/AceyDucey17.java +++ b/01_Acey_Ducey/java/src/AceyDucey17.java @@ -1,196 +1,201 @@ -import java.util.Random; -import java.util.Scanner; - -/** - * A modern version (JDK17) of ACEY DUCEY using post Java 8 features. Notes - * regarding new java features or differences in the original basic - * implementation are numbered and at the bottom of this code. - * The goal is to recreate the exact look and feel of the original program - * minus a large glaring bug in the original code that lets you cheat. - */ -public class AceyDucey17 { - - public static void main(String[] args) { - // notes [1] - System.out.println(""" - ACEY DUCEY CARD GAME - CREATIVE COMPUTING MORRISTOWN, NEW JERSEY - - - 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"""); - - do { - playGame(); - } while (stillInterested()); - System.out.println("O.K., HOPE YOU HAD FUN!"); - } - - public static void playGame() { - int cashOnHand = 100; // our only mutable variable note [11] - System.out.println("YOU NOW HAVE "+ cashOnHand +" DOLLARS.");// note [6] - while (cashOnHand > 0) { - System.out.println(); - System.out.println("HERE ARE YOUR NEXT TWO CARDS:"); - - final Card lowCard = Card.getRandomCard(2, Card.KING); //note [3] - System.out.println(lowCard); - final Card highCard = Card.getRandomCard(lowCard.rank() + 1, Card.ACE); - System.out.println(highCard); - - final int bet = getBet(cashOnHand); - final int winnings = determineWinnings(lowCard,highCard,bet); - cashOnHand += winnings; - if(winnings != 0){ //note [2] - System.out.println("YOU NOW HAVE "+ cashOnHand +" DOLLARS.");//note [6] - } - } - } - - public static int determineWinnings(Card lowCard, Card highCard, int bet){ - if (bet <= 0) { // note [5] - System.out.println("CHICKEN!!"); - return 0; - } - Card nextCard = Card.getRandomCard(2, Card.ACE); - System.out.println(nextCard); - if(nextCard.between(lowCard,highCard)){ - System.out.println("YOU WIN!!!"); - return bet; - } - System.out.println("SORRY, YOU LOSE"); - return -bet; - } - - public static boolean stillInterested(){ - System.out.println(); - System.out.println(); - System.out.println("SORRY, FRIEND, BUT YOU BLEW YOUR WAD."); - System.out.println(); - System.out.println(); - System.out.println("TRY AGAIN (YES OR NO)"); - Scanner input = new Scanner(System.in); - return input.nextLine() - .toUpperCase() - .startsWith("Y"); // note [9] - } - - public static int getBet(int cashOnHand){ - int bet; - do{ - System.out.println(); - System.out.print("WHAT IS YOUR BET? "); - bet = inputNumber(); - if (bet > cashOnHand) { - System.out.println("SORRY, MY FRIEND, BUT YOU BET TOO MUCH."); - System.out.println("YOU HAVE ONLY "+cashOnHand+" DOLLARS TO BET."); - } - }while(bet > cashOnHand); - return bet; - } - - public static int inputNumber() { - final Scanner input = new Scanner(System.in); - // set to negative to mark as not entered yet in case of input error. - int number = -1; - while (number < 0) { - try { - number = input.nextInt(); - } catch(Exception ex) { // note [7] - System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); - System.out.print("? "); - try{ - input.nextLine(); - } - catch(Exception ns_ex){ // received EOF (ctrl-d or ctrl-z if windows) - System.out.println("END OF INPUT, STOPPING PROGRAM."); - System.exit(1); - } - } - } - return number; - } - - record Card(int rank){ - // Some constants to describe face cards. - public static final int JACK = 11, QUEEN = 12, KING = 13, ACE = 14; - private static final Random random = new Random(); - - public static Card getRandomCard(int from, int to){ - return new Card(random.nextInt(from, to+1)); // note [4] - } - - public boolean between(Card lower, Card higher){ - return lower.rank() < this.rank() && this.rank() < higher.rank(); - } - - @Override - public String toString() { // note [13] - return switch (rank) { - case JACK -> "JACK"; - case QUEEN -> "QUEEN"; - case KING -> "KING"; - case ACE -> "ACE\n"; // note [10] - default -> " "+rank+" "; // note [6] - }; - } - } - - /* - Notes: - 1. Multiline strings, a.k.a. text blocks, were added in JDK15. - 2. The original game only displays the players balance if it changed, - which it does not when the player chickens out and bets zero. - 3. To pick two cards to show, the original BASIC implementation has a - bug that could cause a race condition if the RND function never chose - a lower number first and higher number second. It loops infinitely - re-choosing random numbers until the condition is met of the first - one being lower. The logic is changed a bit here so that the first - card picked is anything but an ACE, the highest possible card, - and then the second card is between the just picked first card upto - and including the ACE. - 4. Random.nextInt(origin, bound) was added in JDK17, and allows to - directly pick a range for a random integer to be generated. The second - parameter is exclusive of the range and thus why they are stated with - +1's to the face card. - 5. The original BASIC implementation has a bug that allows negative value - bets. Since you can't bet MORE cash than you have you can always bet - less including a very, very large negative value. You would do this when - the chances of winning are slim or zero since losing a hand SUBTRACTS - your bet from your cash; subtracting a negative number actually ADDS - to your cash, potentially making you an instant billionaire. - This loophole is now closed. - 6. The subtle behavior of the BASIC PRINT command causes a space to be - printed before all positive numbers as well as a trailing space. Any - place a non-face card or the players balance is printed has extra space - to mimic this behavior. - 7. Errors on input were probably specific to the interpreter. This program - tries to match the Vintage Basic interpreter's error messages. The final - input.nextLine() command exists to clear the blockage of whatever - non-number input was entered. But even that could fail if the user - types Ctrl-D (windows Ctrl-Z), signifying an EOF (end of file) and thus - the closing of STDIN channel. The original program on an EOF signal prints - "END OF INPUT IN LINE 660" and thus we cover it roughly the same way. - All of this is necessary to avoid a messy stack trace from being - printed as the program crashes. - 9. The original game only accepted a full upper case "YES" to continue - playing if bankrupted. This program is more lenient and will accept - any input that starts with the letter 'y', uppercase or not. - 10. The original game prints an extra blank line if the card is an ACE. There - is seemingly no rationale for this. - 11. Modern java best practices are edging toward a more functional paradigm - and as such, mutating state is discouraged. All other variables besides - the cashOnHand are final and initialized only once. - 12. Refactoring of the concept of a card is done with a record. Records were - introduced in JDK14. Card functionality is encapsulated in this example - of a record. An enum could be a better alternative since there are - technically only 13 cards possible. - 13. Switch expressions were introduced as far back as JDK12 but continue to - be refined for clarity, exhaustiveness. As of JDK17 pattern matching - for switch expressions can be accessed by enabling preview features. - */ -} +import java.util.Random; +import java.util.Scanner; + +/** + * A modern version (JDK17) of ACEY DUCEY using post Java 8 features. Notes + * regarding new java features or differences in the original basic + * implementation are numbered and at the bottom of this code. + * The goal is to recreate the exact look and feel of the original program + * minus a large glaring bug in the original code that lets you cheat. + */ +public class AceyDucey17 { + + public static void main(String[] args) { + // notes [1] + System.out.println(""" + ACEY DUCEY CARD GAME + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + + + 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"""); + + do { + playGame(); + } while (stillInterested()); + System.out.println("O.K., HOPE YOU HAD FUN!"); + } + + public static void playGame() { + int cashOnHand = 100; // our only mutable variable note [11] + System.out.println("YOU NOW HAVE "+ cashOnHand +" DOLLARS.");// note [6] + while (cashOnHand > 0) { + System.out.println(); + System.out.println("HERE ARE YOUR NEXT TWO CARDS:"); + + final Card lowCard = Card.getRandomCard(2, Card.KING); //note [3] + System.out.println(lowCard); + final Card highCard = Card.getRandomCard(lowCard.rank() + 1, Card.ACE); + System.out.println(highCard); + + final int bet = getBet(cashOnHand); + final int winnings = determineWinnings(lowCard,highCard,bet); + cashOnHand += winnings; + if(winnings != 0 || cashOnHand != 0){ //note [2] + System.out.println("YOU NOW HAVE "+ cashOnHand +" DOLLARS.");//note [6] + } + } + } + + public static int determineWinnings(Card lowCard, Card highCard, int bet){ + if (bet <= 0) { // note [5] + System.out.println("CHICKEN!!"); + return 0; + } + Card nextCard = Card.getRandomCard(2, Card.ACE); + System.out.println(nextCard); + if(nextCard.between(lowCard,highCard)){ + System.out.println("YOU WIN!!!"); + return bet; + } + System.out.println("SORRY, YOU LOSE"); + return -bet; + } + + public static boolean stillInterested(){ + System.out.println(); + System.out.println(); + System.out.println("SORRY, FRIEND, BUT YOU BLEW YOUR WAD."); + System.out.println(); + System.out.println(); + System.out.print("TRY AGAIN (YES OR NO)? "); + Scanner input = new Scanner(System.in); + boolean playAgain = input.nextLine() + .toUpperCase() + .startsWith("Y"); // note [9] + System.out.println(); + System.out.println(); + return playAgain; + } + + public static int getBet(int cashOnHand){ + int bet; + do{ + System.out.println(); + System.out.print("WHAT IS YOUR BET? "); + bet = inputNumber(); + if (bet > cashOnHand) { + System.out.println("SORRY, MY FRIEND, BUT YOU BET TOO MUCH."); + System.out.println("YOU HAVE ONLY "+cashOnHand+" DOLLARS TO BET."); + } + }while(bet > cashOnHand); + return bet; + } + + public static int inputNumber() { + final Scanner input = new Scanner(System.in); + // set to negative to mark as not entered yet in case of input error. + int number = -1; + while (number < 0) { + try { + number = input.nextInt(); + } catch(Exception ex) { // note [7] + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); + System.out.print("? "); + try{ + input.nextLine(); + } + catch(Exception ns_ex){ // received EOF (ctrl-d or ctrl-z if windows) + System.out.println("END OF INPUT, STOPPING PROGRAM."); + System.exit(1); + } + } + } + return number; + } + + record Card(int rank){ + // Some constants to describe face cards. + public static final int JACK = 11, QUEEN = 12, KING = 13, ACE = 14; + private static final Random random = new Random(); + + public static Card getRandomCard(int from, int to){ + return new Card(random.nextInt(from, to+1)); // note [4] + } + + public boolean between(Card lower, Card higher){ + return lower.rank() < this.rank() && this.rank() < higher.rank(); + } + + @Override + public String toString() { // note [13] + return switch (rank) { + case JACK -> "JACK"; + case QUEEN -> "QUEEN"; + case KING -> "KING"; + case ACE -> "ACE\n"; // note [10] + default -> " "+rank+" "; // note [6] + }; + } + } + + /* + Notes: + 1. Multiline strings, a.k.a. text blocks, were added in JDK15. + 2. The original game only displays the players balance if it changed, + which it does not when the player chickens out and bets zero. + It also doesn't display the balance when it becomes zero because it has + a more appropriate message: Sorry, You Lose. + 3. To pick two cards to show, the original BASIC implementation has a + bug that could cause a race condition if the RND function never chose + a lower number first and higher number second. It loops infinitely + re-choosing random numbers until the condition is met of the first + one being lower. The logic is changed a bit here so that the first + card picked is anything but an ACE, the highest possible card, + and then the second card is between the just picked first card upto + and including the ACE. + 4. Random.nextInt(origin, bound) was added in JDK17, and allows to + directly pick a range for a random integer to be generated. The second + parameter is exclusive of the range and thus why they are stated with + +1's to the face card. + 5. The original BASIC implementation has a bug that allows negative value + bets. Since you can't bet MORE cash than you have you can always bet + less including a very, very large negative value. You would do this when + the chances of winning are slim or zero since losing a hand SUBTRACTS + your bet from your cash; subtracting a negative number actually ADDS + to your cash, potentially making you an instant billionaire. + This loophole is now closed. + 6. The subtle behavior of the BASIC PRINT command causes a space to be + printed before all positive numbers as well as a trailing space. Any + place a non-face card or the players balance is printed has extra space + to mimic this behavior. + 7. Errors on input were probably specific to the interpreter. This program + tries to match the Vintage Basic interpreter's error messages. The final + input.nextLine() command exists to clear the blockage of whatever + non-number input was entered. But even that could fail if the user + types Ctrl-D (windows Ctrl-Z), signifying an EOF (end of file) and thus + the closing of STDIN channel. The original program on an EOF signal prints + "END OF INPUT IN LINE 660" and thus we cover it roughly the same way. + All of this is necessary to avoid a messy stack trace from being + printed as the program crashes. + 9. The original game only accepted a full upper case "YES" to continue + playing if bankrupted. This program is more lenient and will accept + any input that starts with the letter 'y', uppercase or not. + 10. The original game prints an extra blank line if the card is an ACE. There + is seemingly no rationale for this. + 11. Modern java best practices are edging toward a more functional paradigm + and as such, mutating state is discouraged. All other variables besides + the cashOnHand are final and initialized only once. + 12. Refactoring of the concept of a card is done with a record. Records were + introduced in JDK14. Card functionality is encapsulated in this example + of a record. An enum could be a better alternative since there are + technically only 13 cards possible. + 13. Switch expressions were introduced as far back as JDK12 but continue to + be refined for clarity, exhaustiveness. As of JDK17 pattern matching + for switch expressions can be accessed by enabling preview features. + */ +} From 513892322e9eef7888f65196b07b38f82a1299bd Mon Sep 17 00:00:00 2001 From: Joseph Nellis Date: Sun, 9 Jan 2022 01:32:41 -0800 Subject: [PATCH 195/331] Update HOW_TO_RUN_THE_GAMES.md Add notice that you really don't need to compile single java files anymore. --- HOW_TO_RUN_THE_GAMES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/HOW_TO_RUN_THE_GAMES.md b/HOW_TO_RUN_THE_GAMES.md index 44d82e98..6df23205 100644 --- a/HOW_TO_RUN_THE_GAMES.md +++ b/HOW_TO_RUN_THE_GAMES.md @@ -32,6 +32,8 @@ To run from the command line, you will need a Java SDK (eg. [Oracle JDK](https:/ * eg. `javac AceyDuceyGame.java` 1. Run the compiled program with `java`: * eg. `java AceyDuceyGame` + +or if you are **using JDK11 or later** you can now execute a self contained java file that has a main method directly with `java .java`. ## javascript From 5bb1bb5c384a8ac27519570bd2d5e68cc0343472 Mon Sep 17 00:00:00 2001 From: Ahmad Masykur Date: Sun, 9 Jan 2022 16:43:31 +0700 Subject: [PATCH 196/331] Add tictactoe1 in C# --- 89_Tic-Tac-Toe/csharp/tictactoe1/Program.cs | 75 +++++++++++++++++++ .../csharp/tictactoe1/tictactoe1.csproj | 10 +++ 2 files changed, 85 insertions(+) create mode 100644 89_Tic-Tac-Toe/csharp/tictactoe1/Program.cs create mode 100644 89_Tic-Tac-Toe/csharp/tictactoe1/tictactoe1.csproj diff --git a/89_Tic-Tac-Toe/csharp/tictactoe1/Program.cs b/89_Tic-Tac-Toe/csharp/tictactoe1/Program.cs new file mode 100644 index 00000000..58f7d36f --- /dev/null +++ b/89_Tic-Tac-Toe/csharp/tictactoe1/Program.cs @@ -0,0 +1,75 @@ +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); +// Print text on the screen with 30 spaces before text +Console.WriteLine("TIC TAC TOE".PadLeft(30)); +// Print text on screen with 15 spaces before text +Console.WriteLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".PadLeft(15)); +// Print three blank lines on screen +Console.WriteLine("\n\n\n"); +// THIS PROGRAM PLAYS TIC TAC TOE +// THE MACHINE GOES FIRST +Console.WriteLine("THE GAME BOARD IS NUMBERED:\n"); +Console.WriteLine("1 2 3"); +Console.WriteLine("8 9 4"); +Console.WriteLine("7 6 5"); + +// Main program +while(true) { + int a, b, c, d, e; + int p, q, r, s; + a = 9; + Console.WriteLine("\n\n"); + computerMoves(a); + p = readYourMove(); + b = move(p + 1); + computerMoves(b); + q = readYourMove(); + if (q == move(b + 4)) { + c = move(b + 2); + computerMoves(c); + r = readYourMove(); + if (r == move(c + 4)) { + if (p % 2 != 0) { + d = move(c + 3); + computerMoves(d); + s = readYourMove(); + if (s != move(d + 4)) { + e = move(d + 4); + computerMoves(e); + } + e = move(d + 6); + computerMoves(e); + Console.WriteLine("THE GAME IS A DRAW."); + } else { + d = move(c + 7); + computerMoves(d); + Console.WriteLine("AND WINS ********"); + } + } else { + d = move(c + 4); + computerMoves(d); + Console.WriteLine("AND WINS ********"); + } + } else { + c = move(b + 4); + computerMoves(c); + Console.WriteLine("AND WINS ********"); + } +} + +void computerMoves(int move) { + Console.WriteLine("COMPUTER MOVES " + move); +} +int readYourMove() { + while(true) { + Console.Write("YOUR MOVE?"); + string input = Console.ReadLine(); + if (int.TryParse(input, out int number)) { + return number; + } + } +} + +int move(int number) { + return number - 8 * (int)((number - 1) / 8); +} diff --git a/89_Tic-Tac-Toe/csharp/tictactoe1/tictactoe1.csproj b/89_Tic-Tac-Toe/csharp/tictactoe1/tictactoe1.csproj new file mode 100644 index 00000000..74abf5c9 --- /dev/null +++ b/89_Tic-Tac-Toe/csharp/tictactoe1/tictactoe1.csproj @@ -0,0 +1,10 @@ + + + + Exe + net6.0 + enable + enable + + + From b492671bf038d204abb3218e8a2579523b2ccdec Mon Sep 17 00:00:00 2001 From: Tom Wyant Date: Sun, 9 Jan 2022 08:59:40 -0500 Subject: [PATCH 197/331] Revise the documentation for 80_Slots/perl Add instructions on how to restore the BASIC behavior to 80_Slots/perl/slots.pl Add the entire description section of the Perl documentation (including the change I made because I thought the original was a bug, and how to restore the original behavior) to 80_Slots/perl/README.md --- 80_Slots/perl/README.md | 20 ++++++++++++++++++++ 80_Slots/perl/slots.pl | 8 ++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/80_Slots/perl/README.md b/80_Slots/perl/README.md index e69c8b81..3a14d6cf 100644 --- a/80_Slots/perl/README.md +++ b/80_Slots/perl/README.md @@ -1,3 +1,23 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) Conversion to [Perl](https://www.perl.org/) + +This Perl script is a port of slots, which is the 80th entry in Basic +Computer Games. + +I know nothing about slot machines, and my research into them says to me +that the payout tables can be fairly arbitrary. But I have taken the +liberty of deeming the BASIC program's refusal to pay on LEMON CHERRY +LEMON a bug, and made that case a double. + +My justification for this is that at the point where the BASIC has +detected the double in the first and third reels it has already detected +that there is no double in the first and second reels. After the check +for a bar (and therefore a double bar) fails it goes back and checks for +a double on the second and third reels. But we know this check will +fail, since the check for a double on the first and second reels failed. +So if a loss was intended at this point, why not just call it a loss? + +To restore the original behavior, comment out the entire line commented +'# Bug fix?' (about line 75) and uncomment the line with the trailing +comment '# Bug?' (about line 83). diff --git a/80_Slots/perl/slots.pl b/80_Slots/perl/slots.pl index b5c1ee39..b6749606 100755 --- a/80_Slots/perl/slots.pl +++ b/80_Slots/perl/slots.pl @@ -72,7 +72,7 @@ while ( 1 ) { # Iterate indefinitely } } elsif ( $reel_x == $reel_z ) { if ( $reel_z ) { - $winnings += double( $bet ); + $winnings += double( $bet ); # Bug fix? # NOTE that the below code is what is actually implemented # in the basic, but it is implemented strangely enough (a # GOTO a line that contains a test that, if I understand the @@ -80,7 +80,7 @@ while ( 1 ) { # Iterate indefinitely # I know nothing about slot machines, but research suggests # the payoff table is fairly arbitrary. The code above makes # code above makes the game orthogonal. - # $winnings += you_lost( $bet ); + # $winnings += you_lost( $bet ); # Bug? } else { $winnings += double_bar( $bet ); } @@ -215,6 +215,10 @@ a double on the second and third reels. But we know this check will fail, since the check for a double on the first and second reels failed. So if a loss was intended at this point, why not just call it a loss? +To restore the original behavior, comment out the entire line commented +C<'# Bug fix?'> (about line 75) and uncomment the line with the trailing +comment C<'# Bug?'> (about line 83). + =head1 PORTED BY Thomas R. Wyant, III F From d0c124a31257fef31d319ed33f166e8f4c32e87b Mon Sep 17 00:00:00 2001 From: Alex Scown Date: Sat, 8 Jan 2022 20:11:47 +0000 Subject: [PATCH 198/331] Initial port Game works, but AI behaves differently to the original. Need to try and remove the globals. --- 04_Awari/ruby/README.md | 2 +- 04_Awari/ruby/awari.rb | 286 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 04_Awari/ruby/awari.rb diff --git a/04_Awari/ruby/README.md b/04_Awari/ruby/README.md index fb32811e..9c8c96bf 100644 --- a/04_Awari/ruby/README.md +++ b/04_Awari/ruby/README.md @@ -1,3 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Ruby](https://www.ruby-lang.org/en/) +Conversion to [Ruby](https://www.ruby-lang.org/en/) by [Alex Scown](https://github.com/TheScown) diff --git a/04_Awari/ruby/awari.rb b/04_Awari/ruby/awari.rb new file mode 100644 index 00000000..aaf29632 --- /dev/null +++ b/04_Awari/ruby/awari.rb @@ -0,0 +1,286 @@ +require 'strscan' + +def print_beans(beans) + puts + + # Print computer beans + print " " + beans[7..12].reverse.each {|bean_count| print_bean(bean_count)} + puts + + # Print home beans + print_bean(beans[13]) + print ' ' + print_number(beans[6]) # This is not print_bean in line with the original version + puts + + # Print player beans + print " " + beans[0..5].each {|bean_count| print_bean(bean_count)} + puts + + puts +end + +def print_bean(bean_count) + print ' ' if bean_count < 10 + print_number(bean_count) +end + +def print_number(n) + # PRINT adds padding after a number and before a positive number + print ' ' if n >= 0 + print n.to_s + print ' ' +end + +def get_move(prompt, beans) + move = get_integer_input(prompt) + + while move < 1 || move > 6 || beans[move - 1] == 0 + puts "ILLEGAL MOVE" + move = get_integer_input("AGAIN") + end + + move - 1 +end + +def get_integer_input(prompt) + integer_value = nil + + input_values = input(prompt) + + while integer_value.nil? + print '!EXTRA INPUT IGNORED' if (input_values.size > 1) + + value = input_values.first + + begin + integer_value = Integer(value) + rescue + puts '!NUMBER EXPECTED - RETRY INPUT LINE' + input_values = input('') + end + end + + integer_value +end + +def input(prompt) + prompt_suffix = '? ' + print "#{prompt}#{prompt_suffix}" + + input = gets.chomp.strip + scanner = StringScanner.new(input) + input_values = [] + + until scanner.eos? + scanner.scan(/\s+/) + + if scanner.check(/"/) + scanner.scan(/"/) + next_string = scanner.scan_until(/"/) + + if next_string + # Remove the trailing close quote + next_string.chomp!('"') + else + # No close quote – Vintage Basic crashes in this case + raise ArgumentError('Unmatched quotes in input') + end + elsif scanner.exist?(/,/) + next_string = scanner.scan_until(/,/).chomp(',') + else + next_string = scanner.scan_until(/\s+|$/).rstrip + end + + input_values << next_string + end + + input_values << '' if input_values.empty? + + input_values +end + + +def distribute_beans(beans, start_pit, home_pit) + beans_to_distribute = beans[start_pit] + beans[start_pit] = 0 + + current_pit = start_pit + + (0...beans_to_distribute).each do + current_pit = (current_pit + 1) % beans.size + beans[current_pit] += 1 + end + + # If the last pit was empty before we put a bean in it (and it's not a scoring pit), add beans to score + if beans[current_pit] == 1 && current_pit != 6 && current_pit != 13 && beans[12 - current_pit] != 0 + beans[home_pit] = beans[home_pit] + beans[12 - current_pit] + 1 + beans[current_pit] = 0 + beans[12 - current_pit] = 0 + end + + current_pit +end + +def update_internals(beans) + $k = $k - 7 if $k > 6 + $c = $c + 1 + + $f[$n] = $f[$n] * 6 + $k if $c < 9 + + unless beans[0...6].find { |b| b != 0 } && beans[7...13].find { |b| b != 0 } + $game_over = true + end +end + +# @param [Array] beans +# @param [Integer] move +# @param [Integer] home_pit +def perform_move(beans, move, home_pit) + last_pit = distribute_beans(beans, move, home_pit) + + update_internals(beans) + + last_pit +end + +def end_game(beans) + puts + puts "GAME OVER" + + difference = beans[6] - beans[13] + + if difference < 0 + puts "I WIN BY #{-difference} POINTS" + + return + end + + $n += 1 + + puts "YOU WIN BY #{difference} POINTS" if difference > 0 + puts "DRAWN GAME" if difference == 0 +end + +# @param [Array] beans +def get_computer_move(beans) + d = -99 + home_pit = 13 + beans_copy = beans.dup + + move_to_do = 0 + + (7..12).each do |move_under_test| + if beans[move_under_test] == 0 + next + end + + max_score = 0 + + distribute_beans(beans_copy, move_under_test, home_pit) + + (0...6).each do |i| + next if beans_copy[i] == 0 + + l = beans_copy[i] + i + r = l / 14 + l_mod_14 = l % 14 + + r = beans_copy[12 - l_mod_14] + r if beans_copy[l_mod_14] == 0 && l_mod_14 != 6 && l_mod_14 != 13 + + max_score = r if r > max_score + end + + final_score = beans_copy[13] - beans_copy[6] - max_score + + if $c <=8 + $k = move_under_test + $k = $k - 7 if $k > 6 + end + + (1...$n).each do |i| + final_score = final_score - 2 if $f[$n] * 6 + $k == (($f[i]/6 ** (7-$c)) + 0.1).floor + end + + if final_score >= d + move_to_do = move_under_test + d = final_score + end + end + + last_pit = perform_move(beans, move_to_do, home_pit) + + [move_to_do, last_pit] +end + +puts 'AWARI'.center(80) +puts 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'.center(80) + +# Initialise stable variables +$f = Array.new(50) +$n = 0 + +# APPLICATION LOOP +:game +while true + print "\n", "\n" + beans = Array.new(13, 3) + beans[6] = 0 + beans[13] = 0 + + $f[$n] = 0 + $game_over = false + $c = 0 + + until $game_over + print_beans(beans) + + move = get_move("YOUR MOVE", beans) + home_pit = 6 + computer_home_pit = 13 + $k = move + + last_pit = perform_move(beans, move, home_pit) + + print_beans(beans) + + if $game_over + end_game(beans) + next :game + end + + if home_pit == last_pit + second_move = get_move("AGAIN", beans) + $k = second_move + + perform_move(beans, second_move, home_pit) + + print_beans(beans) + + if $game_over + end_game(beans) + next :game + end + end + + computer_move, computer_last_pit = get_computer_move(beans) + print "MY MOVE IS #{computer_move - 6}" + + if $game_over + end_game(beans) + next :game + end + + if computer_last_pit == computer_home_pit + second_computer_move, _ = get_computer_move(beans) + print ",#{second_computer_move - 6}" + + if $game_over + end_game(beans) + next :game + end + end + end +end From 7239ca244ef590a1a6c4d28b143ca9c4f764e401 Mon Sep 17 00:00:00 2001 From: Alex Scown Date: Sun, 9 Jan 2022 12:41:49 +0000 Subject: [PATCH 199/331] Fix AI The issue was not resetting the clone array for every test move. Clarify some variable names. Shout out to Flavio Poletti for the comments on the Perl translation. --- 04_Awari/ruby/awari.rb | 56 ++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/04_Awari/ruby/awari.rb b/04_Awari/ruby/awari.rb index aaf29632..fa149d5f 100644 --- a/04_Awari/ruby/awari.rb +++ b/04_Awari/ruby/awari.rb @@ -125,7 +125,7 @@ def distribute_beans(beans, start_pit, home_pit) end def update_internals(beans) - $k = $k - 7 if $k > 6 + $k = $k % 7 $c = $c + 1 $f[$n] = $f[$n] * 6 + $k if $c < 9 @@ -168,51 +168,65 @@ end def get_computer_move(beans) d = -99 home_pit = 13 - beans_copy = beans.dup - move_to_do = 0 + chosen_move = 7 - (7..12).each do |move_under_test| - if beans[move_under_test] == 0 - next - end + # Test all possible moves + (7...13).each do |move_under_test| + # Create a copy of the beans to test against + beans_copy = beans.dup - max_score = 0 + # If the move is not legal, skip it + next if beans[move_under_test] == 0 + # Determine the best response the player may make to this move + player_max_score = 0 + + # Make the move under test against the copy distribute_beans(beans_copy, move_under_test, home_pit) + # Test every player response (0...6).each do |i| + # Skip the move if it would be illegal next if beans_copy[i] == 0 - l = beans_copy[i] + i - r = l / 14 - l_mod_14 = l % 14 + # Determine the last + landing_with_overflow = beans_copy[i] + i + # If landing > 13 the player has put a bean in both home pits + player_move_score = (landing_with_overflow > 14) ? 1 : 0 + # Find the actual pit + landing = landing_with_overflow % 14 - r = beans_copy[12 - l_mod_14] + r if beans_copy[l_mod_14] == 0 && l_mod_14 != 6 && l_mod_14 != 13 + # If the landing pit is empty, the player will steal beans + if beans_copy[landing] == 0 && landing != 6 && landing != 13 + player_move_score = beans_copy[12 - landing] + player_move_score + end - max_score = r if r > max_score + # Update the max score if this move is the best player move + player_max_score = player_move_score if player_move_score > player_max_score end - final_score = beans_copy[13] - beans_copy[6] - max_score + # Final score for move is computer score, minus the player's score and any player gains from their best move + final_score = beans_copy[13] - beans_copy[6] - player_max_score if $c <=8 - $k = move_under_test - $k = $k - 7 if $k > 6 + $k = move_under_test % 7 end - (1...$n).each do |i| - final_score = final_score - 2 if $f[$n] * 6 + $k == (($f[i]/6 ** (7-$c)) + 0.1).floor + (0...$n).each do |i| + final_score = final_score - 2 if $f[$n] * 6 + $k == ((Float($f[i])/6 ** (7-$c)) + 0.1).floor end + # Choose the move if it is the best move found so far if final_score >= d - move_to_do = move_under_test + chosen_move = move_under_test d = final_score end end - last_pit = perform_move(beans, move_to_do, home_pit) + last_pit = perform_move(beans, chosen_move, home_pit) - [move_to_do, last_pit] + [chosen_move, last_pit] end puts 'AWARI'.center(80) From 2fa142a246be226b4779e93fef5e7d8e9803f075 Mon Sep 17 00:00:00 2001 From: Alex Scown Date: Sun, 9 Jan 2022 12:51:48 +0000 Subject: [PATCH 200/331] Remove k global --- 04_Awari/ruby/awari.rb | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/04_Awari/ruby/awari.rb b/04_Awari/ruby/awari.rb index fa149d5f..466f1c71 100644 --- a/04_Awari/ruby/awari.rb +++ b/04_Awari/ruby/awari.rb @@ -124,11 +124,11 @@ def distribute_beans(beans, start_pit, home_pit) current_pit end -def update_internals(beans) - $k = $k % 7 +def update_internals(beans, current_move) + k = current_move % 7 $c = $c + 1 - $f[$n] = $f[$n] * 6 + $k if $c < 9 + $f[$n] = $f[$n] * 6 + k if $c < 9 unless beans[0...6].find { |b| b != 0 } && beans[7...13].find { |b| b != 0 } $game_over = true @@ -141,7 +141,7 @@ end def perform_move(beans, move, home_pit) last_pit = distribute_beans(beans, move, home_pit) - update_internals(beans) + update_internals(beans, move) last_pit end @@ -210,11 +210,11 @@ def get_computer_move(beans) final_score = beans_copy[13] - beans_copy[6] - player_max_score if $c <=8 - $k = move_under_test % 7 - end + k = move_under_test % 7 - (0...$n).each do |i| - final_score = final_score - 2 if $f[$n] * 6 + $k == ((Float($f[i])/6 ** (7-$c)) + 0.1).floor + (0...$n).each do |i| + final_score = final_score - 2 if $f[$n] * 6 + k == ((Float($f[i])/6 ** (7-$c)) + 0.1).floor + end end # Choose the move if it is the best move found so far @@ -254,7 +254,6 @@ while true move = get_move("YOUR MOVE", beans) home_pit = 6 computer_home_pit = 13 - $k = move last_pit = perform_move(beans, move, home_pit) @@ -267,7 +266,6 @@ while true if home_pit == last_pit second_move = get_move("AGAIN", beans) - $k = second_move perform_move(beans, second_move, home_pit) From a0fdf42166232e7825cbfd7dcbbb6e496f94b084 Mon Sep 17 00:00:00 2001 From: Alex Scown Date: Sun, 9 Jan 2022 13:19:18 +0000 Subject: [PATCH 201/331] Initial conversion to class --- 04_Awari/ruby/awari.rb | 150 ++++++++++++++++++++++------------------- 1 file changed, 82 insertions(+), 68 deletions(-) diff --git a/04_Awari/ruby/awari.rb b/04_Awari/ruby/awari.rb index 466f1c71..cd57132c 100644 --- a/04_Awari/ruby/awari.rb +++ b/04_Awari/ruby/awari.rb @@ -5,7 +5,7 @@ def print_beans(beans) # Print computer beans print " " - beans[7..12].reverse.each {|bean_count| print_bean(bean_count)} + beans[7..12].reverse.each { |bean_count| print_bean(bean_count) } puts # Print home beans @@ -16,7 +16,7 @@ def print_beans(beans) # Print player beans print " " - beans[0..5].each {|bean_count| print_bean(bean_count)} + beans[0..5].each { |bean_count| print_bean(bean_count) } puts puts @@ -102,7 +102,6 @@ def input(prompt) input_values end - def distribute_beans(beans, start_pit, home_pit) beans_to_distribute = beans[start_pit] beans[start_pit] = 0 @@ -124,15 +123,11 @@ def distribute_beans(beans, start_pit, home_pit) current_pit end -def update_internals(beans, current_move) +def update_history(current_move) k = current_move % 7 $c = $c + 1 - $f[$n] = $f[$n] * 6 + k if $c < 9 - - unless beans[0...6].find { |b| b != 0 } && beans[7...13].find { |b| b != 0 } - $game_over = true - end + $history[$non_win_count] = $history[$non_win_count] * 6 + k if $c < 9 end # @param [Array] beans @@ -141,11 +136,12 @@ end def perform_move(beans, move, home_pit) last_pit = distribute_beans(beans, move, home_pit) - update_internals(beans, move) + update_history(move) last_pit end +# @return [Boolean] True if the computer did not win def end_game(beans) puts puts "GAME OVER" @@ -158,10 +154,12 @@ def end_game(beans) return end - $n += 1 + $non_win_count += 1 puts "YOU WIN BY #{difference} POINTS" if difference > 0 puts "DRAWN GAME" if difference == 0 + + difference >= 0 end # @param [Array] beans @@ -209,11 +207,11 @@ def get_computer_move(beans) # Final score for move is computer score, minus the player's score and any player gains from their best move final_score = beans_copy[13] - beans_copy[6] - player_max_score - if $c <=8 + if $c < 9 k = move_under_test % 7 - (0...$n).each do |i| - final_score = final_score - 2 if $f[$n] * 6 + k == ((Float($f[i])/6 ** (7-$c)) + 0.1).floor + (0...$non_win_count).each do |i| + final_score = final_score - 2 if $history[$non_win_count] * 6 + k == ((Float($history[i]) / 6 ** (7 - $c)) + 0.1).floor end end @@ -229,70 +227,86 @@ def get_computer_move(beans) [chosen_move, last_pit] end +class Game + def initialize(history, non_win_count) + @beans = Array.new(13, 3) + @beans[6] = 0 + @beans[13] = 0 + + @turn_counter = 0 + + @history = history + @non_win_count = non_win_count + end + + def game_over + @beans[0...6].all? { |b| b == 0 } || @beans[7...13].all? { |b| b == 0 } + end + + def play + until game_over + print_beans(@beans) + + move = get_move("YOUR MOVE", @beans) + home_pit = 6 + computer_home_pit = 13 + + last_pit = perform_move(@beans, move, home_pit) + + print_beans(@beans) + + if game_over + return end_game(@beans) + end + + if home_pit == last_pit + second_move = get_move("AGAIN", @beans) + + perform_move(@beans, second_move, home_pit) + + print_beans(@beans) + + if game_over + return end_game(@beans) + end + end + + computer_move, computer_last_pit = get_computer_move(@beans) + print "MY MOVE IS #{computer_move - 6}" + + if game_over + return end_game(@beans) + end + + if computer_last_pit == computer_home_pit + second_computer_move, _ = get_computer_move(@beans) + print ",#{second_computer_move - 6}" + + if game_over + return end_game(@beans) + end + end + end + end + +end + puts 'AWARI'.center(80) puts 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'.center(80) # Initialise stable variables -$f = Array.new(50) -$n = 0 +$history = Array.new(50) +$non_win_count = 0 # APPLICATION LOOP -:game while true print "\n", "\n" - beans = Array.new(13, 3) - beans[6] = 0 - beans[13] = 0 - $f[$n] = 0 - $game_over = false + $history[$non_win_count] = 0 $c = 0 - until $game_over - print_beans(beans) + game = Game.new($history, $non_win_count) - move = get_move("YOUR MOVE", beans) - home_pit = 6 - computer_home_pit = 13 - - last_pit = perform_move(beans, move, home_pit) - - print_beans(beans) - - if $game_over - end_game(beans) - next :game - end - - if home_pit == last_pit - second_move = get_move("AGAIN", beans) - - perform_move(beans, second_move, home_pit) - - print_beans(beans) - - if $game_over - end_game(beans) - next :game - end - end - - computer_move, computer_last_pit = get_computer_move(beans) - print "MY MOVE IS #{computer_move - 6}" - - if $game_over - end_game(beans) - next :game - end - - if computer_last_pit == computer_home_pit - second_computer_move, _ = get_computer_move(beans) - print ",#{second_computer_move - 6}" - - if $game_over - end_game(beans) - next :game - end - end - end + computer_didnt_win = game.play + $non_win_count += 1 if computer_didnt_win end From 5195ef74c673094e2290ea38f3f77b5af7102865 Mon Sep 17 00:00:00 2001 From: Alex Scown Date: Sun, 9 Jan 2022 13:55:27 +0000 Subject: [PATCH 202/331] Move remaining functions into class --- 04_Awari/ruby/awari.rb | 453 ++++++++++++++++++++--------------------- 1 file changed, 223 insertions(+), 230 deletions(-) diff --git a/04_Awari/ruby/awari.rb b/04_Awari/ruby/awari.rb index cd57132c..a9864dc7 100644 --- a/04_Awari/ruby/awari.rb +++ b/04_Awari/ruby/awari.rb @@ -1,32 +1,5 @@ require 'strscan' -def print_beans(beans) - puts - - # Print computer beans - print " " - beans[7..12].reverse.each { |bean_count| print_bean(bean_count) } - puts - - # Print home beans - print_bean(beans[13]) - print ' ' - print_number(beans[6]) # This is not print_bean in line with the original version - puts - - # Print player beans - print " " - beans[0..5].each { |bean_count| print_bean(bean_count) } - puts - - puts -end - -def print_bean(bean_count) - print ' ' if bean_count < 10 - print_number(bean_count) -end - def print_number(n) # PRINT adds padding after a number and before a positive number print ' ' if n >= 0 @@ -34,38 +7,6 @@ def print_number(n) print ' ' end -def get_move(prompt, beans) - move = get_integer_input(prompt) - - while move < 1 || move > 6 || beans[move - 1] == 0 - puts "ILLEGAL MOVE" - move = get_integer_input("AGAIN") - end - - move - 1 -end - -def get_integer_input(prompt) - integer_value = nil - - input_values = input(prompt) - - while integer_value.nil? - print '!EXTRA INPUT IGNORED' if (input_values.size > 1) - - value = input_values.first - - begin - integer_value = Integer(value) - rescue - puts '!NUMBER EXPECTED - RETRY INPUT LINE' - input_values = input('') - end - end - - integer_value -end - def input(prompt) prompt_suffix = '? ' print "#{prompt}#{prompt_suffix}" @@ -102,131 +43,6 @@ def input(prompt) input_values end -def distribute_beans(beans, start_pit, home_pit) - beans_to_distribute = beans[start_pit] - beans[start_pit] = 0 - - current_pit = start_pit - - (0...beans_to_distribute).each do - current_pit = (current_pit + 1) % beans.size - beans[current_pit] += 1 - end - - # If the last pit was empty before we put a bean in it (and it's not a scoring pit), add beans to score - if beans[current_pit] == 1 && current_pit != 6 && current_pit != 13 && beans[12 - current_pit] != 0 - beans[home_pit] = beans[home_pit] + beans[12 - current_pit] + 1 - beans[current_pit] = 0 - beans[12 - current_pit] = 0 - end - - current_pit -end - -def update_history(current_move) - k = current_move % 7 - $c = $c + 1 - - $history[$non_win_count] = $history[$non_win_count] * 6 + k if $c < 9 -end - -# @param [Array] beans -# @param [Integer] move -# @param [Integer] home_pit -def perform_move(beans, move, home_pit) - last_pit = distribute_beans(beans, move, home_pit) - - update_history(move) - - last_pit -end - -# @return [Boolean] True if the computer did not win -def end_game(beans) - puts - puts "GAME OVER" - - difference = beans[6] - beans[13] - - if difference < 0 - puts "I WIN BY #{-difference} POINTS" - - return - end - - $non_win_count += 1 - - puts "YOU WIN BY #{difference} POINTS" if difference > 0 - puts "DRAWN GAME" if difference == 0 - - difference >= 0 -end - -# @param [Array] beans -def get_computer_move(beans) - d = -99 - home_pit = 13 - - chosen_move = 7 - - # Test all possible moves - (7...13).each do |move_under_test| - # Create a copy of the beans to test against - beans_copy = beans.dup - - # If the move is not legal, skip it - next if beans[move_under_test] == 0 - - # Determine the best response the player may make to this move - player_max_score = 0 - - # Make the move under test against the copy - distribute_beans(beans_copy, move_under_test, home_pit) - - # Test every player response - (0...6).each do |i| - # Skip the move if it would be illegal - next if beans_copy[i] == 0 - - # Determine the last - landing_with_overflow = beans_copy[i] + i - # If landing > 13 the player has put a bean in both home pits - player_move_score = (landing_with_overflow > 14) ? 1 : 0 - # Find the actual pit - landing = landing_with_overflow % 14 - - # If the landing pit is empty, the player will steal beans - if beans_copy[landing] == 0 && landing != 6 && landing != 13 - player_move_score = beans_copy[12 - landing] + player_move_score - end - - # Update the max score if this move is the best player move - player_max_score = player_move_score if player_move_score > player_max_score - end - - # Final score for move is computer score, minus the player's score and any player gains from their best move - final_score = beans_copy[13] - beans_copy[6] - player_max_score - - if $c < 9 - k = move_under_test % 7 - - (0...$non_win_count).each do |i| - final_score = final_score - 2 if $history[$non_win_count] * 6 + k == ((Float($history[i]) / 6 ** (7 - $c)) + 0.1).floor - end - end - - # Choose the move if it is the best move found so far - if final_score >= d - chosen_move = move_under_test - d = final_score - end - end - - last_pit = perform_move(beans, chosen_move, home_pit) - - [chosen_move, last_pit] -end - class Game def initialize(history, non_win_count) @beans = Array.new(13, 3) @@ -239,74 +55,251 @@ class Game @non_win_count = non_win_count end + def play + while true + print_beans + + move = get_move("YOUR MOVE") + home_pit = 6 + computer_home_pit = 13 + + last_pit = perform_move(move, home_pit) + + print_beans + + break if game_over + + if home_pit == last_pit + second_move = get_move("AGAIN") + + perform_move(second_move, home_pit) + + print_beans + + break if game_over + end + + computer_move, computer_last_pit = get_computer_move + print "MY MOVE IS #{computer_move - 6}" + + break if game_over + + if computer_last_pit == computer_home_pit + second_computer_move, _ = get_computer_move + print ",#{second_computer_move - 6}" + + break if game_over + end + end + + end_game + end + + private + def game_over @beans[0...6].all? { |b| b == 0 } || @beans[7...13].all? { |b| b == 0 } end - def play - until game_over - print_beans(@beans) + # @return [Boolean] True if the computer did not win + def end_game + puts + puts "GAME OVER" - move = get_move("YOUR MOVE", @beans) - home_pit = 6 - computer_home_pit = 13 + difference = @beans[6] - @beans[13] - last_pit = perform_move(@beans, move, home_pit) + if difference < 0 + puts "I WIN BY #{-difference} POINTS" - print_beans(@beans) - - if game_over - return end_game(@beans) - end - - if home_pit == last_pit - second_move = get_move("AGAIN", @beans) - - perform_move(@beans, second_move, home_pit) - - print_beans(@beans) - - if game_over - return end_game(@beans) - end - end - - computer_move, computer_last_pit = get_computer_move(@beans) - print "MY MOVE IS #{computer_move - 6}" - - if game_over - return end_game(@beans) - end - - if computer_last_pit == computer_home_pit - second_computer_move, _ = get_computer_move(@beans) - print ",#{second_computer_move - 6}" - - if game_over - return end_game(@beans) - end - end + return end + + puts "YOU WIN BY #{difference} POINTS" if difference > 0 + puts "DRAWN GAME" if difference == 0 + + difference >= 0 end + # @param [Integer] move + # @param [Integer] home_pit + def perform_move(move, home_pit) + last_pit = distribute_beans(move, home_pit) + + update_history(move) + + last_pit + end + + def update_history(current_move) + k = current_move % 7 + @turn_counter += 1 + + # Add the move to the history + @history[@non_win_count] = @history[@non_win_count] * 6 + k if @turn_counter < 9 + end + + def print_beans + puts + + # Print computer beans + print ' ' * 3 + @beans[7...13].reverse.each { |bean_count| print_bean(bean_count) } + puts + + # Print home beans + print_bean(@beans[13]) + print ' ' * 23 + print_number(@beans[6]) # This is not print_bean in line with the original version + puts + + # Print player beans + print ' ' * 3 + @beans[0...6].each { |bean_count| print_bean(bean_count) } + puts + + puts + end + + def get_move(prompt) + move = get_integer_input(prompt) + + while move < 1 || move > 6 || @beans[move - 1] == 0 + puts "ILLEGAL MOVE" + move = get_integer_input("AGAIN") + end + + move - 1 + end + + def distribute_beans(start_pit, home_pit, beans = @beans) + beans_to_distribute = beans[start_pit] + beans[start_pit] = 0 + + current_pit = start_pit + + (0...beans_to_distribute).each do + current_pit = (current_pit + 1) % beans.size + beans[current_pit] += 1 + end + + # If the last pit was empty before we put a bean in it (and it's not a scoring pit), add beans to score + if beans[current_pit] == 1 && current_pit != 6 && current_pit != 13 && beans[12 - current_pit] != 0 + beans[home_pit] = beans[home_pit] + beans[12 - current_pit] + 1 + beans[current_pit] = 0 + beans[12 - current_pit] = 0 + end + + current_pit + end + + def print_bean(bean_count) + print ' ' if bean_count < 10 + print_number(bean_count) + end + + def get_integer_input(prompt) + integer_value = nil + + input_values = input(prompt) + + while integer_value.nil? + print '!EXTRA INPUT IGNORED' if (input_values.size > 1) + + value = input_values.first + + begin + integer_value = Integer(value) + rescue + puts '!NUMBER EXPECTED - RETRY INPUT LINE' + input_values = input('') + end + end + + integer_value + end + + # @param [Array] beans + def get_computer_move + d = -99 + home_pit = 13 + + chosen_move = 7 + + # Test all possible moves + (7...13).each do |move_under_test| + # Create a copy of the beans to test against + beans_copy = @beans.dup + + # If the move is not legal, skip it + next if beans_copy[move_under_test] == 0 + + # Determine the best response the player may make to this move + player_max_score = 0 + + # Make the move under test against the copy + distribute_beans(move_under_test, home_pit, beans_copy) + + # Test every player response + (0...6).each do |i| + # Skip the move if it would be illegal + next if beans_copy[i] == 0 + + # Determine the last + landing_with_overflow = beans_copy[i] + i + # If landing > 13 the player has put a bean in both home pits + player_move_score = (landing_with_overflow > 14) ? 1 : 0 + # Find the actual pit + landing = landing_with_overflow % 14 + + # If the landing pit is empty, the player will steal beans + if beans_copy[landing] == 0 && landing != 6 && landing != 13 + player_move_score = beans_copy[12 - landing] + player_move_score + end + + # Update the max score if this move is the best player move + player_max_score = player_move_score if player_move_score > player_max_score + end + + # Final score for move is computer score, minus the player's score and any player gains from their best move + final_score = beans_copy[13] - beans_copy[6] - player_max_score + + if @turn_counter < 9 + k = move_under_test % 7 + + (0...@non_win_count).each do |i| + # Penalise move if it was used in a losing game + final_score = final_score - 2 if @history[@non_win_count] * 6 + k == ((Float(@history[i]) / 6 ** (7 - @turn_counter)) + 0.1).floor + end + end + + # Choose the move if it is the best move found so far + if final_score >= d + chosen_move = move_under_test + d = final_score + end + end + + last_pit = perform_move(chosen_move, home_pit) + + [chosen_move, last_pit] + end end puts 'AWARI'.center(80) puts 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'.center(80) # Initialise stable variables -$history = Array.new(50) -$non_win_count = 0 +history = Array.new(50) +non_win_count = 0 # APPLICATION LOOP while true print "\n", "\n" - $history[$non_win_count] = 0 - $c = 0 + history[non_win_count] = 0 - game = Game.new($history, $non_win_count) + game = Game.new(history, non_win_count) computer_didnt_win = game.play - $non_win_count += 1 if computer_didnt_win + non_win_count += 1 if computer_didnt_win end From 10a2f535ebed117a68e8782dfe1edd24d612529e Mon Sep 17 00:00:00 2001 From: Alex Scown Date: Sun, 9 Jan 2022 14:12:00 +0000 Subject: [PATCH 203/331] Final tidy --- 04_Awari/ruby/awari.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/04_Awari/ruby/awari.rb b/04_Awari/ruby/awari.rb index a9864dc7..65e27c25 100644 --- a/04_Awari/ruby/awari.rb +++ b/04_Awari/ruby/awari.rb @@ -1,5 +1,7 @@ require 'strscan' +# Prints a number according to Vintage Basic's PRINT statement +# @param n The number to print def print_number(n) # PRINT adds padding after a number and before a positive number print ' ' if n >= 0 @@ -7,6 +9,9 @@ def print_number(n) print ' ' end +# Mimic the INPUT statement using Vintage Basic as a reference +# @param prompt The prompt to show to the user +# @return An array of strings representing the inputted values def input(prompt) prompt_suffix = '? ' print "#{prompt}#{prompt_suffix}" @@ -55,6 +60,7 @@ class Game @non_win_count = non_win_count end + # @return [Boolean] True if the computer did not win the game def play while true print_beans @@ -218,7 +224,6 @@ class Game integer_value end - # @param [Array] beans def get_computer_move d = -99 home_pit = 13 @@ -294,7 +299,8 @@ non_win_count = 0 # APPLICATION LOOP while true - print "\n", "\n" + puts + puts history[non_win_count] = 0 From 63100a55921e863064de7fe7f7e09c848c13b29d Mon Sep 17 00:00:00 2001 From: Alex Scown Date: Sun, 9 Jan 2022 14:29:39 +0000 Subject: [PATCH 204/331] Fix unmatched quotes error --- 04_Awari/ruby/awari.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/04_Awari/ruby/awari.rb b/04_Awari/ruby/awari.rb index 65e27c25..6c68a4e0 100644 --- a/04_Awari/ruby/awari.rb +++ b/04_Awari/ruby/awari.rb @@ -32,7 +32,7 @@ def input(prompt) next_string.chomp!('"') else # No close quote – Vintage Basic crashes in this case - raise ArgumentError('Unmatched quotes in input') + raise 'Unmatched quotes in input' end elsif scanner.exist?(/,/) next_string = scanner.scan_until(/,/).chomp(',') From 3dacdcc878e4c74e80c7027e60639d4760a1cae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=8C=AF=E8=80=80?= Date: Sun, 9 Jan 2022 23:51:08 +0800 Subject: [PATCH 205/331] Ignore program-independent content generated by VisualStudio --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d2115efc..c3aa9f13 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ out/ Pipfile .DS_Store +/.vs/basic-computer-games/v16 +/.vs From d2e2b920f1fced0d6d3c049e349c3b8017718a7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E6=8C=AF=E8=80=80?= Date: Sun, 9 Jan 2022 23:54:29 +0800 Subject: [PATCH 206/331] 93_23_Matches\csharp The program is available in two versions, a "goto" version that mimics the original program and an "object-oriented" version. --- 93_23_Matches/csharp/23matches.csproj | 9 + 93_23_Matches/csharp/23matches.sln | 25 +++ 93_23_Matches/csharp/Goto.Program.cs | 129 ++++++++++++++ .../csharp/ObjectOrientedVersion.Program.cs | 161 ++++++++++++++++++ 93_23_Matches/csharp/README.md | 2 + 5 files changed, 326 insertions(+) create mode 100644 93_23_Matches/csharp/23matches.csproj create mode 100644 93_23_Matches/csharp/23matches.sln create mode 100644 93_23_Matches/csharp/Goto.Program.cs create mode 100644 93_23_Matches/csharp/ObjectOrientedVersion.Program.cs diff --git a/93_23_Matches/csharp/23matches.csproj b/93_23_Matches/csharp/23matches.csproj new file mode 100644 index 00000000..11091f71 --- /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 00000000..78fce16e --- /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 00000000..e23be8a4 --- /dev/null +++ b/93_23_Matches/csharp/Goto.Program.cs @@ -0,0 +1,129 @@ +using System; +using System.Threading; + +namespace _23matches +{ + class Program + { + ///