diff --git a/01_Acey_Ducey/python/acey_ducey_oo.py b/01_Acey_Ducey/python/acey_ducey_oo.py
new file mode 100644
index 00000000..d8b7c752
--- /dev/null
+++ b/01_Acey_Ducey/python/acey_ducey_oo.py
@@ -0,0 +1,125 @@
+#
+# AceyDuchy
+#
+# From: BASIC Computer Games (1978)
+# Edited by David Ahl
+#
+# "The original BASIC program author was Bill Palmby
+# of Prairie View, Illinois."
+#
+# Python port by Aviyam Fischer, 2022
+#
+######################################################
+
+class Card:
+ def __init__(self, suit, rank):
+ self.suit = suit
+ self.rank = rank
+
+ def __str__(self):
+ r = self.rank
+ if r == 11:
+ r = 'J'
+ elif r == 12:
+ r = 'Q'
+ elif r == 13:
+ r = 'K'
+ elif r == 14:
+ r = 'A'
+ return f'{r}{self.suit}'
+
+
+class Deck:
+ def __init__(self):
+ self.cards = []
+ self.build()
+
+ def build(self):
+ for suit in ['\u2665', '\u2666', '\u2663', '\u2660']:
+ for rank in range(1, 14):
+ self.cards.append(Card(suit, rank))
+
+ def shuffle(self):
+ import random
+ random.shuffle(self.cards)
+
+ def deal(self):
+ return self.cards.pop()
+
+
+class Game:
+ def __init__(self):
+ self.deck = Deck()
+ self.deck.shuffle()
+ self.card_a = self.deck.deal()
+ self.card_b = self.deck.deal()
+ self.money = 100
+ self.not_done = True
+
+ def play(self):
+ while self.not_done:
+ while self.money > 0:
+ card_a = self.card_a
+ card_b = self.card_b
+
+ if card_a.rank > card_b.rank:
+ card_a, card_b = card_b, card_a
+
+ if card_a.rank == card_b.rank:
+ self.card_b = self.deck.deal()
+ card_b = self.card_b
+
+ print(f'You have:\t ${self.money} ')
+ print(f'Your cards:\t {card_a} {card_b}')
+
+ bet = int(input('What is your bet? '))
+ player_card = self.deck.deal()
+ if 0 < bet <= self.money:
+
+ print(f'Your deal:\t {player_card}')
+ if card_a.rank < player_card.rank < card_b.rank:
+ print('You Win!')
+ self.money += bet
+ else:
+ print('You Lose!')
+ self.money -= bet
+ self.not_done = False
+ else:
+ print('Chicken!')
+ print(f'Your deal should have been: {player_card}')
+ if card_a.rank < player_card.rank < card_b.rank:
+ print(f'You could have won!')
+ else:
+ print(f'You would lose, so it was wise of you to chicken out!')
+
+ self.not_done = False
+ break
+
+ if len(self.deck.cards) <= 1:
+ print('You ran out of cards. Game over.')
+ self.not_done = False
+ break
+
+ if self.money == 0:
+ self.not_done = False
+
+
+if __name__ == '__main__':
+ print('''
+ Acey Ducey is a card game where you play against the computer.
+ The Dealer(computer) will deal two cards facing up.
+ You have an option to bet or not bet depending on whether or not you
+ feel the card will have a value between the first two.
+ If you do not want to bet input a 0
+ ''')
+ GAME_OVER = False
+
+ while not GAME_OVER:
+ game = Game()
+ game.play()
+ print(f'You have ${game.money} left')
+ print('Would you like to play again? (y/n)')
+ if input() == 'n':
+ GAME_OVER = True
+
+ print('\nThanks for playing!')
diff --git a/01_Acey_Ducey/ruby/aceyducey.rb b/01_Acey_Ducey/ruby/aceyducey.rb
index b9648ef8..3d49754a 100644
--- a/01_Acey_Ducey/ruby/aceyducey.rb
+++ b/01_Acey_Ducey/ruby/aceyducey.rb
@@ -56,9 +56,9 @@ while true # Game loop
puts
puts "HERE ARE YOUR NEXT TWO CARDS:"
- # Randomly draw two cards from 2 to 14 and make sure the first card is lower in value than the second
+ # Randomly draw two cards and make sure the first card is lower in value than the second
# Using array destructuring, this sorted array can be assigned to `first_card` and `second_card`
- first_card, second_card = [rand(2..14), rand(2..14)].sort
+ first_card, second_card = (2...14).to_a.shuffle.pop(2).sort
# Helper method to convert a numeric card into a String for printing
def card_name(card)
diff --git a/01_Acey_Ducey/vbnet/AceyDucy.sln b/01_Acey_Ducey/vbnet/AceyDucy.sln
new file mode 100644
index 00000000..881d7c9c
--- /dev/null
+++ b/01_Acey_Ducey/vbnet/AceyDucy.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "AceyDucy", "AceyDucy\AceyDucy.vbproj", "{37496710-B458-4502-ADCB-4C57203866F9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {37496710-B458-4502-ADCB-4C57203866F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {37496710-B458-4502-ADCB-4C57203866F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {37496710-B458-4502-ADCB-4C57203866F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {37496710-B458-4502-ADCB-4C57203866F9}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {C01D9DAE-644C-455F-8365-E14E49074BC3}
+ EndGlobalSection
+EndGlobal
diff --git a/01_Acey_Ducey/vbnet/AceyDucy/AceyDucy.vbproj b/01_Acey_Ducey/vbnet/AceyDucy/AceyDucy.vbproj
new file mode 100644
index 00000000..98a07001
--- /dev/null
+++ b/01_Acey_Ducey/vbnet/AceyDucy/AceyDucy.vbproj
@@ -0,0 +1,9 @@
+
+
+
+ Exe
+ AceyDucy
+ net6.0
+
+
+
diff --git a/01_Acey_Ducey/vbnet/AceyDucy/Program.vb b/01_Acey_Ducey/vbnet/AceyDucy/Program.vb
new file mode 100644
index 00000000..bfa518ca
--- /dev/null
+++ b/01_Acey_Ducey/vbnet/AceyDucy/Program.vb
@@ -0,0 +1,178 @@
+Imports System
+
+'''
+''' This is a modern adapation of Acey Ducey from BASIC Computer Games.
+'''
+''' 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 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.
+'''
+''' 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!")
+
+ 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
diff --git a/04_Awari/csharp/Game.cs b/04_Awari/csharp/Game.cs
new file mode 100644
index 00000000..8a673dea
--- /dev/null
+++ b/04_Awari/csharp/Game.cs
@@ -0,0 +1,264 @@
+namespace Awari;
+
+public class Game
+{
+ public int[] PlayerPits => _beans[0..6];
+ public int[] ComputerPits => _beans[7..13];
+ public int PlayerHome => _beans[_playerHome];
+ public int ComputerHome => _beans[_computerHome];
+
+ private bool IsDone =>
+ PlayerPits.All(b => b == 0) // if all the player's pits are empty
+ || ComputerPits.All(b => b == 0); // or if all the computer's pits are empty
+
+ public GameState State { get; private set; }
+
+ public void Reset()
+ {
+ State = GameState.PlayerMove;
+
+ Array.Fill(_beans, _initialPitValue);
+ _beans[_playerHome] = 0;
+ _beans[_computerHome] = 0;
+
+ _moveCount = 0;
+ _notWonGameMoves[^1] = 0;
+ }
+
+ public bool IsLegalPlayerMove(int move) =>
+ move is > 0 and < 7
+ && _beans[move - 1] > 0; // arrays are zero-based, but moves are one-based
+
+ public void PlayerMove(int move) => MoveAndRegister(move - 1, _playerHome);
+
+ public List ComputerTurn()
+ {
+ // keep a list of moves made by the computer in a single turn (1 or 2)
+ List moves = new();
+
+ moves.Add(ComputerMove()); // ComputerMove() returns the move made
+
+ // only if a second move is possible, do it
+ if (State == GameState.ComputerSecondMove)
+ moves.Add(ComputerMove());
+
+ return moves;
+ }
+
+ public GameOutcome GetOutcome()
+ {
+ if (State != GameState.Done)
+ throw new InvalidOperationException("Game is not yet done.");
+
+ int difference = _beans[_playerHome] - _beans[_computerHome];
+ var winner = difference switch
+ {
+ < 0 => GameWinner.Computer,
+ 0 => GameWinner.Draw,
+ > 0 => GameWinner.Player,
+ };
+
+ return new GameOutcome(winner, Math.Abs(difference));
+ }
+
+ private void MoveAndRegister(int pit, int homePosition)
+ {
+ int lastMovedBean = Move(_beans, pit, homePosition);
+
+ // encode moves by player and computer into a 'base 6' number
+ // e.g. if the player moves 5, the computer moves 2, and the player moves 4,
+ // that would be encoded as ((5 * 6) * 6) + (2 * 6) + 4 = 196
+ if (pit > 6) pit -= 7;
+ _moveCount++;
+ if (_moveCount < 9)
+ _notWonGameMoves[^1] = _notWonGameMoves[^1] * 6 + pit;
+
+ // determine next state based on current state, whether the game's done, and whether the last moved bean moved
+ // into the player's home position
+ State = (State, IsDone, lastMovedBean == homePosition) switch
+ {
+ (_, true, _) => GameState.Done,
+ (GameState.PlayerMove, _, true) => GameState.PlayerSecondMove,
+ (GameState.PlayerMove, _, false) => GameState.ComputerMove,
+ (GameState.PlayerSecondMove, _, _) => GameState.ComputerMove,
+ (GameState.ComputerMove, _, true) => GameState.ComputerSecondMove,
+ (GameState.ComputerMove, _, false) => GameState.PlayerMove,
+ (GameState.ComputerSecondMove, _, _) => GameState.PlayerMove,
+ _ => throw new InvalidOperationException("Unexpected game state"),
+ };
+
+ // do some bookkeeping if the game is done, but not won by the computer
+ if (State == GameState.Done
+ && _beans[_playerHome] >= _beans[_computerHome])
+ // add an entry for the next game
+ _notWonGameMoves.Add(0);
+ }
+
+ private static int Move(int[] beans, int pit, int homePosition)
+ {
+ int beansToMove = beans[pit];
+ beans[pit] = 0;
+
+ // add the beans that were in the pit to other pits, moving clockwise around the board
+ for (; beansToMove >= 1; beansToMove--)
+ {
+ // wrap around if pit exceeds 13
+ pit = (pit + 1) % 14;
+
+ beans[pit]++;
+ }
+
+ if (beans[pit] == 1 // if the last bean was sown in an empty pit
+ && pit is not _playerHome and not _computerHome // which is not either player's home
+ && beans[12 - pit] != 0) // and the pit opposite is not empty
+ {
+ // move the last pit sown and the _beans in the pit opposite to the player's home
+ beans[homePosition] = beans[homePosition] + beans[12 - pit] + 1;
+ beans[pit] = 0;
+ beans[12 - pit] = 0;
+ }
+
+ return pit;
+ }
+
+ private int ComputerMove()
+ {
+ int move = DetermineComputerMove();
+ MoveAndRegister(move, homePosition: _computerHome);
+
+ // the result is only used to return it to the application, so translate it from an array index (between 7 and
+ // 12) to a pit number (between 1 and 6)
+ return move - 6;
+ }
+
+ private int DetermineComputerMove()
+ {
+ int bestScore = -99;
+ int move = 0;
+
+ // for each of the computer's possible moves, simulate them to calculate a score and pick the best one
+ for (int j = 7; j < 13; j++)
+ {
+ if (_beans[j] <= 0)
+ continue;
+
+ int score = SimulateMove(j);
+
+ if (score >= bestScore)
+ {
+ move = j;
+ bestScore = score;
+ }
+ }
+
+ return move;
+ }
+
+ private int SimulateMove(int move)
+ {
+ // make a copy of the current state, so we can safely mess with it
+ var hypotheticalBeans = new int[14];
+ _beans.CopyTo(hypotheticalBeans, 0);
+
+ // simulate the move in our copy
+ Move(hypotheticalBeans, move, homePosition: _computerHome);
+
+ // determine the 'best' move the player could make after this (best for them, not for the computer)
+ int score = ScoreBestNextPlayerMove(hypotheticalBeans);
+
+ // score this move by calculating how far ahead we would be after the move, and subtracting the player's next
+ // move score
+ score = hypotheticalBeans[_computerHome] - hypotheticalBeans[_playerHome] - score;
+
+ // have we seen the current set of moves before in a drawn/lost game? after 8 moves it's unlikely we'll find any
+ // matches, since games will have diverged. also we don't have space to store that many moves.
+ if (_moveCount < 8)
+ {
+ int translatedMove = move - 7; // translate from 7 through 12 to 0 through 5
+
+ // if the first two moves in this game were 1 and 2, and this hypothetical third move would be a 3,
+ // movesSoFar would be (1 * 36) + (2 * 6) + 3 = 51
+ int movesSoFar = _notWonGameMoves[^1] * 6 + translatedMove;
+
+ // since we store moves as a 'base 6' number, we need to divide stored moves by a power of 6
+ // let's say we've a stored lost game where the moves were, in succession, 1 through 8, the value stored
+ // would be:
+ // 8 + (7 * 6) + (6 * 36) + (5 * 216) + (4 * 1296) + (3 * 7776) + (2 * 46656) + (1 * 279936) = 403106
+ // to figure out the first three moves, we'd need to divide by 7776, resulting in 51.839...
+ double divisor = Math.Pow(6.0, 7 - _moveCount);
+
+ foreach (int previousGameMoves in _notWonGameMoves)
+ // if this combination of moves so far ultimately resulted in a draw/loss, give it a lower score
+ // note that this can happen multiple times
+ if (movesSoFar == (int) (previousGameMoves / divisor + 0.1))
+ score -= 2;
+ }
+
+ return score;
+ }
+
+ private static int ScoreBestNextPlayerMove(int[] hypotheticalBeans)
+ {
+ int bestScore = 0;
+
+ for (int i = 0; i < 6; i++)
+ {
+ if (hypotheticalBeans[i] <= 0)
+ continue;
+
+ int score = ScoreNextPlayerMove(hypotheticalBeans, i);
+
+ if (score > bestScore)
+ bestScore = score;
+ }
+
+ return bestScore;
+ }
+
+ private static int ScoreNextPlayerMove(int[] hypotheticalBeans, int move)
+ {
+ // figure out where the last bean will land
+ int target = hypotheticalBeans[move] + move;
+ int score = 0;
+
+ // if it wraps around, that means the player is adding to his own pits, which is good
+ if (target > 13)
+ {
+ // prevent overrunning the number of pits we have
+ target %= 14;
+ score = 1;
+ }
+
+ // if the player's move ends up in an empty pit, add the value of the pit on the opposite side to the score
+ if (hypotheticalBeans[target] == 0 && target is not _playerHome and not _computerHome)
+ score += hypotheticalBeans[12 - target];
+
+ return score;
+ }
+
+ private const int _playerHome = 6;
+ private const int _computerHome = 13;
+ private const int _initialPitValue = 3;
+
+ private readonly int[] _beans = new int[14];
+ private readonly List _notWonGameMoves = new() { 0 }; // not won means draw or lose
+ private int _moveCount;
+}
+
+public enum GameState
+{
+ PlayerMove,
+ PlayerSecondMove,
+ ComputerMove,
+ ComputerSecondMove,
+ Done,
+}
+
+public enum GameWinner
+{
+ Player,
+ Computer,
+ Draw,
+}
+
+public record struct GameOutcome(GameWinner Winner, int Difference);
\ No newline at end of file
diff --git a/04_Awari/csharp/Program.cs b/04_Awari/csharp/Program.cs
new file mode 100644
index 00000000..750787e7
--- /dev/null
+++ b/04_Awari/csharp/Program.cs
@@ -0,0 +1,98 @@
+using Awari;
+
+Console.WriteLine(Tab(34) + "AWARI");
+Console.WriteLine(Tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
+
+Game game = new();
+
+while (true)
+{
+ game.Reset();
+ DisplayGame();
+
+ while (game.State != GameState.Done)
+ {
+ switch (game.State)
+ {
+ case GameState.PlayerMove:
+ PlayerMove(second: false);
+ break;
+ case GameState.PlayerSecondMove:
+ PlayerMove(second: true);
+ break;
+ case GameState.ComputerMove:
+ ComputerTurn();
+ break;
+ }
+
+ DisplayGame();
+ }
+
+ var outcome = game.GetOutcome();
+
+ string outcomeLabel =
+ outcome.Winner switch
+ {
+ GameWinner.Computer => $"I WIN BY {outcome.Difference} POINTS",
+ GameWinner.Draw => "DRAWN GAME",
+ GameWinner.Player => $"YOU WIN BY {outcome.Difference} POINTS",
+ _ => throw new InvalidOperationException($"Unexpected winner {outcome.Winner}."),
+ };
+ Console.WriteLine(outcomeLabel);
+ Console.WriteLine();
+}
+
+void DisplayGame()
+{
+ // display the computer's pits
+ Console.Write(" ");
+ foreach (var pit in game.ComputerPits.Reverse())
+ Console.Write($"{pit,2} ");
+ Console.WriteLine();
+
+ // display both homes
+ Console.WriteLine($"{game.ComputerHome,2}{Tab(19)}{game.PlayerHome,2}");
+
+ // display the player's pits
+ Console.Write(" ");
+ foreach (var pit in game.PlayerPits)
+ Console.Write($"{pit,2} ");
+ Console.WriteLine();
+
+ Console.WriteLine();
+}
+
+void PlayerMove(bool second = false)
+{
+ int move = GetMove(second);
+ game.PlayerMove(move);
+}
+
+int GetMove(bool second)
+{
+ string prompt = second ? "AGAIN? " : "YOUR MOVE? ";
+
+ while (true)
+ {
+ Console.Write(prompt);
+
+ string input = Console.ReadLine() ?? "";
+
+ // input must be a number between 1 and 6, and the pit must have > 0 beans
+ if (int.TryParse(input, out int move)
+ && game.IsLegalPlayerMove(move))
+ return move;
+
+ Console.WriteLine("ILLEGAL MOVE");
+ }
+}
+
+void ComputerTurn()
+{
+ var moves = game.ComputerTurn();
+ string movesString = string.Join(",", moves);
+
+ Console.WriteLine($"MY MOVE IS {movesString}");
+}
+
+string Tab(int n) => new(' ', n);
\ No newline at end of file
diff --git a/04_Awari/csharp/csharp.csproj b/04_Awari/csharp/csharp.csproj
new file mode 100644
index 00000000..6bf2a525
--- /dev/null
+++ b/04_Awari/csharp/csharp.csproj
@@ -0,0 +1,11 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+ Awari
+
+
+
diff --git a/05_Bagels/perl/bagels.pl b/05_Bagels/perl/bagels.pl
new file mode 100755
index 00000000..739ded0e
--- /dev/null
+++ b/05_Bagels/perl/bagels.pl
@@ -0,0 +1,195 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+# global variable declaration (just the user's score)
+my($Y) = 0;
+
+
+# yes_input is a subroutine that returns a true value
+# if the first character of the user's input from STDIN
+# is a 'Y' (checking case-insensitively via regex)
+sub yes_input {
+ chomp(my $A = );
+ return $A =~ m/^Y/i;
+}
+
+# Main code starts here.
+
+print ' 'x32; print "Bagels\n";
+print ' 'x14; print "Creative Computing Morristown, New Jersey\n\n";
+
+# Provide instructions if requested
+print "Would you like the rules (yes or no)? ";
+if (yes_input()) {
+
+ # Print out the instructions using a here doc
+ # (useful for large blocks of text)
+ print <);
+
+ # Use a regex to check if the user entered three digits,
+ # and complain if they did not.
+ if ($A !~ m{^(\d)(\d)(\d)$}) {
+ print "What?\n";
+ # Program execution will now pass through the rest
+ # of the logic below and loop back to the start
+ # of the CHECK loop.
+ } else {
+
+ # As a side effect of the regex match above, the
+ # $1, $2, and $3 variables are each of the digits
+ # of the user's guess. Perl treats numbers and
+ # strings interchangably, so we will not have to
+ # use the ASC() conversion functions required
+ # by the BASIC program.
+ my @B = ($1,$2,$3);
+
+ # Check for duplicate digits in the user's guess
+ if ($B[0] == $B[1] || $B[0] == $B[2] || $B[1] == $B[2]) {
+ print "Oh, I forgot to tell you that the number I have in mind\n";
+ print "has no two digits the same.\n";
+ # Again, no further action is required here
+ # because we want to loop back to the start
+ # of the CHECK loop.
+ } else {
+
+ # This code block is the actual game logic, so
+ # it's executed only if the user's input has
+ # passed all the above checks.
+ my($C,$D);
+ $C = 0; $D = 0;
+
+ # As a replacement for the original BASIC logic,
+ # this for loop works over an anonymous array of
+ # pairs of digits to compare the computer's and
+ # the user's digits to see how many similar ones
+ # there are. Keep in mind that Perl arrays are
+ # zero-indexed, so we're comparing items numbered
+ # 0, 1, and 2, instead of 1, 2, and 3 in BASIC.
+
+ for my $PAIR ( [0,1], [1,0], [1,2], [2,1], [0,2], [2,0] ) {
+ if ($A[$PAIR->[0]] == $B[$PAIR->[1]]) {
+ ++$C;
+ }
+ }
+
+ # Check for digits that are correctly guessed
+ for my $i (0..2) {
+ if ($A[$i] == $B[$i]) {
+ ++$D;
+ }
+ }
+
+ # If the user guessed all 3 digits they get
+ # a point, and the 'PLAY' loop is restarted
+ # (see the 'continue' loop below)
+ if ($D == 3) {
+ print "You got it!!!\n\n";
+ ++$Y;
+ next PLAY;
+ }
+
+ # Print out the clues. The 'x' operator
+ # prints out the string the indicated number
+ # of times. The "BAGELS" line uses Perl's
+ # ternary operator to print the word if
+ # the expression ($C + $D) is equal to 0.
+
+ printf("%s%s%s\n",
+ "PICO " x$C,
+ "FERMI "x$D,
+ ($C+$D==0 ? "BAGELS" : '')
+ );
+
+ # Program execution leaves the CHECK loop and
+ # goes to the next iteration of the $i loop.
+ last CHECK;
+
+ } # end of game logic else block
+ } # end of regex match else block
+
+ # If program execution reaches this particular point,
+ # then the user's input has not been accepted (the
+ # only ways out of this loop are the "next PLAY" statement
+ # when the user wins, and the "last CHECK" statement
+ # when the user's input is successfully parsed).
+ # So the program execution goes back to the top of the
+ # CHECK loop, printing the request for user input
+ # again.
+
+ } # end of CHECK loop
+
+ # This location is reached by the "last CHECK" statement,
+ # and it's another execution of the $i loop.
+
+ } # end of $i loop
+
+ # If program execution reaches here, the user has guessed 20
+ # times and not won.
+
+ print "Oh well.\n";
+ printf("That's twenty guesses. My number was %s\n", join('',@A));
+
+} # end of the PLAY loop
+
+# This 'continue' block is executed before the conditional part of the
+# PLAY loop is evaluated, so we can ask if the user wants another game
+# (i.e., if we should restart the PLAY loop).
+
+continue {
+
+ # This 'continue' loop is reached either when the PLAY loop has completed
+ # or via the 'next PLAY' statement when the user wins a game. In either
+ # case we ask if the player wants to go again, and use the 'last'
+ # statement to exit the loop if the response is not yes.
+ print "Play again (yes or no) ? ";
+ last unless yes_input();
+}
+
+# And as in the original BASIC program, print out
+# the user's score only if it is > 0.
+printf("A %d point bagels buff!\n", $Y) if $Y > 0;
+print "Hope you had fun. Bye.\n";
diff --git a/22_Change/csharp/Change.csproj b/22_Change/csharp/Change.csproj
new file mode 100644
index 00000000..1d2d39a9
--- /dev/null
+++ b/22_Change/csharp/Change.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ net5.0
+
+
+
diff --git a/22_Change/csharp/Change.sln b/22_Change/csharp/Change.sln
new file mode 100644
index 00000000..c0f2e5e8
--- /dev/null
+++ b/22_Change/csharp/Change.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.810.16
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Change", "Change.csproj", "{AE094667-8496-4ECF-8B42-B1648EE26073}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {AE094667-8496-4ECF-8B42-B1648EE26073}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AE094667-8496-4ECF-8B42-B1648EE26073}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AE094667-8496-4ECF-8B42-B1648EE26073}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AE094667-8496-4ECF-8B42-B1648EE26073}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {65684CBD-CD74-46AF-8E9E-0F69DCF72697}
+ EndGlobalSection
+EndGlobal
diff --git a/22_Change/csharp/Program.cs b/22_Change/csharp/Program.cs
new file mode 100644
index 00000000..12804731
--- /dev/null
+++ b/22_Change/csharp/Program.cs
@@ -0,0 +1,129 @@
+using System;
+
+namespace Change
+{
+ class Program
+ {
+ ///
+ /// Prints header.
+ ///
+ static void Header()
+ {
+ Console.WriteLine("Change".PadLeft(33));
+ Console.WriteLine("Creative Computing Morristown, New Jersey".PadLeft(15));
+ Console.WriteLine();
+ Console.WriteLine();
+ Console.WriteLine();
+ Console.WriteLine("I, your friendly microcomputer, will determine\n"
+ + "the correct change for items costing up to $100.");
+ Console.WriteLine();
+ Console.WriteLine();
+ }
+
+ ///
+ /// Gets user input for price and payment.
+ ///
+ ///
+ /// False if any input can't be parsed to double. Price and payment returned would be 0.
+ /// True if it was possible to parse inputs into doubles. Price and payment returned
+ /// would be as provided by the user.
+ ///
+ static (bool status, double price, double payment) GetInput()
+ {
+ Console.Write("Cost of item? ");
+ var priceString = Console.ReadLine();
+ if (!double.TryParse(priceString, out double price))
+ {
+ Console.WriteLine($"{priceString} isn't a number!");
+ return (false, 0, 0);
+ }
+
+ Console.Write("Amount of payment? ");
+ var paymentString = Console.ReadLine();
+ if (!double.TryParse(paymentString, out double payment))
+ {
+ Console.WriteLine($"{paymentString} isn't a number!");
+ return (false, 0, 0);
+ }
+
+ return (true, price, payment);
+ }
+
+ ///
+ /// Prints bills and coins for given change.
+ ///
+ ///
+ static void PrintChange(double change)
+ {
+ var tens = (int)(change / 10);
+ if (tens > 0)
+ Console.WriteLine($"{tens} ten dollar bill(s)");
+
+ var temp = change - (tens * 10);
+ var fives = (int)(temp / 5);
+ if (fives > 0)
+ Console.WriteLine($"{fives} five dollar bill(s)");
+
+ temp -= fives * 5;
+ var ones = (int)temp;
+ if (ones > 0)
+ Console.WriteLine($"{ones} one dollar bill(s)");
+
+ temp -= ones;
+ var cents = temp * 100;
+ var half = (int)(cents / 50);
+ if (half > 0)
+ Console.WriteLine($"{half} one half dollar(s)");
+
+ temp = cents - (half * 50);
+ var quarters = (int)(temp / 25);
+ if (quarters > 0)
+ Console.WriteLine($"{quarters} quarter(s)");
+
+ temp -= quarters * 25;
+ var dimes = (int)(temp / 10);
+ if (dimes > 0)
+ Console.WriteLine($"{dimes} dime(s)");
+
+ temp -= dimes * 10;
+ var nickels = (int)(temp / 5);
+ if (nickels > 0)
+ Console.WriteLine($"{nickels} nickel(s)");
+
+ temp -= nickels * 5;
+ var pennies = (int)(temp + 0.5);
+ if (pennies > 0)
+ Console.WriteLine($"{pennies} penny(s)");
+ }
+
+ static void Main(string[] args)
+ {
+ Header();
+
+ while (true)
+ {
+ (bool result, double price, double payment) = GetInput();
+ if (!result)
+ continue;
+
+ var change = payment - price;
+ if (change == 0)
+ {
+ Console.WriteLine("Correct amount, thank you!");
+ continue;
+ }
+
+ if (change < 0)
+ {
+ Console.WriteLine($"Sorry, you have short-changed me ${price - payment:N2}!");
+ continue;
+ }
+
+ Console.WriteLine($"Your change ${change:N2}");
+ PrintChange(change);
+ Console.WriteLine("Thank you, come again!");
+ Console.WriteLine();
+ }
+ }
+ }
+}
diff --git a/29_Craps/python/craps.py b/29_Craps/python/craps.py
new file mode 100644
index 00000000..38faeed3
--- /dev/null
+++ b/29_Craps/python/craps.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+"""This game simulates the games of craps played according to standard Nevada craps table rules.
+
+That is:
+
+1. A 7 or 11 on the first roll wins
+2. A 2, 3, or 12 on the first roll loses
+3. Any other number rolled becomes your "point." You continue to roll; if you get your point you win. If you
+ roll a 7, you lose and the dice change hands when this happens.
+
+This version of craps was modified by Steve North of Creative Computing. It is based on an original which
+appeared one day one a computer at DEC.
+"""
+from random import randint
+
+
+def throw_dice():
+ return randint(1, 6) + randint(1, 6)
+
+
+print(" " * 33 + "Craps")
+print(" " * 15 + "Creative Computing Morristown, New Jersey")
+print()
+print()
+print()
+
+winnings = 0
+print("2,3,12 are losers; 4,5,6,8,9,10 are points; 7,11 are natural winners.")
+
+play_again = True
+while play_again:
+ wager = int(input("Input the amount of your wager: "))
+
+ print("I will now throw the dice")
+ roll_1 = throw_dice()
+
+ if roll_1 in [7, 11]:
+ print(f"{roll_1} - natural.... a winner!!!!")
+ print(f"{roll_1} pays even money, you win {wager} dollars")
+ winnings += wager
+ elif roll_1 == 2:
+ print(f"{roll_1} - snake eyes.... you lose.")
+ print(f"You lose {wager} dollars")
+ winnings -= wager
+ elif roll_1 in [3, 12]:
+ print(f"{roll_1} - craps.... you lose.")
+ print(f"You lose {wager} dollars")
+ winnings -= wager
+ else:
+ print(f"{roll_1} is the point. I will roll again")
+ roll_2 = 0
+ while roll_2 not in [roll_1, 7]:
+ roll_2 = throw_dice()
+ if roll_2 == 7:
+ print(f"{roll_2} - craps. You lose.")
+ print(f"You lose $ {wager}")
+ winnings -= wager
+ elif roll_2 == roll_1:
+ print(f"{roll_1} - a winner.........congrats!!!!!!!!")
+ print(f"{roll_1} at 2 to 1 odds pays you...let me see... {2 * wager} dollars")
+ winnings += 2 * wager
+ else:
+ print(f"{roll_2} - no point. I will roll again")
+
+ m = input(" If you want to play again print 5 if not print 2: ")
+ if winnings < 0:
+ print(f"You are now under ${-winnings}")
+ elif winnings > 0:
+ print(f"You are now ahead ${winnings}")
+ else:
+ print("You are now even at 0")
+ play_again = (m == "5")
+
+if winnings < 0:
+ print(f"Too bad, you are in the hole. Come again.")
+elif winnings > 0:
+ print(f"Congratulations---you came out a winner. Come again.")
+else:
+ print(f"Congratulations---you came out even, not bad for an amateur")
diff --git a/31_Depth_Charge/ruby/.editorconfig b/31_Depth_Charge/ruby/.editorconfig
new file mode 100644
index 00000000..9d7e93d0
--- /dev/null
+++ b/31_Depth_Charge/ruby/.editorconfig
@@ -0,0 +1,69 @@
+# EditorConfig is awesome: https://EditorConfig.org
+# .editorconfig
+
+# Please see doc/developer_notes.md
+# If you find anything egregious or missing, please consider submitting a pull request
+# to https://github.com/theias/ias_package_shell
+
+
+# top-most EditorConfig file
+root = true
+
+# Sensible defaults for everything
+[*]
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
+
+# JavaScript
+[**.js]
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+
+# Ruby
+[**.rb]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+
+# Python
+[**.py]
+charset = utf-8
+indent_style = space
+indent_size = 4
+insert_final_newline = true
+
+# Perl
+[**.pl]
+charset = utf-8
+insert_final_newline = true
+[**.pm]
+charset = utf-8
+insert_final_newline = true
+
+# PHP
+[**.php]
+charset = utf-8
+indent_size = 4
+indent_style = space
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+# Makefiles
+[Makefile]
+indent_style = tab
+
+[**.gmk]
+indent_style = tab
+
+# Configuration Files
+# Matches the exact files either package.json or .travis.yml
+[{package.json,.travis.yml}]
+indent_style = space
+indent_size = 2
+
+# Diff files
+[*.{diff,patch}]
+trim_trailing_whitespace = false
diff --git a/31_Depth_Charge/ruby/depthcharge.rb b/31_Depth_Charge/ruby/depthcharge.rb
new file mode 100755
index 00000000..5ba36ba6
--- /dev/null
+++ b/31_Depth_Charge/ruby/depthcharge.rb
@@ -0,0 +1,211 @@
+#!/usr/bin/ruby
+
+class DepthCharge
+
+ def run_game
+ output_title()
+ while true
+ printf("----------\n")
+ print_instructions()
+ setup_game()
+ printf("\n")
+ game_loop()
+ break if ! get_input_another_game()
+ end
+
+ # 420 PRINT "OK. HOPE YOU ENJOYED YOURSELF." : GOTO 600
+ printf("OK. HOPE YOU ENJOYED YOURSELF.\n")
+ end
+
+ def output_title
+ printf("--- DEPTH CHARGE ---\n")
+ printf("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n")
+ printf("\n")
+ end
+
+ def get_input_y_or_n(message)
+ while true
+ print(message)
+
+ value = gets.chomp
+
+ if (value == 'Y' || value == 'y')
+ return true
+ elsif value == 'N' || value == 'n'
+ return false
+ end
+
+ printf("PLEASE ENTER Y/y OR N/n...\n\n")
+ end
+ end
+
+ def get_input_positive_integer(message)
+
+ while true
+ print(message)
+ value = gets.chomp
+ if (value == 'd')
+ debug_game()
+ next
+ end
+
+ the_input = Integer(value) rescue nil
+
+ if the_input == nil || the_input < 0
+ printf("PLEASE ENTER A POSITIVE NUMBER\n\n")
+ next
+
+ end
+
+ return the_input
+ end
+ end
+
+ def get_search_area_dimension
+ # 20 INPUT "DIMENSION OF SEARCH AREA";G: PRINT
+ @search_area_dimension = get_input_positive_integer("DIMENSION OF SEARCH AREA: ")
+ # 30 N=INT(LOG(G)/LOG(2))+1
+
+ @num_tries = Integer(
+ Math.log(@search_area_dimension)/Math.log(2)
+ )
+
+ end
+
+ def print_instructions
+ # 40 PRINT "YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER"
+ # 50 PRINT "AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR"
+ # 60 PRINT "MISSION IS TO DESTROY IT. YOU HAVE";N;"SHOTS."
+ # 70 PRINT "SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A"
+ # 80 PRINT "TRIO OF NUMBERS -- THE FIRST TWO ARE THE"
+ # 90 PRINT "SURFACE COORDINATES; THE THIRD IS THE DEPTH."
+ # 100 PRINT : PRINT "GOOD LUCK !": PRINT
+ printf( <<~INSTRUCTIONS
+YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER
+AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR
+MISSION IS TO DESTROY IT.
+
+SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A
+TRIO OF NUMBERS -- THE FIRST TWO ARE THE
+SURFACE COORDINATES (X, Y):
+ WEST < X < EAST
+ SOUTH < Y < NORTH
+
+THE THIRD IS THE DEPTH (Z):
+ SHALLOW < Z < DEEP
+
+GOOD LUCK !
+
+ INSTRUCTIONS
+ )
+ end
+
+ def debug_game
+ printf("@enemy_x: %d\n", @enemy_x)
+ printf("@enemy_y: %d\n", @enemy_y)
+ printf("@enemy_z: %d\n", @enemy_z)
+ printf("@num_tries: %d\n", @num_tries)
+ printf("@trial: %d\n", @trial)
+ printf("\n")
+ end
+
+ def setup_game
+ get_search_area_dimension()
+ setup_enemy()
+ end
+
+ def setup_enemy
+ # 110 A=INT(G*RND(1)) : B=INT(G*RND(1)) : C=INT(G*RND(1))
+ @enemy_x = rand(1..@search_area_dimension)
+ @enemy_y = rand(1..@search_area_dimension)
+ @enemy_z = rand(1..@search_area_dimension)
+ end
+
+ def game_loop
+ # 120 FOR D=1 TO N : PRINT : PRINT "TRIAL #";D; : INPUT X,Y,Z
+ for @trial in 1..@num_tries do
+ output_game_status()
+
+ @shot_x = get_input_positive_integer("X: ")
+ @shot_y = get_input_positive_integer("Y: ")
+ @shot_z = get_input_positive_integer("Z: ")
+
+ # 130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300
+ if (
+ (@enemy_x - @shot_x).abs \
+ + (@enemy_y - @shot_y).abs \
+ + (@enemy_z - @shot_z).abs \
+ == 0
+ )
+ you_win()
+ return
+ else
+ # 140 GOSUB 500 : PRINT : NEXT D
+ missed_shot()
+ end
+ end
+
+ printf("\n")
+
+ you_lose()
+
+ end
+
+ def output_game_status
+ printf("YOU HAVE %d SHOTS REMAINING.\n", @num_tries - @trial + 1)
+ printf("TRIAL \#%d\n", @trial)
+ end
+ def you_win
+ printf("B O O M ! ! YOU FOUND IT IN %d TRIES!\n\n", @trial )
+ end
+ def missed_shot
+ missed_directions = []
+
+ # 530 IF X>A THEN PRINT "EAST";
+ # 540 IF X @enemy_x
+ missed_directions.push('TOO FAR EAST')
+ elsif @shot_x < @enemy_x
+ missed_directions.push('TOO FAR WEST')
+ end
+
+ # 510 IF Y>B THEN PRINT "NORTH";
+ # 520 IF Y @enemy_y
+ missed_directions.push('TOO FAR NORTH')
+ elsif @shot_y < @enemy_y
+ missed_directions.push('TOO FAR SOUTH')
+ end
+
+ # 560 IF Z>C THEN PRINT " TOO LOW."
+ # 570 IF Z @enemy_z
+ missed_directions.push('TOO DEEP')
+ elsif @shot_z < @enemy_z
+ missed_directions.push('TOO SHALLOW')
+ end
+
+ # 500 PRINT "SONAR REPORTS SHOT WAS ";
+ printf("SONAR REPORTS SHOT WAS: \n")
+ printf("%s\n", "\t" + missed_directions.join("\n\t"))
+ # 550 IF Y<>B OR X<>A THEN PRINT " AND";
+ # 590 RETURN
+ end
+
+ def you_lose
+ # You took too long!
+ printf("YOU HAVE BEEN TORPEDOED! ABANDON SHIP!\n")
+ printf("THE SUBMARINE WAS AT %d %d %d\n", @enemy_x, @enemy_y, @enemy_z)
+
+ end
+
+ def get_input_another_game
+ # 400 PRINT : PRINT: INPUT "ANOTHER GAME (Y OR N)";A$
+ return get_input_y_or_n("ANOTHER GAME (Y OR N): ")
+ # 410 IF A$="Y" THEN 100
+ end
+end
+
+game = DepthCharge.new
+game.run_game()
diff --git a/36_Flip_Flop/python/flipflop.py b/36_Flip_Flop/python/flipflop.py
new file mode 100644
index 00000000..9b6e2323
--- /dev/null
+++ b/36_Flip_Flop/python/flipflop.py
@@ -0,0 +1,129 @@
+# Flip Flop
+#
+# The object of this game is to change a row of ten X's
+# X X X X X X X X X X
+# to a row of ten O's:
+# O O O O O O O O O O
+# by typing in a number corresponding
+# to the position of an "X" in the line. On
+# some numbers one position will
+# change while on other numbers, two
+# will change. For example, inputting a 3
+# may reverse the X and O in position 3,
+# but it might possibly reverse some
+# other position too! You ought to be able
+# to change all 10 in 12 or fewer
+# moves. Can you figure out a good win-
+# ning strategy?
+# To reset the line to all X's (same
+# game), type 0 (zero). To start a new
+# game at any point, type 11.
+# The original author of this game was
+# Michael Kass of New Hyde Park, New
+# York.
+import random
+import math
+from typing import Callable, List, Tuple
+
+flip_dict = {"X": "O", "O": "X"}
+
+
+def flip_bits(
+ row: List[str], m: int, n: int, r_function: Callable[[int], float]
+) -> Tuple[List[str], int]:
+ """
+ Function that flips the positions at the computed steps
+ """
+ while m == n:
+ r = r_function(n)
+ n = r - int(math.floor(r))
+ n = int(10 * n)
+ if row[n] == "X":
+ row[n] = "O"
+ break
+ elif row[n] == "O":
+ row[n] = "X"
+ return row, n
+
+
+def print_instructions():
+ print(" " * 32 + "FLIPFLOP")
+ print(" " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
+ print("\n" * 2)
+ print("THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\n")
+ print("X X X X X X X X X X\n")
+ print("TO THIS:\n")
+ print("O O O O O O O O O O\n")
+ print("BY TYPING TH NUMBER CORRESPONDING TO THE POSITION OF THE")
+ print("LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON")
+ print("OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0")
+ print("(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE ")
+ print("11 (ELEVEN).\n")
+
+
+def main():
+ q = random.random()
+
+ print("HERE IS THE STARTING LINE OF X'S.\n")
+ # We add an extra 0-th item because this sometimes is set to something
+ # but we never check what it is for completion of the puzzle
+ row = [""] + ["X"] * 10
+ counter_turns = 0
+ n = -1
+ legal_move = True
+ while row[1:] != ["O"] * 10:
+ if legal_move:
+ print(" ".join([str(i) for i in range(1, 11)]))
+ print(" ".join(row[1:]) + "\n")
+ m = input("INPUT THE NUMBER\n")
+ try:
+ m = int(m)
+ if m > 11 or m < 0:
+ raise ValueError()
+ except ValueError:
+ print("ILLEGAL ENTRY--TRY AGAIN")
+ legal_move = False
+ continue
+ legal_move = True
+ if m == 11:
+ # completely reset the puzzle
+ counter_turns = 0
+ row = [""] + ["X"] * 10
+ q = random.random()
+ continue
+ elif m == 0:
+ # reset the board, but not the counter or the random number
+ row = [""] + ["X"] * 10
+ elif m == n:
+ row[n] = flip_dict[row[n]]
+ r_function = lambda n_t: 0.592 * (1 / math.tan(q / n_t + q)) / math.sin(
+ n_t * 2 + q
+ ) - math.cos(n_t)
+ row, n = flip_bits(row, m, n, r_function)
+ else:
+ n = m
+ row[n] = flip_dict[row[n]]
+ r_function = lambda n_t: (
+ math.tan(q + n_t / q - n_t)
+ - math.sin(n_t * 2 + q)
+ + 336 * math.sin(8 * n_t)
+ )
+ row, n = flip_bits(row, m, n, r_function)
+
+ counter_turns += 1
+ print()
+
+ if counter_turns <= 12:
+ print(f"VERY GOOD. YOU GUESSED IT IN ONLY {counter_turns} GUESSES.")
+ else:
+ print(f"TRY HARDER NEXT TIME. IT TOOK YOU {counter_turns} GUESSES.")
+ return
+
+
+if __name__ == "__main__":
+ print_instructions()
+
+ another = ""
+ while another != "NO":
+ main()
+ another = input("DO YOU WANT TO TRY ANOTHER PUZZLE\n")
diff --git a/45_Hello/perl/hello.pl b/45_Hello/perl/hello.pl
new file mode 100644
index 00000000..53590595
--- /dev/null
+++ b/45_Hello/perl/hello.pl
@@ -0,0 +1,136 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+print ' ' x 33 . "HELLO\n";
+print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+
+print "HELLO. MY NAME IS CREATIVE COMPUTER.\n\n\n";
+print "WHAT'S YOUR NAME?\n";
+chomp( my $N = uc );
+
+print "\nHI THERE, $N, ARE YOU ENJOYING YOURSELF HERE?\n";
+
+GREET:
+{
+ chomp( my $B = uc );
+ print "\n";
+
+ if ( $B eq 'YES' ) {
+ print "I'M GLAD TO HEAR THAT, $N.\n\n";
+ }
+ elsif ( $B eq 'NO' ) {
+ print "OH, I'M SORRY TO HEAR THAT, $N. MAYBE WE CAN\n";
+ print "BRIGHTEN UP YOUR VISIT A BIT.\n";
+ }
+ else {
+ print "$N, I DON'T UNDERSTAND YOUR ANSWER OF '$B'.\n";
+ print "PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE?\n";
+ redo GREET;
+ }
+}
+
+print "\nSAY, $N, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\n";
+print "THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO\n";
+print "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)?\n";
+
+ADVICE:
+{
+ chomp( my $C = uc );
+ print "\n";
+
+ if ( $C eq 'SEX' ) {
+ print "IS YOUR PROBLEM TOO MUCH OR TOO LITTLE?\n";
+
+ SEX:
+ {
+ chomp( my $D = uc );
+ print "\n";
+
+ if ( $D eq 'TOO MUCH' ) {
+ print "YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!\n";
+ print "IF IT BOTHERS YOU, $N, TAKE A COLD SHOWER.\n";
+ }
+ elsif ( $D eq 'TOO LITTLE' ) {
+ print "WHY ARE YOU HERE IN SUFFERN, $N? YOU SHOULD BE\n";
+ print "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\n";
+ print "REAL ACTION.\n";
+ }
+ else {
+ print "DON'T GET ALL SHOOK, $N, JUST ANSWER THE QUESTION\n";
+ print "WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT?\n";
+ redo SEX;
+ }
+ }
+ }
+ elsif ( $C eq 'HEALTH' ) {
+ print "MY ADVICE TO YOU $N IS:\n";
+ print " 1. TAKE TWO ASPRIN\n";
+ print " 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\n";
+ print " 3. GO TO BED (ALONE)\n";
+ }
+ elsif ( $C eq 'MONEY' ) {
+ print "SORRY, $N, I'M BROKE TOO. WHY DON'T YOU SELL\n";
+ print "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\n";
+ print "SO YOU WON'T NEED SO MUCH MONEY?\n";
+ }
+ elsif ( $C eq 'JOB' ) {
+ print "I CAN SYMPATHIZE WITH YOU $N. I HAVE TO WORK\n";
+ print "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\n";
+ print "REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, $N,\n";
+ print "IS TO OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.\n";
+ }
+ else {
+ print "OH, $N, YOUR ANSWER OF '$C' IS GREEK TO ME.\n";
+ }
+
+ MORE:
+ {
+ print "\nANY MORE PROBLEMS YOU WANT SOLVED, $N?\n";
+ chomp( my $E = uc );
+ print "\n";
+
+ if ( $E eq 'YES' ) {
+ print "WHAT KIND (SEX, MONEY, HEALTH, JOB)?\n";
+ redo ADVICE;
+ }
+ elsif ( $E eq 'NO' ) {
+ print "\nTHAT WILL BE \$5.00 FOR THE ADVICE, $N.\n";
+ print "PLEASE LEAVE THE MONEY ON THE TERMINAL.\n";
+ }
+ else {
+ print "JUST A SIMPLE 'YES' OR 'NO' PLEASE, $N.\n";
+ redo MORE;
+ }
+ }
+
+ sleep 2;
+ print "\n\n\n";
+
+ MONEY:
+ {
+ print "DID YOU LEAVE THE MONEY?\n";
+ chomp( my $G = uc );
+ print "\n";
+
+ if ( $G eq 'YES' ) {
+ print "HEY, $N??? YOU LEFT NO MONEY AT ALL!\n";
+ print "YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\n";
+ print "\nWHAT A RIP OFF, $N!!!\n\n";
+ }
+ elsif ( $G eq 'NO' ) {
+ print "THAT'S HONEST, $N, BUT HOW DO YOU EXPECT\n";
+ print "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\n";
+ print "DON'T PAY THEIR BILLS?\n";
+ }
+ else {
+ print "YOUR ANSWER OF '$G' CONFUSES ME, $N.\n";
+ print "PLEASE RESPOND WITH 'YES' OR 'NO'.\n";
+ redo MONEY;
+ }
+
+ print "\nTAKE A WALK, $N.\n\n\n";
+ }
+}
diff --git a/90_Tower/python/tower_test.py b/90_Tower/python/tower_test.py
new file mode 100644
index 00000000..a7023a0f
--- /dev/null
+++ b/90_Tower/python/tower_test.py
@@ -0,0 +1,49 @@
+import unittest
+import tower
+
+class MyTestCase(unittest.TestCase):
+ def test_something(self):
+ t = tower.Tower()
+ self.assertTrue(t.empty())
+
+ d = tower.Disk(3)
+ t.add(d)
+ self.assertFalse(t.empty())
+
+ d5 = tower.Disk(5)
+ self.assertRaises(Exception, t.add, d5)
+ self.assertFalse(t.empty())
+
+ def test_oksize(self):
+ t = tower.Tower()
+ self.assertTrue(t.empty())
+
+ d5 = tower.Disk(5)
+ t.add(d5)
+ self.assertFalse(t.empty())
+
+ d3 = tower.Disk(3)
+ t.add(d3)
+ self.assertFalse(t.empty())
+
+ self.assertEqual(t.top(), d3)
+ self.assertEqual(t.pop(), d3)
+ self.assertEqual(t.pop(), d5)
+
+ def test_game(self):
+ g = tower.Game()
+ self.assertEqual(g.moves(), 0)
+ self.assertFalse(g.winner())
+
+ def test_format(self):
+ t = tower.Tower()
+ d3 = tower.Disk(3)
+ d5 = tower.Disk(5)
+ t.add(d5)
+ t.add(d3)
+
+ f = t.vertical_format(6, 3)
+ self.assertEqual(f, [' ', '[ 3 ] ', '[ 5 ] '])
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/91_Train/csharp/Train/Train.sln b/91_Train/csharp/Train/Train.sln
new file mode 100644
index 00000000..7735a737
--- /dev/null
+++ b/91_Train/csharp/Train/Train.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31129.286
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrainGame", "Train\TrainGame.csproj", "{42617537-4E7C-4082-A17B-7F18DFA04C35}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrainTests", "..\TrainTests\TrainTests\TrainTests.csproj", "{7C740A47-99C6-44E1-BDEE-140086BCFE8B}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {42617537-4E7C-4082-A17B-7F18DFA04C35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {42617537-4E7C-4082-A17B-7F18DFA04C35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {42617537-4E7C-4082-A17B-7F18DFA04C35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {42617537-4E7C-4082-A17B-7F18DFA04C35}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7C740A47-99C6-44E1-BDEE-140086BCFE8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7C740A47-99C6-44E1-BDEE-140086BCFE8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7C740A47-99C6-44E1-BDEE-140086BCFE8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7C740A47-99C6-44E1-BDEE-140086BCFE8B}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {919F73B8-DE34-4992-9B05-E1FEC2D2F7C6}
+ EndGlobalSection
+EndGlobal
diff --git a/91_Train/csharp/Train/Train/TrainGame.cs b/91_Train/csharp/Train/Train/TrainGame.cs
new file mode 100644
index 00000000..98e0db68
--- /dev/null
+++ b/91_Train/csharp/Train/Train/TrainGame.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Linq;
+
+namespace Train
+{
+ public class TrainGame
+ {
+ private Random Rnd { get; } = new Random();
+ private readonly int ALLOWED_PERCENTAGE_DIFFERENCE = 5;
+
+ static void Main()
+ {
+ TrainGame train = new TrainGame();
+ train.GameLoop();
+ }
+
+ public void GameLoop()
+ {
+ DisplayIntroText();
+
+ do
+ {
+ PlayGame();
+ } while (TryAgain());
+ }
+
+ private void PlayGame()
+ {
+ int carSpeed = (int)GenerateRandomNumber(40, 25);
+ int timeDifference = (int)GenerateRandomNumber(5, 15);
+ int trainSpeed = (int)GenerateRandomNumber(20, 19);
+
+ Console.WriteLine($"A CAR TRAVELING {carSpeed} MPH CAN MAKE A CERTAIN TRIP IN");
+ Console.WriteLine($"{timeDifference} HOURS LESS THAN A TRAIN TRAVELING AT {trainSpeed} MPH");
+ Console.WriteLine("HOW LONG DOES THE TRIP TAKE BY CAR?");
+
+ double userInputCarJourneyDuration = double.Parse(Console.ReadLine());
+ double actualCarJourneyDuration = CalculateCarJourneyDuration(carSpeed, timeDifference, trainSpeed);
+ int percentageDifference = CalculatePercentageDifference(userInputCarJourneyDuration, actualCarJourneyDuration);
+
+ if (IsWithinAllowedDifference(percentageDifference, ALLOWED_PERCENTAGE_DIFFERENCE))
+ {
+ Console.WriteLine($"GOOD! ANSWER WITHIN {percentageDifference} PERCENT.");
+ }
+ else
+ {
+ Console.WriteLine($"SORRY. YOU WERE OFF BY {percentageDifference} PERCENT.");
+ }
+ Console.WriteLine($"CORRECT ANSWER IS {actualCarJourneyDuration} HOURS.");
+ }
+
+ public static bool IsWithinAllowedDifference(int percentageDifference, int allowedDifference)
+ {
+ return percentageDifference <= allowedDifference;
+ }
+
+ private static int CalculatePercentageDifference(double userInputCarJourneyDuration, double carJourneyDuration)
+ {
+ return (int)(Math.Abs((carJourneyDuration - userInputCarJourneyDuration) * 100 / userInputCarJourneyDuration) + .5);
+ }
+
+ public static double CalculateCarJourneyDuration(double carSpeed, double timeDifference, double trainSpeed)
+ {
+ return timeDifference * trainSpeed / (carSpeed - trainSpeed);
+ }
+
+ public double GenerateRandomNumber(int baseSpeed, int multiplier)
+ {
+ return multiplier * Rnd.NextDouble() + baseSpeed;
+ }
+
+ private bool TryAgain()
+ {
+ Console.WriteLine("ANOTHER PROBLEM (YES OR NO)? ");
+ return IsInputYes(Console.ReadLine());
+ }
+
+ public static bool IsInputYes(string consoleInput)
+ {
+ var options = new string[] { "Y", "YES" };
+ return options.Any(o => o.Equals(consoleInput, StringComparison.CurrentCultureIgnoreCase));
+ }
+
+ private void DisplayIntroText()
+ {
+ Console.WriteLine("TRAIN");
+ Console.WriteLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
+ Console.WriteLine();
+ Console.WriteLine("TIME - SPEED DISTANCE EXERCISE");
+ Console.WriteLine();
+ }
+ }
+}
diff --git a/91_Train/csharp/Train/Train/TrainGame.csproj b/91_Train/csharp/Train/Train/TrainGame.csproj
new file mode 100644
index 00000000..c73e0d16
--- /dev/null
+++ b/91_Train/csharp/Train/Train/TrainGame.csproj
@@ -0,0 +1,8 @@
+
+
+
+ Exe
+ netcoreapp3.1
+
+
+
diff --git a/91_Train/csharp/TrainTests/TrainTests/TrainGameTests.cs b/91_Train/csharp/TrainTests/TrainTests/TrainGameTests.cs
new file mode 100644
index 00000000..a9804283
--- /dev/null
+++ b/91_Train/csharp/TrainTests/TrainTests/TrainGameTests.cs
@@ -0,0 +1,53 @@
+using Train;
+using Xunit;
+
+namespace TrainTests
+{
+ public class TrainGameTests
+ {
+ [Fact]
+ public void MiniumRandomNumber()
+ {
+ TrainGame game = new TrainGame();
+ Assert.True(game.GenerateRandomNumber(10, 10) >= 10);
+ }
+
+ [Fact]
+ public void MaximumRandomNumber()
+ {
+ TrainGame game = new TrainGame();
+ Assert.True(game.GenerateRandomNumber(10, 10) <= 110);
+ }
+
+ [Fact]
+ public void IsInputYesWhenY()
+ {
+ Assert.True(TrainGame.IsInputYes("y"));
+ }
+
+ [Fact]
+ public void IsInputYesWhenNotY()
+ {
+ Assert.False(TrainGame.IsInputYes("a"));
+ }
+
+ [Fact]
+ public void CarDurationTest()
+ {
+ Assert.Equal(1, TrainGame.CalculateCarJourneyDuration(30, 1, 15) );
+ }
+
+ [Fact]
+ public void IsWithinAllowedDifference()
+ {
+ Assert.True(TrainGame.IsWithinAllowedDifference(5,5));
+ }
+
+
+ [Fact]
+ public void IsNotWithinAllowedDifference()
+ {
+ Assert.False(TrainGame.IsWithinAllowedDifference(6, 5));
+ }
+ }
+}
diff --git a/91_Train/csharp/TrainTests/TrainTests/TrainTests.csproj b/91_Train/csharp/TrainTests/TrainTests/TrainTests.csproj
new file mode 100644
index 00000000..a8de6dde
--- /dev/null
+++ b/91_Train/csharp/TrainTests/TrainTests/TrainTests.csproj
@@ -0,0 +1,26 @@
+
+
+
+ netcoreapp3.1
+
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/96_Word/perl/word.pl b/96_Word/perl/word.pl
new file mode 100755
index 00000000..5369cc71
--- /dev/null
+++ b/96_Word/perl/word.pl
@@ -0,0 +1,169 @@
+#!/usr/bin/env perl
+
+use 5.010; # To get 'state' and 'say'
+
+use strict; # Require explicit declaration of variables
+use warnings; # Enable optional compiler warnings
+
+use English; # Use more friendly names for Perl's magic variables
+use Term::ReadLine; # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+print <<'EOD';
+ WORD
+ Creative Computing Morristown, New Jersey
+
+
+
+I am thinking of a word -- you guess it. I will give you
+clues to help you get it. Good luck!!
+
+
+EOD
+
+# Read the content of __DATA__, remove the trailing newlines, and store
+# each line into @words. Stop at __END__, since Perl does not see this
+# as an end-of-file.
+my @words;
+while ( ) {
+ chomp;
+ last if $ARG eq '__END__';
+ push @words, lc $ARG; # Normalize case to lower.
+}
+
+# This loop represents an actual game. We execute it until the player
+# does something that makes us explicitly break out.
+while ( 1 ) {
+ print <<'EOD';
+
+
+You are starting a new game ...
+EOD
+
+ # Choose a random target word. The rand() function returns a number
+ # from 0 to its argument, and coerces its argument to a scalar. In
+ # scalar context, an array evaluates to the number of elements it
+ # contains.
+ my $target = $words[ rand @words ];
+
+ # We generalize the code by using the actual length of the target.
+ my $target_length = length $target;
+
+ my $count = 0; # Number of guesses
+
+ # Make an array of the individual letters in the target. We will
+ # iterate over this to determine matching letters.
+ my @target_array = split qr<>, $target;
+
+ # Make a hash of those letters. We will use this to determine common
+ # letters. Any true value will do for the value of the hash. By
+ # making use of this hash we avoid the nested loops of the original
+ # BASIC program.
+ my %target_hash = map { $ARG => 1 } @target_array;
+
+ # We keep prompting the player until we get a response that causes
+ # us to break out of the loop.
+ while ( 1 ) {
+
+ # Create the readline object. The state keyword means the
+ # variable is only initialized once, no matter how many times
+ # execution passes this point.
+ state $term = Term::ReadLine->new( 'word' );
+
+ # Read the next guess. A return of undef means end-of-file.
+ my $guess = $term->readline( "Guess a $target_length letter word: " );
+ exit unless defined $guess;
+
+ last if $guess eq '?'; # A question mark means we give up
+ if ( length( $guess ) != $target_length ) {
+ # Wrong length. Ask again.
+ say "You must guess a $target_length letter word. Try again.";
+ redo; # Redo the innermost loop
+ }
+
+ $guess = lc $guess; # Lower-case the guess
+ $count++; # Count another guess
+
+ if ( $guess eq $target ) {
+ # We guessed the word.
+ say "You have guessed the word. It took $count guesses!";
+ my $answer = $term->readline( 'Want to play again? [y/N]: ');
+ exit unless defined $guess; # End of file
+ exit unless $guess =~ m/ \A y /smxi;
+ last; # Exit the innermost loop.
+ }
+
+ my @common_letters; # Letters common to guess and target
+ my $match = '-' x length $target; # Assume no matches
+ my $inx = 0; # Iterator
+ foreach my $letter ( split qr<>, $guess ) {
+ if ( $target_hash{$letter} ) {
+ # If the letter is in the hash, it occurs in the target
+ push @common_letters, $letter;
+ # If it is at the current position in the target, it is
+ # an actual match.
+ $target_array[$inx] eq $letter
+ and substr $match, $inx, 1, $letter;
+ }
+ $inx++;
+ }
+
+ say 'There were ', scalar @common_letters,
+ ' matches and the common letters were... ', @common_letters;
+ say "From the exact letter matches, you know................ $match";
+ say '';
+ say q;
+ redo;
+ }
+
+}
+__DATA__
+dinky
+smoke
+water
+grass
+train
+might
+first
+candy
+champ
+would
+clump
+dopey
+__END__
+
+=head1 TITLE
+
+word.pl - Play the game 'word' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ word.pl
+
+=head1 DETAILS
+
+This Perl script is a port of C, which is the 96th entry in Basic
+Computer Games.
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :