From d82a637152968ff3dd6e035965b6bf65f1a228de Mon Sep 17 00:00:00 2001 From: Marc Durdin Date: Tue, 4 Jan 2022 16:47:32 +1100 Subject: [PATCH 01/21] 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 02/21] 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 03/21] 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 ec43a4fc9490c220e76b434c045b3c84198eeefd Mon Sep 17 00:00:00 2001 From: Bastiaan Veelo Date: Mon, 3 Jan 2022 00:19:19 +0100 Subject: [PATCH 04/21] 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 05/21] 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 06/21] 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 07/21] 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 08/21] 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 09/21] 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 c744cd928247fd0059dad04645667fe6dc74446c Mon Sep 17 00:00:00 2001 From: Paul Holt Date: Wed, 5 Jan 2022 02:09:38 +1100 Subject: [PATCH 10/21] 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 11/21] 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 12/21] 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 13/21] 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 14/21] 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 05f597b12c1518da66b104fca8875aaf6ad00bd9 Mon Sep 17 00:00:00 2001 From: Alvaro Frias Garay Date: Tue, 4 Jan 2022 14:37:22 -0300 Subject: [PATCH 15/21] 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 16/21] 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 17/21] 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 18/21] 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 19/21] 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 20/21] 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 21/21] 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. +# +########################################################