Bulls And Cows
A challenge made by the forum "FXP", to build a quick game of "bulls and cows" in a short time. Entry creator: CC_CCunknown
csharp
4 years ago
4.4 kB
16
Indexable
using System;
using System.Collections.Generic;
using System.Linq;
// namespace: bullsandcows
//
// summary: A challenge made by the forum "FXP",
// to build a quick game of "bulls and cows"
// in a short time.
// Entry creator: CC_CC
namespace bullsandcows
{
/// <summary> A static class to provide assistant functions over generic type. </summary>
public static class Applier
{
/// <summary> Applies a function over argument. </summary>
///
/// <typeparam name="TIn"> Type of the argument for application. </typeparam>
/// <typeparam name="TOut"> Type of the applied argument result. </typeparam>
/// <param name="x"> The applied argument. </param>
/// <param name="f"> The function applied over the argument. </param>
///
/// <returns> The applied argument result. </returns>
public static TOut Apply<TIn, TOut>(this TIn x, Func<TIn, TOut> f) => f(x);
}
/// <summary> The program main class. </summary>
class Program
{
/// <summary> Returns how many values are similar
/// in the same position in guess and gen,
/// and in different position in guess and gen. </summary>
///
/// <exception cref="ArgumentException"> Thrown when guess or gen
/// aren't the same length. </exception>
///
/// <typeparam name="T"> Type of argument to compare guess and gen. </typeparam>
/// <param name="guess"> The guessed input. </param>
/// <param name="gen"> The generated value. </param>
///
/// <returns> First result number of similar values in the same position,
/// Second result number of similar values in different position. </returns>
private static (int, int) Score<T>(IEnumerable<T> guess, IEnumerable<T> gen) where T : IEquatable<T>
{
var (bulls, nonbulls) = guess.Zip(gen)
.ToLookup(x =>
{
if (x.First == null || x.Second == null)
throw new System.ArgumentException("guess and gen aren't the same length");
return x.First.Equals(x.Second);
})
.Apply(x => (x[true], x[false]));
var cows = nonbulls
.Apply(x => (x.Select(xs => xs.First)
,x.Select(xs => xs.Second)))
.Apply(x => x.Item1.Intersect(x.Item2));
return (bulls.Count(), cows.Count());
}
/// <summary> The game's logic loop. </summary>
///
/// <param name="gen"> The generated value. </param>
/// <param name="length"> The length of the value. </param>
/// <param name="nTry"> The current iteration. </param>
///
/// <returns> whether the game have been won </returns>
public static bool GameLoop(IEnumerable<char> gen, int length, ref int nTry)
{
Console.Write($"{nTry}: ");
var guess = Console.ReadLine().ToCharArray();
if (guess.Length != length)
{
Console.WriteLine("Wrong length");
return false;
}
var (bulls, cows) = Score(guess, gen);
Console.WriteLine($"Bulls={bulls}, Cows={cows}");
nTry++;
return bulls == length;
}
/// <summary> Main entry-point for this application. </summary>
public static void Main()
{
var length = 0;
var nTry = 1;
var rand = new Random(Guid.NewGuid().GetHashCode());
Console.WriteLine("Enter the length of the number you intending to guess");
while (int.TryParse(Console.ReadLine(), out length))
Console.WriteLine("Invalid number");
var gen = Enumerable.Range(0, length)
.Select(_ => (char)rand.Next('0', '9'))
.ToList(); //forces evaluation of rand.next at initialization, preventing generation of new value every time gen is called
while (!GameLoop(gen, length, ref nTry));
Console.WriteLine($"ou win! tries: {nTry}");
}
}
}Editor is loading...