刚学了C#委托,做了个五子棋练习,把前台绘制和后台逻辑分开,前台绘制方法用委托传给后台逻辑。

界面好简单。。。

先看类图

控制类控制整个游戏的逻辑,包括调用棋盘类的属性初始化棋盘、初始化两个棋手、轮流落子。棋盘里有一个二维数组保存整个棋盘的落子情况,棋手里也有一个二维数组保存自己的落子情况。方向类是为了方便判断输赢的。

下面是代码:注释很详细就不说明了:

主要控制类:

 using System;
using System.Collections.Generic;
using System.Drawing;
using 五子棋.Properties; namespace 五子棋.Control
{
class Controler
{
#region 字段
///// <summary>
///// 画家对象
///// </summary>
//Graphics g;
/// <summary>
/// 棋盘对象
/// </summary>
QiPan qipan;
/// <summary>
/// 棋手列表
/// </summary>
List<QiShou> qishou;
/// <summary>
/// 游戏是否结束
/// </summary>
bool Gameover = false;
/// <summary>
/// 绘制直线委托
/// </summary>
Action<Point, Point> actionDrawLine;
/// <summary>
/// 绘制棋子图像委托
/// </summary>
Action<Image, int, int, float> actionDrawimage;
/// <summary>
/// 取得胜利事件,返回胜利选手的名称
/// </summary>
Action<string> actionWin;
#endregion #region 构造函数 /// <summary>
/// 构造函数
/// </summary>
/// <param name="actionDrawLine">绘制直线委托</param>
/// <param name="actionDrawimage">绘制棋子图像委托</param>
public Controler(Action< Point, Point> actionDrawLine, Action<Image, int, int, float> actionDrawimage,Action<string> actionWin)
{
//开始游戏
this.actionDrawLine = actionDrawLine;
this.actionDrawimage = actionDrawimage;
this.actionWin = actionWin;
StartGame();
}
#endregion #region 方法 /// <summary>
/// 棋手轮流下棋
/// </summary>
/// <param name="x">棋子X坐标</param>
/// <param name="y">棋子Y坐标</param>
public void LuoZi(int x, int y)
{
if (Gameover)
{
return;
}
//把不在棋盘交点上的坐标换算到最接近的棋盘交点上 //x = (int)Math.Round((double)(x - qipan.start.X) / qipan.Grid)
// * qipan.Grid + qipan.start.X;
//y = (int)Math.Round((double)(y - qipan.start.Y) / qipan.Grid)
// * qipan.Grid + qipan.start.Y;
//换算到棋盘第几条线
int qipanX = (int)Math.Round((double)(x - qipan.start.X) / qipan.Grid);
int qipanY = (int)Math.Round((double)(y - qipan.start.Y) / qipan.Grid);
if (qipan[qipanX, qipanY] == )
{
for (int i = ; i < qishou.Count; i++)
{
if (qishou[i].IsZouqi)
{
qipan[qipanX, qipanY] = ;
qishou[i].LuoZi(qipanX, qipanY);
//换算到棋盘控件坐标并绘制棋子
qishou[i].Render(qipanX * qipan.Grid + qipan.start.X,
qipanY * qipan.Grid + qipan.start.Y, actionDrawimage); //判断当前玩家是否获胜,获胜则游戏结束
Gameover = IsWin(qishou[i], new Point(qipanX, qipanY));
if (Gameover)
{
//if (actionWin!=null)
//{
// actionWin.Invoke(qishou[i].PlayerName);
//}
actionWin?.Invoke(qishou[i].PlayerName);
} //走棋后设置棋手不可走棋
//qishou[i].LuoZi(x, y, g);
}
qishou[i].IsZouqi = !qishou[i].IsZouqi;
}
}
}
/// <summary>
/// 刷新界面
/// </summary>
public void Render()
{
qipan.Render(actionDrawLine);
for (int i = ; i < qishou.Count; i++)
{
qishou[i].Render(qipan.start, qipan.Grid, actionDrawimage);
}
}
/// <summary>
/// 判断是否获胜
/// </summary>
/// <param name="qishou">棋手</param>
/// <param name="p">当前棋子坐标</param>
/// <returns></returns>
public bool IsWin(QiShou qishou, Point p)
{ //如果点在连续直线上就累加,当sum=5时,表示连续5个棋子在一条直线上
int sum = ;
for (int i = ; i < ; i++)
{
Console.WriteLine(i);
//下一个要检查的点
Point nextP = p;
Direction dr = (Direction)i;
if (i % == )
{
sum = ;
}
for (int j = ; j < ; j++)
{
//根据当前方向判断设置下一个点
#region switch
switch (dr)
{
case Direction.Top:
nextP.X = nextP.X;
nextP.Y = nextP.Y - ;
break;
case Direction.RightTop:
nextP.X = nextP.X + ;
nextP.Y = nextP.Y - ;
break;
case Direction.Rigth:
nextP.X = nextP.X + ;
nextP.Y = nextP.Y;
break;
case Direction.RigthBotton:
nextP.X = nextP.X + ;
nextP.Y = nextP.Y + ;
break;
case Direction.Botton:
nextP.X = nextP.X;
nextP.Y = nextP.Y + ;
break;
case Direction.LeftBotton:
nextP.X = nextP.X - ;
nextP.Y = nextP.Y + ;
break;
case Direction.Left:
nextP.X = nextP.X - ;
nextP.Y = nextP.Y;
break;
case Direction.LeftTop:
nextP.X = nextP.X - ;
nextP.Y = nextP.Y - ;
break;
default:
break;
}
#endregion if (nextP.X >= && nextP.X < qishou.ZouQiQiPan.GetLength()
&& nextP.Y >= && nextP.Y < qishou.ZouQiQiPan.GetLength())
{
if (qishou.ZouQiQiPan[nextP.X, nextP.Y] == )
{
break;
}
else
{
sum += qishou.ZouQiQiPan[nextP.X, nextP.Y];
}
}
else
{
break;
}
}
if (sum == )
{
return true;
} } return false;
}
/// <summary>
/// 开始游戏
/// </summary>
public void StartGame()
{
Gameover = false;
//初始化棋盘
qipan = new QiPan();
//初始化两种棋手:白棋和黑棋
qishou = new List<QiShou>()
{
new QiShou(Resources.白棋,0.08f,new byte[qipan.Heigth/qipan.Grid+,qipan.Width/qipan.Grid+]) {IsZouqi=true,PlayerName="Bai" }, new QiShou(Resources.黑棋,0.08f,new byte[qipan.Heigth/qipan.Grid+,qipan.Width/qipan.Grid+]) { IsZouqi=false,PlayerName="Hei" }
};
Render();
}
#endregion }
} 棋手类:
 using System;
using System.Drawing; namespace 五子棋.Control
{
class QiShou
{
#region 字段
/// <summary>
/// 棋子图像
/// </summary>
/// /// <summary>
/// 走棋棋盘
/// </summary>
byte[,] zouqiqipan;
#endregion
#region 属性
public string PlayerName { get; set; }
public Image ImagePlayer { get; set; }
/// <summary>
/// 棋子图像缩放比例
/// </summary>
public float ImageScale { get; set; } /// <summary>
/// 走棋棋盘
/// </summary>
public byte[,] ZouQiQiPan
{
get
{
return zouqiqipan;
}
set
{
zouqiqipan = value;
}
}
/// <summary>
/// 是否可以走棋
/// </summary>
public bool IsZouqi { get; set; }
#endregion
/// <summary>
/// 构造函数
/// </summary>
/// <param name="image">棋子图像</param>
/// <param name="imagescale">棋子缩放比例</param>
/// /// <param name="zouqiqipan">走棋棋盘大小</param>
public QiShou(Image image, float imagescale, byte[,] zouqiqipan)
{
this.zouqiqipan = zouqiqipan;
ImagePlayer = image;
ImageScale = imagescale;
Init();
}
/// <summary>
/// 初始化棋手
/// </summary>
private void Init()
{
for (int i = ; i < zouqiqipan.GetLength(); i++)
{
for (int j = ; j < zouqiqipan.GetLength(); j++)
{
zouqiqipan[i, j] = ;
}
}
} /// <summary>
/// 下棋落字
/// </summary>
/// <param name="x">棋盘X网格</param>
/// <param name="y">棋盘Y网格</param>
public void LuoZi(int x, int y)
{
ZouQiQiPan[x, y] = ;
}
#region 绘制棋子
/// <summary>
/// 绘制所有棋子
/// </summary>
/// <param name="start"></param>
/// <param name="grid"></param>
public void Render(Point start, int grid,Action<Image, int,int,float> actionDrawImage)
{
for (int i = ; i < ZouQiQiPan.GetLength(); i++)
{
for (int j = ; j < ZouQiQiPan.GetLength(); j++)
{
if (zouqiqipan[i, j] == )
{
Render(i * grid + start.X, i * grid + start.Y,actionDrawImage); }
}
}
}
public void Render(int x,int y, Action<Image, int, int, float> actionDrawImage)
{
actionDrawImage?.Invoke(ImagePlayer, x, y, ImageScale);
}
///// <summary>
///// 绘制棋子
///// </summary>
///// <param name="x">棋盘X网格坐标</param>
///// <param name="y">棋盘Y网格坐标</param>
///// <param name="g">画家对象</param>
//public void Render(int x, int y)
//{
// //actionDrawimage(x, y, ImagePlayer, ImageScale); // //绘制棋子,绘制的坐标应该换算到中心
// g.DrawImage(ImagePlayer, x - ImagePlayer.Width * ImageScale / 2, y - ImagePlayer.Height * ImageScale / 2,
// ImagePlayer.Width * ImageScale, ImagePlayer.Height * ImageScale);
//}
#endregion } }

棋盘类:

 using System;
using System.Drawing; namespace 五子棋.Control
{
class QiPan
{ /// <summary>
/// 棋盘绘制起点坐标
/// </summary>
public readonly Point start;
/// <summary>
/// X缩放
/// </summary>
public int ScaleX { get; set; }
/// <summary>
/// Y缩放
/// </summary>
public int ScaleY { get; set; }
/// <summary>
/// 棋盘宽度
/// </summary>
public int Width { get; set; }
/// <summary>
/// 棋盘高度
/// </summary>
public int Heigth { get; set; }
/// <summary>
/// 网格大小
/// </summary>
public int Grid { get; set; }
/// <summary>
/// 棋盘棋子
/// </summary>
private byte[,] qipanQiZi;
public byte this[int x, int y]
{
get
{
if (x < qipanQiZi.GetLength() && y < qipanQiZi.GetLength())
{
return qipanQiZi[x, y];
}
else
{
return ;
}
}
set
{
if (x < qipanQiZi.GetLength() && y < qipanQiZi.GetLength())
{
qipanQiZi[x, y] = value;
}
}
} /// <summary>
/// 构造函数
/// </summary>
/// <param name="width">棋盘宽度</param>
/// <param name="height">棋盘高度</param>
/// <param name="grid">棋盘网格大小</param>
public QiPan(Point start, int width, int height, int grid)
{
this.start = start;
Width = width;
Heigth = height;
Grid = grid;
Init(); } private void Init()
{
qipanQiZi = new byte[Width / Grid + , Heigth / Grid + ];
for (int i = ; i < qipanQiZi.GetLength(); i++)
{
for (int j = ; j < qipanQiZi.GetLength(); j++)
{
qipanQiZi[i, j] = ;
}
}
} /// <summary>
/// 构造函数
/// 默认棋盘大小为400*400,方格大小为40
/// </summary>
public QiPan() : this(new Point(, ), , , )
{
}
#region Graphics绘制棋盘 /// <summary>
/// 绘制棋盘
/// </summary>
/// <param name="g"></param>
//public void Render(Graphics g)
//{
// for (int i = 0; i <= Width / Grid; i++)
// {
// g.DrawLine(Pens.Black, start.X + (Grid * i), start.Y, start.X + (Grid * i), start.Y + Heigth); // }
// for (int i = 0; i <= Heigth / Grid; i++)
// {
// g.DrawLine(Pens.Black, start.X, start.Y + (Grid * i), start.X + Width, start.Y + (Grid * i));
// }
//}
#endregion
public void Render(Action< Point, Point> actionDrawLine)
{
int row = Heigth / Grid + ;
int cel = Width / Grid + ;
for (int i = ; i < row; i++)
{
actionDrawLine?.Invoke( new Point(start.X, start.Y + Grid * i), new Point(start.X + Width, start.Y + Grid * i));
}
for (int i = ; i < cel; i++)
{
actionDrawLine?.Invoke( new Point(start.X + Grid * i, start.Y), new Point(start.X + Grid * i, start.Y + Heigth));
}
}
}
}

简单五子棋,没有电脑AI的更多相关文章

  1. 五子棋(无AI winform gdi+)

    之前无意间在博客园看到一篇用深度学习玩马里奥的文章,于是就想做这个小东西来测试人工智能算法(准备用PYTHON的库,对神经网络的梦已经做了好多年了,但是太难了,一直懒得动它),本来是想用WPF做UI, ...

  2. [收藏]C++简单五子棋

    #include<iostream> #include<iomanip> using namespace std; ; //棋盘行数 ; //棋盘列数 char p[X][Y] ...

  3. C++的简单“五子棋”游戏,只是核心代码,资源代码未添加

    ChessBoard.h #ifndef __CHESS_BOARD_H__ #define __CHESS_BOARD_H__ #include "DataStruct.h" # ...

  4. 用Java写的简单五子棋游戏(原创五子连珠算法)

    源码jar包(已安装jdk环境可直接运行) 下载地址:http://download.csdn.net/detail/eguid_1/9532912 五子连珠算法为自创算法,对于五子棋该算法性能足以. ...

  5. 37行代码实现一个简单的打游戏AI

    不废话,直接上码,跟神经网络一点关系都没有,这37行代码只能保证电脑的对敌牺牲率是1:10左右,如果想手动操控,注释掉autopilot后边的代码即可. 哪个大神有兴趣可以用tensorflow或者s ...

  6. js+canvas五子棋人机大战ai算法

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. C++五子棋(五)——实现AI落子

    AI思考落子点 在之前我们已经实现计算权值了,现在要想让AI落子,应根据之前的计算结果使棋子落在分值最大点上.当然可能会出现多个分值相同的最大点,这时在其中随机取一个点落下即可. chessData. ...

  8. Leo-io 的C语言实现简单五子棋游戏观后感

    源代码: /************************************************************** ** 文 件 名:wuziqi.cpp ** 功    能:扫 ...

  9. C++ 之 简单的五子棋AI程序

    本人是大一新生,寒假无聊,抱着试试看的心态(没有想到可以完成),写了C++的简单五子棋程序,开心.     下面是效果图:     一.首先讲讲大致思路.            五子棋实现的基础:  ...

随机推荐

  1. CUDA随机数生成库curand——deviceAPI

    原创作品,如要转载请注明出处:http://www.cnblogs.com/shrimp-can/p/6590152.html 最近要在device函数中使用curand库生成随机数,查找了下资料,除 ...

  2. MySQL从库忽略某些错误

    z熬配置MySQL主从同步的时候常常会因为主库的中SQL语句的错误造成从库的同步出现错误,一旦从库同步出现错误就会造成同步的卡壳影响后续的同步: 可以在从库的配置文件中加入如下的参数,使从库可以自动忽 ...

  3. deepin系统下如何设置wifi热点(亲测有效)

    deepin系统下如何设置wifi热点(亲测有效) deepin wifi ap linux 热点 首先必须吐槽一下linux下设置wifi太累了....来来回回折腾了我好久的说.心累... 好了废话 ...

  4. flask-mail发送QQ邮件代码示例(亲测可行)

    from flask import Flask from flask_mail import Mail, Message app = Flask(__name__) app.config.update ...

  5. 关于微信小程序图片失真的解决方案

    今天来说一说 关于微信小程序的图片失真问题的解决,微信小程序的image标签要设置其宽高,不然图片若宽高过大会撑开原始图片大小的区域:如下 但是宽高设置固定了会导致有些图片和规定显示图片大小的比例不一 ...

  6. java类的equals()函数和hashCode()函数用法

    以前总觉得java类对象很简单,但是今天的一个同事的点播,让我对java的对象有了不一样的理解,下面我来介绍一下equals()和hashCode()的用法: 先粘一段代码: public class ...

  7. 七个 Android 程序猿提高效率必备工具

    Android 程序猿提高效率必备工具 0x00 Code tree for GitHub 这个 Chrome 浏览器插件.Github 作为最大同性交友网站,每天的工作几乎是从打开这个网站开始的.当 ...

  8. Maven基础学习(一)—Maven入门

    一.概述      Maven是一个项目管理工具,它包含了一个项目对象模型(Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管 ...

  9. SpringMVC 自定义全局日期转换器

    第一步: 编写自定义转换器的类 /* * 自定义日期转换器 */ public class CustomDateConverter implements Converter<String, Da ...

  10. JavaScript 简易版 自动轮播 手动轮播 菜鸟交流

    本人刚刚接触前端,许多知识还不了解,以前经常到博客园查询自己需要的东西,现在也终于反客为主了.作为新手,所展示的东西也是浅显易懂,希望同是新手的伙伴们共同交流.共同进步,若是成功捕获一位大大,也请您赐 ...