当前位置: 首页 > news >正文

winform 五子棋

半年前写过一个winform小游戏五子棋,比较粗糙,页面如下:

代码结构如下:

ok. 入口程序Program.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;namespace WindowsFormsApp1
{// 游戏状态public enum State{PUT_WTITE, PUT_BLACK, FINISH,}public static class Program{//const int state = 0; // 0 : 未开始  1: 已开始  2:结束public static State state = State.FINISH;public static Form1 form = null;// 字典,表示棋盘状态,所有的棋子:public static Dictionary<string, int> dic = new Dictionary<string, int>(); // key: 棋子横坐标_纵坐标  value: 1:白棋, 2:黑棋/// <summary>/// 应用程序的主入口点。/// </summary>[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(form = new Form1());// Console.WriteLine("state: " + state);}}
}

常量Constant.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace WindowsFormsApp1
{class Constant{public const int size = 11; // 棋盘大小 11 X 11public const int range = 15; // 棋盘中每个棋子的点击范围,鼠标在这个范围就可以把棋子放在这个地方。public const int QI_RADIUS = 10; // 棋盘中的棋子半径public const int paddingEdge = 30; // 棋盘间距public const int writeQi = 1;public const int blackQi = 2;public const int MAX_WEIGHT = 9; // 计算分数的各种场景的权重中, 直接能赢是最大权重。即10的9次方的分数。}
}

页面是拖控件生成的,左边部分绘制棋盘和棋子,右边显示一些信息,以及有一些控制按钮,如下:

核心类Form1.cs,代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Media;
using System.Threading;namespace WindowsFormsApp1
{public partial class Form1 : Form{private Nullable<Point> mMousePos = null; // 鼠标在panel1中的位置private Panel panel_mourse = null;private int panel_mourse_width;private int panel_mourse_height;private bool showPanel_mourse = false; // 是否会绘制自定义跟手鼠标// 记录棋盘中每个可以防止棋子位置的感应范围,鼠标在这个范围内则可以放置棋子.//private Dictionary<string, int[]> rangeDir = new Dictionary<string, int[]>();int[] xLocs = new int[Constant.size]; // 棋子所有的横坐标int[] yLocs = new int[Constant.size];//int[,] locs = new int[Constant.size, Constant.size]; private bool isRangeInited = false;int playTime = 0;// 这俩变量决定白棋和黑棋是否为AIprivate bool isWriteAI = false; // 白棋是否为AIprivate bool isBlackAI = true; // 黑棋是否为AI// AI水平enum AILevel { FOOL,CLEVER,}private AILevel aiLevel = AILevel.FOOL; // AI默认是个傻瓜private int[] curPosition = new int[] { -1, -1 }; // 记录最新放置的位置public Form1(){// 日志相关System.Diagnostics.Trace.WriteLine("日志开始");System.Diagnostics.Trace.Listeners.Add(new System.Diagnostics.TextWriterTraceListener("logfile.log"));System.Diagnostics.Trace.AutoFlush = true;System.Diagnostics.Trace.WriteLine("to init ...");System.Diagnostics.Debug.WriteLine("love u vicky du...");aiLevel = AILevel.CLEVER; // 聪明电脑InitializeComponent();this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);this.panel2.MouseMove += new MouseEventHandler(panel2_MouseMove); // panel2设置鼠标移动监听panel2.MouseLeave += new EventHandler(panel2_MouseLeave);panel2.MouseEnter += new EventHandler(panel2_MouseEnter);panel2.MouseClick += new MouseEventHandler(panel2_MouseClick);if (showPanel_mourse) {panel_mourse = new Panel();Image hand = Properties.Resources.hand_mourse;panel_mourse.Width = (panel_mourse_width = hand.Width / 4);panel_mourse.Height = (panel_mourse_height = hand.Height / 4);panel_mourse.Location = new Point(panel2.Location.X//+ panel_mourse_width / 2, panel2.Location.Y//+ panel_mourse_height / 2);this.Controls.Add(panel_mourse);panel_mourse.Paint += new PaintEventHandler(panel_mourse_Paint);panel_mourse.BackColor = System.Drawing.Color.Transparent;panel_mourse.Parent = this; ;panel_mourse.BringToFront(); // 置于最上层, 会拦截住下面panel的鼠标事件panel_mourse.MouseEnter += new EventHandler(panel_mourse_MouseEnter);panel_mourse.MouseLeave += new EventHandler(panel_mourse_MouseLeave);panel_mourse.Visible = false;}//this.MouseMove += new MouseEventHandler(Form1_MouseMove); // 实现不了// 初始化rangeDirinitRangeDir();// 计时器timer1.Interval = 1000;timer1.Tick += new EventHandler(TimerEventProcessor);}private void Form1_MouseMove(object sender, MouseEventArgs e){Cursor.Show();}private void button1_Click(object sender, EventArgs e){this.button1.Text = "爱你哦";}private void Form1_Load(object sender, EventArgs e){this.panel1.Text = "love u vicky du";this.Text = "i love u vicky du!";}private void panel1_Paint(object sender, PaintEventArgs e){ }private void button2_Click(object sender, EventArgs e){}private void pictureBox1_Click(object sender, EventArgs e){}private void initRangeDir() {// 棋盘中每个棋子的范围 x坐标和y坐标10范围内}private void panel2_Paint(object sender, PaintEventArgs e) // 该面板绘制棋盘和棋子{// 这样是相对于整个容器的位置画图的/*Console.WriteLine("panel2_Paint ...");// 绘制棋盘Graphics g = this.CreateGraphics();Pen pen = new Pen(Color.Black);g.DrawLine(pen, 0, 0, 800, 800);g.DrawLine(pen, 0, 0, 100, 1000);*/// 创建一个与Panel控件大小相同的Bitmap对象Bitmap buffer = new Bitmap(panel2.Width, panel2.Height);// 创建Graphics对象来绘制到Bitmap上using (Graphics g = Graphics.FromImage(buffer)) {// 在这里进行所有的绘制操作g.FillRectangle(Brushes.White, 0, 0, panel2.Width, panel2.Height);// 绘制图片Pen pen2 = new Pen(Color.Black);//e.Graphics.DrawLine(pen, 0, 0, 1000, 1000); // 这个是在当前组件绘制// Bitmap bitmap = WindowsFormsApp1.Properties.Resources.haidi;//Image image = Utils.GetImageFromResource("WindowsFormsApplication1.Properties.Resources.haidi.png");Image image = Properties.Resources.haidi;g.DrawImage(image, new Rectangle(0, 0, panel2.Width, panel2.Height));// 绘制棋盘边缘int startX = Constant.paddingEdge;int endX = panel2.Width - Constant.paddingEdge;int paddingX = (endX - startX) / (Constant.size - 1);int paddingY = paddingX;int size = panel2.Width - 2 * Constant.paddingEdge;int startY = Constant.paddingEdge;int endY = startY + size;Pen edgePen = new Pen(Color.Black, (float)4.1);g.DrawLines(edgePen,new PointF[] { new PointF(startX, startY), new PointF(endX, startY), new PointF(endX, endY), new PointF(startX, endY), new PointF(startX, startY)});if (!isRangeInited) {for (int i = 0; i < xLocs.Length; i++) {xLocs[i] = startX + i * paddingX;}for (int i = 0; i < yLocs.Length; i++){yLocs[i] = startY + i * paddingY;}}// 绘制其他横线startX = Constant.paddingEdge;startY = Constant.paddingEdge;for (int i = 0; i < Constant.size - 2; i++){startY += paddingY;g.DrawLines(pen2,new PointF[] { new PointF(startX, startY), new PointF(endX, startY) });}// 绘制其他竖线startX = Constant.paddingEdge;startY = Constant.paddingEdge;for (int i = 0; i < Constant.size - 2; i++){startX += paddingX;g.DrawLines(pen2,new PointF[] { new PointF(startX, startY), new PointF(startX, endY) });}//  绘制棋子foreach (var item in Program.dic){string[] result = item.Key.Split('_');string xStr = result[0];string yStr = result[1];int x = int.Parse(xStr); // 棋子横坐标,即第多少列,索引从0开始int y = int.Parse(yStr); // 棋子纵坐标,即哪一行,索引从0开始int qi = item.Value; // 1:白棋 2: 黑棋// 圆心位置int locX = xLocs[x];int locY = yLocs[y];Brush brush = new SolidBrush(qi == Constant.writeQi? Color.White: Color.Black); // // 设置填充颜色g.FillEllipse(brush, locX - Constant.QI_RADIUS, locY - Constant.QI_RADIUS, Constant.QI_RADIUS * 2, Constant.QI_RADIUS * 2);if (x == curPosition[0] && y == curPosition[1]) {// 绘制棋子的圆形粗线,标识这是刚下的棋子Pen penKx = new Pen(Color.Blue, 2);int r = Constant.QI_RADIUS + 1;g.DrawEllipse(penKx, locX - r, locY - r, r << 1, r << 1);}}// TODO 绘制鼠标处可以放置的棋子,起到提示作用,需要判断游戏状态。 //  鼠标在棋盘上移动时,绘制鼠标.  绘制太频繁,移走单独绘制!//if (mMousePos != null)//{//Image hand = Properties.Resources.hand_mourse;//e.Graphics.DrawImage(hand, new Rectangle(mMousePos.Value.X, mMousePos.Value.Y, hand.Width, hand.Height));//}//g.DrawLine(pen2, 0, 0, 10, 0);}// 最后, 将绘制好的Bitmap一次性绘制到Panel上e.Graphics.DrawImage(buffer, 0, 0);}// 鼠标在棋盘上移动时,绘制鼠标private void panel2_MouseMove(object sender, MouseEventArgs e){// 获取鼠标在Panel中的位置mMousePos = new Point(e.X, e.Y);// 刷新太频繁!单独绘制long timestamp = DateTime.Now.Ticks;if (timestamp % 10 == 0) {//panel2.Refresh();}if (panel_mourse != null) {panel_mourse.Location = new Point(mMousePos.Value.X//+ panel_mourse.Width / 2, mMousePos.Value.Y// + panel_mourse.Height / 2);panel_mourse.Refresh();}}// 点击棋盘,下棋private void panel2_MouseClick(object sender, MouseEventArgs e) {// AI下棋时点击无效if (Program.state == State.PUT_WTITE && isWriteAI) {return;}if (Program.state == State.PUT_BLACK && isBlackAI) {return;}// 判断如果鼠标坐标靠近某个可以放棋的位置,其正在游戏,就将棋子加入,并刷新界面.if (Program.state != State.PUT_BLACK && Program.state != State.PUT_WTITE) {return;}int x = -1;int y = -1;for (int i = 0; i < this.xLocs.Length; i++) {int minX = xLocs[i] - Constant.range;if (e.X < minX) {return;}int maxX = xLocs[i] + Constant.range;if (e.X <= maxX) {x = i;break;}}if (x == -1) {return;}for (int i = 0; i < this.yLocs.Length; i++){int minY = yLocs[i] - Constant.range;if (e.Y < minY){return;}int maxY = yLocs[i] + Constant.range;if (e.Y <= maxY){y = i;break;}}if (y >= 0) { // 即找到了点击位置putQizi(x, y);}}private void putQizi(int x, int y) {string key = x.ToString() + "_" + y.ToString();if (!Program.dic.ContainsKey(key)){ // 这个位置空白int qizi = Program.state == State.PUT_WTITE ? Constant.writeQi : Constant.blackQi;Program.dic.Add(key, qizi);curPosition[0] = x;curPosition[1] = y;//MessageBox.Show("点中:" + (x.ToString() + "_" + y.ToString()));panel2.Refresh();// 判断状态是否赢bool win = isWin(Program.state, x, y);//  判断是否赢了if (win){timer1.Stop();label3.Text = Program.state == State.PUT_WTITE ? "白方" : "黑方";MessageBox.Show(Program.state == State.PUT_WTITE ? "白方胜!" : "黑方胜!");Program.state = State.FINISH;button2.Enabled = false;button1.Enabled = true;label5.Enabled = false;}else{// 先判断棋盘是否已满,满了则平局if (Program.dic.Count == xLocs.Length * yLocs.Length){// 平局:Program.state = State.FINISH;label3.Text = "亲,平局, 还不错哦~";button2.Enabled = false;button1.Enabled = true;label5.Enabled = false;timer1.Stop();MessageBox.Show("亲,平局, 还不错哦~");return;}if (Program.state == State.PUT_WTITE){Program.state = State.PUT_BLACK;}else{Program.state = State.PUT_WTITE;}label5.Text = (Program.state == State.PUT_BLACK ? "黑方走棋" : "白方走棋");}}if (Program.state != State.FINISH)procesAIIfNeed(); // 判断是AI走棋,则AI走棋}// AI计算棋子下在哪里最优,即计算最优解。// 思路:计算每个位置下棋能得多少分。// 计算一个位置下棋的分数,需要考虑4个方向的分数。计算4个方向分数之和// 1、如果这个位置下棋直接能赢,则这个位置可以获得最高分。且权重最高,其他位置不用计算了。//private int[] getGoodPutPozition(State state) { int[] res = new int[2]; // 最佳位置, 第一个数为列, 第二个数为行if (Program.dic.Count == 0) {res[0] = xLocs.Length >> 1;res[1] = yLocs.Length >> 1;return res;}if (Program.dic.Count == 1) { // 只有一个,说明是对方的int midX = xLocs.Length >> 1;int midY = yLocs.Length >> 1;if (Program.dic.ContainsKey(midX.ToString() + "_" + midY.ToString())){res[0] = midX + 1;res[1] = midY + 1;return res;}else {res[0] = midX;res[1] = midY;return res;}}double maxScore = 0; // 最高分, 优先把棋子放在分数最高的最佳位置for (int i = 0; i < xLocs.Length; i++) {for (int j = 0; j < yLocs.Length; j++) {if (Program.dic.ContainsKey(i.ToString() + "_" + j.ToString())) {// 这个位置已经有棋子了continue;}double score = getScore(state, i, j);System.Diagnostics.Debug.WriteLine("i:" + i + ", j:" + j + ", score: " + score);if (score > maxScore) {maxScore = score;res[0] = i;res[1] = j;// 判断直接能赢,就不用继续判断其他位置了。if (maxScore >= Math.Pow(10, Constant.MAX_WEIGHT)) {return res;}}}}return res;}// AI计算棋子下在这里能得多少分// 计算一个位置下棋的分数,需要考虑4个方向的分数。计算4个方向分数之和// 1、如果这个位置下棋直接能赢,则这个位置可以获得最高分。且权重最高。private double getScore(State state, int x, int y) {// 调试if ((x == 2 || x == 3) && y == 6) {System.Diagnostics.Debug.WriteLine("x:" + x + ",y:" + y +  ",左右方向:" + getScore(state, x, y, 0)+ ", 上下方向:" + getScore(state, x, y, 1) + ", 左上右下方向:" + getScore(state, x, y, 2)+ ", 右上左下方向:" + getScore(state, x, y, 3));}double score = getScore(state, x, y, 0) + getScore(state, x, y, 1) + getScore(state, x, y, 2) + getScore(state, x, y, 3);return score;}// 某方向的得分。dir为方向,一共有4个方向,约定0: 左右方向, 1: 上下方向, 2: 左上角和右下角的方向, 3:右上角和左下角的方向private double getScore(State state, int x, int y, int dir) {int qizi = state == State.PUT_WTITE ? Constant.writeQi : Constant.blackQi;int[] scene = getScene(state, x, y, dir);//MessageBox.Show("scene:" + String.Join(",", scene) + ", dir: " + dir);// 判断这个方向的分数:if (scene[0] >= 5) { // 直接能赢//MessageBox.Show("直接能赢");return Math.Pow(10, Constant.MAX_WEIGHT);}// 判断对方是否直接能赢, 即,如果对方放这个位置,对方直接就赢了int otherQizi = state == State.PUT_WTITE ? Constant.blackQi : Constant.writeQi;State otherState = state == State.PUT_WTITE ? State.PUT_BLACK : State.PUT_WTITE;int[] otherScene = getScene(otherState, x, y, dir); // 如果让对方在这里下棋,对方能得多少分// debug调试if (x == 2 && y == 6 && dir == 3) {System.Diagnostics.Debug.WriteLine("x:" + x + ", y:" + y + ", dir:" + dir+ ", otherScene[0]:" + otherScene[0] + ", otherScene[1]:" + otherScene[1]+ ", otherScene[2]:" + otherScene[2]);}// if (otherScene[0] >= 4 && otherScene[1] > 0 && otherScene[2] > 0) {// 调试// MessageBox.Show("对方再放这里就连成4个了, x:" + x + ", y:" + y);// }if (otherScene[0] >= 5) {// 如果不放这里,对方放这里,对方就赢了,所以需要堵住这里!//MessageBox.Show("如果不放这里,对方放这里,对方就赢了,所以需要堵住这里!");return Math.Pow(10, Constant.MAX_WEIGHT - 1);}if (aiLevel == AILevel.FOOL) { // 傻瓜电脑先考虑这一步。聪明电脑在后面再考虑这一步if (scene[0] + scene[1] + scene[2] == 5){// 得数有点低,因为对方只要堵住一个子就可以了//MessageBox.Show("有点低,因为对方只要堵住一个子就可以了");return Math.Pow(10, Constant.MAX_WEIGHT - 9);}// 肯定连不成5个的场景,给个最低分if (scene[0] + scene[1] + scene[2] < 5){//MessageBox.Show("肯定连不成5个的场景,给个最低分");return 0;}}// 判断放置在这里,我方的棋子能连续连上4个,且两头都是空白,对方堵不住!if (scene[0] == 4 && scene[1] >= 1 && scene[2] >= 1) {//MessageBox.Show("判断放置在这里,我方的棋子能连续连上4个,且两头都是空白,对方堵不住!");return Math.Pow(10, Constant.MAX_WEIGHT - 2);}// 判断对方放置在这里,棋子能连续连上4个,且两头都是空白,我方堵不住!if (otherScene[0] == 4 && otherScene[1] >= 1 && otherScene[2] >= 1){ // TODO 为啥没起作用?//MessageBox.Show("对方再放这里就连成4个了, x:" + x + ", y:" + y);if (x == 2 && y == 6 && dir == 3) {System.Diagnostics.Debug.WriteLine("zx, 不能让对方在这里放置棋子,不然右上左下方向堵不住");}return Math.Pow(10, Constant.MAX_WEIGHT - 3);}// 判断放置在这里, 我方棋子连成4个,但是被堵住了一头,对方必须堵住另一头才能阻止我方获胜if (scene[0] == 4 && (scene[1] >= 1 || scene[2] >= 1)){return Math.Pow(10, Constant.MAX_WEIGHT - 4);}// 我方棋子连成3个,且两头没被堵住,对方必须立即堵住一头才能阻止我方获胜// TODO 这种情况需考虑两头空白琪格的数量。如果两头一共只有俩空白琪格,对方只要堵住一个就行了,威胁不大,和连成4个但被堵住一个是一样的。if (scene[0] == 3 && (scene[1] >= 1 && scene[2] >= 1)){return Math.Pow(10, Constant.MAX_WEIGHT - 4);}// 判断放置在这里, 对方棋子连成4个,但是被堵住了一头,我方必须堵住另一头才能阻止对方获胜if (otherScene[0] == 4 && (otherScene[1] >= 1 || otherScene[2] >= 1)){return Math.Pow(10, Constant.MAX_WEIGHT - 5);}// 对方棋子连成3个,且两头没被堵住,我方必须立即堵住一头才能阻止对方获胜if (otherScene[0] == 3 && (otherScene[1] >= 1 && otherScene[2] >= 1)){return Math.Pow(10, Constant.MAX_WEIGHT - 5);}           if (scene[0] + scene[1] + scene[2] == 5){// 得数有点低,因为对方只要堵住一个子就可以了//MessageBox.Show("有点低,因为对方只要堵住一个子就可以了");return Math.Pow(10, Constant.MAX_WEIGHT - 9);}// 肯定连不成5个的场景,给个最低分if (scene[0] + scene[1] + scene[2] < 5){//MessageBox.Show("肯定连不成5个的场景,给个最低分");return 0;}// TODO 其他场景:if (scene[0] > 1) {return Math.Pow(10, Constant.MAX_WEIGHT - 6);}if (!isEdege(x, y)) {return Math.Pow(10, Constant.MAX_WEIGHT - 7);}return Math.Pow(10, Constant.MAX_WEIGHT - 8); }// 从某个方向判断棋子形状, x,y 假设已放置。 棋子形状可以判断走这步棋是好棋还是臭棋.// 返回int数组,第一个元素为连成连续棋子的个数。// 第二个元素为一头(左或上)是否还可以放置该颜色棋子(即没被堵死,下次若没被对方占领,还可以放),以及能放的棋子的数量// TODO 第二个元素改造为计算一头的空白的数量// 第三个参数为另一头(右或下)是否还可以和放置该颜色棋子. TODO 聪明的电脑需要考虑另一头空白数量// dir为方向。一共有4个方向,约定0: 左右方向, 1: 上下方向, 2: 左上角和右下角的方向, 3:右上角和左下角的方向private int[] getScene(State state, int x, int y, int dir) { // TODO arr[1]、arr[2]计算不对 为啥int[] arr = new int[3];arr[1] = 0; // 初始化为0,代表一头不能放置. 表示空白或己方棋子数量arr[2] = 0; int qizi = state == State.PUT_WTITE ? Constant.writeQi : Constant.blackQi;int count = 1; // 连续的棋子数// debug调试if (dir == 0 && Program.dic.Count == 3 && x == 4 && y == 5) {// MessageBox.Show("debug start");}if (dir == 0) { // 左右方向// 向左看// 还需判断往左边是否可以放置棋子, 比如3个白棋没有空隙水平排列在一起, 最左侧白棋的左边如果是空白,下次如果没被对方占用就可以自己占bool isEncounterBlank = false;for (int i = x - 1; i >= 0; i--){string key = i.ToString() + "_" + y.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){if (!isEncounterBlank){count++;// MessageBox.Show("count: " + count + ", x:" + x  + ", y:" + y);}else {arr[1] += 1;}}else{if (!Program.dic.ContainsKey(key)){// 空白isEncounterBlank = true;arr[1] += 1;}else {// 非空白,即对方棋子占了这个位置break;}                     }}// 向右看isEncounterBlank = false;for (int i = x + 1; i < xLocs.Length; i++){string key = i.ToString() + "_" + y.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){if (!isEncounterBlank)count++;elsearr[2] += 1;}else{if (!Program.dic.ContainsKey(key)){isEncounterBlank = true;arr[2] += 1;}else {break;}}}arr[0] = count;return arr;}if (dir == 1) { // 上下方向// 向上看bool isEncounterBlank = false;for (int i = y - 1; i >= 0; i--){string key = x.ToString() + "_" + i.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){if (!isEncounterBlank)count++;elsearr[1] += 1;}else{if (!Program.dic.ContainsKey(key)){isEncounterBlank = true;arr[1] += 1;}else {break;}}}// 向下看isEncounterBlank = false;for (int i = y + 1; i < yLocs.Length; i++){string key = x.ToString() + "_" + i.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){if (!isEncounterBlank)count++;elsearr[2] += 1;}else{if (!Program.dic.ContainsKey(key)){isEncounterBlank = true;arr[2] += 1;}else {break;}}}arr[0] = count;return arr;}if (dir == 2){ // 左上角和右下角的方向// 向左上角数bool isEncounterBlank = false;for (int i = x - 1, j = y - 1; i >= 0 && j >= 0;){string key = i.ToString() + "_" + j.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){if (!isEncounterBlank)count++;elsearr[1] += 1;}else{if (!Program.dic.ContainsKey(key)){isEncounterBlank = true;arr[1] += 1;}else {break;}}i--;j--;}// 向右下数isEncounterBlank = false;for (int i = x + 1, j = y + 1; i <= xLocs.Length && j <= yLocs.Length;){string key = i.ToString() + "_" + j.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){if (!isEncounterBlank)count++;elsearr[2] += 1;}else{if (!Program.dic.ContainsKey(key)){isEncounterBlank = true;arr[2] += 1;}else {break;}}i++;j++;}arr[0] = count;return arr;}if (dir == 3){ // 右上角和左下角的方向// 向右上角数bool isEncounterBlank = false;for (int i = x + 1, j = y - 1; i < xLocs.Length && j >= 0;){string key = i.ToString() + "_" + j.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){if (!isEncounterBlank)count++;elsearr[1] += 1;}else{if (!Program.dic.ContainsKey(key)){isEncounterBlank = true;arr[1] += 1;}else {break;}}i++;j--;}// 向左下角isEncounterBlank = false;for (int i = x - 1, j = y + 1; i >= 0 && j <= yLocs.Length;){string key = i.ToString() + "_" + j.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){if (!isEncounterBlank)count++;elsearr[2] += 1;}else{if (!Program.dic.ContainsKey(key)){isEncounterBlank = true;arr[2] += 1;}else {break;}}i--;j++;}arr[0] = count;return arr;}throw new ArgumentException("参数dir值不对!");}// 这个位置是否在边缘.private bool isEdege(int x, int y) {return x == 0 || y == 0 || x == xLocs.Length - 1 || y == yLocs.Length - 1;}// 判断赢了没有private bool isWin(State state, int x, int y) {int qizi = state == State.PUT_WTITE ? Constant.writeQi : Constant.blackQi;// 判断几个方向是否有连上5个的int count = 1;// 1、向上数for (int i = y - 1; i >= 0; i--) {string key = x.ToString() + "_" + i.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){count++;}else {break;}}if (count >= 5){return true;}// 2、向下数for (int i = y + 1; i < yLocs.Length; i++){string key = x.ToString() + "_" + i.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){count++;}else{break;}}if (count >= 5) {return true;}count = 1;// 3、向左数:for (int i = x - 1; i >= 0; i--) {string key = i.ToString() + "_" + y.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){count++;}else{break;}}if (count >= 5){return true;}// 4、向右数:for (int i = x + 1; i < xLocs.Length; i++){string key = i.ToString() + "_" + y.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){count++;}else{break;}}if (count >= 5){return true;}count = 1;// 5、向左上角数for (int i = x - 1, j = y - 1; i >= 0 && j >= 0;) {string key = i.ToString() + "_" + j.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){count++;}else{break;}i--;j--;}if (count >= 5){return true;}// 6、向右下数for (int i = x + 1, j = y + 1; i <= xLocs.Length && j <= yLocs.Length;){string key = i.ToString() + "_" + j.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){count++;}else{break;}i++;j++;}if (count >= 5){return true;}count = 1;// 向右上角数for (int i = x + 1, j = y - 1; i < xLocs.Length && j >= 0; ) {string key = i.ToString() + "_" + j.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){count++;}else{break;}i++;j--;}if (count >= 5){return true;}// 向左下角for (int i = x - 1, j = y + 1; i >= 0 && j <= yLocs.Length;){string key = i.ToString() + "_" + j.ToString();if (Program.dic.ContainsKey(key) && Program.dic[key] == qizi){count++;}else{break;}i--;j++;}return count >= 5;}private void panel_mourse_Paint(object sender, PaintEventArgs e) {// test/*Pen pen = new Pen(Color.Black);e.Graphics.DrawLine(pen, 0, 0, panel_mourse.Width, panel_mourse.Height);if (mMousePos != null){e.Graphics.DrawString("x:" + mMousePos.Value.X + ",Y:" + mMousePos.Value.Y, new Font("Arial", 9), Brushes.Black, 0, 0);}else {e.Graphics.DrawString("x:" +0 + ",Y:" + 0, new Font("Arial", 20), Brushes.Black, 0, 0);}*/if (mMousePos != null){// 画手//Image hand = Properties.Resources.hand_mourse;//e.Graphics.DrawImage(hand, new Rectangle(0, 0, panel_mourse.Width, panel_mourse.Height));// 画棋子if (Program.state == State.PUT_WTITE){ // 白棋Draw3DCircle(e.Graphics, panel_mourse.ClientRectangle, Color.Brown);}}}private void Draw3DCircle(Graphics graphics, Rectangle bounds, Color color){// 圆的半径int radius = Math.Min(bounds.Width, bounds.Height) / 2;// 圆心Point center = new Point(bounds.X + bounds.Width / 2, bounds.Y + bounds.Height / 2);// 绘制圆的底部和顶部弧形,模拟立体感using (Pen pen = new Pen(color)){/*// 绘制底部弧graphics.DrawArc(pen,center.X - radius, center.Y, 2 * radius, 2 * radius,90, 180);// 绘制顶部弧graphics.DrawArc(pen,center.X - radius, center.Y, 2 * radius, 2 * radius,270, 180);*///graphics.DrawLine(pen, 0, 0, bounds.Width, bounds.Height);}}private void panel2_MouseLeave(object sender, EventArgs e){// 鼠标离开Pane2时要执行的代码// MessageBox.Show("鼠标离开了Pane2!");Cursor.Show();mMousePos = null;//MessageBox.Show("离开了");if (panel_mourse != null) {panel_mourse.Visible = false;}}private void panel2_MouseEnter(object sender, EventArgs e){if (panel_mourse != null) {Cursor.Hide();panel_mourse.Visible = true;}}private void panel_mourse_MouseEnter(object sender, EventArgs e){Cursor.Hide();panel_mourse.Visible = true;}private void panel_mourse_MouseLeave(object sender, EventArgs e) {Cursor.Show();panel_mourse.Visible = false;}private void pictureBox1_Click_1(object sender, EventArgs e){}private void button1_Click_1(object sender, EventArgs e){// 开始游戏Program.state = State.PUT_WTITE;button1.Enabled = false;Program.dic.Clear();panel2.Refresh();label3.Text = "未知";button2.Enabled = true;label5.Text = "白方走棋";label5.Enabled = true;label4.Text = "0秒";playTime = 0;timer1.Enabled = true;timer1.Start();playMusic();curPosition = new int[] { -1, -1 };// 如果该机器人走棋,让他走:procesAIIfNeed();}private void procesAIIfNeed() { // 判断如果是机器人走棋,让机器人走一步棋if (Program.state == State.PUT_WTITE && isWriteAI){// 模拟机器人思考耗时,不然一瞬间棋子就摆上了Thread.Sleep(500);int[] position = getGoodPutPozition(Program.state);putQizi(position[0], position[1]);}else if (Program.state == State.PUT_BLACK && isBlackAI){Thread.Sleep(500);int[] position = getGoodPutPozition(Program.state);putQizi(position[0], position[1]);}}private void TimerEventProcessor(Object myObject, EventArgs myEventArgs){playTime++;label4.Text = playTime.ToString() + "秒";}private void label1_Click(object sender, EventArgs e){}private void label3_Click(object sender, EventArgs e){}private void button2_Click_1(object sender, EventArgs e){// 认输:if (Program.state == State.PUT_WTITE){label3.Text = "白方认输,黑方获胜";}else {label3.Text = "黑方认输,白方获胜";}button1.Enabled = true;button2.Enabled = false;label5.Enabled = false;timer1.Stop();MessageBox.Show(label3.Text);}// TODO 播放音乐private void playMusic() {/*SoundPlayer player = new SoundPlayer();string mp3FilePath = "F:\\KwDownload\\song\\ReadingAudio\\caimogudexiaoguniang.mp3";player.SoundLocation = mp3FilePath;// 加载音频文件player.Load();// 播放音频文件player.Play();*/}// TODO 播放按键音private void playKeySound() {}private void label5_Click(object sender, EventArgs e){}private void label4_Click(object sender, EventArgs e){}}
}

ok. 这个类代码量庞大,不赘述,资源已上传。主要是页面的绘制,以及游戏逻辑。其中还加入了AI, 支持人机对战。AI遍历整个棋盘,给每个位置落子计算分数值,用以判断在哪个位置落子最佳。我现在已经下不过AI了。缺点:刷新绘制棋盘时会闪烁,页面也比较粗糙,没有音效。

http://www.dtcms.com/a/438269.html

相关文章:

  • Java实现BCH与BTC的地址相互转换
  • CyberSecurity:SSL Client-Initiated Renegotiation 客户端发起的重新协商ddos攻击
  • 关于Mybatis-Plus的insertOrUpdate()方法使用时的问题与解决—数值精度转化问题
  • 石家庄做网站制作公司网站写作赚钱
  • Docker、容器、虚拟机到底是什么
  • 西安微信商城网站开发做阿里巴巴怎么进公司网站
  • Go语言入门(17)-接口
  • WebPages 安全
  • 安卓基础组件030-进程和线程
  • [ vue 前端框架 ] 基本用法和vue.cli脚手架搭建
  • 鸿蒙Next中使用Socket进行网络通信:完整指南与实战
  • dw如何做商业网站淘宝网站建设流程
  • 网站做好了 怎么做解析wordpress 怎么迁移
  • GNS3 3.0.5新版教程,以及Cloud设备找不到VMware网卡的解决方法
  • 比奇堡合唱团制作教学,AI翻唱教学动漫角色歌曲
  • 活动展板设计:大尺寸 + 高分辨率,打印清晰
  • 深圳市城乡建设部网站首页一个网站如何做盈利
  • 【IMX6ULL驱动学习】I2C驱动
  • 基于物联网数据采集的大型应用程序软件架构设计:核心要点、结构内容与链路关系
  • 【连载5】云数据库 MySQL 热点更新功能介绍
  • (四)Webpack、Slot与Vue CLI脚手架
  • 【附源码】个人事务管理系统的设计与实现
  • 基于PCIe(XDMA)的多路(1-32路)信号采集与回放子系统,多路视频、AD、光纤等信号,支持PR over PCIe
  • 【STM32项目开源】基于STM32的智能电子秤
  • 网站建设专用图形库西安网站快速排名提升
  • 红色php企业网站模板下载wordpress slider设置
  • Starting again-02
  • 【IMX6ULL驱动学习】PWM驱动
  • 智能向善” 核心,解析技术发展中的红利与风险平衡
  • 品牌 RWA 化构建白皮书