Last active
May 30, 2018 01:38
-
-
Save cawhitworth/8c7ac7d309750a7dde73 to your computer and use it in GitHub Desktop.
Countdown solver in C#
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
namespace Countdown | |
{ | |
internal interface IExpression { }; | |
class Op : IExpression | |
{ | |
public Func<int, int, int> Func { get; private set; } | |
public string Name { get; private set; } | |
public Op(string name, Func<int, int, int> op) | |
{ | |
Func = op; | |
Name = name; | |
} | |
public override string ToString() | |
{ | |
return Name; | |
} | |
} | |
class Num : IExpression | |
{ | |
public int Val { get; set; } | |
public Num(int val) { Val = val; } | |
public override string ToString() | |
{ | |
return Val.ToString(); | |
} | |
} | |
class Program | |
{ | |
static readonly Random r = new Random(); | |
private static readonly Op[] Ops = | |
{ | |
new Op("+", (a, b) => a + b), | |
new Op("-", (a, b) => a - b), | |
new Op("*", (a, b) => a * b), | |
new Op("/", (a, b) => | |
{ | |
if (a%b != 0) | |
{ | |
throw new ArgumentException(); | |
} | |
return a/b; | |
}) | |
}; | |
static void Main(string[] args) | |
{ | |
var target = r.Next(1000); | |
var stack = new Stack<IExpression>(); | |
var numbers = new List<int> | |
{ | |
OneFromTheTop(), | |
AnyOther(), | |
AnyOther(), | |
AnyOther(), | |
AnyOther(), | |
AnyOther(), | |
}; | |
Console.WriteLine("Target {0}", target); | |
Console.Write("Using {0}", string.Join(", ", numbers)); | |
Console.WriteLine(); | |
NextGen(numbers, stack, target); | |
} | |
private static void NextGen(List<int> numbers, Stack<IExpression> stack, int target) | |
{ | |
for (int i = 0; i < numbers.Count; i++) | |
{ | |
var n = numbers[i]; | |
var nextList = new List<int>(numbers); | |
nextList.RemoveAt(i); | |
stack.Push(new Num(n)); | |
try | |
{ | |
var val = Evaluate(stack); | |
if (val == target) | |
{ | |
Print(stack); | |
} | |
if (val < 0) throw new Exception(); | |
foreach (var op in Ops) | |
{ | |
stack.Push(op); | |
NextGen(nextList, stack, target); | |
stack.Pop(); | |
} | |
} | |
catch | |
{ } | |
stack.Pop(); | |
} | |
} | |
private static void Print(IEnumerable<IExpression> stack) | |
{ | |
foreach (var expression in stack.Reverse()) | |
{ | |
Console.Write(expression); | |
} | |
Console.WriteLine(); | |
} | |
private static int Evaluate(IEnumerable<IExpression> stack) | |
{ | |
int acc = 0; | |
Op currentOp = null; | |
foreach (var expression in stack.Reverse()) | |
{ | |
if (expression is Num) | |
{ | |
int val = (expression as Num).Val; | |
acc = currentOp != null ? currentOp.Func(acc, val) : val; | |
} | |
else | |
{ | |
currentOp = expression as Op; | |
} | |
} | |
return acc; | |
} | |
private static int OneFromTheTop() | |
{ | |
return PickFrom(25, 50, 75, 100); | |
} | |
private static int AnyOther() | |
{ | |
return PickFrom(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); | |
} | |
private static int PickFrom(params int[] numbers) | |
{ | |
return numbers[r.Next(numbers.Length)]; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The output isn't mathematically correct - it should be read strictly left-to-right, there's no operator precedence. It also doesn't attempt to eliminate equivalent solutions. Both of these problems might be interesting extensions for a kata :)