C# 版本的24点实现
C# 版本的24点实现。
已经实现基本功能,可以正确的算 3, 3, 8, 8 这类组合。
稍加修改就可以支持任意数目的操作数和操作符组合形成的四则运算表达式,不限于24点。
代码还比较简单粗糙,晚一点优化了再更新此贴。
关于二叉树拓扑结构的遍历,参考了:
http://blogs.msdn.com/b/ericlippert/archive/2010/04/19/every-binary-tree-there-is.aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace calc24
{
class MainClass
{
public static void Main (string[] args)
{
var permuteOfNums = Permute (new List<int> { 4, 5, 6, 7 });
foreach (var op1 in new List<string>{"+","-","*","/"}) {
foreach (var op2 in new List<string>{"+","-","*","/"}) {
foreach (var op3 in new List<string>{"+","-","*","/"}) {
var ops = new List<string>{ op1, op2, op3 };
foreach (var node in AllCompleteBinaryTreesOf7Nodes()) {
foreach (var nums in permuteOfNums) {
var tree = CreateOne24CalculationFormula (node, nums, ops);
try {
var result = Evaluate (tree);
if (Math.Abs (result - 24) < 0.0001) {
Console.WriteLine (BinaryTreeString (tree));
}
} catch (DivideByZeroException) {
}
}
}
}
}
}
}
static float Evaluate (Node node)
{
switch (node.Data) {
case "+":
return Evaluate (node.Left) + Evaluate (node.Right);
case "-":
return Evaluate (node.Left) - Evaluate (node.Right);
case "*":
return Evaluate (node.Left) * Evaluate (node.Right);
case "/":
return Evaluate (node.Left) / Evaluate (node.Right);
default:
return float.Parse (node.Data);
}
}
static Node CreateOne24CalculationFormula (Node node, List<int> nums, List<string> operators)
{
Node result = null;
var iNums = 0;
var iOps = 0;
Func<Node, Node> copy = null;
copy = (src) => {
Node dest;
if (src.Left == null && src.Right == null) {
dest = new Node (null, null, nums [iNums++].ToString ());
} else {
var left = copy (src.Left);
var right = copy (src.Right);
dest = new Node (left, right, operators [iOps++]);
}
return dest;
};
result = copy (node);
return result;
}
static IEnumerable<List<T>> Permute<T> (List<T> elements)
{
if (elements.Count == 1)
return EnumerableOfOneElement (elements);
IEnumerable<List<T>> result = null;
foreach (var first in elements) {
var remaining = elements.ToArray ().ToList ();
remaining.Remove (first);
var permutesOfRemaining = Permute (remaining);
foreach (var p in permutesOfRemaining) {
var arr = new List<T> { first };
arr.AddRange (p);
var seq = EnumerableOfOneElement (arr);
if (result == null) {
result = seq;
} else {
result = Enumerable.Union (result, seq);
}
}
}
return result;
}
static IEnumerable<T> EnumerableOfOneElement<T> (T element)
{
yield return element;
}
static IEnumerable<Node> AllCompleteBinaryTreesOf7Nodes ()
{
var trees = AllBinaryTrees (7);
return (from t in trees
where IsCompleteBinaryTree (t)
select t);
}
static bool IsCompleteBinaryTree (Node node)
{
if (node == null)
return true;
if (node.Left == null && node.Right != null ||
node.Left != null && node.Right == null)
return false;
return IsCompleteBinaryTree (node.Left) && IsCompleteBinaryTree (node.Right);
}
static IEnumerable<Node> AllBinaryTrees (int size)
{
if (size == 0)
return new Node[] { null };
return from i in Enumerable.Range (0, size)
from left in AllBinaryTrees (i)
from right in AllBinaryTrees (size - 1 - i)
select new Node (left, right, "");
}
public static string BinaryTreeString (Node node)
{
var sb = new StringBuilder ();
Action<Node> f = null;
f = n => {
if (n == null) {
//sb.Append ("x");
} else if (new []{ "+", "-", "*", "/" }.Contains (n.Data)) {
sb.Append ("(");
f (n.Left);
sb.Append (" " + n.Data + " ");
f (n.Right);
sb.Append (")");
} else {
sb.Append (n.Data);
}
};
f (node);
return sb.ToString ();
}
}
class Node
{
public Node Left { get; set; }
public Node Right { get; set; }
public string Data { get; set; }
public Node ()
{
}
public Node (Node left, Node right, string data)
{
this.Left = left;
this.Right = right;
this.Data = data;
}
}
}
测试:
(4 * ((5 + 7) - 6))
(4 * ((7 + 5) - 6))
((5 + 7) * (6 - 4))
((7 + 5) * (6 - 4))
(((5 + 7) - 6) * 4)
(((7 + 5) - 6) * 4)
(4 * (5 + (7 - 6)))
(4 * (7 + (5 - 6)))
(4 * ((5 - 6) + 7))
(4 * ((7 - 6) + 5))
((6 - 4) * (5 + 7))
((6 - 4) * (7 + 5))
((5 + (7 - 6)) * 4)
((7 + (5 - 6)) * 4)
(((5 - 6) + 7) * 4)
(((7 - 6) + 5) * 4)
(4 * (5 - (6 - 7)))
(4 * (7 - (6 - 5)))
((5 - (6 - 7)) * 4)
((7 - (6 - 5)) * 4)
Press any key to continue...