diff --git a/01_Acey_Ducey/vbnet/AceyDucey.vb b/01_Acey_Ducey/vbnet/AceyDucey.vb
new file mode 100644
index 00000000..8727e6b2
--- /dev/null
+++ b/01_Acey_Ducey/vbnet/AceyDucey.vb
@@ -0,0 +1,242 @@
+Public Class AceyDucey
+ '''
+ ''' Create a single instance of the Random class to be used
+ ''' throughout the program.
+ '''
+ Private ReadOnly Property Rnd As New Random()
+
+ '''
+ ''' Define a varaible to store the the player balance.
+ ''' Defaults to 0
+ '''
+ '''
+ ''' Since is a value type, and no value
+ ''' has been explicitly set, the default value of the type is used.
+ '''
+ Private _balance As Integer
+
+ Public Sub New()
+ DisplayIntroduction()
+ End Sub
+
+ '''
+ ''' Play multiple games of Acey Ducey until the player chooses to quit.
+ '''
+ Public Sub Play()
+ Do
+ PlayGame()
+ Loop While TryAgain() 'Loop (play again) based on the Boolean value returned by TryAgain
+
+ Console.WriteLine("O.K., HOPE YOU HAD FUN!")
+ End Sub
+
+ '''
+ ''' Play a game of Acey Ducey, which ends when the player balance reaches 0
+ '''
+ Private Sub PlayGame()
+ _balance = 100 'At the start of the game, set the player balance to 100
+
+ Console.WriteLine()
+ Console.WriteLine($"YOU NOW HAVE {_balance} DOLLARS.")
+
+ Do
+ PlayTurn()
+ Loop While _balance > 0 'Continue playing while the user has a balance
+
+ Console.WriteLine()
+ Console.WriteLine("SORRY, FRIEND, BUT YOU BLEW YOUR WAD.")
+ End Sub
+
+ '''
+ ''' Play one turn of Acey Ducey
+ '''
+ '''
+ ''' A turn consists of displaying to cards, making a wager
+ ''' and determining the result (win/lose)
+ '''
+ Private Sub PlayTurn()
+ Console.WriteLine()
+ Console.WriteLine("HERE ARE YOUR NEXT TWO CARDS: ")
+
+ Dim cards = GetOrderedCards()
+
+ For Each card In cards
+ DisplayCard(card)
+ Next
+
+ Dim wager As Integer = GetWager()
+ Dim finalCard As Integer = GetCard()
+
+ If wager = 0 Then
+ Console.WriteLine("CHICKEN!!")
+ Return
+ End If
+
+ DisplayCard(finalCard)
+
+ Console.WriteLine()
+
+ '''Check if the value of the final card is between the first and second cards.
+ '''
+ '''The use of AndAlso is used to short-circuit the evaluation of the IF condition.
+ '''Short-circuiting means that both sides of the condition do not need to be
+ '''evaluated. In this case, if the left criteria returns FALSE, the right criteria
+ '''is ignored and the evaluation result is returned as FALSE.
+ '''
+ '''This works because AndAlso requires both condition to return TRUE in order to be
+ '''evaluated as TRUE. If the first condition is FALSE we already know the evaluation result.
+ If finalCard >= cards.First() AndAlso finalCard <= cards.Last() Then
+ Console.WriteLine("YOU WIN!!!")
+ _balance += wager 'Condensed version of _balance = _balance + wager
+ Else
+ Console.WriteLine("SORRY, YOU LOSE.")
+ _balance -= wager 'Condensed version of _balance = _balance - wager
+ End If
+ End Sub
+
+ '''
+ ''' Get two cards in ascending order
+ '''
+ '''
+ ''' The original version generates two cards (A and B)
+ ''' If A is greater than or equal to B, both cards are regenerated.
+ '''
+ ''' This version generates the two cards, but only regenerates A
+ ''' if A is equal to B. The cards are then returned is ascending order,
+ ''' ensuring that A is less than B (maintaining the original end result)
+ '''
+ Private Function GetOrderedCards() As Integer()
+ '''When declaring fixed size arrays in VB.NET you declare the MAX INDEX of the array
+ '''and NOT the SIZE (number of elements) of the array.
+ '''As such, card(1) gives you and array with index 0 and index 1, which means
+ '''the array stores two elements and not one
+ Dim cards(1) As Integer
+
+ cards(0) = GetCard()
+ cards(1) = GetCard()
+
+ 'Perform this action as long as the first card is equal to the second card
+ While cards(0) = cards(1)
+ cards(0) = GetCard()
+ End While
+
+ Array.Sort(cards) 'Sort the values in ascending order
+
+ Return cards
+ End Function
+
+ '''
+ ''' Get a random number (card) ranked 2 to 14
+ '''
+ Private Function GetCard() As Integer
+ Return Rnd.Next(2, 15)
+ End Function
+
+ '''
+ ''' Display the face value of the card
+ '''
+ Private Sub DisplayCard(card As Integer)
+ Dim output As String
+
+ Select Case card
+ Case 2 To 10
+ output = card.ToString()
+ Case 11
+ output = "JACK"
+ Case 12
+ output = "QUEEN"
+ Case 13
+ output = "KING"
+ Case 14
+ output = "ACE"
+ Case Else
+ Throw New ArgumentOutOfRangeException(NameOf(card), "Value must be between 2 and 14")
+ End Select
+
+ Console.WriteLine(output)
+ End Sub
+
+ '''
+ ''' Prompt the user to make a bet
+ '''
+ '''
+ ''' The function will not return until a valid bet is made.
+ ''' is used to validate that the user input is a valid
+ '''
+ Private Function GetWager() As Integer
+ Dim wager As Integer
+ Do
+ Console.WriteLine()
+ Console.Write("WHAT IS YOUR BET? ")
+
+ Dim input As String = Console.ReadLine()
+
+ '''Determine if the user input is an Integer
+ '''If it is an Integer, store the value in the variable wager
+ If Not Integer.TryParse(input, wager) Then
+ Console.WriteLine("SORRY, I DID'T QUITE GET THAT.")
+ Continue Do 'restart the loop
+ End If
+
+ 'Prevent the user from betting more than their current balance
+ If _balance < wager Then
+ Console.WriteLine("SORRY, MY FRIEND, BUT YOU BET TOO MUCH.")
+ Console.WriteLine($"YOU HAVE ONLY {_balance} DOLLARS TO BET.")
+ Continue Do 'restart the loop
+ End If
+
+ 'Prevent the user from betting negative values
+ If wager < 0 Then
+ Console.WriteLine("FUNNY GUY! YOU CANNOT MAKE A NEGATIVE BET.")
+ Continue Do 'restart the loop
+ End If
+
+ Exit Do 'If we get to this line, exit the loop as all above validations passed
+ Loop
+
+ Return wager
+ End Function
+
+ '''
+ ''' Prompt the user to try again
+ '''
+ '''
+ ''' This function will not return until a valid reponse is given
+ '''
+ Private Function TryAgain() As Boolean
+ Dim response As String
+ Do
+ Console.Write("TRY AGAIN (YES OR NO) ")
+
+ response = Console.ReadLine()
+
+ If response.Equals("YES", StringComparison.OrdinalIgnoreCase) Then Return True
+ If response.Equals("NO", StringComparison.OrdinalIgnoreCase) Then Return False
+
+ Console.WriteLine("SORRY, I DID'T QUITE GET THAT.")
+ Loop
+ End Function
+
+ '''
+ ''' Display the opening title and instructions
+ '''
+ '''
+ ''' Refer to
+ '''
+ ''' Interpolated Strings
+ ''' documentation for the use of $ and { } with strings
+ '''
+ Private Sub DisplayIntroduction()
+ Console.WriteLine($"{Space((Console.WindowWidth \ 2) - 10)}ACEY DUCEY CARD GAME")
+ Console.WriteLine($"{Space((Console.WindowWidth \ 2) - 21)}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
+ Console.WriteLine("")
+ Console.WriteLine("")
+ Console.WriteLine("ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER")
+ Console.WriteLine("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP")
+ Console.WriteLine("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING")
+ Console.WriteLine("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE")
+ Console.WriteLine("A VALUE BETWEEN THE FIRST TWO.")
+ Console.WriteLine("IF YOU DO NOT WANT TO BET, INPUT A 0")
+ Console.WriteLine("")
+ End Sub
+End Class
diff --git a/01_Acey_Ducey/vbnet/Program.vb b/01_Acey_Ducey/vbnet/Program.vb
index bfa518ca..2f82fd60 100644
--- a/01_Acey_Ducey/vbnet/Program.vb
+++ b/01_Acey_Ducey/vbnet/Program.vb
@@ -6,173 +6,16 @@ Imports System
''' The structural changes primarily consist of replacing the many GOTOs with
''' Do/Loop constructs to force the continual execution of the program.
'''
-''' Because modern Basic allows multi-line If/Then blocks, many GOTO jumps were
-''' able to be eliminated and the logic was able to be moved to more relevant areas,
-''' For example, the increment/decrement of the player's balance could be in the same
-''' area as the notification of win/loss.
+''' Some modern improvements were added, primarily the inclusion of a multiple
+''' subroutines and functions, which eliminates repeated logic and reduces
+''' then need for nested loops.
'''
-''' Some modern improvements were added, primarily the inclusion of a function, which
-''' eliminated a thrice-repeated block of logic to display the card value. The archaic
-''' RND function is greatly simplified with the .NET Framework's Random class.
+''' The archaic RND function is greatly simplified with the .NET Framework's Random class.
'''
''' Elementary comments are provided for non-programmers or novices.
'''
Module Program
- Sub Main(args As String())
- ' These are the variables that will hold values during the program's execution
- Dim input As String
- Dim rnd As New Random ' You can create a new instance of an object during declaration
- Dim currentBalance As Integer = 100 ' You can set a initial value at declaration
- Dim currentWager As Integer
- Dim cardA, cardB, cardC As Integer ' You can specify multiple variables of the same type in one declaration statement
-
- ' Display the opening title and instructions
- ' Use a preceding $ to insert calculated values within the string using {}
- Console.WriteLine($"{Space((Console.WindowWidth \ 2) - 10)}ACEY DUCEY CARD GAME")
- Console.WriteLine($"{Space((Console.WindowWidth \ 2) - 21)}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
- Console.WriteLine("")
- Console.WriteLine("")
- Console.WriteLine("ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER")
- Console.WriteLine("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP")
- Console.WriteLine("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING")
- Console.WriteLine("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE")
- Console.WriteLine("A VALUE BETWEEN THE FIRST TWO.")
- Console.WriteLine("IF YOU DO NOT WANT TO BET, INPUT A 0")
-
- Do ' This loop continues as long as the player wants to keep playing
-
- Do ' This loop continues as long as the player has money to play
-
- Console.WriteLine("")
- Console.WriteLine($"YOU NOW HAVE {currentBalance} DOLLARS.")
- Console.WriteLine("")
-
- Console.WriteLine("HERE ARE YOUR NEXT TWO CARDS:")
-
- ' We need to ensure that card B is a higher value for our later comparison,
- ' so we will loop until we have two cards that meet this criteria
- Do
- cardA = rnd.Next(2, 14)
- cardB = rnd.Next(2, 14)
-
- Loop While cardA > cardB
-
- ' We use a function to display the text value of the numeric card value
- ' because we do this 3 times and a function reduces repetition of code
- Console.WriteLine(DisplayCard(cardA))
- Console.WriteLine(DisplayCard(cardB))
-
- Do ' This loop continues until the player provides a valid wager value
- Console.WriteLine("")
- Console.WriteLine("WHAT IS YOUR BET")
-
- currentWager = 0
- input = Console.ReadLine
-
- ' Any input from the console is a string, but we require a number.
- ' Test the input to make sure it is a numeric value.
- If Integer.TryParse(input, currentWager) Then
- ' Test to ensure the player has not wagered more than their balance
- If currentWager > currentBalance Then
- Console.WriteLine("SORRY, MY FRIEND, BUT YOU BET TOO MUCH.")
- Console.WriteLine($"YOU HAVE ONLY {currentBalance} DOLLARS TO BET.")
-
- Else
- ' The player has provided a numeric value that is less/equal to their balance,
- ' exit the loop and continue play
- Exit Do
-
- End If ' check player balance
-
- End If ' check numeric input
-
- Loop ' wager loop
-
- ' If the player is wagering, draw the third card, otherwise, mock them.
- If currentWager > 0 Then
- cardC = rnd.Next(2, 14)
-
- Console.WriteLine(DisplayCard(cardC))
-
- ' The effort we made to have two cards in numeric order earlier makes this check easier,
- ' otherwise we would have to have a second check in the opposite direction
- If cardC < cardA OrElse cardC >= cardB Then
- Console.WriteLine("SORRY, YOU LOSE")
- currentBalance -= currentWager ' Shorthand code to decrement a number (currentBalance=currentBalance - currentWager)
-
- Else
- Console.WriteLine("YOU WIN!!!")
- currentBalance += currentWager ' Shorthand code to increment a number (currentBalance=currentBalance + currentWager)
-
- End If
-
- Else
- Console.WriteLine("CHICKEN!!")
- Console.WriteLine("")
-
- End If
-
- Loop While currentBalance > 0 ' loop as long as the player has money
-
- ' At this point, the player has no money (currentBalance=0). Inform them of such.
- Console.WriteLine("")
- Console.WriteLine("SORRY, FRIEND, BUT YOU BLEW YOUR WAD.")
- Console.WriteLine("")
- Console.WriteLine("")
-
- ' We will loop to ensure the player provides some answer.
- Do
- Console.WriteLine("TRY AGAIN (YES OR NO)")
- Console.WriteLine("")
-
- input = Console.ReadLine
-
- Loop While String.IsNullOrWhiteSpace(input)
-
- ' We will assume that the player wants to play again only if they answer yes.
- ' (yeah and ya are valid as well, because we only check the first letter)
- If input.Substring(0, 1).Equals("y", StringComparison.CurrentCultureIgnoreCase) Then ' This allows upper and lower case to be entered.
- currentBalance = 100 ' Reset the players balance before restarting
-
- Else
- ' Exit the outer loop which will end the game.
- Exit Do
-
- End If
-
- Loop ' The full game loop
-
- Console.WriteLine("O.K., HOPE YOU HAD FUN!")
-
+ Sub Main()
+ Call New AceyDucey().Play()
End Sub
-
- ' This function is called for each of the 3 cards used in the game.
- ' The input and the output are both consistent, making it a good candidate for a function.
- Private Function DisplayCard(value As Integer) As String
- ' We check the value of the input and run a block of code for whichever
- ' evaluation matches
- Select Case value
- Case 2 To 10 ' Case statements can be ranges of values, also multiple values (Case 2,3,4,5,6,7,8,9,10)
- Return value.ToString
-
- Case 11
- Return "JACK"
-
- Case 12
- Return "QUEEN"
-
- Case 13
- Return "KING"
-
- Case 14
- Return "ACE"
-
- End Select
-
- ' Although we have full knowledge of the program and never plan to send an invalid
- ' card value, it's important to provide a message for the next developer who won't
- Throw New ArgumentOutOfRangeException("Card value must be between 2 and 14")
-
- End Function
-
End Module