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: + +
months_days[n]: + break + + if d2 <= 0: + print("{}".format(' '), end=' ') + elif d2 < 10: + print(" {}".format(d2), end=' ') + else: + print("{}".format(d2), end=' ') + print() + + if d2 >= months_days[n]: + break + + if d2 > months_days[n]: + d -= g + + print("\n") + + 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__": + 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. +# +######################################################## 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"; 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 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; } } 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 diff --git a/53_King/README.md b/53_King/README.md index 206202f0..0687224d 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,9 @@ 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 +⚠️ This game includes references to suicide or self-harm. + +### Bugs Implementers should be aware that this game contains at least one bug. diff --git a/53_King/kotlin/King.kt b/53_King/kotlin/King.kt index 01558c99..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) @@ -19,29 +20,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 +51,8 @@ private fun header() { } fun instructions(yearsRequired: Int) { - println(""" + println( + """ CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS @@ -80,10 +78,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 GameEndingException.DataEntryValidation() + currentYear = validatedInput { it > 0 } if (currentYear >= yearsRequired) { println(" COME ON, YOUR TERM IN OFFICE IS ONLY $yearsRequired YEARS.") @@ -92,21 +87,19 @@ fun loadOldGame(): GameState = GameState().apply { } while (retry) print("HOW MUCH DID YOU HAVE IN THE TREASURY? ") - rallods = numberInput() - if (rallods < 0) - throw GameEndingException.DataEntryValidation() + rallods = validatedInput { it >= 0 } + + print("HOW MANY COUNTRYMEN? ") + countrymen = validatedInput { it >= 0 } print("HOW MANY WORKERS? ") - foreignWorkers = numberInput() - if (foreignWorkers < 0) - throw GameEndingException.DataEntryValidation() + foreignWorkers = validatedInput { it >= 0 } do { var retry = false print("HOW MANY SQUARE MILES OF LAND? ") - landArea = numberInput() - if (landArea<0) - throw GameEndingException.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.") @@ -118,11 +111,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 +130,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,74 +167,68 @@ 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(""" - 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()) + println( + 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() + } + ) } } - 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. @@ -240,8 +250,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 @@ -252,10 +262,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 @@ -265,8 +275,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 @@ -339,7 +349,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 @@ -362,6 +371,7 @@ class GameState(val yearsRequired: Int = 8) { } while (sellThisYear < 0 || sellThisYear > landArea - 1000) } + /** * Input the value of `welfareThisYear` */ @@ -444,7 +454,7 @@ class GameState(val yearsRequired: Int = 8) { plantingArea == 0 && moneySpentOnPollutionControl == 0 - fun simulateOneYear() { + fun simulateOneYear(): YearOutcome { rallods -= moneySpentOnPollutionControl val rallodsAfterPollutionControl = rallods @@ -460,7 +470,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") @@ -568,33 +578,37 @@ 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) } 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 + } } } - 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() } 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): diff --git a/94_War/javascript/war.js b/94_War/javascript/war.js index eb74fb0c..ededa1ed 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.push(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 = cards.length; // Number of cards to shuffle into the game deck. Can be <= cards.length. + 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 playerCard = deck.shift(); // Take a card + const computerCard = deck.shift(); // Take a card + printCards(cards[playerCard], cards[computerCard]); + + 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"); + } 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");