Private Sub btnPlay_Click(sender As Object, e As EventArgs) Handles btnPlay.Click Dim tStart As Date = Now() Dim tEnd As Date Dim iGames As Integer Dim iMaxGames As Integer = 1 Dim iTurns As Integer = 0 Dim iMinTurns As Integer = 9999 Dim iMaxTurns As Integer = 0 Dim iTotalTurns As Integer = 0 Dim lstTurns As New List(Of Integer) Dim rand As New Random() 'get the number of games to play If IsNumeric(txtGameCnt.Text) Then iMaxGames = CInt(txtGameCnt.Text) End If Using sw As New StreamWriter($"C:\Data\WarStats\WARstats_{Now:HHmmss}.txt") For iGames = 1 To iMaxGames 'shuffle the deck for a new game BuildDeck(rand) 'play a game and record the number of turns iTurns = modWAR.TurnsToWin iTotalTurns += iTurns If iMinTurns > iTurns Then iMinTurns = iTurns End If If iMaxTurns < iTurns Then iMaxTurns = iTurns End If lstTurns.Add(iTurns) Next tEnd = Now 'sort the list of results from lowest to highest lstTurns.Sort(Function(a As Integer, b As Integer) a.CompareTo(b)) 'output stats to log sw.WriteLine($"Min = {iMinTurns}") sw.WriteLine($"Avg = {iTotalTurns / (iGames - 1)}") sw.WriteLine($"Max = {iMaxTurns}") For Each i As Integer In lstTurns sw.WriteLine($"{i:0000}") Next 'output stats to form text field txtStatus.Text = $"Min = {iMinTurns}{vbCrLf}Avg = {iTotalTurns / (iGames - 1)}{vbCrLf}Max = {iMaxTurns}{vbCrLf}{iMaxGames} games played in {DateDiff("s", tStart, tEnd)} sec" End Using End Sub Module modWAR Dim qA As Queue(Of Int16) Dim qB As Queue(Of Int16) Public Sub BuildDeck(ByRef rand As Random) 'create a list of integers from 1-13, 4 of each value to mimic a deck of cards Dim lstDeck As New List(Of Int16) For i As Int16 = 1 To 13 For j As Int16 = 0 To 3 lstDeck.Add(i) Next Next 'shuffle the deck 5 times For q As Int16 = 0 To 4 lstDeck = Randomize(Of Int16)(lstDeck, rand) Next 'create a hand (queue) for each player qA = New Queue(Of Int16) qB = New Queue(Of Int16) 'deal cards to each player For q As Int16 = 0 To 51 If q Mod 2 = 0 Then qA.Enqueue(lstDeck(q)) Else qB.Enqueue(lstDeck(q)) End If Next End Sub Function Randomize(Of T)(ByVal list As List(Of T), ByRef rand As Random) As List(Of T) 'a function to randomize a list of objects Dim temp As T Dim indexRand As Integer Dim indexLast As Integer = list.Count - 1 For index As Integer = 0 To indexLast indexRand = rand.Next(index, indexLast) temp = list(indexRand) list(indexRand) = list(index) list(index) = temp Next index Return list End Function Public Function TurnsToWin() As Integer TurnsToWin = 0 Dim iWarCount As Int16 = 1 Dim iA As Int16 = 0 Dim iB As Int16 = 0 Dim iTurn As Integer = 0 Dim lstPot As List(Of Int16) = Nothing Dim lstTurns As New List(Of String) Do iTurn += 1 'turn over the top card from each hand iA = qA.Dequeue iB = qB.Dequeue If iA > iB Then qA.Enqueue(iA) qA.Enqueue(iB) lstTurns.Add($"Turn {iTurn:0000} - A:{iA:00} - B:{iB:00} - A takes the cards - {qA.Count} to {qB.Count}") ElseIf iA < iB Then qB.Enqueue(iB) qB.Enqueue(iA) lstTurns.Add($"Turn {iTurn:0000} - A:{iA:00} - B:{iB:00} - B takes the cards - {qA.Count} to {qB.Count}") Else 'cards are equal, war ensues 'create a list to hold the pot of cards at risk in this war lstPot = New List(Of Int16) Do lstTurns.Add($"Turn {iTurn:0000} - A:{iA:00} - B:{iB:00} - time to go to war - {qA.Count} to {qB.Count}") If qA.Count = 0 And qB.Count = 0 Then lstTurns.Add($"Turn {iTurn:0000} - both players are out of cards and it's a draw") Exit Do End If If qA.Count = 0 Then 'player A does not have enough cards for a war and loses lstTurns.Add($"Turn {iTurn:0000} - A has no more cards and loses") qB.Enqueue(iA) qB.Enqueue(iB) Exit Do End If If qB.Count = 0 Then 'player B does not have enough cards for a war and loses lstTurns.Add($"Turn {iTurn:0000} - B has no more cards and loses") qA.Enqueue(iB) qA.Enqueue(iA) Exit Do End If 'add the matching cards to the pot lstPot.Add(iA) lstPot.Add(iB) 'determine how many cards go into the war pot. '3: player has 2 or more cards, iWarCount = 1 '4: player has 1 cards, iWarCount = 0 and the last card is compared '5: player has no cards left is handled above If qA.Count < iWarCount + 1 Then iWarCount = qA.Count - 1 End If If qB.Count < iWarCount + 1 Then iWarCount = qB.Count - 1 End If 'pull cards from each hand and add to the pot For r As Int16 = 1 To iWarCount lstPot.Add(qA.Dequeue) lstPot.Add(qB.Dequeue) Next 'the cards to be compared to win the pot iA = qA.Dequeue iB = qB.Dequeue Loop While iA = iB If iA > iB Then For Each n As Int16 In lstPot qA.Enqueue(n) Next qA.Enqueue(iA) qA.Enqueue(iB) lstTurns.Add($"Turn {iTurn:0000} - A:{iA:00} - B:{iB:00} - A wins the war and adds {lstPot.Count + 2} - {qA.Count} to {qB.Count}") ElseIf iA < iB Then For Each n As Int16 In lstPot qB.Enqueue(n) Next qB.Enqueue(iB) qB.Enqueue(iA) lstTurns.Add($"Turn {iTurn:0000} - A:{iA:00} - B:{iB:00} - B wins the war and adds {lstPot.Count + 2} - {qA.Count} to {qB.Count}") End If End If Loop Until (qA.Count = 0 Or qB.Count = 0) If iTurn = 272 Then Using sw As New StreamWriter($"C:\Data\WarStats\WAR_{Now:HHmmssfff}.txt") For Each s As String In lstTurns sw.WriteLine(s) Next End Using End If TurnsToWin = iTurn End Function End Module