From ec2d063fb94e776e81cd616bb7316cc5f8e55643 Mon Sep 17 00:00:00 2001 From: Joe Walter Date: Sun, 30 May 2021 10:51:29 -0400 Subject: [PATCH] Port Batnum to Python and VB --- .gitignore | 1 + 08 Batnum/python/batnum.py | 159 +++++++++++++++++++++++++++ 08 Batnum/vbnet/Program.vb | 199 ++++++++++++++++++++++++++++++++++ 08 Batnum/vbnet/batnum.sln | 25 +++++ 08 Batnum/vbnet/batnum.vbproj | 9 ++ 5 files changed, 393 insertions(+) create mode 100644 08 Batnum/python/batnum.py create mode 100644 08 Batnum/vbnet/Program.vb create mode 100644 08 Batnum/vbnet/batnum.sln create mode 100644 08 Batnum/vbnet/batnum.vbproj diff --git a/.gitignore b/.gitignore index a186b7a3..78bed0e0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ */.vs +*.suo bin/ obj/ diff --git a/08 Batnum/python/batnum.py b/08 Batnum/python/batnum.py new file mode 100644 index 00000000..0f3473ed --- /dev/null +++ b/08 Batnum/python/batnum.py @@ -0,0 +1,159 @@ +from enum import Enum + +class WinOptions(Enum): + Undefined = 0 + TakeLast = 1 + AvoidLast = 2 + +class StartOptions(Enum): + Undefined = 0 + ComputerFirst = 1 + PlayerFirst = 2 + +def PrintIntro(): + '''Prints out the introduction and rules for the game.''' + print("BATNUM".rjust(33, ' ')) + print("CREATIVE COMPUTING MORRISSTOWN, NEW JERSEY".rjust(15, ' ')) + print() + print() + print() + print("THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE") + print("COMPUTER IS YOUR OPPONENT.") + print() + print("THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU") + print( "AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.") + print("WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR") + print("NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.") + print("DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.") + print("ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.") + print() + return + +def GetParams(): + '''This requests the necessary parameters to play the game. + + Returns a set with the five game parameters: + pileSize - the starting size of the object pile + minSelect - minimum selection that can be made on each turn + maxSelect - maximum selection that can be made on each turn + startOption - 1 if the computer is first + or 2 if the player is first + winOption - 1 if the goal is to take the last object + or 2 if the goal is to not take the last object + ''' + pileSize = 0 + winOption = WinOptions.Undefined + minSelect = 0 + maxSelect = 0 + startOption = StartOptions.Undefined + + while pileSize < 1: + pileSize = int(input("ENTER PILE SIZE ")) + while winOption == WinOptions.Undefined: + winOption = int(input("ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: ")) + while minSelect < 1 or maxSelect < 1 or minSelect > maxSelect: + (minSelect, maxSelect) = [int(x) for x in input("ENTER MIN AND MAX ").split(' ')] + while startOption == StartOptions.Undefined: + startOption = int(input("ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ")) + return (pileSize, minSelect, maxSelect, startOption, winOption) + +def PlayerMove(pileSize, minSelect, maxSelect, startOption, winOption): + '''This handles the player's turn - asking the player how many objects + to take and doing some basic validation around that input. Then it + checks for any win conditions. + + Returns a boolean indicating whether the game is over and the new pileSize.''' + playerDone = False + while not playerDone: + playerMove = int(input("YOUR MOVE ")) + if playerMove == 0: + print ("I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.") + return (True, pileSize) + if playerMove > maxSelect or playerMove < minSelect: + print("ILLEGAL MOVE, REENTER IT") + continue + pileSize = pileSize - playerMove + playerDone = True + if pileSize <= 0: + if winOption == WinOptions.AvoidLast: + print("TOUGH LUCK, YOU LOSE.") + else: + print("CONGRATULATIONS, YOU WIN.") + return (True, pileSize) + return (False, pileSize) + +def ComputerPick(pileSize, minSelect, maxSelect, startOption, winOption): + '''This handles the logic to determine how many objects the computer + will select on its turn. + ''' + q = pileSize - 1 if winOption == WinOptions.AvoidLast else pileSize + c = minSelect + maxSelect + computerPick = q - (c * int(q / c)) + if computerPick < minSelect: + computerPick = minSelect + if computerPick > maxSelect: + computerPick = maxSelect + return computerPick + +def ComputerMove(pileSize, minSelect, maxSelect, startOption, winOption): + '''This handles the computer's turn - first checking for the various + win/lose conditions and then calculating how many objects + the computer will take. + + Returns a boolean indicating whether the game is over and the new pileSize.''' + # First, check for win conditions on this move + # In this case, we win by taking the last object and + # the remaining pile is less than max select + # so the computer can grab them all and win + if winOption == WinOptions.TakeLast and pileSize <= maxSelect: + print (f"COMPUTER TAKES {pileSize} AND WINS.") + return (True, pileSize) + # In this case, we lose by taking the last object and + # the remaining pile is less than minsize and the computer + # has to take all of them. + if winOption == WinOptions.AvoidLast and pileSize <= minSelect: + print (f"COMPUTER TAKES {minSelect} AND LOSES.") + return (True, pileSize) + + # Otherwise, we determine how many the computer selects + currSel = ComputerPick(pileSize, minSelect, maxSelect, startOption, winOption) + pileSize = pileSize - currSel + print(f"COMPUTER TAKES {currSel} AND LEAVES {pileSize}") + return (False, pileSize) + +def PlayGame(pileSize, minSelect, maxSelect, startOption, winOption): + '''This is the main game loop - repeating each turn until one + of the win/lose conditions is met. + ''' + gameOver = False + # playersTurn is a boolean keeping track of whether it's the + # player's or computer's turn + playersTurn = startOption == StartOptions.PlayerFirst + + while not gameOver: + if playersTurn: + (gameOver, pileSize) = PlayerMove(pileSize, minSelect, maxSelect, startOption, winOption) + playersTurn = False + if gameOver: + return + if not playersTurn: + (gameOver, pileSize) = ComputerMove(pileSize, minSelect, maxSelect, startOption, winOption) + playersTurn = True + + return + +if __name__ == "__main__": + + pileSize = 0 + minSelect = 0 + maxSelect = 0 + # 1 = to take last, 2 = to avoid last + winOption = 0 + # 1 = computer first, 2 = user first + startOption = 0 + + while True: + PrintIntro() + (pileSize, minSelect, maxSelect, startOption, winOption) = GetParams() + # Just keep playing the game until the user kills it with ctrl-C + PlayGame(pileSize, minSelect, maxSelect, startOption, winOption) diff --git a/08 Batnum/vbnet/Program.vb b/08 Batnum/vbnet/Program.vb new file mode 100644 index 00000000..4ba9ad9d --- /dev/null +++ b/08 Batnum/vbnet/Program.vb @@ -0,0 +1,199 @@ +Imports System + +Module BatNum + Enum WinOptions + Undefined = 0 + TakeLast = 1 + AvoidLast = 2 + End Enum + + Enum StartOptions + Undefined = 0 + ComputerFirst = 1 + PlayerFirst = 2 + End Enum + + Dim pileSize As Integer = 0 + Dim minSelect As Integer = 0 + Dim maxSelect As Integer = 0 + Dim startOption As StartOptions = StartOptions.Undefined + Dim winOption As WinOptions = WinOptions.Undefined + + ' + ' Prints the intro and rules of the game. + ' + Private Sub PrintIntro() + Console.WriteLine("BATNUM".PadLeft(33, " ")) + Console.WriteLine("CREATIVE COMPUTING MORRISSTOWN, NEW JERSEY".PadLeft(15, " ")) + Console.WriteLine() + Console.WriteLine() + Console.WriteLine() + Console.WriteLine("THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE") + Console.WriteLine("COMPUTER IS YOUR OPPONENT.") + Console.WriteLine() + Console.WriteLine("THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU") + Console.WriteLine("AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE.") + Console.WriteLine("WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR") + Console.WriteLine("NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS.") + Console.WriteLine("DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME.") + Console.WriteLine("ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING.") + Console.WriteLine() + End Sub + + ' + ' Asks the user for the various parameters necessary + ' to play the game. + ' + Private Sub GetParams() + ' Reset the game parameters + pileSize = 0 + minSelect = 0 + maxSelect = 0 + startOption = StartOptions.Undefined + winOption = WinOptions.Undefined + + While pileSize < 1 + Console.Write("ENTER PILE SIZE ") + pileSize = Convert.ToInt32(Console.ReadLine()) + End While + While winOption = WinOptions.Undefined + Console.Write("ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: ") + winOption = Convert.ToInt32(Console.ReadLine()) + End While + While minSelect < 1 Or maxSelect < 1 Or minSelect > maxSelect + Console.Write("ENTER MIN AND MAX ") + Dim vals = Console.ReadLine().ToString().Split(" ").[Select](Function(n) Integer.Parse(n)).ToList() + If vals.Count() <> 2 Then + Continue While + End If + minSelect = vals(0) + maxSelect = vals(1) + End While + While startOption = StartOptions.Undefined + Console.Write("ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ") + startOption = Convert.ToInt32(Console.ReadLine()) + End While + End Sub + + ' + 'This handles the player's turn - asking the player how many objects + 'to take And doing some basic validation around that input. Then it + 'checks for any win conditions. + ' + 'Returns a Boolean indicating whether the game Is over And the New pileSize.' + Private Function PlayerMove() As Boolean + Dim playerDone As Boolean = False + + While Not playerDone + Console.WriteLine("YOUR MOVE ") + Dim playerNum As Integer = Convert.ToInt32(Console.ReadLine()) + If playerNum = 0 Then + Console.WriteLine("I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT.") + Return True + End If + If playerNum > maxSelect Or playerNum < minSelect Then + Console.WriteLine("ILLEGAL MOVE, REENTER IT") + Continue While + End If + + pileSize = pileSize - playerNum + playerDone = True + If pileSize <= 0 Then + If winOption = WinOptions.AvoidLast Then + Console.WriteLine("TOUGH LUCK, YOU LOSE.") + Else + Console.WriteLine("CONGRATULATIONS, YOU WIN.") + End If + Return True + End If + End While + + Return False + End Function + + ' + 'This handles the logic to determine how many objects the computer + 'will select on its turn. + ' + Private Function ComputerPick() As Integer + Dim q As Integer = IIf(winOption = WinOptions.AvoidLast, pileSize - 1, pileSize) + Dim c As Integer = minSelect + maxSelect + Dim computerNum As Integer = q - (c * Int(q / c)) + If computerNum < minSelect Then + computerNum = minSelect + End If + If computerNum > maxSelect Then + ComputerPick = maxSelect + End If + + Return computerNum + End Function + + ' + 'This handles the computer's turn - first checking for the various + 'win/lose conditions And then calculating how many objects + 'the computer will take. + ' + 'Returns a boolean indicating whether the game is over.' + Private Function ComputerMove() As Boolean + ' First, check For win conditions On this move + ' In this Case, we win by taking the last Object And + ' the remaining pile Is less than max Select + ' so the computer can grab them all And win + If winOption = WinOptions.TakeLast And pileSize <= maxSelect Then + Console.WriteLine($"COMPUTER TAKES {pileSize} AND WINS.") + Return True + End If + ' In this Case, we lose by taking the last Object And + ' the remaining pile Is less than minsize And the computer + ' has To take all Of them. + If winOption = WinOptions.AvoidLast And pileSize <= minSelect Then + Console.WriteLine($"COMPUTER TAKES {minSelect} AND LOSES.") + Return True + End If + + ' Otherwise, we determine how many the computer selects + Dim currSel As Integer = ComputerPick() + pileSize = pileSize - currSel + Console.WriteLine($"COMPUTER TAKES {currSel} AND LEAVES {pileSize}") + Return False + End Function + + ' + 'This is the main game loop - repeating each turn until one + 'of the win/lose conditions Is met. + ' + Private Sub PlayGame() + Dim gameOver As Boolean = False + ' playersTurn Is a Boolean keeping track Of whether it's the + ' player's or computer's turn + Dim playersTurn As Boolean = (startOption = StartOptions.PlayerFirst) + + While Not gameOver + If playersTurn Then + gameOver = PlayerMove() + playersTurn = False + If gameOver Then Return + End If + + If Not playersTurn Then + gameOver = ComputerMove() + playersTurn = True + End If + End While + End Sub + + Public Sub Play() + While True + PrintIntro() + GetParams() + PlayGame() + End While + End Sub +End Module + +Module Program + Sub Main(args As String()) + BatNum.Play() + End Sub +End Module diff --git a/08 Batnum/vbnet/batnum.sln b/08 Batnum/vbnet/batnum.sln new file mode 100644 index 00000000..b3f63f59 --- /dev/null +++ b/08 Batnum/vbnet/batnum.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}") = "batnum", "batnum.vbproj", "{D577E429-F84D-4E84-86E7-E6526CFD5FD9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D577E429-F84D-4E84-86E7-E6526CFD5FD9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {426DF7FE-66E7-4319-9AD8-7A2DD3964A2F} + EndGlobalSection +EndGlobal diff --git a/08 Batnum/vbnet/batnum.vbproj b/08 Batnum/vbnet/batnum.vbproj new file mode 100644 index 00000000..3c21499c --- /dev/null +++ b/08 Batnum/vbnet/batnum.vbproj @@ -0,0 +1,9 @@ + + + + Exe + batnum + netcoreapp3.1 + + +