雪尘

我躲在/濒临深秋的树下/享受孤独/我听着/紫罗兰色的琴声/迎接黎明

博客园 首页 新随笔 联系 订阅 管理

最近做了一个24点的程序,思想是循环生成4个数的排列和11种表达式,再计算结果,如果为24则成功。 

注:生成的数使用扑克牌显示。 

一些关键的类如下: 

1.排列组合类 

2.表达式计算类 

3.24点计算类

软件截图:

对应的源代码如下: 

1.排列组合类:

//-----------------------------------------------------------------------------
//
// 算法:排列组合类
//
// 版权所有(C) Snowdust
// 个人博客    http://blog.csdn.net/snowdust & http://snowdust.cnblogs.com
// MSN & Email snowdust77@sina.com
//
// 此源代码可免费用于各类软件(含商业软件)
// 允许对此代码的进一步修改与开发
// 但必须完整保留此版权信息
//
// 调用方法如下:
//
// 1.GetPermutation(T[], startIndex, endIndex)
// 对startIndex到endIndex进行排列,其余元素不变
//
// 2.GetPermutation(T[])
// 返回数组所有元素的全排列
//
// 3.GetPermutation(T[], n)
// 返回数组中n个元素的排列
//
// 4.GetCombination(T[], n)
// 返回数组中n个元素的组合
//
// 版本历史:
// V0.1 2010-01-20 摘要:首次创建 
//
//-----------------------------------------------------------------------------

using System;
using System.Collections.Generic;

namespace Arithmetic
{
    
public class PermutationAndCombination<T>
    {
        
#region 内部方法
        
/// <summary>
        
/// 递归算法求数组的组合(私有成员)
        
/// </summary>
        
/// <param name="list">返回的范型</param>
        
/// <param name="t">所求数组</param>
        
/// <param name="n">辅助变量</param>
        
/// <param name="m">辅助变量</param>
        
/// <param name="b">辅助数组</param>
        
/// <param name="M">辅助变量M</param>
        private static void GetCombination(ref List<T[]> list, T[] t, int n, int m, int[] b, int M)
        {
            
for (int i = n; i >= m; i--)
            {
                b[m 
- 1= i - 1;
                
if (m > 1)
                {
                    GetCombination(
ref list, t, i - 1, m - 1, b, M);
                }
                
else
                {
                    
if (list == null)
                    {
                        list 
= new List<T[]>();
                    }
                    T[] temp 
= new T[M];
                    
for (int j = 0; j < b.Length; j++)
                    {
                        temp[j] 
= t[b[j]];
                    }
                    list.Add(temp);
                }
            }
        }

        
/// <summary>
        
/// 递归算法求排列(私有成员)
        
/// </summary>
        
/// <param name="list">返回的列表</param>
        
/// <param name="t">所求数组</param>
        
/// <param name="startIndex">起始标号</param>
        
/// <param name="endIndex">结束标号</param>
        private static void GetPermutation(ref List<T[]> list, T[] t, int startIndex, int endIndex)
        {
            
if (startIndex == endIndex)
            {
                
if (list == null)
                {
                    list 
= new List<T[]>();
                }
                T[] temp 
= new T[t.Length];
                t.CopyTo(temp, 
0);
                list.Add(temp);
            }
            
else
            {
                
for (int i = startIndex; i <= endIndex; i++)
                {
                    Swap(
ref t[startIndex], ref t[i]);
                    GetPermutation(
ref list, t, startIndex + 1, endIndex);
                    Swap(
ref t[startIndex], ref t[i]);
                }
            }
        }
        
#endregion

        
#region 公共方法
        
/// <summary>
        
/// 交换两个变量
        
/// </summary>
        
/// <param name="a">变量1</param>
        
/// <param name="b">变量2</param>
        public static void Swap(ref T a, ref T b)
        {
            T temp 
= a;
            a 
= b;
            b 
= temp;
        }

        
/// <summary>
        
/// 求从起始标号到结束标号的排列,其余元素不变
        
/// </summary>
        
/// <param name="t">所求数组</param>
        
/// <param name="startIndex">起始标号</param>
        
/// <param name="endIndex">结束标号</param>
        
/// <returns>从起始标号到结束标号排列的范型</returns>
        public static List<T[]> GetPermutation(T[] t, int startIndex, int endIndex)
        {
            
if (startIndex < 0 || endIndex > t.Length - 1)
            {
                
return null;
            }
            List
<T[]> list = new List<T[]>();
            GetPermutation(
ref list, t, startIndex, endIndex);
            
return list;
        }

        
/// <summary>
        
/// 返回数组所有元素的全排列
        
/// </summary>
        
/// <param name="t">所求数组</param>
        
/// <returns>全排列的范型</returns>
        public static List<T[]> GetPermutation(T[] t)
        {
            
return GetPermutation(t, 0, t.Length - 1);
        }

        
/// <summary>
        
/// 求数组中n个元素的排列
        
/// </summary>
        
/// <param name="t">所求数组</param>
        
/// <param name="n">元素个数</param>
        
/// <returns>数组中n个元素的排列</returns>
        public static List<T[]> GetPermutation(T[] t, int n)
        {
            
if (n > t.Length)
            {
                
return null;
            }
            List
<T[]> list = new List<T[]>();
            List
<T[]> c = GetCombination(t, n);
            
for (int i = 0; i < c.Count; i++)
            {
                List
<T[]> l = new List<T[]>();
                GetPermutation(
ref l, c[i], 0, n - 1);
                list.AddRange(l);
            }
            
return list;
        }


        
/// <summary>
        
/// 求数组中n个元素的组合
        
/// </summary>
        
/// <param name="t">所求数组</param>
        
/// <param name="n">元素个数</param>
        
/// <returns>数组中n个元素的组合的范型</returns>
        public static List<T[]> GetCombination(T[] t, int n)
        {
            
if (t.Length < n)
            {
                
return null;
            }
            
int[] temp = new int[n];
            List
<T[]> list = new List<T[]>();
            GetCombination(
ref list, t, t.Length, n, temp, n);
            
return list;
        }
        
#endregion
    }
}

 

2.表达式计算类

//-----------------------------------------------------------------------------
//
// 算法:表达式计算类
//
// 版权所有(C) Snowdust
// 个人博客    http://blog.csdn.net/snwodust & http://snowdust.cnblogs.com
// MSN & Email snwodust77@sina.com
//
// 此源代码可免费用于各类软件(含商业软件)
// 允许对此代码的进一步修改与开发
// 但必须完整保留此版权信息
//
// 支持以下运算符:加(+)、减(-)、乘(*)、除(/)和幂(^)
//
// 如果表达式错误,将返回null值
//
// 调用方法如下:
//
// Calculate(expression)
// 返回double?类型的值
// 例如 Calculate("3+4*(5-2)^2+4") = 43
//
// 版本历史:
// V0.1 2010-01-20 摘要:首次创建 
//
//-----------------------------------------------------------------------------

using System;
using System.Collections.Generic;

namespace Arithmetic
{
    
public class Calculator
    {
        
#region 定义变量

        
/// <summary>
        
/// 运算符左优先级
        
/// </summary>
        private static Dictionary<charint> m_LeftPriority = new Dictionary<charint>();

        
/// <summary>
        
/// 运算符右优先级
        
/// </summary>
        private static Dictionary<charint> m_RightPriority = new Dictionary<charint>();

        
/// <summary>
        
/// 栈
        
/// </summary>
        private static Stack<double> m_Stack = new Stack<double>();

        
#endregion

        
#region 构造函数

        
/// <summary>
        
/// 构造函数
        
/// </summary>
        static Calculator()
        {
            
if (m_LeftPriority.Count == 0)
            {
                m_LeftPriority.Add(
'='0);
                m_LeftPriority.Add(
'('10);
                m_LeftPriority.Add(
'*'50);
                m_LeftPriority.Add(
'/'50);
                m_LeftPriority.Add(
'^'70);
                m_LeftPriority.Add(
'+'30);
                m_LeftPriority.Add(
'-'30);
                m_LeftPriority.Add(
')'80);
            }
            
if (m_RightPriority.Count == 0)
            {
                m_RightPriority.Add(
'='0);
                m_RightPriority.Add(
'('80);
                m_RightPriority.Add(
'*'40);
                m_RightPriority.Add(
'/'40);
                m_RightPriority.Add(
'^'60);
                m_RightPriority.Add(
'+'20);
                m_RightPriority.Add(
'-'20);
                m_RightPriority.Add(
')'10);
            }
        }
        
#endregion

        
#region 内部方法
        
/// <summary>
        
/// 判断字符是否为运算符
        
/// </summary>
        
/// <param name="ch">待判断的字符</param>
        
/// <returns>如果是运算符,返回True,否则返回False</returns>
        private static bool IsOperator(char ch)
        {
            
if (ch == '(' || ch == ')' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^')
            {
                
return true;
            }
            
return false;
        }

        
/// <summary>
        
/// 判断运算符的优先级
        
/// </summary>
        
/// <param name="op1">第1个运算符</param>
        
/// <param name="op2">第2个运算符</param>
        
/// <returns>优先级:op1大于op2,返回1,op1等于op2-返回0,op1小于op2,返回-1</returns>
        private static int Precede(char op1, char op2)
        {
            
return m_LeftPriority[op1].CompareTo(m_RightPriority[op2]);
        }

        
/// <summary>
        
/// 操作数进栈
        
/// </summary>
        
/// <param name="operand"></param>
        private static void PushOperand(double operand)
        {
            m_Stack.Push(operand);
        }

        
/// <summary>
        
/// 获取栈中最近的两个操作数
        
/// </summary>
        
/// <param name="operand1">第1个操作数</param>
        
/// <param name="operand2">第2个操作数</param>
        private static bool GetTwoOperands(ref double operand1, ref double operand2)
        {
            
bool ret = true;
            
if (m_Stack.Count == 0)
            {
                
// 表达式有误
                m_Stack.Clear();
                ret 
= false;
            }
            operand1 
= m_Stack.Pop();
            
if (m_Stack.Count == 0)
            {
                
// 表达式有误
                m_Stack.Clear();
                ret 
= false;
            }
            operand2 
= m_Stack.Pop();
            
return ret;
        }

        
/// <summary>
        
/// 计算一次结果
        
/// </summary>
        
/// <param name="op">操作符</param>
        private static bool Calculate(char op)
        {
            
double operand1 = 0, operand2 = 0, result = 0;
            
bool ret = GetTwoOperands(ref operand1, ref operand2);
            
if (!ret)
            {
                ret 
= false;
                
return ret;
            }
            
switch (op)
            {
                
case '+': result = operand2 + operand1; break;
                
case '-': result = operand2 - operand1; break;
                
case '*': result = operand2 * operand1; break;
                
case '^': result = System.Math.Pow(operand2, operand1); break;
                
case '/':
                    
if (operand1 == 0)
                    {
                        
// 被0除
                        m_Stack.Clear();
                        ret 
= false;
                    }
                    
else
                    {
                        result 
= operand2 / operand1;
                    }
                    
break;
            }
            m_Stack.Push(result);
            
return ret;
        }
        
#endregion

        
#region 公共方法
        
/// <summary>
        
/// 将中缀表达式转换成后缀表达式
        
/// </summary>
        
/// <param name="expression">中缀表达式</param>
        
/// <returns>后缀表达式</returns>
        public static string TransExpression(string expression)
        {
            Stack
<char> s = new Stack<char>();
            s.Push(
'=');
            
int index = 0;
            
string ret = string.Empty;
            
while (index < expression.Length)
            {
                
char ch = expression[index];
                
if (!IsOperator(ch))
                {
                    
while (index < expression.Length && expression[index] >= '0' && expression[index] <= '9')
                    {
                        ret 
+= expression[index];
                        index
++;
                    }
                    ret 
+= '#';
                }
                
else
                {
                    
switch (Precede(s.Peek(), ch))
                    {
                        
case -1:
                            s.Push(ch);
                            index
++;
                            
break;
                        
case 0:
                            s.Pop();
                            index
++;
                            
break;
                        
case 1:
                            ret 
+= s.Pop();
                            
break;
                    }
                }
            }
            
while (s.Peek() != '=')
            {
                ret 
+= s.Pop();
            }
            
return ret;
        }

        
/// <summary>
        
/// 计算表达式的值(无需带=号)
        
/// </summary>
        
/// <param name="expression">待计算的表达式</param>
        
/// <returns>表达式的值</returns>
        public static double? Calculate(string expression)
        {
            
double operand;
            m_Stack.Clear();
            
string exp = TransExpression(expression);
            exp 
+= ' ';
            
int index = 0;
            
char ch = exp[index];
            
try
            {
                
while (ch != ' ')
                {
                    
if (ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '^')
                    {
                        
bool ret = Calculate(ch);
                        
if (!ret)
                        {
                            
return null;
                        }
                        index
++;
                        ch 
= exp[index];
                    }
                    
else if (ch == '#')
                    {
                        index
++;
                        ch 
= exp[index];
                    }
                    
else
                    {
                        operand 
= 0;
                        
while (ch >= '0' && ch <= '9')
                        {
                            operand 
= operand * 10 + Convert.ToDouble(ch.ToString());
                            index
++;
                            ch 
= exp[index];
                        }
                        m_Stack.Push(operand);
                    }
                }
                
if (m_Stack.Count == 0)
                {
                    
// 表达式有误
                    return null;
                }
                
double d = m_Stack.Pop();
                m_Stack.Clear();
                
return d;
            }
            
catch
            {
                
return null;
            }
        }
        
#endregion
    }
}

 

3.24点计算类

//-----------------------------------------------------------------------------
//
// 算法:24点计算类
//
// 版权所有(C) Snowdust
// 个人博客    http://blog.csdn.net/snowdust & http://snowdust.cnblogs.com
// MSN & Email snowdust77@sina.com
//
// 此源代码可免费用于各类软件(含商业软件)
// 允许对此代码的进一步修改与开发
// 但必须完整保留此版权信息
//
// 调用方法如下:
//
// 1.GetTwentyFourPointResultList(int[] array)
// 返回List<string>类型的所有结果列表
//
// 2.GetTwentyFourPointResultString(int[] array)
// 只返回一条结果
//
// 版本历史:
// V0.1 2010-01-21 摘要:首次创建 
//
//-----------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;

namespace Arithmetic
{
    
public class TwentyFourPoint
    {

        
#region 定义变量
        
/// <summary>
        
/// 表达式类型
        
/// 其中{0}{1}{2}{3}将会替换成数值,{5}{6}{7}替换成运算符(+-*/)
        
/// </summary>
        protected static string[] m_Expression = new string[] {
            
"{0}{4}{1}{5}{2}{6}{3}",     // 类型1: 1+2*3/4
            "({0}{4}{1}){5}{2}{6}{3}",   // 类型2: (1+2)*3/4
            "({0}{4}{1}{5}{2}){6}{3}",   // 类型3: (1+2*3)/4
            "(({0}{4}{1}){5}{2}){6}{3}"// 类型4: ((1+2)*3)/4
            "({0}{4}({1}{5}{2})){6}{3}"// 类型5: (1+(2*3))/4
            "{0}{4}({1}{5}{2}){6}{3}",   // 类型6: 1+(2*3)/4
            "{0}{4}({1}{5}{2}{6}{3})",   // 类型7: 1+(2*3/4)
            "{0}{4}(({1}{5}{2}){6}{3})"// 类型8: 1+((2*3)/4)
            "{0}{4}({1}{5}({2}{6}{3}))"// 类型9: 1+(2*(3/4))
            "{0}{4}{1}{5}({2}{6}{3})",   // 类型10:1+2*(3/4)
            "({0}{4}{1}){5}({2}{6}{3})"  // 类型11:(1+2)*(3/4)
        };
        
/// <summary>
        
/// 运算符类型
        
/// </summary>
        protected static string[] m_Operator = new string[] { "+""-""*""/" };

        
/// <summary>
        
/// 运算结果为24
        
/// </summary>
        protected static int m_ObjectNumber = 24;

        
/// <summary>
        
/// 结果误差
        
/// </summary>
        protected static double m_Error = 0.0001;

        
#endregion

        
#region 公共方法
        
/// <summary>
        
/// 计算24点的结果
        
/// </summary>
        
/// <param name="array">数值数组</param>
        
/// <param name="getAllResult">是否获取所有结果</param>
        
/// <returns>结果列表</returns>
        public static List<string> GetResultList(int[] array, bool getAllResult)
        {
            
if (array.Length != 4)
            {
                
return null;
            }
            List
<string> m_Result = new List<string>();
            List
<int[]> m_OperandPermutation = Arithmetic.PermutationAndCombination<int>.GetPermutation(array);
            
for (int i = 0; i < m_OperandPermutation.Count; i++)
            {
                
for (int op1 = 0; op1 < 4; op1++)
                {
                    
for (int op2 = 0; op2 < 4; op2++)
                    {
                        
for (int op3 = 0; op3 < 4; op3++)
                        {
                            
for (int k = 0; k < m_Expression.Length; k++)
                            {
                                
string str = string.Format(m_Expression[k], m_OperandPermutation[i][0], m_OperandPermutation[i][1], m_OperandPermutation[i][2], m_OperandPermutation[i][3], m_Operator[op1], m_Operator[op2], m_Operator[op3]);
                                
double? d = Arithmetic.Calculator.Calculate(str);
                                
if (d != null && d.Value >= m_ObjectNumber - m_Error && d.Value <= m_ObjectNumber + m_Error) //由于浮点数操作可能会导致误差,因此忽略小于0.0001的误差
                                {
                                    
if (!m_Result.Contains(str))
                                    {
                                        m_Result.Add(str);
                                        
if (!getAllResult)
                                        {
                                            
return m_Result;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            
return m_Result;
        }

        
/// <summary>
        
/// 计算24点的结果(返回所有解的记录)
        
/// </summary>
        
/// <param name="array">数值数组</param>
        
/// <returns>结果列表</returns>
        public static List<string> GetResultList(int[] array)
        {
            
return GetResultList(array, true);
        }

        
/// <summary>
        
/// 计算24点的结果(如果有解,只返回一条记录)
        
/// </summary>
        
/// <param name="array">数值数组</param>
        
/// <returns>结果字符串</returns>
        public static string GetResultString(int[] array)
        {
            List
<string> list = GetResultList(array, false);
            
if (list.Count == 1)
            {
                
return list[0];
            }
            
else
            {
                
return string.Empty;
            }
        }
        
#endregion

    }
}

 

主窗体的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Runtime.InteropServices; 
using System.Windows.Forms;

namespace AppMain
{
    
public partial class MainForm : Form
    {

        
#region 声明扑克牌API

        
// cards.dll文件位于System32目录下

        [DllImport(
"cards.dll")]
        
public static extern bool cdtInit(ref int width, ref int height);

        [DllImport(
"cards.dll")]
        
public static extern void cdtTerm();

        [DllImport(
"cards.dll")]
        
public static extern bool cdtDraw(IntPtr hdc, int x, int y, int card, int mode, long color);
        
        
private IntPtr m_HDC = new IntPtr();
        
        
#endregion

        
#region 定义变量

        
/// <summary>
        
/// 四个数
        
/// </summary>
        private int[] m_FourNumber = new int[4];

        
/// <summary>
        
/// 四种花色
        
/// </summary>
        private int[] m_CardsColor = new int[4];

        
/// <summary>
        
/// 计算结果
        
/// </summary>
        private string m_Result = string.Empty;

        
#endregion

        
#region 自定义方法
        
/// <summary>
        
/// 初始化
        
/// </summary>
        private void Init()
        {
            
//清除结果
            this.txt_Result.Text = string.Empty;            

            
//随机生成四个数,直至有解
            Random rand = new Random();
            m_Result 
= string.Empty;
            
while (m_Result == string.Empty)
            {
                
for (int i = 0; i < m_FourNumber.Length; i++)
                {
                    m_FourNumber[i] 
= rand.Next(10+ 1;
                }
                m_Result 
= Arithmetic.TwentyFourPoint.GetResultString(m_FourNumber);
            }

            
//随机生成扑克牌的花色
            for (int i = 0; i < m_FourNumber.Length; i++)
            {
                m_CardsColor[i] 
= rand.Next(4);
            }

            
//重绘以正确显示扑克牌
            this.Refresh();
        }

        
/// <summary>
        
/// 绘制四张扑克牌
        
/// </summary>
        private void DrawCards()
        {
            
for (int i = 0; i < this.m_FourNumber.Length; i++)
            {
                
if (m_FourNumber[i] > 0)
                {
                    cdtDraw(m_HDC, 
25 + i * 9070, m_FourNumber[i] * 4 - 4 + m_CardsColor[i], 01);
                }
            }
        }
        
#endregion

        
#region 事件处理
        
        
public MainForm()
        {
            InitializeComponent();
            
            
int width, height;
            width 
= 0; height = 0;
            cdtInit(
ref width, ref height);  // 初始化扑克牌
        }

        
private void MainForm_Load(object sender, EventArgs e)
        {
            
this.Icon = Properties.Resources.App;
            Init();
        }

        
private void TwentyFourPointForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            cdtTerm(); 
        }

        
// 重写窗体的OnPaint方法
        protected override void OnPaint(PaintEventArgs e)
        {
            Graphics g 
= e.Graphics;
            m_HDC 
= g.GetHdc();
            g.ReleaseHdc(m_HDC);
            DrawCards();
        }

        
private void btn_Build_Click(object sender, EventArgs e)
        {
            Init();
        }

        
private void btn_Setup_Click(object sender, EventArgs e)
        {
            SetupForm form 
= new SetupForm();
            form.FourNumber 
= m_FourNumber;
            
if (form.ShowDialog() == DialogResult.OK)
            {
                m_FourNumber 
= form.FourNumber;
                m_Result 
= Arithmetic.TwentyFourPoint.GetResultString(m_FourNumber);
                
this.txt_Result.Text = m_Result;
                
this.Refresh();
                
if (m_Result == string.Empty)
                {
                    MessageBox.Show(
"无解");
                }
            }
        }

        
private void btn_Result_Click(object sender, EventArgs e)
        {
            
this.txt_Result.Text = m_Result;
        }
        
#endregion

    }
}

 

下载地址1:点此下载

下载地址2:点此下载

posted on 2010-01-21 11:41  雪尘的博客  阅读(3185)  评论(12编辑  收藏  举报