mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2026-01-15 22:42:38 -08:00
Removed spaces from top-level directory names.
Spaces tend to cause annoyances in a Unix-style shell environment. This change fixes that.
This commit is contained in:
7
60_Mastermind/README.md
Normal file
7
60_Mastermind/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
### MasterMind
|
||||
|
||||
As published in Basic Computer Games (1978)
|
||||
https://www.atariarchives.org/basicgames/showpage.php?page=110
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
7
60_Mastermind/csharp/Game/Game.csproj
Normal file
7
60_Mastermind/csharp/Game/Game.csproj
Normal file
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
91
60_Mastermind/csharp/Game/src/Code.cs
Normal file
91
60_Mastermind/csharp/Game/src/Code.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a secret code in the game.
|
||||
/// </summary>
|
||||
public class Code
|
||||
{
|
||||
private readonly int[] m_colors;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Code class from the given set
|
||||
/// of positions.
|
||||
/// </summary>
|
||||
/// <param name="colors">
|
||||
/// Contains the color for each position.
|
||||
/// </param>
|
||||
public Code(IEnumerable<int> colors)
|
||||
{
|
||||
m_colors = colors.ToArray();
|
||||
if (m_colors.Length == 0)
|
||||
throw new ArgumentException("A code must contain at least one position");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares this code with the given code.
|
||||
/// </summary>
|
||||
/// <param name="other">
|
||||
/// The code to compare.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// A number of black pegs and a number of white pegs. The number
|
||||
/// of black pegs is the number of positions that contain the same
|
||||
/// color in both codes. The number of white pegs is the number of
|
||||
/// colors that appear in both codes, but in the wrong positions.
|
||||
/// </returns>
|
||||
public (int blacks, int whites) Compare(Code other)
|
||||
{
|
||||
// What follows is the O(N^2) from the original BASIC program
|
||||
// (where N is the number of positions in the code). Note that
|
||||
// there is an O(N) algorithm. (Finding it is left as an
|
||||
// exercise for the reader.)
|
||||
if (other.m_colors.Length != m_colors.Length)
|
||||
throw new ArgumentException("Only codes of the same length can be compared");
|
||||
|
||||
// Keeps track of which positions in the other code have already
|
||||
// been marked as exact or close matches.
|
||||
var consumed = new bool[m_colors.Length];
|
||||
|
||||
var blacks = 0;
|
||||
var whites = 0;
|
||||
|
||||
for (var i = 0; i < m_colors.Length; ++i)
|
||||
{
|
||||
if (m_colors[i] == other.m_colors[i])
|
||||
{
|
||||
++blacks;
|
||||
consumed[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if the current color appears elsewhere in the
|
||||
// other code. We must be careful not to consider
|
||||
// positions that are also exact matches.
|
||||
for (var j = 0; j < m_colors.Length; ++j)
|
||||
{
|
||||
if (!consumed[j] &&
|
||||
m_colors[i] == other.m_colors[j] &&
|
||||
m_colors[j] != other.m_colors[j])
|
||||
{
|
||||
++whites;
|
||||
consumed[j] = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (blacks, whites);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a string representation of the code.
|
||||
/// </summary>
|
||||
public override string ToString() =>
|
||||
new (m_colors.Select(index => Colors.List[index].ShortName).ToArray());
|
||||
}
|
||||
}
|
||||
92
60_Mastermind/csharp/Game/src/CodeFactory.cs
Normal file
92
60_Mastermind/csharp/Game/src/CodeFactory.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides methods for generating codes with a given number of positions
|
||||
/// and colors.
|
||||
/// </summary>
|
||||
public class CodeFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the number of colors in codes generated by this factory.
|
||||
/// </summary>
|
||||
public int Colors { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of positions in codes generated by this factory.
|
||||
/// </summary>
|
||||
public int Positions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of distinct codes that this factory can
|
||||
/// generate.
|
||||
/// </summary>
|
||||
public int Possibilities { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the CodeFactory class.
|
||||
/// </summary>
|
||||
/// <param name="positions">
|
||||
/// The number of positions.
|
||||
/// </param>
|
||||
/// <param name="colors">
|
||||
/// The number of colors.
|
||||
/// </param>
|
||||
public CodeFactory(int positions, int colors)
|
||||
{
|
||||
if (positions < 1)
|
||||
throw new ArgumentException("A code must contain at least one position");
|
||||
|
||||
if (colors < 1)
|
||||
throw new ArgumentException("A code must contain at least one color");
|
||||
|
||||
if (colors > Game.Colors.List.Length)
|
||||
throw new ArgumentException($"A code can contain no more than {Game.Colors.List.Length} colors");
|
||||
|
||||
Positions = positions;
|
||||
Colors = colors;
|
||||
Possibilities = (int)Math.Pow(colors, positions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a specified code.
|
||||
/// </summary>
|
||||
/// <param name="number">
|
||||
/// The number of the code to create from 0 to Possibilities - 1.
|
||||
/// </param>
|
||||
public Code Create(int number) =>
|
||||
EnumerateCodes().Skip(number).First();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a random code using the provided random number generator.
|
||||
/// </summary>
|
||||
/// <param name="random">
|
||||
/// The random number generator.
|
||||
/// </param>
|
||||
public Code Create(Random random) =>
|
||||
Create(random.Next(Possibilities));
|
||||
|
||||
/// <summary>
|
||||
/// Generates a collection of codes containing every code that this
|
||||
/// factory can create exactly once.
|
||||
/// </summary>
|
||||
public IEnumerable<Code> EnumerateCodes()
|
||||
{
|
||||
var current = new int[Positions];
|
||||
var position = default(int);
|
||||
|
||||
do
|
||||
{
|
||||
yield return new Code(current);
|
||||
|
||||
position = 0;
|
||||
while (position < Positions && ++current[position] == Colors)
|
||||
current[position++] = 0;
|
||||
}
|
||||
while (position < Positions);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
60_Mastermind/csharp/Game/src/ColorInfo.cs
Normal file
20
60_Mastermind/csharp/Game/src/ColorInfo.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores information about a color.
|
||||
/// </summary>
|
||||
public record ColorInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a single character that represents the color.
|
||||
/// </summary>
|
||||
public char ShortName { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the color's full name.
|
||||
/// </summary>
|
||||
public string LongName { get; init; } = String.Empty;
|
||||
}
|
||||
}
|
||||
20
60_Mastermind/csharp/Game/src/Colors.cs
Normal file
20
60_Mastermind/csharp/Game/src/Colors.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides information about the colors that can be used in codes.
|
||||
/// </summary>
|
||||
public static class Colors
|
||||
{
|
||||
public static readonly ColorInfo[] List = new[]
|
||||
{
|
||||
new ColorInfo { ShortName = 'B', LongName = "BLACK" },
|
||||
new ColorInfo { ShortName = 'W', LongName = "WHITE" },
|
||||
new ColorInfo { ShortName = 'R', LongName = "RED" },
|
||||
new ColorInfo { ShortName = 'G', LongName = "GREEN" },
|
||||
new ColorInfo { ShortName = 'O', LongName = "ORANGE" },
|
||||
new ColorInfo { ShortName = 'Y', LongName = "YELLOW" },
|
||||
new ColorInfo { ShortName = 'P', LongName = "PURPLE" },
|
||||
new ColorInfo { ShortName = 'T', LongName = "TAN" }
|
||||
};
|
||||
}
|
||||
}
|
||||
13
60_Mastermind/csharp/Game/src/Command.cs
Normal file
13
60_Mastermind/csharp/Game/src/Command.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumerates the different commands that the user can issue during
|
||||
/// the game.
|
||||
/// </summary>
|
||||
public enum Command
|
||||
{
|
||||
MakeGuess,
|
||||
ShowBoard,
|
||||
Quit
|
||||
}
|
||||
}
|
||||
175
60_Mastermind/csharp/Game/src/Controller.cs
Normal file
175
60_Mastermind/csharp/Game/src/Controller.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains functions for getting input from the end user.
|
||||
/// </summary>
|
||||
public static class Controller
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps the letters for each color to the integer value representing
|
||||
/// that color.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// We derive this map from the Colors list rather than defining the
|
||||
/// entries directly in order to keep all color related information
|
||||
/// in one place. (This makes it easier to change the color options
|
||||
/// later.)
|
||||
/// </remarks>
|
||||
private static ImmutableDictionary<char, int> ColorsByKey = Colors.List
|
||||
.Select((info, index) => (key: info.ShortName, index))
|
||||
.ToImmutableDictionary(entry => entry.key, entry => entry.index);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of colors to use in the secret code.
|
||||
/// </summary>
|
||||
public static int GetNumberOfColors()
|
||||
{
|
||||
var maximumColors = Colors.List.Length;
|
||||
var colors = 0;
|
||||
|
||||
while (colors < 1 || colors > maximumColors)
|
||||
{
|
||||
colors = GetInteger(View.PromptNumberOfColors);
|
||||
if (colors > maximumColors)
|
||||
View.NotifyTooManyColors(maximumColors);
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of positions in the secret code.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static int GetNumberOfPositions()
|
||||
{
|
||||
// Note: We should probably ensure that the user enters a sane
|
||||
// number of positions here. (Things go south pretty quickly
|
||||
// with a large number of positions.) But since the original
|
||||
// program did not, neither will we.
|
||||
return GetInteger(View.PromptNumberOfPositions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of rounds to play.
|
||||
/// </summary>
|
||||
public static int GetNumberOfRounds()
|
||||
{
|
||||
// Note: Silly numbers of rounds (like 0, or a negative number)
|
||||
// are harmless, but it would still make sense to validate.
|
||||
return GetInteger(View.PromptNumberOfRounds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a command from the user.
|
||||
/// </summary>
|
||||
/// <param name="moveNumber">
|
||||
/// The current move number.
|
||||
/// </param>
|
||||
/// <param name="positions">
|
||||
/// The number of code positions.
|
||||
/// </param>
|
||||
/// <param name="colors">
|
||||
/// The maximum number of code colors.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The entered command and guess (if applicable).
|
||||
/// </returns>
|
||||
public static (Command command, Code? guess) GetCommand(int moveNumber, int positions, int colors)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
View.PromptGuess (moveNumber);
|
||||
|
||||
var input = Console.ReadLine();
|
||||
if (input is null)
|
||||
Environment.Exit(0);
|
||||
|
||||
switch (input.ToUpperInvariant())
|
||||
{
|
||||
case "BOARD":
|
||||
return (Command.ShowBoard, null);
|
||||
case "QUIT":
|
||||
return (Command.Quit, null);
|
||||
default:
|
||||
if (input.Length != positions)
|
||||
View.NotifyBadNumberOfPositions();
|
||||
else
|
||||
if (input.FindFirstIndex(c => !TranslateColor(c).HasValue) is int invalidPosition)
|
||||
View.NotifyInvalidColor(input[invalidPosition]);
|
||||
else
|
||||
return (Command.MakeGuess, new Code(input.Select(c => TranslateColor(c)!.Value)));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Waits until the user indicates that he or she is ready to continue.
|
||||
/// </summary>
|
||||
public static void WaitUntilReady()
|
||||
{
|
||||
View.PromptReady();
|
||||
var input = Console.ReadLine();
|
||||
if (input is null)
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of blacks and whites for the given code from the
|
||||
/// user.
|
||||
/// </summary>
|
||||
public static (int blacks, int whites) GetBlacksWhites(Code code)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
View.PromptBlacksWhites(code);
|
||||
|
||||
var input = Console.ReadLine();
|
||||
if (input is null)
|
||||
Environment.Exit(0);
|
||||
|
||||
var parts = input.Split(',');
|
||||
|
||||
if (parts.Length != 2)
|
||||
View.PromptTwoValues();
|
||||
else
|
||||
if (!Int32.TryParse(parts[0], out var blacks) || !Int32.TryParse(parts[1], out var whites))
|
||||
View.PromptValidInteger();
|
||||
else
|
||||
return (blacks, whites);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an integer value from the user.
|
||||
/// </summary>
|
||||
private static int GetInteger(Action prompt)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
prompt();
|
||||
|
||||
var input = Console.ReadLine();
|
||||
if (input is null)
|
||||
Environment.Exit(0);
|
||||
|
||||
if (Int32.TryParse(input, out var result))
|
||||
return result;
|
||||
else
|
||||
View.PromptValidInteger();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Translates the given character into the corresponding color.
|
||||
/// </summary>
|
||||
private static int? TranslateColor(char c) =>
|
||||
ColorsByKey.TryGetValue(c, out var index) ? index : null;
|
||||
}
|
||||
}
|
||||
88
60_Mastermind/csharp/Game/src/EnumerableExtensions.cs
Normal file
88
60_Mastermind/csharp/Game/src/EnumerableExtensions.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides additional methods for the <see cref="IEnumerable{T}"/>
|
||||
/// interface.
|
||||
/// </summary>
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Cycles through the integer values in the range [0, count).
|
||||
/// </summary>
|
||||
/// <param name="start">
|
||||
/// The first value to return.
|
||||
/// </param>
|
||||
/// <param name="count">
|
||||
/// The number of values to return.
|
||||
/// </param>
|
||||
public static IEnumerable<int> Cycle(int start, int count)
|
||||
{
|
||||
if (count < 1)
|
||||
throw new ArgumentException("count must be at least 1");
|
||||
|
||||
if (start < 0 || start >= count)
|
||||
throw new ArgumentException("start must be in the range [0, count)");
|
||||
|
||||
for (var i = start; i < count; ++i)
|
||||
yield return i;
|
||||
|
||||
for (var i = 0; i < start; ++i)
|
||||
yield return i;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the index of the first item in the given sequence that
|
||||
/// satisfies the given predicate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// The type of elements in the sequence.
|
||||
/// </typeparam>
|
||||
/// <param name="source">
|
||||
/// The source sequence.
|
||||
/// </param>
|
||||
/// <param name="predicate">
|
||||
/// The predicate function.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The index of the first element in the source sequence for which
|
||||
/// predicate(element) is true. If there is no such element, return
|
||||
/// is null.
|
||||
/// </returns>
|
||||
public static int? FindFirstIndex<T>(this IEnumerable<T> source, Func<T, bool> predicate) =>
|
||||
source.Select((element, index) => predicate(element) ? index : default(int?))
|
||||
.FirstOrDefault(index => index.HasValue);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first item in the given sequence that matches the
|
||||
/// given predicate.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">
|
||||
/// The type of elements in the sequence.
|
||||
/// </typeparam>
|
||||
/// <param name="source">
|
||||
/// The source sequence.
|
||||
/// </param>
|
||||
/// <param name="predicate">
|
||||
/// The predicate to check against each element.
|
||||
/// </param>
|
||||
/// <param name="defaultValue">
|
||||
/// The value to return if no elements match the predicate.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The first item in the source sequence that matches the given
|
||||
/// predicate, or the provided default value if none do.
|
||||
/// </returns>
|
||||
public static T FirstOrDefault<T>(this IEnumerable<T> source, Func<T, bool> predicate, T defaultValue)
|
||||
{
|
||||
foreach (var element in source)
|
||||
if (predicate(element))
|
||||
return element;
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
173
60_Mastermind/csharp/Game/src/Program.cs
Normal file
173
60_Mastermind/csharp/Game/src/Program.cs
Normal file
@@ -0,0 +1,173 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
// MASTERMIND II
|
||||
// STEVE NORTH
|
||||
// CREATIVE COMPUTING
|
||||
// PO BOX 789-M MORRISTOWN NEW JERSEY 07960
|
||||
class Program
|
||||
{
|
||||
public const int MaximumGuesses = 10;
|
||||
|
||||
static void Main()
|
||||
{
|
||||
var (codeFactory, rounds) = StartGame();
|
||||
|
||||
var random = new Random();
|
||||
var humanScore = 0;
|
||||
var computerScore = 0;
|
||||
|
||||
for (var round = 1; round <= rounds; ++round)
|
||||
{
|
||||
View.ShowStartOfRound(round);
|
||||
|
||||
if (!HumanTakesTurn())
|
||||
return;
|
||||
|
||||
while (!ComputerTakesTurn())
|
||||
View.ShowInconsistentInformation();
|
||||
}
|
||||
|
||||
View.ShowScores(humanScore, computerScore, isFinal: true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the game start parameters from the user.
|
||||
/// </summary>
|
||||
(CodeFactory codeFactory, int rounds) StartGame()
|
||||
{
|
||||
View.ShowBanner();
|
||||
|
||||
var colors = Controller.GetNumberOfColors();
|
||||
var positions = Controller.GetNumberOfPositions();
|
||||
var rounds = Controller.GetNumberOfRounds();
|
||||
|
||||
var codeFactory = new CodeFactory(positions, colors);
|
||||
|
||||
View.ShowTotalPossibilities(codeFactory.Possibilities);
|
||||
View.ShowColorTable(codeFactory.Colors);
|
||||
|
||||
return (codeFactory, rounds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the human's turn.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// True if thue human completed his or her turn and false if
|
||||
/// he or she quit the game.
|
||||
/// </returns>
|
||||
bool HumanTakesTurn()
|
||||
{
|
||||
// Store a history of the human's guesses (used for the show
|
||||
// board command below).
|
||||
var history = new List<TurnResult>();
|
||||
var code = codeFactory.Create(random);
|
||||
var guessNumber = default(int);
|
||||
|
||||
for (guessNumber = 1; guessNumber <= MaximumGuesses; ++guessNumber)
|
||||
{
|
||||
var guess = default(Code);
|
||||
|
||||
while (guess is null)
|
||||
{
|
||||
switch (Controller.GetCommand(guessNumber, codeFactory.Positions, codeFactory.Colors))
|
||||
{
|
||||
case (Command.MakeGuess, Code input):
|
||||
guess = input;
|
||||
break;
|
||||
case (Command.ShowBoard, _):
|
||||
View.ShowBoard(history);
|
||||
break;
|
||||
case (Command.Quit, _):
|
||||
View.ShowQuitGame(code);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var (blacks, whites) = code.Compare(guess);
|
||||
if (blacks == codeFactory.Positions)
|
||||
break;
|
||||
|
||||
View.ShowResults(blacks, whites);
|
||||
|
||||
history.Add(new TurnResult(guess, blacks, whites));
|
||||
}
|
||||
|
||||
if (guessNumber <= MaximumGuesses)
|
||||
View.ShowHumanGuessedCode(guessNumber);
|
||||
else
|
||||
View.ShowHumanFailedToGuessCode(code);
|
||||
|
||||
humanScore += guessNumber;
|
||||
|
||||
View.ShowScores(humanScore, computerScore, isFinal: false);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes the computers turn.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// True if the computer completes its turn successfully and false
|
||||
/// if it does not (due to human error).
|
||||
/// </returns>
|
||||
bool ComputerTakesTurn()
|
||||
{
|
||||
var isCandidate = new bool[codeFactory.Possibilities];
|
||||
var guessNumber = default(int);
|
||||
|
||||
Array.Fill(isCandidate, true);
|
||||
|
||||
View.ShowComputerStartTurn();
|
||||
Controller.WaitUntilReady();
|
||||
|
||||
for (guessNumber = 1; guessNumber <= MaximumGuesses; ++guessNumber)
|
||||
{
|
||||
// Starting with a random code, cycle through codes until
|
||||
// we find one that is still a candidate solution. If
|
||||
// there are no remaining candidates, then it implies that
|
||||
// the user made an error in one or more responses.
|
||||
var codeNumber = EnumerableExtensions.Cycle(random.Next(codeFactory.Possibilities), codeFactory.Possibilities)
|
||||
.FirstOrDefault(i => isCandidate[i], -1);
|
||||
|
||||
if (codeNumber < 0)
|
||||
return false;
|
||||
|
||||
var guess = codeFactory.Create(codeNumber);
|
||||
|
||||
var (blacks, whites) = Controller.GetBlacksWhites(guess);
|
||||
if (blacks == codeFactory.Positions)
|
||||
break;
|
||||
|
||||
// Mark codes which are no longer potential solutions. We
|
||||
// know that the current guess yields the above number of
|
||||
// blacks and whites when compared to the solution, so any
|
||||
// code that yields a different number of blacks or whites
|
||||
// can't be the answer.
|
||||
foreach (var (candidate, index) in codeFactory.EnumerateCodes().Select((candidate, index) => (candidate, index)))
|
||||
{
|
||||
if (isCandidate[index])
|
||||
{
|
||||
var (candidateBlacks, candidateWhites) = guess.Compare(candidate);
|
||||
if (blacks != candidateBlacks || whites != candidateWhites)
|
||||
isCandidate[index] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (guessNumber <= MaximumGuesses)
|
||||
View.ShowComputerGuessedCode(guessNumber);
|
||||
else
|
||||
View.ShowComputerFailedToGuessCode();
|
||||
|
||||
computerScore += guessNumber;
|
||||
View.ShowScores(humanScore, computerScore, isFinal: false);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
38
60_Mastermind/csharp/Game/src/TurnResult.cs
Normal file
38
60_Mastermind/csharp/Game/src/TurnResult.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the result of a player's turn.
|
||||
/// </summary>
|
||||
public record TurnResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the code guessed by the player.
|
||||
/// </summary>
|
||||
public Code Guess { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of black pegs resulting from the guess.
|
||||
/// </summary>
|
||||
public int Blacks { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of white pegs resulting from the guess.
|
||||
/// </summary>
|
||||
public int Whites { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the TurnResult record.
|
||||
/// </summary>
|
||||
/// <param name="guess">
|
||||
/// The player's guess.
|
||||
/// </param>
|
||||
/// <param name="blacks">
|
||||
/// The number of black pegs.
|
||||
/// </param>
|
||||
/// <param name="whites">
|
||||
/// The number of white pegs.
|
||||
/// </param>
|
||||
public TurnResult(Code guess, int blacks, int whites) =>
|
||||
(Guess, Blacks, Whites) = (guess, blacks, whites);
|
||||
}
|
||||
}
|
||||
178
60_Mastermind/csharp/Game/src/View.cs
Normal file
178
60_Mastermind/csharp/Game/src/View.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Game
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains functions for displaying information to the end user.
|
||||
/// </summary>
|
||||
public static class View
|
||||
{
|
||||
public static void ShowBanner()
|
||||
{
|
||||
Console.WriteLine(" MASTERMIND");
|
||||
Console.WriteLine(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
public static void ShowTotalPossibilities(int possibilities)
|
||||
{
|
||||
Console.WriteLine($"TOTAL POSSIBILITIES = {possibilities}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
public static void ShowColorTable(int numberOfColors)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("COLOR LETTER");
|
||||
Console.WriteLine("===== ======");
|
||||
|
||||
foreach (var color in Colors.List.Take(numberOfColors))
|
||||
Console.WriteLine($"{color.LongName,-13}{color.ShortName}");
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
public static void ShowStartOfRound(int roundNumber)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"ROUND NUMBER {roundNumber} ----");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("GUESS MY COMBINATION.");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
public static void ShowBoard(IEnumerable<TurnResult> history)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("BOARD");
|
||||
Console.WriteLine("MOVE GUESS BLACK WHITE");
|
||||
|
||||
var moveNumber = 0;
|
||||
foreach (var result in history)
|
||||
Console.WriteLine($"{++moveNumber,-9}{result.Guess,-16}{result.Blacks,-10}{result.Whites}");
|
||||
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
public static void ShowQuitGame(Code code)
|
||||
{
|
||||
Console.WriteLine($"QUITTER! MY COMBINATION WAS: {code}");
|
||||
Console.WriteLine("GOOD BYE");
|
||||
}
|
||||
|
||||
public static void ShowResults(int blacks, int whites)
|
||||
{
|
||||
Console.WriteLine($"YOU HAVE {blacks} BLACKS AND {whites} WHITES.");
|
||||
}
|
||||
|
||||
public static void ShowHumanGuessedCode(int guessNumber)
|
||||
{
|
||||
Console.WriteLine($"YOU GUESSED IT IN {guessNumber} MOVES!");
|
||||
}
|
||||
|
||||
public static void ShowHumanFailedToGuessCode(Code code)
|
||||
{
|
||||
// Note: The original code did not print out the combination, but
|
||||
// this appears to be a bug.
|
||||
Console.WriteLine("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!");
|
||||
Console.WriteLine($"THE ACTUAL COMBINATION WAS: {code}");
|
||||
}
|
||||
|
||||
public static void ShowScores(int humanScore, int computerScore, bool isFinal)
|
||||
{
|
||||
if (isFinal)
|
||||
{
|
||||
Console.WriteLine("GAME OVER");
|
||||
Console.WriteLine("FINAL SCORE:");
|
||||
}
|
||||
else
|
||||
Console.WriteLine("SCORE:");
|
||||
|
||||
Console.WriteLine($" COMPUTER {computerScore}");
|
||||
Console.WriteLine($" HUMAN {humanScore}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
public static void ShowComputerStartTurn()
|
||||
{
|
||||
Console.WriteLine("NOW I GUESS. THINK OF A COMBINATION.");
|
||||
}
|
||||
|
||||
public static void ShowInconsistentInformation()
|
||||
{
|
||||
Console.WriteLine("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.");
|
||||
Console.WriteLine("TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.");
|
||||
}
|
||||
|
||||
public static void ShowComputerGuessedCode(int guessNumber)
|
||||
{
|
||||
Console.WriteLine($"I GOT IT IN {guessNumber} MOVES!");
|
||||
}
|
||||
|
||||
public static void ShowComputerFailedToGuessCode()
|
||||
{
|
||||
Console.WriteLine("I USED UP ALL MY MOVES!");
|
||||
Console.WriteLine("I GUESS MY CPU IS JUST HAVING AN OFF DAY.");
|
||||
}
|
||||
|
||||
public static void PromptNumberOfColors()
|
||||
{
|
||||
Console.Write("NUMBER OF COLORS? ");
|
||||
}
|
||||
|
||||
public static void PromptNumberOfPositions()
|
||||
{
|
||||
Console.Write("NUMBER OF POSITIONS? ");
|
||||
}
|
||||
|
||||
public static void PromptNumberOfRounds()
|
||||
{
|
||||
Console.Write("NUMBER OF ROUNDS? ");
|
||||
}
|
||||
|
||||
public static void PromptGuess(int moveNumber)
|
||||
{
|
||||
Console.Write($"MOVE # {moveNumber} GUESS ? ");
|
||||
}
|
||||
|
||||
public static void PromptReady()
|
||||
{
|
||||
Console.Write("HIT RETURN WHEN READY ? ");
|
||||
}
|
||||
|
||||
public static void PromptBlacksWhites(Code code)
|
||||
{
|
||||
Console.Write($"MY GUESS IS: {code}");
|
||||
Console.Write(" BLACKS, WHITES ? ");
|
||||
}
|
||||
|
||||
public static void PromptTwoValues()
|
||||
{
|
||||
Console.WriteLine("PLEASE ENTER TWO VALUES, SEPARATED BY A COMMA");
|
||||
}
|
||||
|
||||
public static void PromptValidInteger()
|
||||
{
|
||||
Console.WriteLine("PLEASE ENTER AN INTEGER VALUE");
|
||||
}
|
||||
|
||||
public static void NotifyBadNumberOfPositions()
|
||||
{
|
||||
Console.WriteLine("BAD NUMBER OF POSITIONS");
|
||||
}
|
||||
|
||||
public static void NotifyInvalidColor(char colorKey)
|
||||
{
|
||||
Console.WriteLine($"'{colorKey}' IS UNRECOGNIZED.");
|
||||
}
|
||||
|
||||
public static void NotifyTooManyColors(int maxColors)
|
||||
{
|
||||
Console.WriteLine($"NO MORE THAN {maxColors}, PLEASE!");
|
||||
}
|
||||
}
|
||||
}
|
||||
25
60_Mastermind/csharp/Mastermind.sln
Normal file
25
60_Mastermind/csharp/Mastermind.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31321.278
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Game\Game.csproj", "{E8D63140-971D-4FBF-8138-964E54CCB7DD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E8D63140-971D-4FBF-8138-964E54CCB7DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E8D63140-971D-4FBF-8138-964E54CCB7DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E8D63140-971D-4FBF-8138-964E54CCB7DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E8D63140-971D-4FBF-8138-964E54CCB7DD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1BDFBEE6-8345-438C-8FCE-B2C9394CC080}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
3
60_Mastermind/csharp/README.md
Normal file
3
60_Mastermind/csharp/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
|
||||
3
60_Mastermind/java/README.md
Normal file
3
60_Mastermind/java/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Oracle Java](https://openjdk.java.net/)
|
||||
3
60_Mastermind/javascript/README.md
Normal file
3
60_Mastermind/javascript/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
|
||||
9
60_Mastermind/javascript/mastermind.html
Normal file
9
60_Mastermind/javascript/mastermind.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>MASTERMIND</title>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="output" style="font-size: 12pt;"></pre>
|
||||
<script src="mastermind.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
361
60_Mastermind/javascript/mastermind.js
Normal file
361
60_Mastermind/javascript/mastermind.js
Normal file
@@ -0,0 +1,361 @@
|
||||
// MASTERMIND
|
||||
//
|
||||
// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
|
||||
//
|
||||
|
||||
function print(str)
|
||||
{
|
||||
document.getElementById("output").appendChild(document.createTextNode(str));
|
||||
}
|
||||
|
||||
function input()
|
||||
{
|
||||
var input_element;
|
||||
var input_str;
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
input_element = document.createElement("INPUT");
|
||||
|
||||
print("? ");
|
||||
input_element.setAttribute("type", "text");
|
||||
input_element.setAttribute("length", "50");
|
||||
document.getElementById("output").appendChild(input_element);
|
||||
input_element.focus();
|
||||
input_str = undefined;
|
||||
input_element.addEventListener("keydown", function (event) {
|
||||
if (event.keyCode == 13) {
|
||||
input_str = input_element.value;
|
||||
document.getElementById("output").removeChild(input_element);
|
||||
print(input_str);
|
||||
print("\n");
|
||||
resolve(input_str);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function tab(space)
|
||||
{
|
||||
var str = "";
|
||||
while (space-- > 0)
|
||||
str += " ";
|
||||
return str;
|
||||
}
|
||||
|
||||
var p9;
|
||||
var c9;
|
||||
var b;
|
||||
var w;
|
||||
var f;
|
||||
var m;
|
||||
|
||||
var qa;
|
||||
var sa;
|
||||
var ss;
|
||||
var as;
|
||||
var gs;
|
||||
var hs;
|
||||
|
||||
function initialize_qa()
|
||||
{
|
||||
for (s = 1; s <= p9; s++)
|
||||
qa[s] = 0;
|
||||
}
|
||||
|
||||
function increment_qa()
|
||||
{
|
||||
if (qa[1] <= 0) {
|
||||
// If zero, this is our firt increment: make all ones
|
||||
for (s = 1; s <= p9; s++)
|
||||
qa[s] = 1;
|
||||
} else {
|
||||
q = 1;
|
||||
while (1) {
|
||||
qa[q] = qa[q] + 1;
|
||||
if (qa[q] <= c9)
|
||||
return;
|
||||
qa[q] = 1;
|
||||
q++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convert_qa()
|
||||
{
|
||||
for (s = 1; s <= p9; s++) {
|
||||
as[s] = ls.substr(qa[s] - 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function get_number()
|
||||
{
|
||||
b = 0;
|
||||
w = 0;
|
||||
f = 0;
|
||||
for (s = 1; s <= p9; s++) {
|
||||
if (gs[s] == as[s]) {
|
||||
b++;
|
||||
gs[s] = String.fromCharCode(f);
|
||||
as[s] = String.fromCharCode(f + 1);
|
||||
f += 2;
|
||||
} else {
|
||||
for (t = 1; t <= p9; t++) {
|
||||
if (gs[s] == as[t] && gs[t] != as[t]) {
|
||||
w++;
|
||||
as[t] = String.fromCharCode(f);
|
||||
gs[s] = String.fromCharCode(f + 1);
|
||||
f += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function convert_qa_hs()
|
||||
{
|
||||
for (s = 1; s <= p9; s++) {
|
||||
hs[s] = ls.substr(qa[s] - 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function copy_hs()
|
||||
{
|
||||
for (s = 1; s <= p9; s++) {
|
||||
gs[s] = hs[s];
|
||||
}
|
||||
}
|
||||
|
||||
function board_printout()
|
||||
{
|
||||
print("\n");
|
||||
print("BOARD\n");
|
||||
print("MOVE GUESS BLACK WHITE\n");
|
||||
for (z = 1; z <= m - 1; z++) {
|
||||
str = " " + z + " ";
|
||||
while (str.length < 9)
|
||||
str += " ";
|
||||
str += ss[z];
|
||||
while (str.length < 25)
|
||||
str += " ";
|
||||
str += sa[z][1];
|
||||
while (str.length < 35)
|
||||
str += " ";
|
||||
str += sa[z][2];
|
||||
print(str + "\n");
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
|
||||
function quit()
|
||||
{
|
||||
print("QUITTER! MY COMBINATION WAS: ");
|
||||
convert_qa();
|
||||
for (x = 1; x <= p9; x++) {
|
||||
print(as[x]);
|
||||
}
|
||||
print("\n");
|
||||
print("GOOD BYE\n");
|
||||
}
|
||||
|
||||
function show_score()
|
||||
{
|
||||
print("SCORE:\n");
|
||||
show_points();
|
||||
}
|
||||
|
||||
function show_points()
|
||||
{
|
||||
print(" COMPUTER " + c + "\n");
|
||||
print(" HUMAN " + h + "\n");
|
||||
print("\n");
|
||||
}
|
||||
|
||||
var color = ["BLACK", "WHITE", "RED", "GREEN",
|
||||
"ORANGE", "YELLOW", "PURPLE", "TAN"];
|
||||
|
||||
// Main program
|
||||
async function main()
|
||||
{
|
||||
print(tab(30) + "MASTERMIND\n");
|
||||
print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
|
||||
print("\n");
|
||||
print("\n");
|
||||
print("\n");
|
||||
//
|
||||
// MASTERMIND II
|
||||
// STEVE NORTH
|
||||
// CREATIVE COMPUTING
|
||||
// PO BOX 789-M MORRISTOWN NEW JERSEY 07960
|
||||
//
|
||||
//
|
||||
while (1) {
|
||||
print("NUMBER OF COLORS");
|
||||
c9 = parseInt(await input());
|
||||
if (c9 <= 8)
|
||||
break;
|
||||
print("NO MORE THAN 8, PLEASE!\n");
|
||||
}
|
||||
print("NUMBER OF POSITIONS");
|
||||
p9 = parseInt(await input());
|
||||
print("NUMBER OF ROUNDS");
|
||||
r9 = parseInt(await input());
|
||||
p = Math.pow(c9, p9);
|
||||
print("TOTAL POSSIBILITIES = " + p + "\n");
|
||||
h = 0;
|
||||
c = 0;
|
||||
qa = [];
|
||||
sa = [];
|
||||
ss = [];
|
||||
as = [];
|
||||
gs = [];
|
||||
ia = [];
|
||||
hs = [];
|
||||
ls = "BWRGOYPT";
|
||||
print("\n");
|
||||
print("\n");
|
||||
print("COLOR LETTER\n");
|
||||
print("===== ======\n");
|
||||
for (x = 1; x <= c9; x++) {
|
||||
str = color[x - 1];
|
||||
while (str.length < 13)
|
||||
str += " ";
|
||||
str += ls.substr(x - 1, 1);
|
||||
print(str + "\n");
|
||||
}
|
||||
print("\n");
|
||||
for (r = 1; r <= r9; r++) {
|
||||
print("\n");
|
||||
print("ROUND NUMBER " + r + " ----\n");
|
||||
print("\n");
|
||||
print("GUESS MY COMBINATION.\n");
|
||||
print("\n");
|
||||
// Get a combination
|
||||
a = Math.floor(p * Math.random() + 1);
|
||||
initialize_qa();
|
||||
for (x = 1; x <= a; x++) {
|
||||
increment_qa();
|
||||
}
|
||||
for (m = 1; m <= 10; m++) {
|
||||
while (1) {
|
||||
print("MOVE # " + m + " GUESS ");
|
||||
str = await input();
|
||||
if (str == "BOARD") {
|
||||
board_printout();
|
||||
} else if (str == "QUIT") {
|
||||
quit();
|
||||
return;
|
||||
} else if (str.length != p9) {
|
||||
print("BAD NUMBER OF POSITIONS.\n");
|
||||
} else {
|
||||
// Unpack str into gs(1-p9)
|
||||
for (x = 1; x <= p9; x++) {
|
||||
y = ls.indexOf(str.substr(x - 1, 1));
|
||||
if (y < 0) {
|
||||
print("'" + str.substr(x - 1, 1) + "' IS UNRECOGNIZED.\n");
|
||||
break;
|
||||
}
|
||||
gs[x] = str.substr(x - 1, 1);
|
||||
}
|
||||
if (x > p9)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Now we convert qa(1-p9) into as(1-p9) [ACTUAL GUESS]
|
||||
convert_qa();
|
||||
// And get number of blacks and white
|
||||
get_number();
|
||||
if (b == p9) {
|
||||
print("YOU GUESSED IT IN " + m + " MOVES!\n");
|
||||
break;
|
||||
}
|
||||
// Save all this stuff for board printout later
|
||||
ss[m] = str;
|
||||
sa[m] = [];
|
||||
sa[m][1] = b;
|
||||
sa[m][2] = w;
|
||||
}
|
||||
if (m > 10) {
|
||||
print("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!\n");
|
||||
}
|
||||
h += m;
|
||||
show_score();
|
||||
|
||||
//
|
||||
// Now computer guesses
|
||||
//
|
||||
for (x = 1; x <= p; x++)
|
||||
ia[x] = 1;
|
||||
print("NOW I GUESS. THINK OF A COMBINATION.\n");
|
||||
print("HIT RETURN WHEN READY:");
|
||||
str = await input();
|
||||
for (m = 1; m <= 10; m++) {
|
||||
initialize_qa();
|
||||
// Find a guess
|
||||
g = Math.floor(p * Math.random() + 1);
|
||||
if (ia[g] != 1) {
|
||||
for (x = g; x <= p; x++) {
|
||||
if (ia[x] == 1)
|
||||
break;
|
||||
}
|
||||
if (x > p) {
|
||||
for (x = 1; x <= g; x++) {
|
||||
if (ia[x] == 1)
|
||||
break;
|
||||
}
|
||||
if (x > g) {
|
||||
print("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\n");
|
||||
print("TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\n");
|
||||
for (x = 1; x <= p; x++)
|
||||
ia[x] = 1;
|
||||
print("NOW I GUESS. THINK OF A COMBINATION.\n");
|
||||
print("HIT RETURN WHEN READY:");
|
||||
str = await input();
|
||||
m = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
g = x;
|
||||
}
|
||||
// Now we convert guess #g into gs
|
||||
for (x = 1; x <= g; x++) {
|
||||
increment_qa();
|
||||
}
|
||||
convert_qa_hs();
|
||||
print("MY GUESS IS: ");
|
||||
for (x = 1; x <= p9; x++) {
|
||||
print(hs[x]);
|
||||
}
|
||||
print(" BLACKS, WHITES ");
|
||||
str = await input();
|
||||
b1 = parseInt(str);
|
||||
w1 = parseInt(str.substr(str.indexOf(",") + 1));
|
||||
if (b1 == p9) {
|
||||
print("I GOT IT IN " + m + " MOVES!\n");
|
||||
break;
|
||||
}
|
||||
initialize_qa();
|
||||
for (x = 1; x <= p; x++) {
|
||||
increment_qa();
|
||||
if (ia[x] != 0) {
|
||||
copy_hs();
|
||||
convert_qa();
|
||||
get_number();
|
||||
if (b1 != b || w1 != w)
|
||||
ia[x] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m > 10) {
|
||||
print("I USED UP ALL MY MOVES!\n");
|
||||
print("I GUESS MY CPU I JUST HAVING AN OFF DAY.\n");
|
||||
}
|
||||
c += m;
|
||||
show_score();
|
||||
}
|
||||
print("GAME OVER\n");
|
||||
print("FINAL SCORE:\n");
|
||||
show_points();
|
||||
}
|
||||
|
||||
main();
|
||||
232
60_Mastermind/mastermind.bas
Normal file
232
60_Mastermind/mastermind.bas
Normal file
@@ -0,0 +1,232 @@
|
||||
2 PRINT TAB(30);"MASTERMIND"
|
||||
4 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
|
||||
6 PRINT: PRINT: PRINT
|
||||
10 REM
|
||||
20 REM MASTERMIND II
|
||||
30 REM STEVE NORTH
|
||||
40 REM CREATIVE COMPUTING
|
||||
50 REM PO BOX 789-M MORRISTOWN NEW JERSEY 07960
|
||||
60 REM
|
||||
70 REM
|
||||
80 INPUT "NUMBER OF COLORS";C9
|
||||
90 IF C9>8 THEN PRINT "NO MORE THAN 8, PLEASE!":GOTO 80
|
||||
100 INPUT "NUMBER OF POSITIONS";P9
|
||||
110 INPUT "NUMBER OF ROUNDS";R9
|
||||
120 P=C9^P9
|
||||
130 PRINT "TOTAL POSSIBILITIES =";P
|
||||
140 H=0:C=0
|
||||
150 DIM Q(P9),S(10,2),S$(10),A$(P9),G$(P9),I(P),H$(P9)
|
||||
160 L$="BWRGOYPT"
|
||||
170 PRINT
|
||||
180 PRINT
|
||||
190 PRINT "COLOR LETTER"
|
||||
200 PRINT "===== ======"
|
||||
210 FOR X=1 TO C9
|
||||
220 READ X$
|
||||
230 PRINT X$;TAB(13);MID$(L$,X,1)
|
||||
240 NEXT X
|
||||
250 PRINT
|
||||
260 FOR R=1 TO R9
|
||||
270 PRINT
|
||||
280 PRINT "ROUND NUMBER";R;"----"
|
||||
290 PRINT
|
||||
300 PRINT "GUESS MY COMBINATION.":PRINT
|
||||
310 REM GET A COMBINATION
|
||||
320 A=INT(P*RND(1)+1)
|
||||
330 GOSUB 3000
|
||||
340 FOR X=1 TO A
|
||||
350 GOSUB 3500
|
||||
360 NEXT X
|
||||
370 FOR M=1 TO 10
|
||||
380 PRINT "MOVE # ";M;" GUESS ";:INPUT X$
|
||||
390 IF X$="BOARD" THEN 2000
|
||||
400 IF X$="QUIT" THEN 2500
|
||||
410 IF LEN(X$)<>P9 THEN PRINT "BAD NUMBER OF POSITIONS.":GOTO 380
|
||||
420 REM UNPACK X$ INTO G$(1-P9)
|
||||
430 FOR X=1 TO P9
|
||||
440 FOR Y=1 TO C9
|
||||
450 IF MID$(X$,X,1)=MID$(L$,Y,1) THEN 480
|
||||
460 NEXT Y
|
||||
470 PRINT "'"; MID$(X$,X,1); "' IS UNRECOGNIZED.":GOTO 380
|
||||
480 G$(X)=MID$(X$,X,1)
|
||||
490 NEXT X
|
||||
500 REM NOW WE CONVERT Q(1-P9) INTO A$(1-P9) [ACTUAL GUESS]
|
||||
510 GOSUB 4000
|
||||
520 REM AND GET NUMBER OF BLACKS AND WHITES
|
||||
530 GOSUB 4500
|
||||
540 IF B=P9 THEN 630
|
||||
550 REM TELL HUMAN RESULTS
|
||||
560 PRINT "YOU HAVE ";B;" BLACKS AND ";W;" WHITES."
|
||||
570 REM SAVE ALL THIS STUFF FOR BOARD PRINTOUT LATER
|
||||
580 S$(M)=X$
|
||||
590 S(M,1)=B
|
||||
600 S(M,2)=W
|
||||
610 NEXT M
|
||||
620 PRINT "YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!":GOTO 640
|
||||
622 GOSUB 4000
|
||||
623 PRINT "THE ACTUAL COMBINATION WAS: ";
|
||||
624 FOR X=1 TO P9
|
||||
625 PRINT A$(X);
|
||||
626 NEXT X
|
||||
627 PRINT
|
||||
630 PRINT "YOU GUESSED IT IN ";M;" MOVES!"
|
||||
640 H=H+M
|
||||
650 GOSUB 5000
|
||||
660 REM
|
||||
670 REM NOW COMPUTER GUESSES
|
||||
680 REM
|
||||
690 FOR X=1 TO P
|
||||
700 I(X)=1
|
||||
710 NEXT X
|
||||
720 PRINT "NOW I GUESS. THINK OF A COMBINATION."
|
||||
730 INPUT "HIT RETURN WHEN READY:";X$
|
||||
740 FOR M=1 TO 10
|
||||
750 GOSUB 3000
|
||||
760 REM FIND A GUESS
|
||||
770 G=INT(P*RND(1)+1)
|
||||
780 IF I(G)=1 THEN 890
|
||||
790 FOR X=G TO P
|
||||
800 IF I(X)=1 THEN 880
|
||||
810 NEXT X
|
||||
820 FOR X=1 TO G
|
||||
830 IF I(X)=1 THEN 880
|
||||
840 NEXT X
|
||||
850 PRINT "YOU HAVE GIVEN ME INCONSISTENT INFORMATION."
|
||||
860 PRINT "TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL."
|
||||
870 GOTO 660
|
||||
880 G=X
|
||||
890 REM NOW WE CONVERT GUESS #G INTO G$
|
||||
900 FOR X=1 TO G
|
||||
910 GOSUB 3500
|
||||
920 NEXT X
|
||||
930 GOSUB 6000
|
||||
940 PRINT "MY GUESS IS: ";
|
||||
950 FOR X=1 TO P9
|
||||
960 PRINT H$(X);
|
||||
970 NEXT X
|
||||
980 INPUT " BLACKS, WHITES ";B1,W1
|
||||
990 IF B1=P9 THEN 1120
|
||||
1000 GOSUB 3000
|
||||
1010 FOR X=1 TO P
|
||||
1020 GOSUB 3500
|
||||
1030 IF I(X)=0 THEN 1070
|
||||
1035 GOSUB 6500
|
||||
1040 GOSUB 4000
|
||||
1050 GOSUB 4500
|
||||
1060 IF B1<>B OR W1<>W THEN I(X)=0
|
||||
1070 NEXT X
|
||||
1080 NEXT M
|
||||
1090 PRINT "I USED UP ALL MY MOVES!"
|
||||
1100 PRINT "I GUESS MY CPU IS JUST HAVING AN OFF DAY."
|
||||
1110 GOTO 1130
|
||||
1120 PRINT "I GOT IT IN ";M;" MOVES!"
|
||||
1130 C=C+M
|
||||
1140 GOSUB 5000
|
||||
1150 NEXT R
|
||||
1160 PRINT "GAME OVER"
|
||||
1170 PRINT "FINAL SCORE:"
|
||||
1180 GOSUB 5040
|
||||
1190 STOP
|
||||
2000 REM
|
||||
2010 REM BOARD PRINTOUT ROUTINE
|
||||
2020 REM
|
||||
2025 PRINT
|
||||
2030 PRINT "BOARD"
|
||||
2040 PRINT "MOVE GUESS BLACK WHITE"
|
||||
2050 FOR Z=1 TO M-1
|
||||
2060 PRINT Z;TAB(9);S$(Z);TAB(25);S(Z,1);TAB(35);S(Z,2)
|
||||
2070 NEXT Z
|
||||
2075 PRINT
|
||||
2080 GOTO 380
|
||||
2500 REM
|
||||
2510 REM QUIT ROUTINE
|
||||
2520 REM
|
||||
2530 PRINT "QUITTER! MY COMBINATION WAS: ";
|
||||
2535 GOSUB 4000
|
||||
2540 FOR X=1 TO P9
|
||||
2550 PRINT A$(X);
|
||||
2560 NEXT X
|
||||
2565 PRINT
|
||||
2570 PRINT "GOOD BYE"
|
||||
2580 STOP
|
||||
3000 REM
|
||||
3010 REM INITIALIZE Q(1-P9) TO ZEROS
|
||||
3020 REM
|
||||
3030 FOR S=1 TO P9
|
||||
3040 Q(S)=0
|
||||
3050 NEXT S
|
||||
3060 RETURN
|
||||
3500 REM
|
||||
3510 REM INCREMENT Q(1-P9)
|
||||
3520 REM
|
||||
3522 IF Q(1)>0 THEN 3530
|
||||
3524 REM IF ZERO, THIS IS OUR FIRST INCREMENT: MAKE ALL ONES
|
||||
3526 FOR S=1 TO P9
|
||||
3527 Q(S)=1
|
||||
3528 NEXT S
|
||||
3529 RETURN
|
||||
3530 Q=1
|
||||
3540 Q(Q)=Q(Q)+1
|
||||
3550 IF Q(Q)<=C9 THEN RETURN
|
||||
3560 Q(Q)=1
|
||||
3570 Q=Q+1
|
||||
3580 GOTO 3540
|
||||
4000 REM
|
||||
4010 REM CONVERT Q(1-P9) TO A$(1-P9)
|
||||
4020 REM
|
||||
4030 FOR S=1 TO P9
|
||||
4040 A$(S)=MID$(L$,Q(S),1)
|
||||
4050 NEXT S
|
||||
4060 RETURN
|
||||
4500 REM
|
||||
4510 REM GET NUMBER OF BLACKS (B) AND WHITES (W)
|
||||
4520 REM MASHES G$ AND A$ IN THE PROCESS
|
||||
4530 REM
|
||||
4540 B=0:W=0:F=0
|
||||
4550 FOR S=1 TO P9
|
||||
4560 IF G$(S)<>A$(S) THEN 4620
|
||||
4570 B=B+1
|
||||
4580 G$(S)=CHR$(F)
|
||||
4590 A$(S)=CHR$(F+1)
|
||||
4600 F=F+2
|
||||
4610 GOTO 4660
|
||||
4620 FOR T=1 TO P9
|
||||
4630 IF G$(S)<>A$(T) THEN 4650
|
||||
4640 IF G$(T)=A$(T) THEN 4650
|
||||
4645 W=W+1:A$(T)=CHR$(F):G$(S)=CHR$(F+1):F=F+2:GOTO 4660
|
||||
4650 NEXT T
|
||||
4660 NEXT S
|
||||
4670 RETURN
|
||||
5000 REM
|
||||
5010 REM PRINT SCORE
|
||||
5020 REM
|
||||
5030 PRINT "SCORE:"
|
||||
5040 PRINT " COMPUTER ";C
|
||||
5050 PRINT " HUMAN ";H
|
||||
5060 PRINT
|
||||
5070 RETURN
|
||||
5500 REM
|
||||
5510 REM CONVERT Q(1-P9) INTO G$(1-P9)
|
||||
5520 REM
|
||||
5530 FOR S=1 TO P9
|
||||
5540 G$(S)=MID$(L$,Q(S),1)
|
||||
5550 NEXT S
|
||||
5560 RETURN
|
||||
6000 REM
|
||||
6010 REM CONVERT Q(1-P9) TO H$(1-P9)
|
||||
6020 REM
|
||||
6030 FOR S=1 TO P9
|
||||
6040 H$(S)=MID$(L$,Q(S),1)
|
||||
6050 NEXT S
|
||||
6060 RETURN
|
||||
6500 REM
|
||||
6510 REM COPY H$ INTO G$
|
||||
6520 REM
|
||||
6530 FOR S=1 TO P9
|
||||
6540 G$(S)=H$(S)
|
||||
6550 NEXT S
|
||||
6560 RETURN
|
||||
8000 REM PROGRAM DATA FOR COLOR NAMES
|
||||
8010 DATA BLACK,WHITE,RED,GREEN,ORANGE,YELLOW,PURPLE,TAN
|
||||
9998 REM ...WE'RE SORRY BUT IT'S TIME TO GO...
|
||||
9999 END
|
||||
3
60_Mastermind/pascal/README.md
Normal file
3
60_Mastermind/pascal/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
|
||||
3
60_Mastermind/perl/README.md
Normal file
3
60_Mastermind/perl/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Perl](https://www.perl.org/)
|
||||
3
60_Mastermind/python/README.md
Normal file
3
60_Mastermind/python/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Python](https://www.python.org/about/)
|
||||
230
60_Mastermind/python/mastermind.py
Normal file
230
60_Mastermind/python/mastermind.py
Normal file
@@ -0,0 +1,230 @@
|
||||
import random, sys
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
global colors, color_letters, num_positions, num_colors, human_score, computer_score
|
||||
colors = ["BLACK", "WHITE", "RED", "GREEN", "ORANGE", "YELLOW", "PURPLE", "TAN"]
|
||||
color_letters = "BWRGOYPT"
|
||||
|
||||
num_colors = 100
|
||||
human_score = 0
|
||||
computer_score = 0
|
||||
|
||||
# get user inputs for game conditions
|
||||
print("Mastermind")
|
||||
print('Creative Computing Morristown, New Jersey')
|
||||
while num_colors > 8:
|
||||
num_colors = int(input("Number of colors (max 8): ")) # C9 in BASIC
|
||||
num_positions = int(input("Number of positions: ")) # P9 in BASIC
|
||||
num_rounds = int(input("Number of rounds: ")) # R9 in BASIC
|
||||
possibilities = num_colors**num_positions
|
||||
all_possibilities = [1] * possibilities
|
||||
|
||||
print("Number of possibilities {}".format(possibilities))
|
||||
print('Color\tLetter')
|
||||
print('=====\t======')
|
||||
for element in range(0, num_colors):
|
||||
print("{}\t{}".format(colors[element], colors[element][0]))
|
||||
|
||||
current_round = 1
|
||||
|
||||
while current_round <= num_rounds:
|
||||
print('Round number {}'.format(current_round))
|
||||
num_moves = 1
|
||||
guesses = []
|
||||
turn_over = False
|
||||
print('Guess my combination ...')
|
||||
answer = int(possibilities * random.random())
|
||||
numeric_answer = [-1] * num_positions
|
||||
for i in range(0, answer):
|
||||
numeric_answer = get_possibility(numeric_answer)
|
||||
#human_readable_answer = make_human_readable(numeric_answer)
|
||||
while (num_moves < 10 and not turn_over ):
|
||||
print('Move # {} Guess : '.format(num_moves))
|
||||
user_command = input('Guess ')
|
||||
if user_command == "BOARD":
|
||||
print_board(guesses) #2000
|
||||
elif user_command == "QUIT": #2500
|
||||
human_readable_answer = make_human_readable(numeric_answer)
|
||||
print('QUITTER! MY COMBINATION WAS: {}'.format(human_readable_answer))
|
||||
print('GOOD BYE')
|
||||
quit()
|
||||
elif len(user_command) != num_positions: #410
|
||||
print("BAD NUMBER OF POSITIONS")
|
||||
else:
|
||||
invalid_letters = get_invalid_letters(user_command)
|
||||
if invalid_letters > "":
|
||||
print("INVALID GUESS: {}".format(invalid_letters))
|
||||
else:
|
||||
guess_results = compare_two_positions(user_command, make_human_readable(numeric_answer))
|
||||
print("Results: {}".format(guess_results))
|
||||
if guess_results[1] == num_positions: # correct guess
|
||||
turn_over = True
|
||||
print("You guessed it in {} moves!".format(num_moves))
|
||||
human_score = human_score + num_moves
|
||||
print_score()
|
||||
else:
|
||||
print("You have {} blacks and {} whites".format(guess_results[1], guess_results[2]))
|
||||
num_moves = num_moves + 1
|
||||
guesses.append(guess_results)
|
||||
if not turn_over: # RAN OUT OF MOVES
|
||||
print ("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!")
|
||||
print("THE ACTUAL COMBINATION WAS: {}".format(make_human_readable(numeric_answer)))
|
||||
human_score = human_score + num_moves
|
||||
print_score()
|
||||
|
||||
# COMPUTER TURN
|
||||
guesses = []
|
||||
turn_over = False
|
||||
inconsistent_information = False
|
||||
while(not turn_over and not inconsistent_information ):
|
||||
all_possibilities = [1] * possibilities
|
||||
num_moves = 1
|
||||
inconsistent_information = False
|
||||
print ("NOW I GUESS. THINK OF A COMBINATION.")
|
||||
player_ready = input("HIT RETURN WHEN READY: ")
|
||||
while (num_moves < 10 and not turn_over and not inconsistent_information):
|
||||
found_guess = False
|
||||
computer_guess = int(possibilities * random.random())
|
||||
if all_possibilities[computer_guess] == 1: # random guess is possible, use it
|
||||
found_guess = True
|
||||
guess = computer_guess
|
||||
else:
|
||||
for i in range (computer_guess, possibilities):
|
||||
if all_possibilities[i] == 1:
|
||||
found_guess = True
|
||||
guess = i
|
||||
break
|
||||
if not found_guess:
|
||||
for i in range (0, computer_guess):
|
||||
if all_possibilities[i] == 1:
|
||||
found_guess = True
|
||||
guess = i
|
||||
break
|
||||
if not found_guess: # inconsistent info from user
|
||||
print('YOU HAVE GIVEN ME INCONSISTENT INFORMATION.')
|
||||
print('TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.')
|
||||
turn_over = True
|
||||
inconsistent_information = True
|
||||
else:
|
||||
numeric_guess = [-1] * num_positions
|
||||
for i in range(0, guess):
|
||||
numeric_guess = get_possibility(numeric_guess)
|
||||
human_readable_guess = make_human_readable(numeric_guess)
|
||||
print('My guess is: {}'.format(human_readable_guess))
|
||||
blacks, whites = input("ENTER BLACKS, WHITES (e.g. 1,2): ").split(",")
|
||||
blacks = int(blacks)
|
||||
whites = int(whites)
|
||||
if blacks == num_positions: #Correct guess
|
||||
print('I GOT IT IN {} MOVES'.format(num_moves))
|
||||
turn_over = True
|
||||
computer_score = computer_score + num_moves
|
||||
print_score()
|
||||
else:
|
||||
num_moves += 1
|
||||
for i in range (0, possibilities):
|
||||
if all_possibilities[i] == 0: #already ruled out
|
||||
continue
|
||||
numeric_possibility = [-1] * num_positions
|
||||
for j in range (0, i):
|
||||
numeric_possibility = get_possibility(numeric_possibility)
|
||||
human_readable_possibility = make_human_readable(numeric_possibility) #4000
|
||||
comparison = compare_two_positions(human_readable_possibility, human_readable_guess)
|
||||
print(comparison)
|
||||
if ((blacks != comparison[1]) or (whites != comparison[2])):
|
||||
all_possibilities[i] = 0
|
||||
if not turn_over: # COMPUTER DID NOT GUESS
|
||||
print("I USED UP ALL MY MOVES!")
|
||||
print("I GUESS MY CPU IS JUST HAVING AN OFF DAY.")
|
||||
computer_score = computer_score + num_moves
|
||||
print_score()
|
||||
current_round += 1
|
||||
print_score(is_final_score=True)
|
||||
sys.exit()
|
||||
|
||||
#470
|
||||
def get_invalid_letters(user_command):
|
||||
"""Makes sure player input consists of valid colors for selected game configuration."""
|
||||
valid_colors = color_letters[:num_colors]
|
||||
invalid_letters = ""
|
||||
for letter in user_command:
|
||||
if letter not in valid_colors:
|
||||
invalid_letters = invalid_letters + letter
|
||||
return invalid_letters
|
||||
|
||||
#2000
|
||||
def print_board(guesses):
|
||||
"""Prints previous guesses within the round."""
|
||||
print("Board")
|
||||
print("Move\tGuess\tBlack White")
|
||||
for idx, guess in enumerate(guesses):
|
||||
print('{}\t{}\t{} {}'.format(idx+1, guess[0], guess[1], guess[2]))
|
||||
|
||||
#3500
|
||||
# Easily the place for most optimization, since they generate every possibility
|
||||
# every time when checking for potential solutions
|
||||
# From the original article:
|
||||
# "We did try a version that kept an actual list of all possible combinations
|
||||
# (as a string array), which was significantly faster than this versionn but
|
||||
# which ate tremendous amounts of memory."
|
||||
def get_possibility(possibility):
|
||||
#print(possibility)
|
||||
if possibility[0] > -1: #3530
|
||||
current_position = 0 # Python arrays are zero-indexed
|
||||
while True:
|
||||
if possibility[current_position] < num_colors-1: # zero-index again
|
||||
possibility[current_position] += 1
|
||||
return possibility
|
||||
else:
|
||||
possibility[current_position] = 0
|
||||
current_position += 1
|
||||
else: #3524
|
||||
possibility = [0] * num_positions
|
||||
return possibility
|
||||
|
||||
#4500
|
||||
def compare_two_positions(guess, answer):
|
||||
"""Returns blacks (correct color and position) and whites (correct color only) for candidate position (guess) versus reference position (answer)."""
|
||||
increment = 0
|
||||
blacks = 0
|
||||
whites = 0
|
||||
initial_guess = guess
|
||||
for pos in range(0, num_positions):
|
||||
if guess[pos] != answer[pos]:
|
||||
for pos2 in range(0, num_positions):
|
||||
if not(guess[pos] != answer[pos2] or guess[pos2] == answer[pos2]): # correct color but not correct place
|
||||
whites = whites + 1
|
||||
answer = answer[:pos2] + chr(increment) + answer[pos2+1:]
|
||||
guess = guess[:pos] + chr(increment+1) + guess[pos+1:]
|
||||
increment = increment + 2
|
||||
else: #correct color and placement
|
||||
blacks = blacks + 1
|
||||
# THIS IS DEVIOUSLY CLEVER
|
||||
guess = guess[:pos] + chr(increment+1) + guess[pos+1:]
|
||||
answer = answer[:pos] + chr(increment) + answer[pos+1:]
|
||||
increment = increment + 2
|
||||
return [initial_guess, blacks, whites]
|
||||
|
||||
#5000 + logic from 1160
|
||||
def print_score(is_final_score=False):
|
||||
"""Prints score after each turn ends, including final score at end of game."""
|
||||
if is_final_score:
|
||||
print("GAME OVER")
|
||||
print("FINAL SCORE:")
|
||||
else:
|
||||
print("SCORE:")
|
||||
print(" COMPUTER {}".format(computer_score))
|
||||
print(" HUMAN {}".format(human_score))
|
||||
|
||||
#4000, 5500, 6000 subroutines are all identical
|
||||
def make_human_readable(num):
|
||||
"""Make the numeric representation of a position human readable."""
|
||||
retval = ''
|
||||
for i in range(0, len(num)):
|
||||
retval = retval + color_letters[int(num[i])]
|
||||
return retval
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
3
60_Mastermind/ruby/README.md
Normal file
3
60_Mastermind/ruby/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Ruby](https://www.ruby-lang.org/en/)
|
||||
3
60_Mastermind/vbnet/README.md
Normal file
3
60_Mastermind/vbnet/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user