mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-29 06:05:36 -08:00
Animal (VB.NET) implementation
This commit is contained in:
@@ -4,5 +4,6 @@
|
||||
<RootNamespace>Animal</RootNamespace>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>16.9</LangVersion>
|
||||
<OptionStrict>On</OptionStrict>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
28
03_Animal/vbnet/Branch.vb
Normal file
28
03_Animal/vbnet/Branch.vb
Normal file
@@ -0,0 +1,28 @@
|
||||
Public Class Branch
|
||||
Public Property Text As String
|
||||
|
||||
Public ReadOnly Property IsEnd As Boolean
|
||||
Get
|
||||
Return Yes Is Nothing AndAlso No Is Nothing
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public Property Yes As Branch
|
||||
Public Property No As Branch
|
||||
|
||||
Public Iterator Function DescendantTexts() As IEnumerable(Of String)
|
||||
If Yes IsNot Nothing Then
|
||||
Yield Yes.Text
|
||||
For Each childText In Yes.DescendantTexts
|
||||
Yield childText
|
||||
Next
|
||||
End If
|
||||
|
||||
If No IsNot Nothing Then
|
||||
Yield No.Text
|
||||
For Each childText In No.DescendantTexts
|
||||
Yield childText
|
||||
Next
|
||||
End If
|
||||
End Function
|
||||
End Class
|
||||
126
03_Animal/vbnet/Game.vb
Normal file
126
03_Animal/vbnet/Game.vb
Normal file
@@ -0,0 +1,126 @@
|
||||
Option Compare Text
|
||||
|
||||
Public Class Game
|
||||
Private Shared ReadOnly YesNoResponses As New Dictionary(Of String, Boolean)(StringComparer.InvariantCultureIgnoreCase) From {
|
||||
{"yes", True},
|
||||
{"y", True},
|
||||
{"true", True},
|
||||
{"t", True},
|
||||
{"1", True},
|
||||
{"no", False},
|
||||
{"n", False},
|
||||
{"false", False},
|
||||
{"f", False},
|
||||
{"0", False}
|
||||
}
|
||||
|
||||
ReadOnly console As ConsoleAdapterBase
|
||||
ReadOnly root As New Branch With {
|
||||
.Text = "DOES IT SWIM?",
|
||||
.Yes = New Branch With {.Text = "FISH"},
|
||||
.No = New Branch With {.Text = "BIRD"}
|
||||
}
|
||||
|
||||
''' <summary>Reduces a string or console input to True, False or Nothing. Case-insensitive.</summary>
|
||||
''' <param name="s">Optional String to reduce via the same logic. If not passed in, will use console.ReadLine</param>
|
||||
''' <returns>
|
||||
''' Returns True for a "yes" response (yes, y, true, t, 1) and False for a "no" response (no, n, false, f, 0).<br/>
|
||||
''' Returns Nothing if the response doesn't match any of these.
|
||||
''' </returns>
|
||||
Private Function GetYesNo(Optional s As String = Nothing) As Boolean?
|
||||
s = If(s, console.ReadLine)
|
||||
Dim ret As Boolean
|
||||
If YesNoResponses.TryGetValue(s, ret) Then Return ret
|
||||
Return Nothing
|
||||
End Function
|
||||
|
||||
Sub New(console As ConsoleAdapterBase)
|
||||
If console Is Nothing Then Throw New ArgumentNullException(NameOf(console))
|
||||
Me.console = console
|
||||
End Sub
|
||||
|
||||
|
||||
Sub BeginLoop()
|
||||
console.WriteCenteredLine("ANIMAL")
|
||||
console.WriteCenteredLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
console.Write(
|
||||
"
|
||||
|
||||
|
||||
PLAY 'GUESS THE ANIMAL'
|
||||
|
||||
THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.
|
||||
|
||||
")
|
||||
|
||||
Do
|
||||
console.Write("ARE YOU THINKING OF AN ANIMAL? ")
|
||||
|
||||
Dim response = console.ReadLine
|
||||
If response = "list" Then
|
||||
console.WriteLine(
|
||||
"
|
||||
ANIMALS I ALREADY KNOW ARE:")
|
||||
root.DescendantTexts.ForEach(Sub(text, index)
|
||||
If index > 0 AndAlso index Mod 4 = 0 Then console.WriteLine()
|
||||
console.Write($"{text.MaxLength(15),-15}")
|
||||
End Sub)
|
||||
console.WriteLine(
|
||||
"
|
||||
")
|
||||
Continue Do
|
||||
End If
|
||||
|
||||
Dim ynResponse = GetYesNo(response)
|
||||
If ynResponse Is Nothing OrElse Not ynResponse Then Continue Do
|
||||
|
||||
Dim currentBranch = root
|
||||
Do While Not currentBranch.IsEnd
|
||||
console.Write($"{currentBranch.Text} ")
|
||||
Do
|
||||
ynResponse = GetYesNo()
|
||||
Loop While ynResponse Is Nothing
|
||||
currentBranch = If(
|
||||
ynResponse,
|
||||
currentBranch.Yes,
|
||||
currentBranch.No
|
||||
)
|
||||
Loop
|
||||
|
||||
'at end
|
||||
console.Write($"IS IT A {currentBranch.Text}? ")
|
||||
ynResponse = GetYesNo()
|
||||
If ynResponse Then ' No difference between False or Nothing
|
||||
console.WriteLine("WHY NOT TRY ANOTHER ANIMAL?")
|
||||
Continue Do
|
||||
End If
|
||||
|
||||
console.Write("THE ANIMAL YOU WERE THINKING OF WAS A ? ")
|
||||
Dim newAnimal = console.ReadLine
|
||||
|
||||
console.WriteLine(
|
||||
$"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A
|
||||
{newAnimal} FROM A {currentBranch.Text}")
|
||||
Dim newQuestion = console.ReadLine
|
||||
|
||||
console.Write(
|
||||
$"FOR A {newAnimal} THE ANSWER WOULD BE ? ")
|
||||
Do
|
||||
ynResponse = GetYesNo()
|
||||
Loop While ynResponse Is Nothing
|
||||
|
||||
Dim newBranch = New Branch With {.Text = newAnimal}
|
||||
Dim currentBranchCopy = New Branch With {.Text = currentBranch.Text}
|
||||
currentBranch.Text = newQuestion
|
||||
If ynResponse Then
|
||||
currentBranch.Yes = newBranch
|
||||
currentBranch.No = currentBranchCopy
|
||||
Else
|
||||
currentBranch.No = newBranch
|
||||
currentBranch.Yes = currentBranchCopy
|
||||
End If
|
||||
|
||||
' TODO how do we exit?
|
||||
Loop
|
||||
End Sub
|
||||
End Class
|
||||
6
03_Animal/vbnet/Program.vb
Normal file
6
03_Animal/vbnet/Program.vb
Normal file
@@ -0,0 +1,6 @@
|
||||
Module Program
|
||||
Sub Main()
|
||||
Dim game As New Game(New ConsoleAdapter)
|
||||
game.BeginLoop()
|
||||
End Sub
|
||||
End Module
|
||||
28
03_Animal/vbnet/Shared/ConsoleAdapter.vb
Normal file
28
03_Animal/vbnet/Shared/ConsoleAdapter.vb
Normal file
@@ -0,0 +1,28 @@
|
||||
Public Class ConsoleAdapter
|
||||
Inherits ConsoleAdapterBase
|
||||
|
||||
Public Overrides Sub Write(value As Object)
|
||||
Console.Write(value)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub WriteLine(value As Object)
|
||||
Console.WriteLine(value)
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub WriteLine()
|
||||
Console.WriteLine()
|
||||
End Sub
|
||||
|
||||
Public Overrides Sub WriteCenteredLine(value As Object)
|
||||
Dim toWrite = If(value?.ToString, "")
|
||||
Console.WriteLine($"{Space((Console.WindowWidth - toWrite.Length) \ 2)}{toWrite}")
|
||||
End Sub
|
||||
|
||||
Public Overrides Function ReadLine() As String
|
||||
Dim response As String
|
||||
Do
|
||||
response = Console.ReadLine
|
||||
Loop While response Is Nothing
|
||||
Return response.Trim
|
||||
End Function
|
||||
End Class
|
||||
9
03_Animal/vbnet/Shared/ConsoleAdapterBase.vb
Normal file
9
03_Animal/vbnet/Shared/ConsoleAdapterBase.vb
Normal file
@@ -0,0 +1,9 @@
|
||||
Public MustInherit Class ConsoleAdapterBase
|
||||
Public MustOverride Sub Write(value As Object)
|
||||
Public MustOverride Sub WriteLine(value As Object)
|
||||
Public MustOverride Sub WriteLine()
|
||||
Public MustOverride Sub WriteCenteredLine(value As Object)
|
||||
|
||||
''' <summary>Implementations should always return a String without leading or trailing whitespace, never Nothng</summary>
|
||||
Public MustOverride Function ReadLine() As String
|
||||
End Class
|
||||
21
03_Animal/vbnet/Shared/Extensions.vb
Normal file
21
03_Animal/vbnet/Shared/Extensions.vb
Normal file
@@ -0,0 +1,21 @@
|
||||
Imports System.Runtime.CompilerServices
|
||||
|
||||
Public Module Extensions
|
||||
<Extension> Public Sub ForEach(Of T)(src As IEnumerable(Of T), action As Action(Of T, Integer))
|
||||
Dim index As Integer
|
||||
For Each x In src
|
||||
action(x, index)
|
||||
index += 1
|
||||
Next
|
||||
End Sub
|
||||
|
||||
<Extension> Public Function MaxLength(s As String, value As Integer) As String
|
||||
If s Is Nothing Then Return Nothing
|
||||
Return s.Substring(0, Math.Min(s.Length, value))
|
||||
End Function
|
||||
|
||||
<Extension> Public Function ForceEndsWith(s As String, toAppend As String) As String
|
||||
If Not s.EndsWith(toAppend, StringComparison.OrdinalIgnoreCase) Then s += toAppend
|
||||
Return s
|
||||
End Function
|
||||
End Module
|
||||
Reference in New Issue
Block a user