mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 15:16:33 -08:00
Test for added animal; minor fixes
This commit is contained in:
7
03_Animal/vbnet/Animal.Tests/EndOfInputsException.vb
Normal file
7
03_Animal/vbnet/Animal.Tests/EndOfInputsException.vb
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
''' <summary>
|
||||||
|
''' <para>Indicates that there are no more inputs in the MockConsole.</para>
|
||||||
|
''' We need this while testing, because otherwise the game loop will continue forever, waiting for a nonexistent input.
|
||||||
|
''' </summary>
|
||||||
|
Public Class EndOfInputsException
|
||||||
|
Inherits Exception
|
||||||
|
End Class
|
||||||
@@ -37,26 +37,21 @@ Public Class MockConsole
|
|||||||
WriteString(value?.ToString)
|
WriteString(value?.ToString)
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Public Overrides Sub WriteLine(value As Object)
|
|
||||||
WriteString(value?.ToString)
|
|
||||||
WriteLine()
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
Public Overrides Sub WriteLine()
|
Public Overrides Sub WriteLine()
|
||||||
Lines.Add(("", False))
|
Lines.Add(("", False))
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Public Overrides Sub WriteCenteredLine(value As Object)
|
Public Overrides Sub WriteCenteredLines(value As Object)
|
||||||
If Lines.Count = 0 Then Lines.Add(("", False))
|
If Lines.Count = 0 Then Lines.Add(("", False))
|
||||||
Dim currentLast = Lines(Lines.Count - 1).line
|
Dim currentLast = Lines(Lines.Count - 1).line
|
||||||
If currentLast.Length > 0 Then Throw New InvalidOperationException("Can only write centered line if cursor is at start of line.")
|
If currentLast.Length > 0 Then Lines.Add(("", False))
|
||||||
WriteString(value?.ToString, True)
|
WriteString(value?.ToString, True)
|
||||||
WriteLine()
|
WriteLine()
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Public Overrides Function ReadLine() As String
|
Public Overrides Function ReadLine() As String
|
||||||
' Indicates the end of a test run, for programs which loop endlessly
|
' Indicates the end of a test run, for programs which loop endlessly
|
||||||
If inputs.Count = 0 Then Throw New EndOfStreamException("End of inputs")
|
If inputs.Count = 0 Then Throw New EndOfInputsException
|
||||||
|
|
||||||
Dim nextInput = inputs.Dequeue.Trim
|
Dim nextInput = inputs.Dequeue.Trim
|
||||||
WriteLine(nextInput)
|
WriteLine(nextInput)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ Public Class TestContainer
|
|||||||
Sub List(listResponse As String)
|
Sub List(listResponse As String)
|
||||||
Dim console As New MockConsole({listResponse})
|
Dim console As New MockConsole({listResponse})
|
||||||
Dim game As New Game(console)
|
Dim game As New Game(console)
|
||||||
Assert.Throws(Of EndOfStreamException)(Sub() game.BeginLoop())
|
Assert.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
{
|
{
|
||||||
"ANIMALS I ALREADY KNOW ARE:",
|
"ANIMALS I ALREADY KNOW ARE:",
|
||||||
@@ -52,7 +52,7 @@ Public Class TestContainer
|
|||||||
Sub YesVariant(yesVariant As String)
|
Sub YesVariant(yesVariant As String)
|
||||||
Dim console As New MockConsole({yesVariant})
|
Dim console As New MockConsole({yesVariant})
|
||||||
Dim game As New Game(console)
|
Dim game As New Game(console)
|
||||||
Assert.Throws(Of EndOfStreamException)(Sub() game.BeginLoop())
|
Assert.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
{
|
{
|
||||||
$"ARE YOU THINKING OF AN ANIMAL? {yesVariant}",
|
$"ARE YOU THINKING OF AN ANIMAL? {yesVariant}",
|
||||||
@@ -68,7 +68,7 @@ Public Class TestContainer
|
|||||||
Sub NoVariant(noVariant As String)
|
Sub NoVariant(noVariant As String)
|
||||||
Dim console As New MockConsole({"y", noVariant})
|
Dim console As New MockConsole({"y", noVariant})
|
||||||
Dim game As New Game(console)
|
Dim game As New Game(console)
|
||||||
Assert.Throws(Of EndOfStreamException)(Sub() game.BeginLoop())
|
Assert.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())
|
||||||
Assert.Equal(
|
Assert.Equal(
|
||||||
{
|
{
|
||||||
$"DOES IT SWIM? {noVariant}",
|
$"DOES IT SWIM? {noVariant}",
|
||||||
@@ -77,4 +77,42 @@ Public Class TestContainer
|
|||||||
console.Lines.Slice(-2, 0).Select(Function(x) x.line)
|
console.Lines.Slice(-2, 0).Select(Function(x) x.line)
|
||||||
)
|
)
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
|
''' <summary>Test adding a new animal and using the new animal in the game</summary>
|
||||||
|
<Fact>
|
||||||
|
Sub TestAddedAnimal()
|
||||||
|
Dim console As New MockConsole({
|
||||||
|
"y",
|
||||||
|
"y",
|
||||||
|
"n",
|
||||||
|
"whale",
|
||||||
|
"is it a mammal?",
|
||||||
|
"y",
|
||||||
|
"y",
|
||||||
|
"y",
|
||||||
|
"y",
|
||||||
|
"y"
|
||||||
|
})
|
||||||
|
Dim game As New Game(console)
|
||||||
|
Assert.Throws(Of EndOfInputsException)(Sub() game.BeginLoop())
|
||||||
|
Assert.Equal(
|
||||||
|
{
|
||||||
|
"ARE YOU THINKING OF AN ANIMAL? y",
|
||||||
|
"DOES IT SWIM? y",
|
||||||
|
"IS IT A FISH? n",
|
||||||
|
"THE ANIMAL YOU WERE THINKING OF WAS A ? whale",
|
||||||
|
"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A",
|
||||||
|
"WHALE FROM A FISH",
|
||||||
|
"is it a mammal?",
|
||||||
|
"FOR A WHALE THE ANSWER WOULD BE? y",
|
||||||
|
"ARE YOU THINKING OF AN ANIMAL? y",
|
||||||
|
"DOES IT SWIM? y",
|
||||||
|
"IS IT A MAMMAL? y",
|
||||||
|
"IS IT A WHALE? y",
|
||||||
|
"WHY NOT TRY ANOTHER ANIMAL?",
|
||||||
|
"ARE YOU THINKING OF AN ANIMAL? "
|
||||||
|
},
|
||||||
|
console.Lines.Slice(9, 100).Select(Function(x) x.line)
|
||||||
|
)
|
||||||
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
|
|||||||
@@ -46,8 +46,11 @@ Public Class Game
|
|||||||
|
|
||||||
Sub BeginLoop()
|
Sub BeginLoop()
|
||||||
' Print the program heading
|
' Print the program heading
|
||||||
console.WriteCenteredLine("ANIMAL")
|
console.WriteCenteredLines(
|
||||||
console.WriteCenteredLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
"ANIMAL
|
||||||
|
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||||
|
|
||||||
|
' Print the program description
|
||||||
console.Write(
|
console.Write(
|
||||||
"
|
"
|
||||||
|
|
||||||
@@ -64,9 +67,10 @@ THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.
|
|||||||
Dim response = console.ReadLine
|
Dim response = console.ReadLine
|
||||||
If response = "list" Then
|
If response = "list" Then
|
||||||
' List all the stored animals
|
' List all the stored animals
|
||||||
console.WriteLine(
|
console.Write(
|
||||||
"
|
"
|
||||||
ANIMALS I ALREADY KNOW ARE:")
|
ANIMALS I ALREADY KNOW ARE:
|
||||||
|
")
|
||||||
|
|
||||||
' We're using a ForEach extension method instead of the regular For Each loop to provide the index alongside the text
|
' We're using a ForEach extension method instead of the regular For Each loop to provide the index alongside the text
|
||||||
root.DescendantTexts.ForEach(Sub(text, index)
|
root.DescendantTexts.ForEach(Sub(text, index)
|
||||||
@@ -76,8 +80,9 @@ ANIMALS I ALREADY KNOW ARE:")
|
|||||||
If index > 0 AndAlso index Mod 4 = 0 Then console.WriteLine()
|
If index > 0 AndAlso index Mod 4 = 0 Then console.WriteLine()
|
||||||
console.Write($"{text.MaxLength(15),-15}")
|
console.Write($"{text.MaxLength(15),-15}")
|
||||||
End Sub)
|
End Sub)
|
||||||
console.WriteLine(
|
console.Write(
|
||||||
"
|
"
|
||||||
|
|
||||||
")
|
")
|
||||||
Continue Do
|
Continue Do
|
||||||
End If
|
End If
|
||||||
@@ -105,25 +110,26 @@ ANIMALS I ALREADY KNOW ARE:")
|
|||||||
' Now we're at an end branch
|
' Now we're at an end branch
|
||||||
console.Write($"IS IT A {currentBranch.Text}? ")
|
console.Write($"IS IT A {currentBranch.Text}? ")
|
||||||
ynResponse = GetYesNo()
|
ynResponse = GetYesNo()
|
||||||
If ynResponse Then ' Only if ynResponse = True will we go into this If Then
|
If ynResponse Then ' Only if ynResponse = True will we go into this If Then block
|
||||||
|
' The computer guessed the animal; we can go back to the beginning of the game
|
||||||
console.WriteLine("WHY NOT TRY ANOTHER ANIMAL?")
|
console.WriteLine("WHY NOT TRY ANOTHER ANIMAL?")
|
||||||
Continue Do
|
Continue Do
|
||||||
End If
|
End If
|
||||||
|
|
||||||
' Get the new animal
|
' Get the new animal from the user
|
||||||
console.Write("THE ANIMAL YOU WERE THINKING OF WAS A ? ")
|
console.Write("THE ANIMAL YOU WERE THINKING OF WAS A ? ")
|
||||||
Dim newAnimal = console.ReadLine
|
Dim newAnimal = console.ReadLine.ToUpperInvariant
|
||||||
|
|
||||||
' Get the question used to distinguish the new animal from the current end branch
|
' Get the question used to distinguish the new animal from the current end branch
|
||||||
console.WriteLine(
|
console.Write(
|
||||||
$"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A
|
$"PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A
|
||||||
{newAnimal} FROM A {currentBranch.Text}")
|
{newAnimal} FROM A {currentBranch.Text}
|
||||||
Dim newQuestion = console.ReadLine
|
")
|
||||||
|
Dim newQuestion = console.ReadLine.ToUpperInvariant
|
||||||
|
|
||||||
' Get the answer to that question, for the new animal
|
' Get the answer to that question, for the new animal
|
||||||
' for the old animal, the answer would be the opposite
|
' for the old animal, the answer will be the opposite
|
||||||
console.Write(
|
console.Write($"FOR A {newAnimal} THE ANSWER WOULD BE? ")
|
||||||
$"FOR A {newAnimal} THE ANSWER WOULD BE ? ")
|
|
||||||
Do
|
Do
|
||||||
ynResponse = GetYesNo()
|
ynResponse = GetYesNo()
|
||||||
Loop While ynResponse Is Nothing
|
Loop While ynResponse Is Nothing
|
||||||
|
|||||||
@@ -5,18 +5,15 @@
|
|||||||
Console.Write(value)
|
Console.Write(value)
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Public Overrides Sub WriteLine(value As Object)
|
|
||||||
Console.WriteLine(value)
|
|
||||||
End Sub
|
|
||||||
|
|
||||||
Public Overrides Sub WriteLine()
|
Public Overrides Sub WriteLine()
|
||||||
Console.WriteLine()
|
Console.WriteLine()
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Public Overrides Sub WriteCenteredLine(value As Object)
|
Public Overrides Sub WriteCenteredLines(value As Object)
|
||||||
If Console.CursorLeft <> 0 Then Throw New InvalidOperationException("Can only write centered line if cursor is at start of line.")
|
If Console.CursorLeft <> 0 Then WriteLine()
|
||||||
Dim toWrite = If(value?.ToString, "")
|
Dim toWrite = If(value?.ToString, "")
|
||||||
Console.WriteLine($"{Space((Console.WindowWidth - toWrite.Length) \ 2)}{toWrite}")
|
Write($"{Space((Console.WindowWidth - toWrite.Length) \ 2)}{toWrite}")
|
||||||
|
WriteLine()
|
||||||
End Sub
|
End Sub
|
||||||
|
|
||||||
Public Overrides Function ReadLine() As String
|
Public Overrides Function ReadLine() As String
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
Public MustInherit Class ConsoleAdapterBase
|
Public MustInherit Class ConsoleAdapterBase
|
||||||
Public MustOverride Sub Write(value As Object)
|
Public MustOverride Sub Write(value As Object)
|
||||||
Public MustOverride Sub WriteLine(value As Object)
|
|
||||||
Public MustOverride Sub WriteLine()
|
Public MustOverride Sub WriteLine()
|
||||||
Public MustOverride Sub WriteCenteredLine(value As Object)
|
Public MustOverride Sub WriteCenteredLines(value As Object)
|
||||||
|
|
||||||
''' <summary>Implementations should always return a String without leading or trailing whitespace, never Nothng</summary>
|
''' <summary>Implementations should always return a String without leading or trailing whitespace, never Nothng</summary>
|
||||||
Public MustOverride Function ReadLine() As String
|
Public MustOverride Function ReadLine() As String
|
||||||
|
|
||||||
|
Public Sub WriteLine(value As Object)
|
||||||
|
Write(value)
|
||||||
|
WriteLine()
|
||||||
|
End Sub
|
||||||
End Class
|
End Class
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
|
Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||||
|
|
||||||
Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
|
Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
|
||||||
|
|
||||||
|
This takes some inspiration from the [C# port of Animal](https://github.com/zspitz/basic-computer-games/tree/main/03_Animal/csharp).
|
||||||
|
|
||||||
|
The `Game` class takes a console abstraction (`ConsoleAdapterBase`), which could also be used for different UIs, such as WinForms or a web page.
|
||||||
|
This solution also has an xUnit tests project.
|
||||||
|
Responses can be entered in any capitalization, but animals and the distinguishing question will be converted to uppercase.
|
||||||
|
|||||||
Reference in New Issue
Block a user