简单五子棋,没有电脑AI
刚学了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的更多相关文章
- 五子棋(无AI winform gdi+)
之前无意间在博客园看到一篇用深度学习玩马里奥的文章,于是就想做这个小东西来测试人工智能算法(准备用PYTHON的库,对神经网络的梦已经做了好多年了,但是太难了,一直懒得动它),本来是想用WPF做UI, ...
- [收藏]C++简单五子棋
#include<iostream> #include<iomanip> using namespace std; ; //棋盘行数 ; //棋盘列数 char p[X][Y] ...
- C++的简单“五子棋”游戏,只是核心代码,资源代码未添加
ChessBoard.h #ifndef __CHESS_BOARD_H__ #define __CHESS_BOARD_H__ #include "DataStruct.h" # ...
- 用Java写的简单五子棋游戏(原创五子连珠算法)
源码jar包(已安装jdk环境可直接运行) 下载地址:http://download.csdn.net/detail/eguid_1/9532912 五子连珠算法为自创算法,对于五子棋该算法性能足以. ...
- 37行代码实现一个简单的打游戏AI
不废话,直接上码,跟神经网络一点关系都没有,这37行代码只能保证电脑的对敌牺牲率是1:10左右,如果想手动操控,注释掉autopilot后边的代码即可. 哪个大神有兴趣可以用tensorflow或者s ...
- js+canvas五子棋人机大战ai算法
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- C++五子棋(五)——实现AI落子
AI思考落子点 在之前我们已经实现计算权值了,现在要想让AI落子,应根据之前的计算结果使棋子落在分值最大点上.当然可能会出现多个分值相同的最大点,这时在其中随机取一个点落下即可. chessData. ...
- Leo-io 的C语言实现简单五子棋游戏观后感
源代码: /************************************************************** ** 文 件 名:wuziqi.cpp ** 功 能:扫 ...
- C++ 之 简单的五子棋AI程序
本人是大一新生,寒假无聊,抱着试试看的心态(没有想到可以完成),写了C++的简单五子棋程序,开心. 下面是效果图: 一.首先讲讲大致思路. 五子棋实现的基础: ...
随机推荐
- Http相关
1.http请求 http请求分为三部分:请求行,请求头,请求正文 1. 请求行 请求方式 GET POST 请求资源路径 协议版本 GET与POST请求区别? get只能传递1kb以下数据,P ...
- 关于SQL的一些小知识
在代码中调用存储过程的时,必须先测试存储过程,存储过程测试成功之后再去java中去调用!!@!@#!@!@! 以后自己写的存储过程写一个本地保存一个.!~~~!!(这个很关键) 以后在代码中的SQL都 ...
- Spring execution表达式
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) th ...
- (转)Java线程面试题 Top 50
原文链接:http://www.importnew.com/12773.html 本文由 ImportNew - 李 广 翻译自 javarevisited.欢迎加入Java小组.转载请参见文章末 ...
- Android Studio 安装后首次启动的 Config path ...... is invalid 问题(转)
原文链接:http://m.blog.csdn.net/blog/hnust_xiehonghao/46127775 1. 问题描述: 安装好Android Studio后,启动时弹出如下信息: Co ...
- 封装Echarts
项目中需要对数据进行图形展示,例如展示柱状图.饼状图等.这类的前端展示脚本很多,常见的是HighCharts和Echarts.HighCharts是基于svg技术的,而echarts基于Echarts ...
- URL转换成二维码
转载请注明出处:http://www.cnblogs.com/cnwutianhao/p/6685804.html 二维码已经成为我们日常生活中的一个不可获取的产物,火车票上,景区门票,超市付款等等都 ...
- ElasticSearch集群安装配置
1. 环境说明 Cent OS 7 jdk-8u121-linux-x64.tar.gz elasticsearch-5.2.1.zip 2. 系统环境配置 新建进程用户 修改File Descrip ...
- for xml path 如何将字段转换为xml的属性
for xml path 如何将字段作为xml的属性: 可在查询时 别名用 as '@..' 如'@value' 如下实例: SELECT A.GiftSetGUID AS '@value',A.Gi ...
- [Android]Gradle 插件 DiscardFilePlugin(class注入&清空类和方法)
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/6732128.html Android Gradle 插件 Di ...