diff --git a/06 Banner/csharp/banner.cs b/06 Banner/csharp/banner.cs new file mode 100644 index 00000000..e3e59b4b --- /dev/null +++ b/06 Banner/csharp/banner.cs @@ -0,0 +1,251 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace banner +{ + class Banner + { + private int Horizontal { get; set; } + private int Vertical { get; set; } + private bool Centered { get; set; } + private string Character { get; set; } + private string Statement { get; set; } + + // This provides a bit-ended representation of each symbol + // that can be output. Each symbol is defined by 7 parts - + // where each part is an integer value that, when converted to + // the binary representation, shows which section is filled in + // with values and which are spaces. i.e., the 'filled in' + // parts represent the actual symbol on the paper. + Dictionary letters = new Dictionary() + { + {' ', new int[] { 0, 0, 0, 0, 0, 0, 0 } }, + {'A', new int[] {505, 37, 35, 34, 35, 37, 505} }, + {'B', new int[] {512, 274, 274, 274, 274, 274, 239} }, + {'C', new int[] {125, 131, 258, 258, 258, 131, 69} }, + {'D', new int[] {512, 258, 258, 258, 258, 131, 125} }, + {'E', new int[] {512, 274, 274, 274, 274, 258, 258} }, + {'F', new int[] {512, 18, 18, 18, 18, 2, 2} }, + {'G', new int[] {125, 131, 258, 258, 290, 163, 101} }, + {'H', new int[] {512, 17, 17, 17, 17, 17, 512} }, + {'I', new int[] {258, 258, 258, 512, 258, 258, 258} }, + {'J', new int[] {65, 129, 257, 257, 257, 129, 128} }, + {'K', new int[] {512, 17, 17, 41, 69, 131, 258} }, + {'L', new int[] {512, 257, 257, 257, 257, 257, 257} }, + {'M', new int[] {512, 7, 13, 25, 13, 7, 512} }, + {'N', new int[] {512, 7, 9, 17, 33, 193, 512} }, + {'O', new int[] {125, 131, 258, 258, 258, 131, 125} }, + {'P', new int[] {512, 18, 18, 18, 18, 18, 15} }, + {'Q', new int[] {125, 131, 258, 258, 322, 131, 381} }, + {'R', new int[] {512, 18, 18, 50, 82, 146, 271} }, + {'S', new int[] {69, 139, 274, 274, 274, 163, 69} }, + {'T', new int[] {2, 2, 2, 512, 2, 2, 2} }, + {'U', new int[] {128, 129, 257, 257, 257, 129, 128} }, + {'V', new int[] {64, 65, 129, 257, 129, 65, 64} }, + {'W', new int[] {256, 257, 129, 65, 129, 257, 256} }, + {'X', new int[] {388, 69, 41, 17, 41, 69, 388} }, + {'Y', new int[] {8, 9, 17, 481, 17, 9, 8} }, + {'Z', new int[] {386, 322, 290, 274, 266, 262, 260} }, + {'0', new int[] {57, 69, 131, 258, 131, 69, 57} }, + {'1', new int[] {0, 0, 261, 259, 512, 257, 257} }, + {'2', new int[] {261, 387, 322, 290, 274, 267, 261} }, + {'3', new int[] {66, 130, 258, 274, 266, 150, 100} }, + {'4', new int[] {33, 49, 41, 37, 35, 512, 33} }, + {'5', new int[] {160, 274, 274, 274, 274, 274, 226} }, + {'6', new int[] {194, 291, 293, 297, 305, 289, 193} }, + {'7', new int[] {258, 130, 66, 34, 18, 10, 8} }, + {'8', new int[] {69, 171, 274, 274, 274, 171, 69} }, + {'9', new int[] {263, 138, 74, 42, 26, 10, 7} }, + {'?', new int[] {5, 3, 2, 354, 18, 11, 5} }, + {'*', new int[] {69, 41, 17, 512, 17, 41, 69} }, + {'=', new int[] {41, 41, 41, 41, 41, 41, 41} }, + {'!', new int[] {1, 1, 1, 384, 1, 1, 1} }, + {'.', new int[] {1, 1, 129, 449, 129, 1, 1} } + }; + + + /// + /// This displays the provided text on the screen and then waits for the user + /// to enter a integer value greater than 0. + /// + /// Text to display on the screen asking for the input + /// The integer value entered by the user + private int GetNumber(string DisplayText) + { + Console.Write(DisplayText); + string TempStr = Console.ReadLine(); + + Int32.TryParse(TempStr, out int TempInt); + + if (TempInt <= 0) + { + throw new ArgumentException($"{DisplayText} must be greater than zero"); + } + + return TempInt; + } + + /// + /// This displays the provided text on the screen and then waits for the user + /// to enter a Y or N. It cheats by just looking for a 'y' and returning that + /// as true. Anything else that the user enters is returned as false. + /// + /// Text to display on the screen asking for the input + /// Returns true or false + private bool GetBool(string DisplayText) + { + Console.Write(DisplayText); + return (Console.ReadLine().StartsWith("y", StringComparison.InvariantCultureIgnoreCase)); + } + + /// + /// This displays the provided text on the screen and then waits for the user + /// to enter an arbitrary string. That string is then returned 'as-is'. + /// + /// Text to display on the screen asking for the input + /// The string entered by the user. + private string GetString(string DisplayText) + { + Console.Write(DisplayText); + return (Console.ReadLine().ToUpper()); + } + + /// + /// This queries the user for the various inputs needed by the program. + /// + private void GetInput() + { + Horizontal = GetNumber("Horizontal "); + Vertical = GetNumber("Vertical "); + Centered = GetBool("Centered "); + Character = GetString("Character (type 'ALL' if you want character being printed) "); + Statement = GetString("Statement "); + // We don't care about what the user enters here. This is just telling them + // to set the page in the printer. + _ = GetString("Set page "); + } + + /// + /// This prints out a single character of the banner - adding + /// a few blanks lines as a spacer between characters. + /// + private void PrintChar(char ch) + { + // In the trivial case (a space character), just print out the spaces + if (ch.Equals(' ')) + { + Console.WriteLine(new string('\n', 7 * Horizontal)); + return; + } + + // If a specific character to be printed was provided by the user, + // then user that as our ouput character - otherwise take the + // current character + char outCh = Character == "ALL" ? ch : Character[0]; + int[] letter = new int[7]; + try + { + letters[outCh].CopyTo(letter, 0); + } + catch (KeyNotFoundException) + { + throw new KeyNotFoundException($"The provided letter {outCh} was not found in the letters list"); + } + + // This iterates through each of the parts that make up + // each letter. Each part represents 1 * Horizontal lines + // of actual output. + for (int idx = 0; idx < 7; idx++) + { + // New int array declarations default to zeros + // numSections decides how many 'sections' need to be printed + // for a given line of each character + int[] numSections = new int[7]; + // fillInSection decides whether each 'section' of the + // character gets filled in with the character or with blanks + int[] fillInSection = new int[9]; + + // This uses the value in each part to decide which + // sections are empty spaces in the letter or filled in + // spaces. For each section marked with 1 in fillInSection, + // that will correspond to 1 * Vertical characters actually + // being output. + for (int exp = 8; exp >= 0; exp--) + { + if (Math.Pow(2, exp) < letter[idx]) + { + fillInSection[8 - exp] = 1; + letter[idx] -= (int)Math.Pow(2, exp); + if (letter[idx] == 1) + { + // Once we've exhausted all of the sections + // defined in this part of the letter, then + // we marked that number and break out of this + // for loop. + numSections[idx] = 8 - exp; + break; + } + } + } + + // Now that we know which sections of this part of the letter + // are filled in or spaces, we can actually create the string + // to print out. + string lineStr = ""; + + if (Centered) + lineStr += new string(' ', (int)(63 - 4.5 * Vertical) * 1 / 1 + 1); + + for (int idx2 = 0; idx2 <= numSections[idx]; idx2++) + { + lineStr = lineStr + new string(fillInSection[idx2] == 0 ? ' ' : outCh, Vertical); + } + + // Then we print that string out 1 * Horizontal number of times + for (int lineidx = 1; lineidx <= Horizontal; lineidx++) + { + Console.WriteLine(lineStr); + } + } + + // Finally, add a little spacer after each character for readability. + Console.WriteLine(new string('\n', 2 * Horizontal - 1)); + } + + /// + /// This prints the entire banner based in the parameters + /// the user provided. + /// + private void PrintBanner() + { + // Iterate through each character in the statement + foreach (char ch in Statement) + { + PrintChar(ch); + } + + // In the original version, it would print an additional 75 blank + // lines in order to feed the printer paper...don't really need this + // since we're not actually printing. + // Console.WriteLine(new string('\n', 75)); + } + + /// + /// Main entry point into the banner class and handles the main loop. + /// + public void Play() + { + GetInput(); + PrintBanner(); + } + } + + class Program + { + static void Main(string[] args) + { + new Banner().Play(); + } + } +} diff --git a/06 Banner/csharp/banner.csproj b/06 Banner/csharp/banner.csproj new file mode 100644 index 00000000..c73e0d16 --- /dev/null +++ b/06 Banner/csharp/banner.csproj @@ -0,0 +1,8 @@ + + + + Exe + netcoreapp3.1 + + + diff --git a/06 Banner/csharp/banner.sln b/06 Banner/csharp/banner.sln new file mode 100644 index 00000000..34f63984 --- /dev/null +++ b/06 Banner/csharp/banner.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "banner", "banner.csproj", "{9E24FA30-F2AC-4BF3-ADFB-92D3F796561C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9E24FA30-F2AC-4BF3-ADFB-92D3F796561C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E24FA30-F2AC-4BF3-ADFB-92D3F796561C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E24FA30-F2AC-4BF3-ADFB-92D3F796561C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E24FA30-F2AC-4BF3-ADFB-92D3F796561C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FF2A268C-9C4A-457F-8733-2E8931E07A1D} + EndGlobalSection +EndGlobal diff --git a/06 Banner/vbnet/banner.sln b/06 Banner/vbnet/banner.sln new file mode 100644 index 00000000..5fdc8737 --- /dev/null +++ b/06 Banner/vbnet/banner.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "banner", "banner.vbproj", "{1738D297-A04C-4E6E-8219-D9E72982C39D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1738D297-A04C-4E6E-8219-D9E72982C39D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1738D297-A04C-4E6E-8219-D9E72982C39D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1738D297-A04C-4E6E-8219-D9E72982C39D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1738D297-A04C-4E6E-8219-D9E72982C39D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {04E18CE1-1C55-432F-A15A-DC2FA9DDC0F1} + EndGlobalSection +EndGlobal diff --git a/06 Banner/vbnet/banner.vb b/06 Banner/vbnet/banner.vb new file mode 100644 index 00000000..90e183b8 --- /dev/null +++ b/06 Banner/vbnet/banner.vb @@ -0,0 +1,226 @@ +Imports System + +Module Banner + Private Horizontal As Integer + Private Vertical As Integer + Private Centered As Boolean + Private Character As String + Private Statement As String + + ' This provides a bit-ended representation of each symbol + ' that can be output. Each symbol Is defined by 7 parts - + ' where each part Is an integer value that, when converted to + ' the binary representation, shows which section Is filled in + ' with values And which are spaces. i.e., the 'filled in' + ' parts represent the actual symbol on the paper. + Private letters As Dictionary(Of Char, Integer()) = New Dictionary(Of Char, Integer()) From + { + {" ", {0, 0, 0, 0, 0, 0, 0}}, + {"A", {505, 37, 35, 34, 35, 37, 505}}, + {"B", {512, 274, 274, 274, 274, 274, 239}}, + {"C", {125, 131, 258, 258, 258, 131, 69}}, + {"D", {512, 258, 258, 258, 258, 131, 125}}, + {"E", {512, 274, 274, 274, 274, 258, 258}}, + {"F", {512, 18, 18, 18, 18, 2, 2}}, + {"G", {125, 131, 258, 258, 290, 163, 101}}, + {"H", {512, 17, 17, 17, 17, 17, 512}}, + {"I", {258, 258, 258, 512, 258, 258, 258}}, + {"J", {65, 129, 257, 257, 257, 129, 128}}, + {"K", {512, 17, 17, 41, 69, 131, 258}}, + {"L", {512, 257, 257, 257, 257, 257, 257}}, + {"M", {512, 7, 13, 25, 13, 7, 512}}, + {"N", {512, 7, 9, 17, 33, 193, 512}}, + {"O", {125, 131, 258, 258, 258, 131, 125}}, + {"P", {512, 18, 18, 18, 18, 18, 15}}, + {"Q", {125, 131, 258, 258, 322, 131, 381}}, + {"R", {512, 18, 18, 50, 82, 146, 271}}, + {"S", {69, 139, 274, 274, 274, 163, 69}}, + {"T", {2, 2, 2, 512, 2, 2, 2}}, + {"U", {128, 129, 257, 257, 257, 129, 128}}, + {"V", {64, 65, 129, 257, 129, 65, 64}}, + {"W", {256, 257, 129, 65, 129, 257, 256}}, + {"X", {388, 69, 41, 17, 41, 69, 388}}, + {"Y", {8, 9, 17, 481, 17, 9, 8}}, + {"Z", {386, 322, 290, 274, 266, 262, 260}}, + {"0", {57, 69, 131, 258, 131, 69, 57}}, + {"1", {0, 0, 261, 259, 512, 257, 257}}, + {"2", {261, 387, 322, 290, 274, 267, 261}}, + {"3", {66, 130, 258, 274, 266, 150, 100}}, + {"4", {33, 49, 41, 37, 35, 512, 33}}, + {"5", {160, 274, 274, 274, 274, 274, 226}}, + {"6", {194, 291, 293, 297, 305, 289, 193}}, + {"7", {258, 130, 66, 34, 18, 10, 8}}, + {"8", {69, 171, 274, 274, 274, 171, 69}}, + {"9", {263, 138, 74, 42, 26, 10, 7}}, + {"?", {5, 3, 2, 354, 18, 11, 5}}, + {"*", {69, 41, 17, 512, 17, 41, 69}}, + {"=", {41, 41, 41, 41, 41, 41, 41}}, + {"!", {1, 1, 1, 384, 1, 1, 1}}, + {".", {1, 1, 129, 449, 129, 1, 1}} + } + + ' + ' This displays the provided text on the screen And then waits for the user + ' to enter a integer value greater than 0. + ' + ' Text to display on the screen asking for the input + ' The integer value entered by the user + Private Function GetNumber(DisplayText As String) As Integer + Console.Write(DisplayText) + Dim TempStr As String = Console.ReadLine() + Dim TempInt As Integer + + Int32.TryParse(TempStr, TempInt) + + If (TempInt <= 0) Then + Throw New ArgumentException($"{DisplayText} must be greater than zero") + End If + + Return TempInt + End Function + + ' + ' This displays the provided text on the screen And then waits for the user + ' to enter a Y Or N. It cheats by just looking for a 'y' and returning that + ' as true. Anything else that the user enters Is returned as false. + ' + ' Text to display on the screen asking for the input + ' Returns true Or false + Private Function GetBool(DisplayText As String) As Boolean + Console.Write(DisplayText) + Return Console.ReadLine().StartsWith("y", StringComparison.InvariantCultureIgnoreCase) + End Function + + ' + ' This displays the provided text on the screen And then waits for the user + ' to enter an arbitrary string. That string Is then returned 'as-is'. + ' + ' Text to display on the screen asking for the input + ' The string entered by the user. + Private Function GetString(DisplayText As String) As String + Console.Write(DisplayText) + Return (Console.ReadLine().ToUpper()) + End Function + + ' + ' This queries the user for the various inputs needed by the program. + ' + Private Sub GetInput() + Horizontal = GetNumber("Horizontal ") + Vertical = GetNumber("Vertical ") + Centered = GetBool("Centered ") + Character = GetString("Character (type 'ALL' if you want character being printed) ") + Statement = GetString("Statement ") + ' We don't care about what the user enters here. This is just telling them + ' to set the page in the printer. + GetString("Set page ") + End Sub + + ' + ' This prints out a single character of the banner - adding + ' a few blanks lines as a spacer between characters. + ' + Private Sub PrintChar(ch As Char) + ' In the trivial case (a space character), just print out the spaces + If ch.Equals(" ") Then + Console.WriteLine(New String("\n", 7 * Horizontal)) + Return + End If + + ' If a specific character to be printed was provided by the user, + ' then user that as our ouput character - otherwise take the + ' current character + Dim outCh As Char = IIf(Character.Equals("ALL"), ch, Character.Substring(0, 1)) + Dim letter(7) As Integer + Try + letters(outCh).CopyTo(letter, 0) + Catch ex As KeyNotFoundException + Throw New KeyNotFoundException($"The provided letter {outCh} was not found in the letters list") + End Try + + ' This iterates through each of the parts that make up + ' each letter. Each part represents 1 * Horizontal lines + ' of actual output. + For idx As Integer = 0 To 7 + ' New int array declarations default to zeros + ' numSections decides how many 'sections' need to be printed + ' for a given line of each character + Dim numSections(7) As Integer + ' fillInSection decides whether each 'section' of the + ' character gets filled in with the character Or with blanks + Dim fillInSection(9) As Integer + + ' This uses the value in each part to decide which + ' sections are empty spaces in the letter Or filled in + ' spaces. For each section marked with 1 in fillInSection, + ' that will correspond to 1 * Vertical characters actually + ' being output. + For exp As Integer = 8 To 0 Step -1 + If (Math.Pow(2, exp) < letter(idx)) Then + fillInSection(8 - exp) = 1 + letter(idx) -= Math.Pow(2, exp) + If (letter(idx) = 1) Then + ' Once we've exhausted all of the sections + ' defined in this part of the letter, then + ' we marked that number And break out of this + ' for loop. + numSections(idx) = 8 - exp + Exit For + End If + End If + Next exp + + ' Now that we know which sections of this part of the letter + ' are filled in Or spaces, we can actually create the string + ' to print out. + Dim lineStr As String = "" + + If (Centered) Then + lineStr += New String(" ", (63 - 4.5 * Vertical) * 1 / 1 + 1) + End If + + For idx2 As Integer = 0 To numSections(idx) + lineStr = lineStr + New String(IIf(fillInSection(idx2) = 0, " ", outCh), Vertical) + Next idx2 + + ' Then we print that string out 1 * Horizontal number of times + For lineIdx As Integer = 1 To Horizontal + Console.WriteLine(lineStr) + Next lineIdx + Next idx + + + ' Finally, add a little spacer after each character for readability. + Console.WriteLine(New String(Environment.NewLine, 2 * Horizontal - 1)) + End Sub + + ' + ' This prints the entire banner based in the parameters + ' the user provided. + ' + Private Sub PrintBanner() + ' Iterate through each character in the statement + For Each ch As Char In Statement + PrintChar(ch) + Next ch + + ' In the original version, it would print an additional 75 blank + ' lines in order to feed the printer paper...don't really need this + ' since we're not actually printing. + Console.WriteLine(New String(Environment.NewLine, 75)) + End Sub + + ' + ' Main entry point into the banner class And handles the main loop. + ' + Public Sub Play() + GetInput() + PrintBanner() + End Sub +End Module + +Module Program + Sub Main(args As String()) + Banner.Play() + End Sub +End Module diff --git a/06 Banner/vbnet/banner.vbproj b/06 Banner/vbnet/banner.vbproj new file mode 100644 index 00000000..659fea7b --- /dev/null +++ b/06 Banner/vbnet/banner.vbproj @@ -0,0 +1,9 @@ + + + + Exe + banner + netcoreapp3.1 + + + diff --git a/13 Bounce/java/Bounce.java b/13 Bounce/java/Bounce.java new file mode 100644 index 00000000..6d39daa2 --- /dev/null +++ b/13 Bounce/java/Bounce.java @@ -0,0 +1,169 @@ +import java.util.Scanner; +import java.lang.Math; + +/** + * Game of Bounce + *

+ * Based on the BASIC game of Bounce here + * https://github.com/coding-horror/basic-computer-games/blob/main/13%20Bounce/bounce.bas + *

+ * Note: The idea was to create a version of the 1970's BASIC game in Java, without introducing + * new features - no additional text, error checking, etc has been added. + * + * Converted from BASIC to Java by Darren Cardenas. + */ + +public class Bounce { + + private final Scanner scan; // For user input + + public Bounce() { + + scan = new Scanner(System.in); + + } // End of constructor Bounce + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private void showIntro() { + + System.out.println(" ".repeat(32) + "BOUNCE"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + } // End of method showIntro + + private void startGame() { + + double coefficient = 0; + double height = 0; + double timeIncrement = 0; + double timeIndex = 0; + double timeTotal = 0; + double velocity = 0; + + double[] timeData = new double[21]; + + int heightInt = 0; + int index = 0; + int maxData = 0; + + String lineContent = ""; + + System.out.println("THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY"); + System.out.println("OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF"); + System.out.println("ELASTICITY OF THE BALL. PLEASE USE A DECIMAL FRACTION"); + System.out.println("COEFFICIENCY (LESS THAN 1)."); + System.out.println(""); + System.out.println("YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN"); + System.out.println("'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY)."); + System.out.println(""); + + // Begin outer while loop + while (true) { + + System.out.print("TIME INCREMENT (SEC)? "); + timeIncrement = Double.parseDouble(scan.nextLine()); + System.out.println(""); + + System.out.print("VELOCITY (FPS)? "); + velocity = Double.parseDouble(scan.nextLine()); + System.out.println(""); + + System.out.print("COEFFICIENT? "); + coefficient = Double.parseDouble(scan.nextLine()); + System.out.println(""); + + System.out.println("FEET"); + System.out.println(""); + + maxData = (int)(70 / (velocity / (16 * timeIncrement))); + + for (index = 1; index <= maxData; index++) { + timeData[index] = velocity * Math.pow(coefficient, index - 1) / 16; + } + + // Begin loop through all rows of y-axis data + for (heightInt = (int)(-16 * Math.pow(velocity / 32, 2) + Math.pow(velocity, 2) / 32 + 0.5) * 10; + heightInt >= 0; heightInt -= 5) { + + height = heightInt / 10.0; + + lineContent = ""; + + if ((int)(Math.floor(height)) == height) { + + lineContent += " " + (int)(height) + " "; + } + + timeTotal = 0; + + for (index = 1; index <= maxData; index++) { + + for (timeIndex = 0; timeIndex <= timeData[index]; timeIndex += timeIncrement) { + + timeTotal += timeIncrement; + + if (Math.abs(height - (0.5 * (-32) * Math.pow(timeIndex, 2) + velocity + * Math.pow(coefficient, index - 1) * timeIndex)) <= 0.25) { + + while (lineContent.length() < (timeTotal / timeIncrement) - 1) { + lineContent += " "; + } + lineContent += "0"; + } + } + + timeIndex = timeData[index + 1] / 2; + + if (-16 * Math.pow(timeIndex, 2) + velocity * Math.pow(coefficient, index - 1) * timeIndex < height) { + + break; + } + } + + System.out.println(lineContent); + + } // End loop through all rows of y-axis data + + lineContent = ""; + + // Show the x-axis + for (index = 1; index <= (int)(timeTotal + 1) / timeIncrement + 1; index++) { + + lineContent += "."; + } + + System.out.println(lineContent); + + lineContent = " 0"; + + for (index = 1; index <= (int)(timeTotal + 0.9995); index++) { + + while (lineContent.length() < (int)(index / timeIncrement)) { + lineContent += " "; + } + lineContent += index; + } + + System.out.println(lineContent); + + System.out.println(" ".repeat((int)((timeTotal + 1) / (2 * timeIncrement) - 3)) + "SECONDS"); + + } // End outer while loop + + } // End of method startGame + + public static void main(String[] args) { + + Bounce game = new Bounce(); + game.play(); + + } // End of method main + +} // End of class Bounce diff --git a/14 Bowling/java/Bowling.java b/14 Bowling/java/Bowling.java new file mode 100644 index 00000000..998f4fb3 --- /dev/null +++ b/14 Bowling/java/Bowling.java @@ -0,0 +1,278 @@ +import java.util.Scanner; +import java.lang.Math; + +/** + * Game of Bowling + *

+ * Based on the BASIC game of Bowling here + * https://github.com/coding-horror/basic-computer-games/blob/main/14%20Bowling/bowling.bas + *

+ * Note: The idea was to create a version of the 1970's BASIC game in Java, without introducing + * new features - no additional text, error checking, etc has been added. + * + * Converted from BASIC to Java by Darren Cardenas. + */ + +public class Bowling { + + private final Scanner scan; // For user input + + public Bowling() { + + scan = new Scanner(System.in); + + } // End of constructor Bowling + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private static void showIntro() { + + System.out.println(" ".repeat(33) + "BOWL"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + } // End of method showIntro + + private void startGame() { + + int ball = 0; + int bell = 0; + int frame = 0; + int ii = 0; // Loop iterator + int jj = 0; // Loop iterator + int kk = 0; // Loop iterator + int numPlayers = 0; + int pinsDownBefore = 0; + int pinsDownNow = 0; + int player = 0; + int randVal = 0; + int result = 0; + + int[] pins = new int[16]; + + int[][] scores = new int[101][7]; + + String userResponse = ""; + + System.out.println("WELCOME TO THE ALLEY"); + System.out.println("BRING YOUR FRIENDS"); + System.out.println("OKAY LET'S FIRST GET ACQUAINTED"); + System.out.println(""); + System.out.println("THE INSTRUCTIONS (Y/N)"); + System.out.print("? "); + + userResponse = scan.nextLine(); + + if (userResponse.toUpperCase().equals("Y")) { + printRules(); + } + + System.out.print("FIRST OF ALL...HOW MANY ARE PLAYING? "); + numPlayers = Integer.parseInt(scan.nextLine()); + + System.out.println(""); + System.out.println("VERY GOOD..."); + + // Begin outer while loop + while (true) { + + for (ii = 1; ii <= 100; ii++) { + for (jj = 1; jj <= 6; jj++) { + scores[ii][jj] = 0; + } + } + + frame = 1; + + // Begin frame while loop + while (frame < 11) { + + // Begin loop through all players + for (player = 1; player <= numPlayers; player++) { + + pinsDownBefore = 0; + ball = 1; + result = 0; + + for (ii = 1; ii <= 15; ii++) { + pins[ii] = 0; + } + + while (true) { + + // Ball generator using mod '15' system + + System.out.println("TYPE ROLL TO GET THE BALL GOING."); + System.out.print("? "); + scan.nextLine(); + + kk = 0; + pinsDownNow = 0; + + for (ii = 1; ii <= 20; ii++) { + + randVal = (int)(Math.random() * 100) + 1; + + for (jj = 1; jj <= 10; jj++) { + + if (randVal < 15 * jj) { + break; + } + } + pins[15 * jj - randVal] = 1; + } + + // Pin diagram + + System.out.println("PLAYER: " + player + " FRAME: " + frame + " BALL: " + ball); + + for (ii = 0; ii <= 3; ii++) { + + System.out.println(""); + + System.out.print(" ".repeat(ii)); + + for (jj = 1; jj <= 4 - ii; jj++) { + + kk++; + + if (pins[kk] == 1) { + + System.out.print("O "); + + } else { + + System.out.print("+ "); + } + } + } + + System.out.println(""); + + // Roll analysis + + for (ii = 1; ii <= 10; ii++) { + pinsDownNow += pins[ii]; + } + + if (pinsDownNow - pinsDownBefore == 0) { + System.out.println("GUTTER!!"); + } + + if (ball == 1 && pinsDownNow == 10) { + System.out.println("STRIKE!!!!!"); + + // Ring bell + for (bell = 1; bell <= 4; bell++) { + System.out.print("\007"); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + result = 3; + } + + if (ball == 2 && pinsDownNow == 10) { + System.out.println("SPARE!!!!"); + result = 2; + } + + if (ball == 2 && pinsDownNow < 10) { + System.out.println("ERROR!!!"); + result = 1; + } + + if (ball == 1 && pinsDownNow < 10) { + System.out.println("ROLL YOUR 2ND BALL"); + } + + // Storage of the scores + + System.out.println(""); + + scores[frame * player][ball] = pinsDownNow; + + if (ball != 2) { + ball = 2; + pinsDownBefore = pinsDownNow; + + if (result != 3) { + scores[frame * player][ball] = pinsDownNow - pinsDownBefore; + if (result == 0) { + continue; + } + } else { + scores[frame * player][ball] = pinsDownNow; + } + + } + break; + } + + scores[frame * player][3] = result; + + } // End loop through all players + + frame++; + + } // End frame while loop + + System.out.println("FRAMES"); + + System.out.print(" "); + for (ii = 1; ii <= 10; ii++) { + System.out.print(ii + " "); + } + + System.out.println(""); + + for (player = 1; player <= numPlayers; player++) { + for (ii = 1; ii <= 3; ii++) { + System.out.print(" "); + for (jj = 1; jj <= 10; jj++) { + System.out.print (scores[jj * player][ii] + " "); + } + System.out.println(""); + } + System.out.println(""); + } + + System.out.println("DO YOU WANT ANOTHER GAME"); + System.out.print("? "); + + userResponse = scan.nextLine(); + + if (!String.valueOf(userResponse.toUpperCase().charAt(0)).equals("Y")) { + break; + } + + } // End outer while loop + + } // End of method startGame + + public static void printRules() { + + System.out.println("THE GAME OF BOWLING TAKES MIND AND SKILL.DURING THE GAME"); + System.out.println("THE COMPUTER WILL KEEP SCORE.YOU MAY COMPETE WITH"); + System.out.println("OTHER PLAYERS[UP TO FOUR].YOU WILL BE PLAYING TEN FRAMES"); + System.out.println("ON THE PIN DIAGRAM 'O' MEANS THE PIN IS DOWN...'+' MEANS THE"); + System.out.println("PIN IS STANDING.AFTER THE GAME THE COMPUTER WILL SHOW YOUR"); + System.out.println("SCORES ."); + + } // End of method printRules + + public static void main(String[] args) { + + Bowling game = new Bowling(); + game.play(); + + } // End of method main + +} // End of class Bowling diff --git a/31 Depth Charge/csharp/DepthCharge.sln b/31 Depth Charge/csharp/DepthCharge.sln new file mode 100644 index 00000000..8d56c717 --- /dev/null +++ b/31 Depth Charge/csharp/DepthCharge.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31129.286 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Game.csproj", "{CBC9D8D9-9EDE-4D34-A20E-C90D929ABF8F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CBC9D8D9-9EDE-4D34-A20E-C90D929ABF8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CBC9D8D9-9EDE-4D34-A20E-C90D929ABF8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CBC9D8D9-9EDE-4D34-A20E-C90D929ABF8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CBC9D8D9-9EDE-4D34-A20E-C90D929ABF8F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {738F08DD-89E9-44C5-B5AC-3F21C6AEEFA1} + EndGlobalSection +EndGlobal diff --git a/31 Depth Charge/csharp/Game.csproj b/31 Depth Charge/csharp/Game.csproj new file mode 100644 index 00000000..3028f277 --- /dev/null +++ b/31 Depth Charge/csharp/Game.csproj @@ -0,0 +1,9 @@ + + + + Exe + net5.0 + DepthCharge + + + diff --git a/31 Depth Charge/csharp/src/Controller.cs b/31 Depth Charge/csharp/src/Controller.cs new file mode 100644 index 00000000..7669e67c --- /dev/null +++ b/31 Depth Charge/csharp/src/Controller.cs @@ -0,0 +1,85 @@ +using System; + +namespace DepthCharge +{ + ///

+ /// Contains functions for reading input from the user. + /// + static class Controller + { + /// + /// Retrives a dimension for the play area from the user. + /// + /// + /// Note that the original BASIC version would allow dimension values + /// of 0 or less. We're doing a little extra validation here in order + /// to avoid strange behaviour. + /// + public static int InputDimension() + { + View.PromptDimension(); + + while (true) + { + if (!Int32.TryParse(Console.ReadLine(), out var dimension)) + View.ShowInvalidNumber(); + else + if (dimension < 1) + View.ShowInvalidDimension(); + else + return dimension; + } + } + + /// + /// Retrieves a set of coordinates from the user. + /// + /// + /// The current trail number. + /// + public static (int x, int y, int depth) InputCoordinates(int trailNumber) + { + View.PromptGuess(trailNumber); + + while (true) + { + var coordinates = Console.ReadLine().Split(','); + + if (coordinates.Length < 3) + View.ShowTooFewCoordinates(); + else + if (coordinates.Length > 3) + View.ShowTooManyCoordinates(); + else + if (!Int32.TryParse(coordinates[0], out var x) || + !Int32.TryParse(coordinates[1], out var y) || + !Int32.TryParse(coordinates[2], out var depth)) + View.ShowInvalidNumber(); + else + return (x, y, depth); + } + } + + /// + /// Retrieves the user's intention to play again (or not). + /// + public static bool InputPlayAgain() + { + View.PromptPlayAgain(); + + while (true) + { + switch (Console.ReadLine()) + { + case "Y": + return true; + case "N": + return false; + default: + View.ShowInvalidYesOrNo(); + break; + } + } + } + } +} diff --git a/31 Depth Charge/csharp/src/Program.cs b/31 Depth Charge/csharp/src/Program.cs new file mode 100644 index 00000000..de3db6d9 --- /dev/null +++ b/31 Depth Charge/csharp/src/Program.cs @@ -0,0 +1,47 @@ +using System; + +namespace DepthCharge +{ + class Program + { + static void Main(string[] args) + { + var random = new Random(); + + View.ShowBanner(); + + var dimension = Controller.InputDimension(); + var maximumGuesses = CalculateMaximumGuesses(); + + View.ShowInstructions(maximumGuesses); + + do + { + View.ShowStartGame(); + + var submarineCoordinates = PlaceSubmarine(); + var trailNumber = 1; + var guess = (0, 0, 0); + + do + { + guess = Controller.InputCoordinates(trailNumber); + if (guess != submarineCoordinates) + View.ShowGuessPlacement(submarineCoordinates, guess); + } + while (guess != submarineCoordinates && trailNumber++ < maximumGuesses); + + View.ShowGameResult(submarineCoordinates, guess, trailNumber); + } + while (Controller.InputPlayAgain()); + + View.ShowFarewell(); + + int CalculateMaximumGuesses() => + (int)Math.Log2(dimension) + 1; + + (int x, int y, int depth) PlaceSubmarine() => + (random.Next(dimension), random.Next(dimension), random.Next(dimension)); + } + } +} diff --git a/31 Depth Charge/csharp/src/View.cs b/31 Depth Charge/csharp/src/View.cs new file mode 100644 index 00000000..71e83a9f --- /dev/null +++ b/31 Depth Charge/csharp/src/View.cs @@ -0,0 +1,121 @@ +using System; + +namespace DepthCharge +{ + /// + /// Contains methods for displaying information to the user. + /// + static class View + { + public static void ShowBanner() + { + Console.WriteLine(" DEPTH CHARGE"); + Console.WriteLine(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); + } + + public static void ShowInstructions(int maximumGuesses) + { + Console.WriteLine("YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER"); + Console.WriteLine("AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR"); + Console.WriteLine($"MISSION IS TO DESTROY IT. YOU HAVE {maximumGuesses} SHOTS."); + Console.WriteLine("SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A"); + Console.WriteLine("TRIO OF NUMBERS -- THE FIRST TWO ARE THE"); + Console.WriteLine("SURFACE COORDINATES; THE THIRD IS THE DEPTH."); + Console.WriteLine(); + } + + public static void ShowStartGame() + { + Console.WriteLine("GOOD LUCK !"); + Console.WriteLine(); + } + + public static void ShowGuessPlacement((int x, int y, int depth) actual, (int x, int y, int depth) guess) + { + Console.Write("SONAR REPORTS SHOT WAS "); + if (guess.y > actual.y) + Console.Write("NORTH"); + if (guess.y < actual.y) + Console.Write("SOUTH"); + if (guess.x > actual.x) + Console.Write("EAST"); + if (guess.x < actual.x) + Console.Write("WEST"); + if (guess.y != actual.y || guess.x != actual.y) + Console.Write(" AND"); + if (guess.depth > actual.depth) + Console.Write (" TOO LOW."); + if (guess.depth < actual.depth) + Console.Write(" TOO HIGH."); + if (guess.depth == actual.depth) + Console.Write(" DEPTH OK."); + + Console.WriteLine(); + } + + public static void ShowGameResult((int x, int y, int depth) submarineLocation, (int x, int y, int depth) finalGuess, int trailNumber) + { + Console.WriteLine(); + + if (submarineLocation == finalGuess) + { + Console.WriteLine($"B O O M ! ! YOU FOUND IT IN {trailNumber} TRIES!"); + } + else + { + Console.WriteLine("YOU HAVE BEEN TORPEDOED! ABANDON SHIP!"); + Console.WriteLine($"THE SUBMARINE WAS AT {submarineLocation.x}, {submarineLocation.y}, {submarineLocation.depth}"); + } + } + + public static void ShowFarewell() + { + Console.WriteLine ("OK. HOPE YOU ENJOYED YOURSELF."); + } + + public static void ShowInvalidNumber() + { + Console.WriteLine("PLEASE ENTER A NUMBER"); + } + + public static void ShowInvalidDimension() + { + Console.WriteLine("PLEASE ENTER A VALID DIMENSION"); + } + + public static void ShowTooFewCoordinates() + { + Console.WriteLine("TOO FEW COORDINATES"); + } + + public static void ShowTooManyCoordinates() + { + Console.WriteLine("TOO MANY COORDINATES"); + } + + public static void ShowInvalidYesOrNo() + { + Console.WriteLine("PLEASE ENTER Y OR N"); + } + + public static void PromptDimension() + { + Console.Write("DIMENSION OF SEARCH AREA? "); + } + + public static void PromptGuess(int trailNumber) + { + Console.WriteLine(); + Console.Write($"TRIAL #{trailNumber}? "); + } + + public static void PromptPlayAgain() + { + Console.WriteLine(); + Console.Write("ANOTHER GAME (Y OR N)? "); + } + } +} diff --git a/34 Digits/java/Digits.java b/34 Digits/java/Digits.java new file mode 100644 index 00000000..36ee58ae --- /dev/null +++ b/34 Digits/java/Digits.java @@ -0,0 +1,186 @@ +import java.util.Arrays; +import java.util.InputMismatchException; +import java.util.Scanner; + +/** + * DIGITS + *

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + */ +public class Digits { + + public static void main(String[] args) { + printIntro(); + Scanner scan = new Scanner(System.in); + + boolean showInstructions = readInstructionChoice(scan); + if (showInstructions) { + printInstructions(); + } + + int a = 0, b = 1, c = 3; + int[][] m = new int[27][3]; + int[][] k = new int[3][3]; + int[][] l = new int[9][3]; + + boolean continueGame = true; + while (continueGame) { + for (int[] ints : m) { + Arrays.fill(ints, 1); + } + for (int[] ints : k) { + Arrays.fill(ints, 9); + } + for (int[] ints : l) { + Arrays.fill(ints, 3); + } + + l[0][0] = 2; + l[4][1] = 2; + l[8][2] = 2; + + int z = 26, z1 = 8, z2 = 2, runningCorrect = 0; + + for (int t = 1; t <= 3; t++) { + boolean validNumbers = false; + int[] numbers = new int[0]; + while (!validNumbers) { + System.out.println(); + numbers = read10Numbers(scan); + validNumbers = true; + for (int number : numbers) { + if (number < 0 || number > 2) { + System.out.println("ONLY USE THE DIGITS '0', '1', OR '2'."); + System.out.println("LET'S TRY AGAIN."); + validNumbers = false; + break; + } + } + } + + System.out.printf("\n%-14s%-14s%-14s%-14s", "MY GUESS", "YOUR NO.", "RESULT", "NO. RIGHT"); + for (int number : numbers) { + int s = 0; + int myGuess = 0; + for (int j = 0; j <= 2; j++) { + //What did the original author have in mind ? The first expression always results in 0 because a is always 0 + int s1 = a * k[z2][j] + b * l[z1][j] + c * m[z][j]; + if (s < s1) { + s = s1; + myGuess = j; + } else if (s1 == s) { + if (Math.random() >= 0.5) { + myGuess = j; + } + } + } + + String result; + if (myGuess != number) { + result = "WRONG"; + } else { + runningCorrect++; + result = "RIGHT"; + m[z][number] = m[z][number] + 1; + l[z1][number] = l[z1][number] + 1; + k[z2][number] = k[z2][number] + 1; + z = z - (z / 9) * 9; + z = 3 * z + number; + } + System.out.printf("\n%-14d%-14d%-14s%-14d", myGuess, number, result, runningCorrect); + + z1 = z - (z / 9) * 9; + z2 = number; + } + } + + //print summary report + System.out.println(); + if (runningCorrect > 10) { + System.out.println(); + System.out.println("I GUESSED MORE THAN 1/3 OF YOUR NUMBERS."); + System.out.println("I WIN.\u0007"); + } else if (runningCorrect < 10) { + System.out.println("I GUESSED LESS THAN 1/3 OF YOUR NUMBERS."); + System.out.println("YOU BEAT ME. CONGRATULATIONS *****"); + } else { + System.out.println("I GUESSED EXACTLY 1/3 OF YOUR NUMBERS."); + System.out.println("IT'S A TIE GAME."); + } + + continueGame = readContinueChoice(scan); + } + + System.out.println("\nTHANKS FOR THE GAME."); + } + + private static boolean readContinueChoice(Scanner scan) { + System.out.print("\nDO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO) ? "); + int choice; + try { + choice = scan.nextInt(); + return choice == 1; + } catch (InputMismatchException ex) { + return false; + } finally { + scan.nextLine(); + } + } + + private static int[] read10Numbers(Scanner scan) { + System.out.print("TEN NUMBERS, PLEASE ? "); + int[] numbers = new int[10]; + + for (int i = 0; i < numbers.length; i++) { + boolean validInput = false; + while (!validInput) { + try { + int n = scan.nextInt(); + validInput = true; + numbers[i] = n; + } catch (InputMismatchException ex) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); + } finally { + scan.nextLine(); + } + } + } + + return numbers; + } + + private static void printInstructions() { + System.out.println("\n"); + System.out.println("PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN"); + System.out.println("THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM."); + System.out.println("ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH."); + System.out.println("I WILL ASK FOR THEN TEN AT A TIME."); + System.out.println("I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR"); + System.out.println("NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,"); + System.out.println("I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER"); + System.out.println("THAN THAT *****"); + System.out.println(); + } + + private static boolean readInstructionChoice(Scanner scan) { + System.out.print("FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0' ? "); + int choice; + try { + choice = scan.nextInt(); + return choice == 1; + } catch (InputMismatchException ex) { + return false; + } finally { + scan.nextLine(); + } + } + + private static void printIntro() { + System.out.println(" DIGITS"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + System.out.println("THIS IS A GAME OF GUESSING."); + } + +} + diff --git a/36 Flip Flop/java/FlipFlop.java b/36 Flip Flop/java/FlipFlop.java new file mode 100644 index 00000000..afca236f --- /dev/null +++ b/36 Flip Flop/java/FlipFlop.java @@ -0,0 +1,287 @@ +import java.util.Scanner; +import java.lang.Math; + +/** + * Game of FlipFlop + *

+ * Based on the BASIC game of FlipFlop here + * https://github.com/coding-horror/basic-computer-games/blob/main/36%20Flip%20Flop/flipflop.bas + *

+ * Note: The idea was to create a version of the 1970's BASIC game in Java, without introducing + * new features - no additional text, error checking, etc has been added. + * + * Converted from BASIC to Java by Darren Cardenas. + */ + +public class FlipFlop { + + private final Scanner scan; // For user input + + private enum Step { + RANDOMIZE, INIT_BOARD, GET_NUMBER, ILLEGAL_ENTRY, FLIP_POSITION, SET_X_FIRST, SET_X_SECOND, + GENERATE_R_FIRST, GENERATE_R_SECOND, PRINT_BOARD, QUERY_RETRY + } + + public FlipFlop() { + + scan = new Scanner(System.in); + + } // End of constructor FlipFlop + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private static void showIntro() { + + System.out.println(" ".repeat(31) + "FLIPFLOP"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(""); + + } // End of method showIntro + + private void startGame() { + + double mathVal = 0; + double randVal = 0; + double tmpVal = 0; + + int index = 0; + int match = 0; + int numFlip = 0; + int numGuesses = 0; + + Step nextStep = Step.RANDOMIZE; + + String userResponse = ""; + + String[] board = new String[21]; + + System.out.println("THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:"); + System.out.println(""); + System.out.println("X X X X X X X X X X"); + System.out.println(""); + System.out.println("TO THIS:"); + System.out.println(""); + System.out.println("O O O O O O O O O O"); + System.out.println(""); + System.out.println("BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE"); + System.out.println("LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON"); + System.out.println("OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0"); + System.out.println("(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE "); + System.out.println("11 (ELEVEN)."); + System.out.println(""); + + // Begin outer while loop + while (true) { + + // Begin switch + switch (nextStep) { + + case RANDOMIZE: + + randVal = Math.random(); + + System.out.println("HERE IS THE STARTING LINE OF X'S."); + System.out.println(""); + + numGuesses = 0; + nextStep = Step.INIT_BOARD; + break; + + case INIT_BOARD: + + System.out.println("1 2 3 4 5 6 7 8 9 10"); + System.out.println("X X X X X X X X X X"); + System.out.println(""); + + // Avoid out of bounds error by starting at zero + for (index = 0; index <= 10; index++) { + board[index] = "X"; + } + + nextStep = Step.GET_NUMBER; + break; + + case GET_NUMBER: + + System.out.print("INPUT THE NUMBER? "); + userResponse = scan.nextLine(); + + try { + numFlip = Integer.parseInt(userResponse); + } + catch (NumberFormatException ex) { + nextStep = Step.ILLEGAL_ENTRY; + break; + } + + // Command to start a new game + if (numFlip == 11) { + nextStep = Step.RANDOMIZE; + break; + } + + if (numFlip > 11) { + nextStep = Step.ILLEGAL_ENTRY; + break; + } + + // Command to reset the board + if (numFlip == 0) { + nextStep = Step.INIT_BOARD; + break; + } + + if (match == numFlip) { + nextStep = Step.FLIP_POSITION; + break; + } + + match = numFlip; + + if (board[numFlip].equals("O")) { + nextStep = Step.SET_X_FIRST; + break; + } + + board[numFlip] = "O"; + nextStep = Step.GENERATE_R_FIRST; + break; + + case ILLEGAL_ENTRY: + System.out.println("ILLEGAL ENTRY--TRY AGAIN."); + nextStep = Step.GET_NUMBER; + break; + + case GENERATE_R_FIRST: + + mathVal = Math.tan(randVal + numFlip / randVal - numFlip) - Math.sin(randVal / numFlip) + 336 + * Math.sin(8 * numFlip); + + tmpVal = mathVal - (int)Math.floor(mathVal); + + numFlip = (int)(10 * tmpVal); + + if (board[numFlip].equals("O")) { + nextStep = Step.SET_X_FIRST; + break; + } + + board[numFlip] = "O"; + nextStep = Step.PRINT_BOARD; + break; + + case SET_X_FIRST: + board[numFlip] = "X"; + + if (match == numFlip) { + nextStep = Step.GENERATE_R_FIRST; + } else { + nextStep = Step.PRINT_BOARD; + } + break; + + case FLIP_POSITION: + + if (board[numFlip].equals("O")) { + nextStep = Step.SET_X_SECOND; + break; + } + + board[numFlip] = "O"; + nextStep = Step.GENERATE_R_SECOND; + break; + + case GENERATE_R_SECOND: + + mathVal = 0.592 * (1 / Math.tan(randVal / numFlip + randVal)) / Math.sin(numFlip * 2 + randVal) + - Math.cos(numFlip); + + tmpVal = mathVal - (int)mathVal; + numFlip = (int)(10 * tmpVal); + + if (board[numFlip].equals("O")) { + nextStep = Step.SET_X_SECOND; + break; + } + + board[numFlip] = "O"; + nextStep = Step.PRINT_BOARD; + break; + + case SET_X_SECOND: + + board[numFlip] = "X"; + if (match == numFlip) { + nextStep = Step.GENERATE_R_SECOND; + break; + } + + nextStep = Step.PRINT_BOARD; + break; + + case PRINT_BOARD: + System.out.println("1 2 3 4 5 6 7 8 9 10"); + + for (index = 1; index <= 10; index++) { + System.out.print(board[index] + " "); + } + + numGuesses++; + + System.out.println(""); + + for (index = 1; index <= 10; index++) { + if (!board[index].equals("O")) { + nextStep = Step.GET_NUMBER; + break; + } + } + + if (nextStep == Step.GET_NUMBER) { + break; + } + + if (numGuesses > 12) { + System.out.println("TRY HARDER NEXT TIME. IT TOOK YOU " + numGuesses + " GUESSES."); + } else { + System.out.println("VERY GOOD. YOU GUESSED IT IN ONLY " + numGuesses + " GUESSES."); + } + nextStep = Step.QUERY_RETRY; + break; + + case QUERY_RETRY: + + System.out.print("DO YOU WANT TO TRY ANOTHER PUZZLE? "); + userResponse = scan.nextLine(); + + if (userResponse.toUpperCase().charAt(0) == 'N') { + return; + } + System.out.println(""); + nextStep = Step.RANDOMIZE; + break; + + default: + System.out.println("INVALID STEP"); + nextStep = Step.QUERY_RETRY; + break; + + } // End of switch + + } // End outer while loop + + } // End of method startGame + + public static void main(String[] args) { + + FlipFlop game = new FlipFlop(); + game.play(); + + } // End of method main + +} // End of class FlipFlop diff --git a/39 Golf/csharp/Program.cs b/39 Golf/csharp/Program.cs new file mode 100644 index 00000000..abbbaf6b --- /dev/null +++ b/39 Golf/csharp/Program.cs @@ -0,0 +1,1142 @@ +// +// 8""""8 8"""88 8 8"""" +// 8 " 8 8 8 8 +// 8e 8 8 8e 8eeee +// 88 ee 8 8 88 88 +// 88 8 8 8 88 88 +// 88eee8 8eeee8 88eee 88 +// +// GOLF +// +// C# +// .NET Core +// TargetFramework: netcoreapp 3.1 +// +// Run source: +// dotnet run +// +// Linux compile: +// dotnet publish --self-contained -c Release -r linux-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true +// +// Windows compile: +// dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true +// +// +// INDEX +// ----------------- methods +// constructor +// NewHole +// TeeUp +// Stroke +// PlotBall +// InterpretResults +// ReportCurrentScore +// FindBall +// IsOnFairway +// IsOnGreen +// IsInHazard +// IsInRough +// IsOutOfBounds +// ScoreCardNewHole +// ScoreCardRecordStroke +// ScoreCardGetPreviousStroke +// ScoreCardGetTotal +// Ask +// Wait +// ReviewBag +// Quit +// GameOver +// ----------------- DATA +// Clubs +// CourseInfo +// ----------------- classes +// HoleInfo +// CircleGameObj +// RectGameObj +// HoleGeometry +// Plot +// ----------------- helper methods +// GetDistance +// IsInRectangle +// ToRadians +// ToDegrees360 +// Odds +// +// Despite being a text based game, the code uses simple geometry to simulate a course. +// Fairways are 40 yard wide rectangles, surrounded by 5 yards of rough around the perimeter. +// The green is a circle of 10 yards radius around the cup. +// The cup is always at point (0,0). +// +// Using basic trigonometry we can plot the ball's location using the distance of the stroke and +// and the angle of deviation (hook/slice). +// +// The stroke distances are based on real world averages of different club types. +// Lots of randomization, "business rules", and luck influence the game play. +// Probabilities are commented in the code. +// +// note: 'courseInfo', 'clubs', & 'scoreCard' arrays each include an empty object so indexing +// can begin at 1. Like all good programmers we count from zero, but in this context, +// it's more natural when hole number one is at index one +// +// +// |-----------------------------| +// | rough | +// | ---------------------- | +// | | | | +// | r | = = | r | +// | o | = = | o | +// | u | = . = | u | +// | g | = green = | g | +// | h | = = | h | +// | | = = | | +// | | | | +// | | | | +// | | Fairway | | +// | | | | +// | | ------ | +// | | -- -- | +// | | -- hazard --| +// | | -- -- | +// | | ------ | +// | | | | +// | | | | out +// | | | | of +// | | | | bounds +// | | | | +// | | | | +// | tee | +// +// +// Typical green size: 20-30 yards +// Typical golf course fairways are 35 to 45 yards wide +// Our fairway extends 5 yards past green +// Our rough is a 5 yard perimeter around fairway +// +// We calculate the new position of the ball given the ball's point, the distance +// of the stroke, and degrees off line (hook or slice). +// +// Degrees off (for a right handed golfer): +// Slice: positive degrees = ball goes right +// Hook: negative degrees = left goes left +// +// The cup is always at point: 0,0. +// We use atan2 to compute the angle between the cup and the ball. +// Setting the cup's vector to 0,-1 on a 360 circle is equivalent to: +// 0 deg = 12 o'clock; 90 deg = 3 o'clock; 180 deg = 6 o'clock; 270 = 9 o'clock +// The reverse angle between the cup and the ball is a difference of PI (using radians). +// +// Given the angle and stroke distance (hypotenuse), we use cosine to compute +// the opposite and adjacent sides of the triangle, which, is the ball's new position. +// +// 0 +// | +// 270 - cup - 90 +// | +// 180 +// +// +// cup +// | +// | +// | opp +// |-----* new position +// | / +// | / +// adj | / +// | / hyp +// |/ +// tee +// +// <- hook slice -> +// +// +// Given the large number of combinations needed to describe a particular stroke / ball location, +// we use the technique of "bitwise masking" to describe stroke results. +// With bit masking, multiple flags (bits) are combined into a single binary number that can be +// tested by applying a mask. A mask is another binary number that isolates a particular bit that +// you are interested in. You can then apply your language's bitwise opeartors to test or +// set a flag. +// +// Game design by Jason Bonthron, 2021 +// www.bonthron.com +// for my father, Raymond Bonthron, an avid golfer +// +// Inspired by the 1978 "Golf" from "Basic Computer Games" +// by Steve North, who modified an existing golf game by an unknown author +// +// + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Threading; + + +namespace Golf +{ + using Ball = Golf.CircleGameObj; + using Hazard = Golf.CircleGameObj; + + // --------------------------------------------------------------------------- Program + class Program + { + static void Main(string[] args) + { + Golf g = new Golf(); + } + } + + + // --------------------------------------------------------------------------- Golf + public class Golf + { + Ball BALL; + int HOLE_NUM = 0; + int STROKE_NUM = 0; + int Handicap = 0; + int PlayerDifficulty = 0; + HoleGeometry holeGeometry; + + // all fairways are 40 yards wide, extend 5 yards beyond the cup, and + // have 5 yards of rough around the perimeter + const int FairwayWidth = 40; + const int FairwayExtension = 5; + const int RoughAmt = 5; + + // ScoreCard records the ball position after each stroke + // a new list for each hole + // include a blank list so index 1 == hole 1 + + List> ScoreCard = new List> { new List() }; + + static void w(string s) { Console.WriteLine(s); } // WRITE + Random RANDOM = new Random(); + + + // --------------------------------------------------------------- constructor + public Golf() + { + Console.Clear(); + w(" "); + w(" 8\"\"\"\"8 8\"\"\"88 8 8\"\"\"\" "); + w(" 8 \" 8 8 8 8 "); + w(" 8e 8 8 8e 8eeee "); + w(" 88 ee 8 8 88 88 "); + w(" 88 8 8 8 88 88 "); + w(" 88eee8 8eeee8 88eee 88 "); + w(" "); + w("Welcome to the Creative Computing Country Club,"); + w("an eighteen hole championship layout located a short"); + w("distance from scenic downtown Lambertville, New Jersey."); + w("The game will be explained as you play."); + w("Enjoy your game! See you at the 19th hole..."); + w(" "); + w("Type QUIT at any time to leave the game."); + w("Type BAG at any time to review the clubs in your bag."); + w(" "); + + Wait((z) => + { + w(" "); + w(" YOUR BAG"); + ReviewBag(); + w("Type BAG at any time to review the clubs in your bag."); + w(" "); + + Wait((zz) => + { + w(" "); + + Ask("PGA handicaps range from 0 to 30.\nWhat is your handicap?", 0, 30, (i) => + { + Handicap = i; + w(" "); + + Ask("Common difficulties at golf include:\n1=Hook, 2=Slice, 3=Poor Distance, 4=Trap Shots, 5=Putting\nWhich one is your worst?", 1, 5, (j) => + { + PlayerDifficulty = j; + Console.Clear(); + NewHole(); + }); + }); + }); + }); + } + + + // --------------------------------------------------------------- NewHole + void NewHole() + { + HOLE_NUM++; + STROKE_NUM = 0; + + HoleInfo info = CourseInfo[HOLE_NUM]; + + int yards = info.Yards; // from tee to cup + int par = info.Par; + var cup = new CircleGameObj(0, 0, 0, GameObjType.CUP); + var green = new CircleGameObj(0, 0, 10, GameObjType.GREEN); + + var fairway = new RectGameObj(0 - (FairwayWidth / 2), + 0 - (green.Radius + FairwayExtension), + FairwayWidth, + yards + (green.Radius + FairwayExtension) + 1, + GameObjType.FAIRWAY); + + var rough = new RectGameObj(fairway.X - RoughAmt, + fairway.Y - RoughAmt, + fairway.Width + (2 * RoughAmt), + fairway.Length + (2 * RoughAmt), + GameObjType.ROUGH); + + BALL = new Ball(0, yards, 0, GameObjType.BALL); + + ScoreCardStartNewHole(); + + holeGeometry = new HoleGeometry(cup, green, fairway, rough, info.Hazard); + + w(" |> " + HOLE_NUM); + w(" | "); + w(" | "); + w(" ^^^^^^^^^^^^^^^"); + + Console.WriteLine("Hole #{0}. You are at the tee. Distance {1} yards, par {2}.", HOLE_NUM, info.Yards, info.Par); + w(info.Description); + + TeeUp(); + } + + + // --------------------------------------------------------------- TeeUp + // on the green? automatically select putter + // otherwise Ask club and swing strength + + void TeeUp() + { + if (IsOnGreen(BALL) && !IsInHazard(BALL, GameObjType.SAND)) + { + var putt = 10; + w("[PUTTER: average 10 yards]"); + var msg = Odds(20) ? "Keep your head down.\n" : ""; + + Ask(msg + "Choose your putt potency. (1-10)", 1, 10, (strength) => + { + var putter = Clubs[putt]; + Stroke(Convert.ToDouble((double)putter.Item2 * ((double)strength / 10.0)), putt); + }); + } + else + { + Ask("What club do you choose? (1-10)", 1, 10, (c) => + { + var club = Clubs[c]; + + w(" "); + Console.WriteLine("[{0}: average {1} yards]", club.Item1.ToUpper(), club.Item2); + + Ask("Now gauge your distance by a percentage of a full swing. (1-10)", 1, 10, (strength) => + { + Stroke(Convert.ToDouble((double)club.Item2 * ((double)strength / 10.0)), c); + }); + }); + }; + } + + + // -------------------------------------------------------- bitwise Flags + int dub = 0b00000000000001; + int hook = 0b00000000000010; + int slice = 0b00000000000100; + int passedCup = 0b00000000001000; + int inCup = 0b00000000010000; + int onFairway = 0b00000000100000; + int onGreen = 0b00000001000000; + int inRough = 0b00000010000000; + int inSand = 0b00000100000000; + int inTrees = 0b00001000000000; + int inWater = 0b00010000000000; + int outOfBounds = 0b00100000000000; + int luck = 0b01000000000000; + int ace = 0b10000000000000; + + + // --------------------------------------------------------------- Stroke + void Stroke(double clubAmt, int clubIndex) + { + STROKE_NUM++; + + var flags = 0b000000000000; + + // fore! only when driving + if ((STROKE_NUM == 1) && (clubAmt > 210) && Odds(30)) { w("\"...Fore !\""); }; + + // dub + if (Odds(5)) { flags |= dub; }; // there's always a 5% chance of dubbing it + + // if you're in the rough, or sand, you really should be using a wedge + if ((IsInRough(BALL) || IsInHazard(BALL, GameObjType.SAND)) && + !(clubIndex == 8 || clubIndex == 9)) + { + if (Odds(40)) { flags |= dub; }; + }; + + // trap difficulty + if (IsInHazard(BALL, GameObjType.SAND) && PlayerDifficulty == 4) + { + if (Odds(20)) { flags |= dub; }; + } + + // hook/slice + // There's 10% chance of a hook or slice + // if it's a known playerDifficulty then increase chance to 30% + // if it's a putt & putting is a playerDifficulty increase to 30% + + bool randHookSlice = (PlayerDifficulty == 1 || + PlayerDifficulty == 2 || + (PlayerDifficulty == 5 && IsOnGreen(BALL))) ? Odds(30) : Odds(10); + + if (randHookSlice) + { + if (PlayerDifficulty == 1) + { + if (Odds(80)) { flags |= hook; } else { flags |= slice; }; + } + else if (PlayerDifficulty == 2) + { + if (Odds(80)) { flags |= slice; } else { flags |= hook; }; + } + else + { + if (Odds(50)) { flags |= hook; } else { flags |= slice; }; + }; + }; + + // beginner's luck ! + // If handicap is greater than 15, there's a 10% chance of avoiding all errors + if ((Handicap > 15) && (Odds(10))) { flags |= luck; }; + + // ace + // there's a 10% chance of an Ace on a par 3 + if (CourseInfo[HOLE_NUM].Par == 3 && Odds(10) && STROKE_NUM == 1) { flags |= ace; }; + + // distance: + // If handicap is < 15, there a 50% chance of reaching club average, + // a 25% of exceeding it, and a 25% of falling short + // If handicap is > 15, there's a 25% chance of reaching club average, + // and 75% chance of falling short + // The greater the handicap, the more the ball falls short + // If poor distance is a known playerDifficulty, then reduce distance by 10% + + double distance; + int rnd = RANDOM.Next(1, 101); + + if (Handicap < 15) + { + if (rnd <= 25) + { + distance = clubAmt - (clubAmt * ((double)Handicap / 100.0)); + } + else if (rnd > 25 && rnd <= 75) + { + distance = clubAmt; + } + else + { + distance = clubAmt + (clubAmt * 0.10); + }; + } + else + { + if (rnd <= 75) + { + distance = clubAmt - (clubAmt * ((double)Handicap / 100.0)); + } + else + { + distance = clubAmt; + }; + }; + + if (PlayerDifficulty == 3) // poor distance + { + if (Odds(80)) { distance = (distance * 0.80); }; + }; + + if ((flags & luck) == luck) { distance = clubAmt; } + + // angle + // For all strokes, there's a possible "drift" of 4 degrees + // a hooks or slice increases the angle between 5-10 degrees, hook uses negative degrees + int angle = RANDOM.Next(0, 5); + if ((flags & slice) == slice) { angle = RANDOM.Next(5, 11); }; + if ((flags & hook) == hook) { angle = 0 - RANDOM.Next(5, 11); }; + if ((flags & luck) == luck) { angle = 0; }; + + var plot = PlotBall(BALL, distance, Convert.ToDouble(angle)); // calculate a new location + if ((flags & luck) == luck) { if(plot.Y > 0){ plot.Y = 2; }; }; + + flags = FindBall(new Ball(plot.X, plot.Y, plot.Offline, GameObjType.BALL), flags); + + InterpretResults(plot, flags); + } + + + // --------------------------------------------------------------- plotBall + Plot PlotBall(Ball ball, double strokeDistance, double degreesOff) + { + var cupVector = new Point(0, -1); + double radFromCup = Math.Atan2((double)ball.Y, (double)ball.X) - Math.Atan2((double)cupVector.Y, (double)cupVector.X); + double radFromBall = radFromCup - Math.PI; + + var hypotenuse = strokeDistance; + var adjacent = Math.Cos(radFromBall + ToRadians(degreesOff)) * hypotenuse; + var opposite = Math.Sqrt(Math.Pow(hypotenuse, 2) - Math.Pow(adjacent, 2)); + + Point newPos; + if (ToDegrees360(radFromBall + ToRadians(degreesOff)) > 180) + { + newPos = new Point(Convert.ToInt32(ball.X - opposite), + Convert.ToInt32(ball.Y - adjacent)); + } + else + { + newPos = new Point(Convert.ToInt32(ball.X + opposite), + Convert.ToInt32(ball.Y - adjacent)); + } + + return new Plot(newPos.X, newPos.Y, Convert.ToInt32(opposite)); + } + + + // --------------------------------------------------------------- InterpretResults + void InterpretResults(Plot plot, int flags) + { + int cupDistance = Convert.ToInt32(GetDistance(new Point(plot.X, plot.Y), + new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y))); + int travelDistance = Convert.ToInt32(GetDistance(new Point(plot.X, plot.Y), + new Point(BALL.X, BALL.Y))); + + w(" "); + + if ((flags & ace) == ace) + { + w("Hole in One! You aced it."); + ScoreCardRecordStroke(new Ball(0, 0, 0, GameObjType.BALL)); + ReportCurrentScore(); + return; + }; + + if ((flags & inTrees) == inTrees) + { + w("Your ball is lost in the trees. Take a penalty stroke."); + ScoreCardRecordStroke(BALL); + TeeUp(); + return; + }; + + if ((flags & inWater) == inWater) + { + var msg = Odds(50) ? "Your ball has gone to a watery grave." : "Your ball is lost in the water."; + w(msg + " Take a penalty stroke."); + ScoreCardRecordStroke(BALL); + TeeUp(); + return; + }; + + if ((flags & outOfBounds) == outOfBounds) + { + w("Out of bounds. Take a penalty stroke."); + ScoreCardRecordStroke(BALL); + TeeUp(); + return; + }; + + if ((flags & dub) == dub) + { + w("You dubbed it."); + ScoreCardRecordStroke(BALL); + TeeUp(); + return; + }; + + if ((flags & inCup) == inCup) + { + var msg = Odds(50) ? "You holed it." : "It's in!"; + w(msg); + ScoreCardRecordStroke(new Ball(plot.X, plot.Y, 0, GameObjType.BALL)); + ReportCurrentScore(); + return; + }; + + if (((flags & slice) == slice) && + !((flags & onGreen) == onGreen)) + { + var bad = ((flags & outOfBounds) == outOfBounds) ? " badly" : ""; + Console.WriteLine("You sliced{0}: {1} yards offline.", bad, plot.Offline); + }; + + if (((flags & hook) == hook) && + !((flags & onGreen) == onGreen)) + { + var bad = ((flags & outOfBounds) == outOfBounds) ? " badly" : ""; + Console.WriteLine("You hooked{0}: {1} yards offline.", bad, plot.Offline); + }; + + if (STROKE_NUM > 1) + { + var prevBall = ScoreCardGetPreviousStroke(); + var d1 = GetDistance(new Point(prevBall.X, prevBall.Y), + new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y)); + var d2 = cupDistance; + if (d2 > d1) { w("Too much club."); }; + }; + + if ((flags & inRough) == inRough) { w("You're in the rough."); }; + + if ((flags & inSand) == inSand) { w("You're in a sand trap."); }; + + if ((flags & onGreen) == onGreen) + { + var pd = (cupDistance < 4) ? ((cupDistance * 3) + " feet") : (cupDistance + " yards"); + Console.WriteLine("You're on the green. It's {0} from the pin.", pd); + }; + + if (((flags & onFairway) == onFairway) || + ((flags & inRough) == inRough)) + { + Console.WriteLine("Shot went {0} yards. It's {1} yards from the cup.", travelDistance, cupDistance); + }; + + ScoreCardRecordStroke(new Ball(plot.X, plot.Y, 0, GameObjType.BALL)); + + BALL = new Ball(plot.X, plot.Y, 0, GameObjType.BALL); + + TeeUp(); + } + + + // --------------------------------------------------------------- ReportCurrentScore + void ReportCurrentScore() + { + var par = CourseInfo[HOLE_NUM].Par; + if (ScoreCard[HOLE_NUM].Count == par + 1) { w("A bogey. One above par."); }; + if (ScoreCard[HOLE_NUM].Count == par) { w("Par. Nice."); }; + if (ScoreCard[HOLE_NUM].Count == (par - 1)) { w("A birdie! One below par."); }; + if (ScoreCard[HOLE_NUM].Count == (par - 2)) { w("An Eagle! Two below par."); }; + if (ScoreCard[HOLE_NUM].Count == (par - 3)) { w("Double Eagle! Unbelievable."); }; + + int totalPar = 0; + for (var i = 1; i <= HOLE_NUM; i++) { totalPar += CourseInfo[i].Par; }; + + w(" "); + w("-----------------------------------------------------"); + Console.WriteLine(" Total par for {0} hole{1} is: {2}. Your total is: {3}.", + HOLE_NUM, + ((HOLE_NUM > 1) ? "s" : ""), //plural + totalPar, + ScoreCardGetTotal()); + w("-----------------------------------------------------"); + w(" "); + + if (HOLE_NUM == 18) + { + GameOver(); + } + else + { + Thread.Sleep(2000); + NewHole(); + }; + } + + + // --------------------------------------------------------------- FindBall + int FindBall(Ball ball, int flags) + { + if (IsOnFairway(ball) && !IsOnGreen(ball)) { flags |= onFairway; } + if (IsOnGreen(ball)) { flags |= onGreen; } + if (IsInRough(ball)) { flags |= inRough; } + if (IsOutOfBounds(ball)) { flags |= outOfBounds; } + if (IsInHazard(ball, GameObjType.WATER)) { flags |= inWater; } + if (IsInHazard(ball, GameObjType.TREES)) { flags |= inTrees; } + if (IsInHazard(ball, GameObjType.SAND)) { flags |= inSand; } + + if (ball.Y < 0) { flags |= passedCup; } + + // less than 2, it's in the cup + var d = GetDistance(new Point(ball.X, ball.Y), + new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y)); + if (d < 2) { flags |= inCup; }; + + return flags; + } + + + // --------------------------------------------------------------- IsOnFairway + bool IsOnFairway(Ball ball) + { + return IsInRectangle(ball, holeGeometry.Fairway); + } + + + // --------------------------------------------------------------- IsOngreen + bool IsOnGreen(Ball ball) + { + var d = GetDistance(new Point(ball.X, ball.Y), + new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y)); + return d < holeGeometry.Green.Radius; + } + + + // --------------------------------------------------------------- IsInHazard + bool IsInHazard(Ball ball, GameObjType hazard) + { + bool result = false; + Array.ForEach(holeGeometry.Hazards, (Hazard h) => + { + var d = GetDistance(new Point(ball.X, ball.Y), new Point(h.X, h.Y)); + if ((d < h.Radius) && h.Type == hazard) { result = true; }; + }); + return result; + } + + + // --------------------------------------------------------------- IsInRough + bool IsInRough(Ball ball) + { + return IsInRectangle(ball, holeGeometry.Rough) && + (IsInRectangle(ball, holeGeometry.Fairway) == false); + } + + + // --------------------------------------------------------------- IsOutOfBounds + bool IsOutOfBounds(Ball ball) + { + return (IsOnFairway(ball) == false) && (IsInRough(ball) == false); + } + + + // --------------------------------------------------------------- ScoreCardNewHole + void ScoreCardStartNewHole() + { + ScoreCard.Add(new List()); + } + + + // --------------------------------------------------------------- ScoreCardRecordStroke + void ScoreCardRecordStroke(Ball ball) + { + var clone = new Ball(ball.X, ball.Y, 0, GameObjType.BALL); + ScoreCard[HOLE_NUM].Add(clone); + } + + + // ------------------------------------------------------------ ScoreCardGetPreviousStroke + Ball ScoreCardGetPreviousStroke() + { + return ScoreCard[HOLE_NUM][ScoreCard[HOLE_NUM].Count - 1]; + } + + + // --------------------------------------------------------------- ScoreCardGetTotal + int ScoreCardGetTotal() + { + int total = 0; + ScoreCard.ForEach((h) => { total += h.Count; }); + return total; + } + + + // --------------------------------------------------------------- Ask + // input from console is always an integer passed to a callback + // or "quit" to end game + + void Ask(string question, int min, int max, Action callback) + { + w(question); + string i = Console.ReadLine().Trim().ToLower(); + if (i == "quit") { Quit(); return; }; + if (i == "bag") { ReviewBag(); }; + + int n; + bool success = Int32.TryParse(i, out n); + + if (success) + { + if (n >= min && n <= max) + { + callback(n); + } + else + { + Ask(question, min, max, callback); + } + } + else + { + Ask(question, min, max, callback); + }; + } + + + // --------------------------------------------------------------- Wait + void Wait(Action callback) + { + w("Press any key to continue."); + + ConsoleKeyInfo keyinfo; + do { keyinfo = Console.ReadKey(true); } + while (keyinfo.KeyChar < 0); + Console.Clear(); + callback(0); + } + + + // --------------------------------------------------------------- ReviewBag + void ReviewBag() + { + w(" "); + w(" # Club Average Yardage"); + w("-----------------------------------"); + w(" 1 Driver 250"); + w(" 2 3 Wood 225"); + w(" 3 5 Wood 200"); + w(" 4 Hybrid 190"); + w(" 5 4 Iron 170"); + w(" 6 7 Iron 150"); + w(" 7 9 Iron 125"); + w(" 8 Pitching wedge 110"); + w(" 9 Sand wedge 75"); + w(" 10 Putter 10"); + w(" "); + } + + + // --------------------------------------------------------------- Quit + void Quit() + { + w(""); + w("Looks like rain. Goodbye!"); + w(""); + Wait((z) => { }); + return; + } + + + // --------------------------------------------------------------- GameOver + void GameOver() + { + var net = ScoreCardGetTotal() - Handicap; + w("Good game!"); + w("Your net score is: " + net); + w("Let's visit the pro shop..."); + w(" "); + Wait((z) => { }); + return; + } + + + // YOUR BAG + // ======================================================== Clubs + (string, int)[] Clubs = new (string, int)[] { + ("",0), + + // name, average yardage + ("Driver", 250), + ("3 Wood", 225), + ("5 Wood", 200), + ("Hybrid", 190), + ("4 Iron", 170), + ("7 Iron", 150), + ("9 Iron", 125), + ("Pitching wedge", 110), + ("Sand wedge", 75), + ("Putter", 10) + }; + + + // THE COURSE + // ======================================================== CourseInfo + + HoleInfo[] CourseInfo = new HoleInfo[]{ + new HoleInfo(0, 0, 0, new Hazard[]{}, ""), // include a blank so index 1 == hole 1 + + + // -------------------------------------------------------- front 9 + // hole, yards, par, hazards, (description) + + new HoleInfo(1, 361, 4, + new Hazard[]{ + new Hazard( 20, 100, 10, GameObjType.TREES), + new Hazard(-20, 80, 10, GameObjType.TREES), + new Hazard(-20, 100, 10, GameObjType.TREES) + }, + "There are a couple of trees on the left and right."), + + new HoleInfo(2, 389, 4, + new Hazard[]{ + new Hazard(0, 160, 20, GameObjType.WATER) + }, + "There is a large water hazard across the fairway about 150 yards."), + + new HoleInfo(3, 206, 3, + new Hazard[]{ + new Hazard( 20, 20, 5, GameObjType.WATER), + new Hazard(-20, 160, 10, GameObjType.WATER), + new Hazard( 10, 12, 5, GameObjType.SAND) + }, + "There is some sand and water near the green."), + + new HoleInfo(4, 500, 5, + new Hazard[]{ + new Hazard(-14, 12, 12, GameObjType.SAND) + }, + "There's a bunker to the left of the green."), + + new HoleInfo(5, 408, 4, + new Hazard[]{ + new Hazard(20, 120, 20, GameObjType.TREES), + new Hazard(20, 160, 20, GameObjType.TREES), + new Hazard(10, 20, 5, GameObjType.SAND) + }, + "There are some trees to your right."), + + new HoleInfo(6, 359, 4, + new Hazard[]{ + new Hazard( 14, 0, 4, GameObjType.SAND), + new Hazard(-14, 0, 4, GameObjType.SAND) + }, + ""), + + new HoleInfo(7, 424, 5, + new Hazard[]{ + new Hazard(20, 200, 10, GameObjType.SAND), + new Hazard(10, 180, 10, GameObjType.SAND), + new Hazard(20, 160, 10, GameObjType.SAND) + }, + "There are several sand traps along your right."), + + new HoleInfo(8, 388, 4, + new Hazard[]{ + new Hazard(-20, 340, 10, GameObjType.TREES) + }, + ""), + + new HoleInfo(9, 196, 3, + new Hazard[]{ + new Hazard(-30, 180, 20, GameObjType.TREES), + new Hazard( 14, -8, 5, GameObjType.SAND) + }, + ""), + + // -------------------------------------------------------- back 9 + // hole, yards, par, hazards, (description) + + new HoleInfo(10, 400, 4, + new Hazard[]{ + new Hazard(-14, -8, 5, GameObjType.SAND), + new Hazard( 14, -8, 5, GameObjType.SAND) + }, + ""), + + new HoleInfo(11, 560, 5, + new Hazard[]{ + new Hazard(-20, 400, 10, GameObjType.TREES), + new Hazard(-10, 380, 10, GameObjType.TREES), + new Hazard(-20, 260, 10, GameObjType.TREES), + new Hazard(-20, 200, 10, GameObjType.TREES), + new Hazard(-10, 180, 10, GameObjType.TREES), + new Hazard(-20, 160, 10, GameObjType.TREES) + }, + "Lots of trees along the left of the fairway."), + + new HoleInfo(12, 132, 3, + new Hazard[]{ + new Hazard(-10, 120, 10, GameObjType.WATER), + new Hazard( -5, 100, 10, GameObjType.SAND) + }, + "There is water and sand directly in front of you. A good drive should clear both."), + + new HoleInfo(13, 357, 4, + new Hazard[]{ + new Hazard(-20, 200, 10, GameObjType.TREES), + new Hazard(-10, 180, 10, GameObjType.TREES), + new Hazard(-20, 160, 10, GameObjType.TREES), + new Hazard( 14, 12, 8, GameObjType.SAND) + }, + ""), + + new HoleInfo(14, 294, 4, + new Hazard[]{ + new Hazard(0, 20, 10, GameObjType.SAND) + }, + ""), + + new HoleInfo(15, 475, 5, + new Hazard[]{ + new Hazard(-20, 20, 10, GameObjType.WATER), + new Hazard( 10, 20, 10, GameObjType.SAND) + }, + "Some sand and water near the green."), + + new HoleInfo(16, 375, 4, + new Hazard[]{ + new Hazard(-14, -8, 5, GameObjType.SAND) + }, + ""), + + new HoleInfo(17, 180, 3, + new Hazard[]{ + new Hazard( 20, 100, 10, GameObjType.TREES), + new Hazard(-20, 80, 10, GameObjType.TREES) + }, + ""), + + new HoleInfo(18, 550, 5, + new Hazard[]{ + new Hazard(20, 30, 15, GameObjType.WATER) + }, + "There is a water hazard near the green.") + }; + + + // -------------------------------------------------------- HoleInfo + class HoleInfo + { + public int Hole { get; } + public int Yards { get; } + public int Par { get; } + public Hazard[] Hazard { get; } + public string Description { get; } + + public HoleInfo(int hole, int yards, int par, Hazard[] hazard, string description) + { + Hole = hole; + Yards = yards; + Par = par; + Hazard = hazard; + Description = description; + } + } + + + public enum GameObjType { BALL, CUP, GREEN, FAIRWAY, ROUGH, TREES, WATER, SAND } + + + // -------------------------------------------------------- CircleGameObj + public class CircleGameObj + { + public GameObjType Type { get; } + public int X { get; } + public int Y { get; } + public int Radius { get; } + + public CircleGameObj(int x, int y, int r, GameObjType type) + { + Type = type; + X = x; + Y = y; + Radius = r; + } + } + + + // -------------------------------------------------------- RectGameObj + public class RectGameObj + { + public GameObjType Type { get; } + public int X { get; } + public int Y { get; } + public int Width { get; } + public int Length { get; } + + public RectGameObj(int x, int y, int w, int l, GameObjType type) + { + Type = type; + X = x; + Y = y; + Width = w; + Length = l; + } + } + + + // -------------------------------------------------------- HoleGeometry + public class HoleGeometry + { + public CircleGameObj Cup { get; } + public CircleGameObj Green { get; } + public RectGameObj Fairway { get; } + public RectGameObj Rough { get; } + public Hazard[] Hazards { get; } + + public HoleGeometry(CircleGameObj cup, CircleGameObj green, RectGameObj fairway, RectGameObj rough, Hazard[] haz) + { + Cup = cup; + Green = green; + Fairway = fairway; + Rough = rough; + Hazards = haz; + } + } + + + // -------------------------------------------------------- Plot + public class Plot + { + public int X { get; } + public int Y { get; set; } + public int Offline { get; } + + public Plot(int x, int y, int offline) + { + X = x; + Y = y; + Offline = offline; + } + } + + + // -------------------------------------------------------- GetDistance + // distance between 2 points + double GetDistance(Point pt1, Point pt2) + { + return Math.Sqrt(Math.Pow((pt2.X - pt1.X), 2) + Math.Pow((pt2.Y - pt1.Y), 2)); + } + + + // -------------------------------------------------------- IsInRectangle + bool IsInRectangle(CircleGameObj pt, RectGameObj rect) + { + return ((pt.X > rect.X) && + (pt.X < rect.X + rect.Width) && + (pt.Y > rect.Y) && + (pt.Y < rect.Y + rect.Length)); + } + + + // -------------------------------------------------------- ToRadians + double ToRadians(double angle) { return angle * (Math.PI / 180.0); } + + + // -------------------------------------------------------- ToDegrees360 + // radians to 360 degrees + double ToDegrees360(double angle) + { + double deg = angle * (180.0 / Math.PI); + if (deg < 0.0) { deg += 360.0; } + return deg; + } + + + // -------------------------------------------------------- Odds + // chance an integer is <= the given argument + // between 1-100 + Random RND = new Random(); + + bool Odds(int x) + { + return RND.Next(1, 101) <= x; + } + } +} diff --git a/39 Golf/csharp/README.md b/39 Golf/csharp/README.md index 4daabb5c..126658a1 100644 --- a/39 Golf/csharp/README.md +++ b/39 Golf/csharp/README.md @@ -1,3 +1,15 @@ 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/) + +There are 2 compiled executables in the compiled/ directory (windows and linux) that you can play right away! + +Program.cs contains the C# source code. +It has been written for .NET Core 3.1 + +The source code is well documented. + + + + + diff --git a/40 Gomoko/java/Gomoko.java b/40 Gomoko/java/Gomoko.java new file mode 100644 index 00000000..64ad7c74 --- /dev/null +++ b/40 Gomoko/java/Gomoko.java @@ -0,0 +1,211 @@ +import java.util.Arrays; +import java.util.InputMismatchException; +import java.util.Scanner; + +/** + * GOMOKO + *

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + */ +public class Gomoko { + + private static final int MIN_BOARD_SIZE = 7; + private static final int MAX_BOARD_SIZE = 19; + + public static void main(String[] args) { + printIntro(); + Scanner scan = new Scanner(System.in); + int boardSize = readBoardSize(scan); + + boolean continuePlay = true; + while (continuePlay) { + int[][] board = new int[boardSize][boardSize]; + //initialize the board elements to 0 + for (int[] ints : board) { + Arrays.fill(ints, 0); + } + + System.out.println("\n\nWE ALTERNATE MOVES. YOU GO FIRST..."); + + boolean doneRound = false; + while (!doneRound) { + Move playerMove = null; + boolean validMove = false; + while (!validMove) { + playerMove = readMove(scan); + if (playerMove.i == -1 || playerMove.j == -1) { + doneRound = true; + System.out.println("\nTHANKS FOR THE GAME!!"); + System.out.print("PLAY AGAIN (1 FOR YES, 0 FOR NO)? "); + final int playAgain = scan.nextInt(); + scan.nextLine(); + if (playAgain == 1) { + continuePlay = true; + break; + } else { + continuePlay = false; + break; + } + } else if (!isLegalMove(playerMove, boardSize)) { + System.out.println("ILLEGAL MOVE. TRY AGAIN..."); + } else if (board[playerMove.i - 1][playerMove.j - 1] != 0) { + System.out.println("SQUARE OCCUPIED. TRY AGAIN..."); + } else { + validMove = true; + } + } + + if (!doneRound) { + board[playerMove.i - 1][playerMove.j - 1] = 1; + Move computerMove = getComputerMove(playerMove, board, boardSize); + if (computerMove == null) { + computerMove = getRandomMove(board, boardSize); + } + board[computerMove.i - 1][computerMove.j - 1] = 2; + + printBoard(board); + } + } + + } + } + + //*** COMPUTER TRIES AN INTELLIGENT MOVE *** + private static Move getComputerMove(Move playerMove, int[][] board, int boardSize) { + for (int e = -1; e <= 1; e++) { + for (int f = -1; f <= 1; f++) { + if ((e + f - e * f) != 0) { + var x = playerMove.i + f; + var y = playerMove.j + f; + final Move newMove = new Move(x, y); + if (isLegalMove(newMove, boardSize)) { + if (board[newMove.i - 1][newMove.j - 1] != 0) { + newMove.i = newMove.i - e; + newMove.i = newMove.j - f; + if (!isLegalMove(newMove, boardSize)) { + return null; + } else { + if (board[newMove.i - 1][newMove.j - 1] == 0) { + return newMove; + } + } + } + } + } + } + } + return null; + } + + private static void printBoard(int[][] board) { + for (int[] ints : board) { + for (int cell : ints) { + System.out.printf(" %s", cell); + } + System.out.println(); + } + } + + //*** COMPUTER TRIES A RANDOM MOVE *** + private static Move getRandomMove(int[][] board, int boardSize) { + boolean legalMove = false; + Move randomMove = null; + while (!legalMove) { + randomMove = randomMove(boardSize); + legalMove = isLegalMove(randomMove, boardSize) && board[randomMove.i - 1][randomMove.j - 1] == 0; + + } + return randomMove; + } + + private static Move randomMove(int boardSize) { + int x = (int) (boardSize * Math.random() + 1); + int y = (int) (boardSize * Math.random() + 1); + return new Move(x, y); + } + + private static boolean isLegalMove(Move move, int boardSize) { + return (move.i >= 1) && (move.i <= boardSize) && (move.j >= 1) && (move.j <= boardSize); + } + + private static void printIntro() { + System.out.println(" GOMOKO"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + System.out.println("WELCOME TO THE ORIENTAL GAME OF GOMOKO."); + System.out.println("\n"); + System.out.println("THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE"); + System.out.println("THAT YOU SPECIFY. DURING YOUR PLAY, YOU MAY COVER ONE GRID"); + System.out.println("INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET"); + System.out.println("5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR"); + System.out.println("DIAGONALLY. ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED"); + System.out.println("WITH A '1' AND THE COMPUTER MOVES WITH A '2'."); + System.out.println("\nTHE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON."); + System.out.println("TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\n "); + } + + private static int readBoardSize(Scanner scan) { + System.out.print("WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)? "); + + boolean validInput = false; + int input = 0; + while (!validInput) { + try { + input = scan.nextInt(); + if (input < MIN_BOARD_SIZE || input > MAX_BOARD_SIZE) { + System.out.printf("I SAID, THE MINIMUM IS %s, THE MAXIMUM IS %s.\n", MIN_BOARD_SIZE, MAX_BOARD_SIZE); + } else { + validInput = true; + } + } catch (InputMismatchException ex) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE\n"); + validInput = false; + } finally { + scan.nextLine(); + } + } + return input; + } + + private static Move readMove(Scanner scan) { + System.out.print("YOUR PLAY (I,J)? "); + boolean validInput = false; + Move move = new Move(); + while (!validInput) { + String input = scan.nextLine(); + final String[] split = input.split(","); + try { + move.i = Integer.parseInt(split[0]); + move.j = Integer.parseInt(split[1]); + validInput = true; + } catch (NumberFormatException nfe) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE\n? "); + } + + } + return move; + } + + private static class Move { + int i; + int j; + + public Move() { + } + + public Move(int i, int j) { + this.i = i; + this.j = j; + } + + @Override + public String toString() { + return "Move{" + + "i=" + i + + ", j=" + j + + '}'; + } + } + +} + diff --git a/43 Hammurabi/README.md b/43 Hammurabi/README.md index 1e5db404..22378ac0 100644 --- a/43 Hammurabi/README.md +++ b/43 Hammurabi/README.md @@ -5,3 +5,7 @@ https://www.atariarchives.org/basicgames/showpage.php?page=78 Downloaded from Vintage Basic at http://www.vintage-basic.net/games.html + +[Port to C language](https://github.com/beyonddream/hamurabi) + +[Port to Rust language](https://github.com/beyonddream/hamurabi.rs) diff --git a/43 Hammurabi/csharp/src/Controller.cs b/43 Hammurabi/csharp/src/Controller.cs index 91d1b64f..afdb83d2 100644 --- a/43 Hammurabi/csharp/src/Controller.cs +++ b/43 Hammurabi/csharp/src/Controller.cs @@ -23,7 +23,7 @@ namespace Hammurabi /// /// The updated game state. /// - public static GameState TryUntilSuccess( + public static GameState UpdateGameState( GameState state, Action prompt, Func rule) @@ -35,29 +35,28 @@ namespace Hammurabi if (!Int32.TryParse(Console.ReadLine(), out var amount)) { View.ShowInvalidNumber(); + continue; } - else - { - var (newState, result) = rule(state, amount); - switch (result) - { - case ActionResult.InsufficientLand: - View.ShowInsufficientLand(state); - break; - case ActionResult.InsufficientPopulation: - View.ShowInsufficientPopulation(state); - break; - case ActionResult.InsufficientStores: - View.ShowInsufficientStores(state); - break; - case ActionResult.Offense: - // Not sure why we have to blow up the game here... - // Maybe this made sense in the 70's. - throw new GreatOffence(); - default: - return newState; - } + var (newState, result) = rule(state, amount); + + switch (result) + { + case ActionResult.InsufficientLand: + View.ShowInsufficientLand(state); + break; + case ActionResult.InsufficientPopulation: + View.ShowInsufficientPopulation(state); + break; + case ActionResult.InsufficientStores: + View.ShowInsufficientStores(state); + break; + case ActionResult.Offense: + // Not sure why we have to blow up the game here... + // Maybe this made sense in the 70's. + throw new GreatOffence(); + default: + return newState; } } } diff --git a/43 Hammurabi/csharp/src/GameResult.cs b/43 Hammurabi/csharp/src/GameResult.cs index 23dfbe28..9c143375 100644 --- a/43 Hammurabi/csharp/src/GameResult.cs +++ b/43 Hammurabi/csharp/src/GameResult.cs @@ -40,6 +40,6 @@ /// Gets a flag indicating whether the player was impeached for /// starving too many people. /// - public bool WasImpeached { get; init; } + public bool WasPlayerImpeached { get; init; } } } diff --git a/43 Hammurabi/csharp/src/GameState.cs b/43 Hammurabi/csharp/src/GameState.cs index 3e2d1eb2..41e6fe11 100644 --- a/43 Hammurabi/csharp/src/GameState.cs +++ b/43 Hammurabi/csharp/src/GameState.cs @@ -68,6 +68,6 @@ ///

/// Gets a flag indicating whether the player has been impeached. /// - public bool IsImpeached { get; init; } + public bool IsPlayerImpeached { get; init; } } } diff --git a/43 Hammurabi/csharp/src/Program.cs b/43 Hammurabi/csharp/src/Program.cs index 45d5b101..8f158839 100644 --- a/43 Hammurabi/csharp/src/Program.cs +++ b/43 Hammurabi/csharp/src/Program.cs @@ -9,7 +9,7 @@ namespace Hammurabi public static void Main(string[] args) { - var random = new Random ((int) (DateTime.UtcNow.Ticks / 10000)) ; + var random = new Random() ; var state = Rules.BeginGame(); var history = ImmutableList.Empty; @@ -17,21 +17,24 @@ namespace Hammurabi try { - while (state.Year <= GameLength && !state.IsImpeached) + while (!state.IsPlayerImpeached) { state = Rules.BeginTurn(state, random); View.ShowCitySummary(state); + if (state.Year > GameLength) + break; + View.ShowLandPrice(state); - var newState = Controller.TryUntilSuccess(state, View.PromptBuyLand, Rules.BuyLand); + var newState = Controller.UpdateGameState(state, View.PromptBuyLand, Rules.BuyLand); state = newState.Acres != state.Acres ? - newState : Controller.TryUntilSuccess(state, View.PromptSellLand, Rules.SellLand); + newState : Controller.UpdateGameState(state, View.PromptSellLand, Rules.SellLand); View.ShowSeparator(); - state = Controller.TryUntilSuccess(state, View.PromptFeedPeople, Rules.FeedPeople); + state = Controller.UpdateGameState(state, View.PromptFeedPeople, Rules.FeedPeople); View.ShowSeparator(); - state = Controller.TryUntilSuccess(state, View.PromptPlantCrops, Rules.PlantCrops); + state = Controller.UpdateGameState(state, View.PromptPlantCrops, Rules.PlantCrops); state = Rules.EndTurn(state, random); history = history.Add(state); diff --git a/43 Hammurabi/csharp/src/Rules.cs b/43 Hammurabi/csharp/src/Rules.cs index 56a59d96..36fc9c50 100644 --- a/43 Hammurabi/csharp/src/Rules.cs +++ b/43 Hammurabi/csharp/src/Rules.cs @@ -12,7 +12,7 @@ namespace Hammurabi public static GameState BeginGame() => new GameState { - Year = 1, + Year = 0, Population = 95, PopulationIncrease = 5, Starvation = 0, @@ -22,7 +22,7 @@ namespace Hammurabi Productivity = 3, Spoilage = 200, IsPlagueYear = false, - IsImpeached = false + IsPlayerImpeached = false }; /// @@ -31,6 +31,7 @@ namespace Hammurabi public static GameState BeginTurn(GameState state, Random random) => state with { + Year = state.Year + 1, Population = (state.Population + state.PopulationIncrease - state.Starvation) / (state.IsPlagueYear ? 2 : 1), LandPrice = random.Next(10) + 17, Stores = state.Stores + (state.AcresPlanted * state.Productivity) - state.Spoilage, @@ -139,23 +140,22 @@ namespace Hammurabi _ => 0 }; - var populationIncrease= (int)((double) random.Next(1, 6) * (20 * state.Acres + state.Stores + harvest - spoilage) / state.Population / 100 + 1); + var populationIncrease= (int)((double)random.Next(1, 6) * (20 * state.Acres + state.Stores + harvest - spoilage) / state.Population / 100 + 1); var plagueYear = random.Next(20) < 3; - var peopleFed = state.FoodDistributed / 20; + var peopleFed = state.FoodDistributed / 20; var starvation = peopleFed < state.Population ? state.Population - peopleFed : 0; var impeached = starvation > state.Population * 0.45; return state with { - Year = state.Year + 1, Productivity = productivity, Spoilage = spoilage, PopulationIncrease = populationIncrease, Starvation = starvation, IsPlagueYear = plagueYear, - IsImpeached = impeached + IsPlayerImpeached = impeached }; } @@ -176,7 +176,7 @@ namespace Hammurabi var acresPerPerson = finalState.Acres / finalState.Population; - var rating = finalState.IsImpeached ? + var rating = finalState.IsPlayerImpeached ? PerformanceRating.Disgraceful : (averageStarvationRate, acresPerPerson) switch { @@ -200,7 +200,7 @@ namespace Hammurabi TotalStarvation = totalStarvation, AverageStarvationRate = averageStarvationRate, Assassins = assassins, - WasImpeached = finalState.IsImpeached + WasPlayerImpeached = finalState.IsPlayerImpeached }; } } diff --git a/43 Hammurabi/csharp/src/View.cs b/43 Hammurabi/csharp/src/View.cs index be10af32..fcfb4cd5 100644 --- a/43 Hammurabi/csharp/src/View.cs +++ b/43 Hammurabi/csharp/src/View.cs @@ -110,7 +110,7 @@ namespace Hammurabi /// public static void ShowGameResult(GameResult result) { - if (!result.WasImpeached) + if (!result.WasPlayerImpeached) { Console.WriteLine($"IN YOUR 10-YEAR TERM OF OFFICE, {result.AverageStarvationRate} PERCENT OF THE"); Console.WriteLine("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF"); @@ -124,7 +124,7 @@ namespace Hammurabi switch (result.Rating) { case PerformanceRating.Disgraceful: - if (result.WasImpeached) + if (result.WasPlayerImpeached) Console.WriteLine($"YOU STARVED {result.FinalStarvation} PEOPLE IN ONE YEAR!!!"); Console.WriteLine("DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY"); @@ -163,7 +163,7 @@ namespace Hammurabi /// public static void PromptBuyLand() { - Console.WriteLine ("HOW MANY ACRES DO YOU WISH TO BUY"); + Console.Write("HOW MANY ACRES DO YOU WISH TO BUY? "); } /// @@ -171,7 +171,7 @@ namespace Hammurabi /// public static void PromptSellLand() { - Console.WriteLine("HOW MANY ACRES DO YOU WISH TO SELL"); + Console.Write("HOW MANY ACRES DO YOU WISH TO SELL? "); } /// @@ -179,7 +179,7 @@ namespace Hammurabi /// public static void PromptFeedPeople() { - Console.WriteLine("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE"); + Console.Write("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? "); } /// @@ -187,7 +187,7 @@ namespace Hammurabi /// public static void PromptPlantCrops() { - Console.WriteLine("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED"); + Console.Write("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? "); } } } diff --git a/57 Literature Quiz/perl/litquiz.pl b/57 Literature Quiz/perl/litquiz.pl new file mode 100644 index 00000000..f7d41075 --- /dev/null +++ b/57 Literature Quiz/perl/litquiz.pl @@ -0,0 +1,82 @@ +#!/usr/bin/perl +use strict; + + +print ' 'x 25 . "LITERATURE QUIZ\n"; +print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n"; print "\n"; print "\n"; +print "TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\n"; +print "\n"; print "THIS IS A MULTIPLE-CHOICE QUIZ.\n"; +print "TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\n"; +print "\n"; print "GOOD LUCK!\n"; +my $R=0; + + +print "\n"; print "\n"; +print "IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT\n"; +print "1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO"; +print "? "; chomp(my $A = ); + +if ($A eq 3) { + $R++; + print "VERY GOOD! HERE'S ANOTHER.\n"; + } else { + print "SORRY...FIGARO WAS HIS NAME.\n"; + } + + +print "\n"; print "\n"; +print "FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\n"; +print "1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S"; +print "? "; chomp($A = ); + +if ($A eq 2) { + print "PRETTY GOOD!\n"; + $R=$R+1; + } else { + print "TOO BAD...IT WAS ELMER FUDD'S GARDEN.\n"; + } + + +print "\n"; print "\n"; +print "IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED\n"; +print "1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO"; +print "? "; chomp($A = ); +if ($A eq 4) { + print "YEA! YOU'RE A REAL LITERATURE GIANT.\n"; + $R=$R+1; + } else { + print "BACK TO THE BOOKS,...TOTO WAS HIS NAME.\n"; + } + + +print "\n"; print "\n"; +print "WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE\n"; +print "1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY"; +print "? "; chomp($A = ); +if ($A eq 3) { + print "GOOD MEMORY!\n"; + $R=$R+1; + } else { + print "OH, COME ON NOW...IT WAS SNOW WHITE.\n"; + } + + +print "\n"; print "\n"; +if ($R eq 4) { + print "WOW! THAT'S SUPER! YOU REALLY KNOW YOUR NURSERY\n"; + print "YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\n"; + print "LITERATURE (HA, HA, HA)\n"; + exit + } +if ($R<2) { + print "UGH. THAT WAS DEFINITELY NOT TOO SWIFT. BACK TO\n"; + print "NURSERY SCHOOL FOR YOU, MY FRIEND.\n"; + exit; + } + +print "NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\n"; +print "READING THE NURSERY GREATS.\n"; +exit; + + diff --git a/86 Target/java/Target.java b/86 Target/java/Target.java new file mode 100644 index 00000000..869c443a --- /dev/null +++ b/86 Target/java/Target.java @@ -0,0 +1,146 @@ +import java.util.Scanner; + +/** + * TARGET + *

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + */ +public class Target { + + private static final double RADIAN = 180 / Math.PI; + + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + + printIntro(); + + //continue till the user aborts + while (true) { + int numberShots = 0; + + final double xAxisInRadians = Math.random() * 2 * Math.PI; + final double yAxisInRadians = Math.random() * 2 * Math.PI; + System.out.printf("RADIANS FROM X AXIS = %.7f FROM Z AXIS = %.7f\n", xAxisInRadians, yAxisInRadians); + + final double p1 = 100000 * Math.random() + Math.random(); + final double x = Math.sin(yAxisInRadians) * Math.cos(xAxisInRadians) * p1; + final double y = Math.sin(yAxisInRadians) * Math.sin(xAxisInRadians) * p1; + final double z = Math.cos(yAxisInRadians) * p1; + System.out.printf("TARGET SIGHTED: APPROXIMATE COORDINATES: X=%.3f Y=%.3f Z=%.3f\n", x, y, z); + boolean targetOrSelfDestroyed = false; + while (!targetOrSelfDestroyed) { + numberShots++; + int estimatedDistance = 0; + switch (numberShots) { + case 1: + estimatedDistance = (int) (p1 * .05) * 20; + break; + case 2: + estimatedDistance = (int) (p1 * .1) * 10; + break; + case 3: + estimatedDistance = (int) (p1 * .5) * 2; + break; + case 4: + case 5: + estimatedDistance = (int) (p1); + break; + } + + System.out.printf(" ESTIMATED DISTANCE: %s\n\n", estimatedDistance); + + final TargetAttempt targetAttempt = readInput(scan); + if (targetAttempt.distance < 20) { + System.out.println("YOU BLEW YOURSELF UP!!"); + targetOrSelfDestroyed = true; + } else { + final double a1 = targetAttempt.xDeviation / RADIAN; + final double b1 = targetAttempt.zDeviation / RADIAN; + System.out.printf("RADIANS FROM X AXIS = %.7f FROM Z AXIS = %.7f\n", a1, b1); + + final double x1 = targetAttempt.distance * Math.sin(b1) * Math.cos(a1); + final double y1 = targetAttempt.distance * Math.sin(b1) * Math.sin(a1); + final double z1 = targetAttempt.distance * Math.cos(b1); + + double distance = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y) + (z1 - z) * (z1 - z)); + if (distance > 20) { + double X2 = x1 - x; + double Y2 = y1 - y; + double Z2 = z1 - z; + if (X2 < 0) { + System.out.printf("SHOT BEHIND TARGET %.7f KILOMETERS.\n", -X2); + } else { + System.out.printf("SHOT IN FRONT OF TARGET %.7f KILOMETERS.\n", X2); + } + if (Y2 < 0) { + System.out.printf("SHOT TO RIGHT OF TARGET %.7f KILOMETERS.\n", -Y2); + } else { + System.out.printf("SHOT TO LEFT OF TARGET %.7f KILOMETERS.\n", Y2); + } + if (Z2 < 0) { + System.out.printf("SHOT BELOW TARGET %.7f KILOMETERS.\n", -Z2); + } else { + System.out.printf("SHOT ABOVE TARGET %.7f KILOMETERS.\n", Z2); + } + System.out.printf("APPROX POSITION OF EXPLOSION: X=%.7f Y=%.7f Z=%.7f\n", x1, y1, z1); + System.out.printf(" DISTANCE FROM TARGET =%.7f\n\n\n\n", distance); + } else { + System.out.println(" * * * HIT * * * TARGET IS NON-FUNCTIONAL"); + System.out.printf("DISTANCE OF EXPLOSION FROM TARGET WAS %.5f KILOMETERS.\n", distance); + System.out.printf("MISSION ACCOMPLISHED IN %s SHOTS.\n", numberShots); + targetOrSelfDestroyed = true; + } + } + } + System.out.println("\n\n\n\n\nNEXT TARGET...\n"); + } + } + + private static TargetAttempt readInput(Scanner scan) { + System.out.println("INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE "); + boolean validInput = false; + TargetAttempt targetAttempt = new TargetAttempt(); + while (!validInput) { + String input = scan.nextLine(); + final String[] split = input.split(","); + try { + targetAttempt.xDeviation = Float.parseFloat(split[0]); + targetAttempt.zDeviation = Float.parseFloat(split[1]); + targetAttempt.distance = Float.parseFloat(split[2]); + validInput = true; + } catch (NumberFormatException nfe) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE\n? "); + } + + } + return targetAttempt; + } + + private static void printIntro() { + System.out.println(" TARGET"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + System.out.println("YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE"); + System.out.println("AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU"); + System.out.println("ARE IN A THREE-DIMENSIONAL RANGE. YOU WILL BE TOLD"); + System.out.println("THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION"); + System.out.println("OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,"); + System.out.println("THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z"); + System.out.println("AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET."); + System.out.println("YOU WILL THEN PROCEED TO SHOOT AT THE TARGET UNTIL IT IS"); + System.out.println("DESTROYED!"); + System.out.println("\nGOOD LUCK!!\n\n"); + } + + /** + * Represents the user input + */ + private static class TargetAttempt { + + double xDeviation; + double zDeviation; + double distance; + } +} + + diff --git a/92 Trap/perl/trap.pl b/92 Trap/perl/trap.pl new file mode 100644 index 00000000..80349056 --- /dev/null +++ b/92 Trap/perl/trap.pl @@ -0,0 +1,62 @@ +#!/usr/bin/perl +use strict; + +print ' 'x 34 . "TRAP\n"; +print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n"; print "\n"; print "\n"; +my $G=6; +my $N=100; +# REM-TRAP; +# REM-STEVE ULLMAN, 8-1-72; + +print "INSTRUCTIONS"; +print "? "; chomp(my $Z = uc()); +if (substr($Z,0,1) eq "Y") { + print "I AM THINKING OF A NUMBER BETWEEN 1 AND $N\n"; + print "TRY TO GUESS MY NUMBER. ON EACH GUESS,\n"; + print "YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP\n"; + print "MY NUMBER BETWEEN THE TWO NUMBERS. I WILL\n"; + print "TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY\n"; + print "NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF\n"; + print "MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.\n"; + print "IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE\n"; + print "YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.\n"; + print "YOU GET $G GUESSES TO GET MY NUMBER.\n"; + } + +while (1) { + my $Flag= 0; + my $X=int($N*rand(1))+1; + for (my $Q=1; $Q<=$G; $Q++) { + print "\n"; + print "GUESS #$Q "; + print "? "; chomp(my $Pair= uc()); + my ($A, $B)= split(",", $Pair); + if ($A eq $B && $X eq $A) { $Flag=1; last; } + + if ($A>$B) { ($A,$B)= ($B,$A); } + if ($X>$B) { + print "MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.\n"; + next; + } + if ($X<$A) { + print "MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.\n"; + next; + } + print "YOU HAVE TRAPPED MY NUMBER.\n"; + } + + if ($Flag==0) { + print "SORRY, THAT'S $G GUESSES. THE NUMBER WAS $X\n"; + } else { + print "YOU GOT IT!!!\n"; + } + + print "\n"; + print "TRY AGAIN.\n"; + print "\n"; + } + +exit; + +