From 5ac95df4184a7effc39255d9736d59b8c09c8d1d Mon Sep 17 00:00:00 2001 From: NezumiRonin Date: Tue, 9 Mar 2021 21:59:33 -0600 Subject: [PATCH 001/132] 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 e2d2cfcc8449cba7fe86c7ba44238d5d0fc8d817 Mon Sep 17 00:00:00 2001 From: Josh Gribbon Date: Sun, 2 Jan 2022 20:55:24 -0500 Subject: [PATCH 002/132] 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 703b410f2e8a80e294a0ab2d11ea06c559e322bc Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 4 Jan 2022 10:03:48 -0500 Subject: [PATCH 003/132] 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 24313121ca9d0d61b038776f8ee94e74f9497f62 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 4 Jan 2022 12:00:29 -0500 Subject: [PATCH 004/132] 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 651ae5fa8e8600d0679a303f5e549150fc4de077 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Tue, 4 Jan 2022 13:59:37 -0500 Subject: [PATCH 005/132] 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 006/132] 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 007/132] 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 2811e23a4f23e69a52790067790103f96ab4fcbf Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 08:36:05 -0500 Subject: [PATCH 008/132] 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 009/132] 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 010/132] 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 011/132] 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 012/132] 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 58f68bcd2fd8271b9f73cfac0ca8ff2bc6f0f45e Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 09:54:18 -0500 Subject: [PATCH 013/132] 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 014/132] 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 c41e7ce057acb8747e7ce159ed9f40214f31a95b Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Thu, 6 Jan 2022 13:58:12 -0500 Subject: [PATCH 015/132] 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 eaf24739e3e8f0b8f4ff5b7e9d7c306a99620622 Mon Sep 17 00:00:00 2001 From: Thomas Kwashnak Date: Mon, 10 Jan 2022 10:05:28 -0500 Subject: [PATCH 016/132] 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 017/132] 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 018/132] 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 019/132] 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 020/132] 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 021/132] 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 022/132] 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 023/132] 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 024/132] 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 025/132] 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 026/132] 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 027/132] 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 028/132] 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 029/132] 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 030/132] 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 031/132] 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 032/132] 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 033/132] 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 034/132] 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 035/132] 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 036/132] 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 037/132] 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 038/132] 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 039/132] 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 040/132] 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 041/132] 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 042/132] 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 043/132] 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 044/132] 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 045/132] 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 046/132] 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 047/132] 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 048/132] 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 049/132] 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 050/132] 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 051/132] 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 052/132] 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 053/132] 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 054/132] 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 055/132] 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 056/132] 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 057/132] 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 058/132] 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 059/132] 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 060/132] 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 061/132] 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 062/132] 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 063/132] 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 064/132] 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 065/132] 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 066/132] 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 067/132] 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 068/132] 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 069/132] 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 070/132] 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 071/132] 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 072/132] 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 073/132] 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 074/132] 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 075/132] 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 076/132] 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 077/132] 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 078/132] 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 079/132] 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 080/132] 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 081/132] 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 082/132] 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 083/132] 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 084/132] 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 085/132] 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 086/132] 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 087/132] 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 088/132] 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 089/132] 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 090/132] 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 091/132] 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 092/132] 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 093/132] 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 094/132] 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 095/132] 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 096/132] 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 097/132] 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 098/132] 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 099/132] 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 100/132] 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 101/132] 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 102/132] 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 103/132] 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 104/132] 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 105/132] 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 106/132] 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 107/132] 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 108/132] 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 109/132] 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 110/132] 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 111/132] 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 112/132] 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 113/132] 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 114/132] 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 115/132] 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 116/132] 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 117/132] 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 118/132] 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 119/132] 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 120/132] 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 121/132] 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 122/132] 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 123/132] 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 124/132] 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 125/132] 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 126/132] 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 127/132] 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 128/132] 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 129/132] 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 130/132] 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 131/132] 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 132/132] 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");