using System.Collections;
using System.Collections.Generic;
private static readonly Operator[] Operators = new Operator[] { new AddOperator(), new SubtractOperator(), new MultiplyOperator(), new DivideOperator(), new NullOperator() };
public static void Main()
var numbers = new[] { 50, 100, 5, 7, 3 };
var stack = new Stack<AttemptState>();
stack.Push(new AttemptState(ImmutableStack<int>.Empty, ImmutableStack<string>.Empty, numbers));
var attempt = stack.Pop();
foreach (var remainingNumber in attempt.RemainingNumbers)
var attemptStack = attempt.Stack.Push(remainingNumber);
var history = attempt.History.Push(remainingNumber.ToString());
foreach (var op in Operators)
var operatedStack = op.TryApply(attemptStack);
if (operatedStack != null)
history = history.Push(op.Name);
if (operatedStack.Count == 1 && operatedStack.Top == target)
Console.WriteLine("GOT ONE");
Console.WriteLine(String.Join(", ", history.Reverse()));
else if (attempt.RemainingNumbers.Length > 1)
stack.Push(new AttemptState(operatedStack, history, attempt.RemainingNumbers.Except(new[] { remainingNumber }).ToArray()));
public static IEnumerable<IEnumerable<T>> Permutations<T>(IEnumerable<T> input)
foreach (var first in input)
var firstList = new[] { first };
foreach (var permutation in Permutations(input.Except(firstList)))
yield return firstList.Concat(permutation);
public struct AttemptState
public readonly ImmutableStack<int> Stack;
public readonly ImmutableStack<string> History;
public readonly int[] RemainingNumbers;
public AttemptState(ImmutableStack<int> stack, ImmutableStack<string> history, int[] remainingNumbers)
this.RemainingNumbers = remainingNumbers;
public abstract class Operator
public abstract string Name { get; }
public virtual ImmutableStack<int> TryApply(ImmutableStack<int> stack)
if (this.Operate(a, b, out result))
return stack.Push(result);
protected abstract bool Operate(int a, int b, out int result);
public class AddOperator : Operator
public override string Name { get { return "+"; } }
protected override bool Operate(int a, int b, out int result)
public class SubtractOperator : Operator
public override string Name { get { return "-"; } }
protected override bool Operate(int a, int b, out int result)
public class MultiplyOperator : Operator
public override string Name { get { return "*"; } }
protected override bool Operate(int a, int b, out int result)
public class DivideOperator : Operator
public override string Name { get { return "/"; } }
protected override bool Operate(int a, int b, out int result)
if (b > a || (a % b) != 0)
public class NullOperator : Operator
public override string Name { get { return ""; } }
public override ImmutableStack<int> TryApply(ImmutableStack<int> stack)
protected override bool Operate(int a, int b, out int result)
throw new NotImplementedException();
public abstract class ImmutableStack<T> : IEnumerable<T>
public static readonly ImmutableStack<T> Empty = new EmptyStack();
public abstract T Top { get; }
public abstract int Count { get; }
public bool IsEmpty { get { return this.Count == 0; } }
public ImmutableStack<T> Push(T item)
return new NonEmptyStack(item, this);
public IEnumerator<T> GetEnumerator()
for (var current = this; !current.IsEmpty; current = current.Pop())
yield return current.Top;
IEnumerator IEnumerable.GetEnumerator()
return this.GetEnumerator();
public abstract ImmutableStack<T> Pop();
private class EmptyStack : ImmutableStack<T>
public override T Top { get { throw new InvalidOperationException("An empty stack has no top"); } }
public override int Count { get { return 0; } }
public override ImmutableStack<T> Pop() { throw new InvalidOperationException("Cannot pop an empty stack"); }
private class NonEmptyStack : ImmutableStack<T>
private readonly ImmutableStack<T> tail;
private readonly int count;
public override T Top { get { return this.head; } }
public override int Count { get { return this.count; } }
public NonEmptyStack(T head, ImmutableStack<T> tail)
this.count = tail.Count + 1;
public override ImmutableStack<T> Pop()