关闭

[分享]24点源代码[使用扑克牌显示]

标签: liststringnullobject算法random
180人阅读 评论(0) 收藏 举报

最近做了一个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<char, int> m_LeftPriority = new Dictionary<char, int>();

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

        /// <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 * 90, 70, m_FourNumber[i] * 4 - 4 + m_CardsColor[i], 0, 1);
                }
            }
        }
        #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

    }
}

原文地址:http://www.cnblogs.com/snowdust/archive/2010/01/22/1653154.html

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:67411次
    • 积分:810
    • 等级:
    • 排名:千里之外
    • 原创:3篇
    • 转载:66篇
    • 译文:0篇
    • 评论:6条
    最新评论