游戏规则介绍:
在一个10*10的方格中,有5种颜色的方块,当双击联通块时,联通块消失。(联通块的定义:至少有2个方块颜色相同,并且相连)联通块中的每一块的价值是n,n由联通块中的个数决定。
当双击联通块消失后,联通块上面的方块会下降,填充消失区域。如果某一列消失,右侧的列会向左靠齐。直到没有联通块为止,游戏结束,看谁的得分高。
分析:
1、联通块越大,最后得分越高。比如由5个小方格组成的联通块价值:5*5=25.而如果是由10块组成的,那就是10*10=100.所以应该尽量让同种色块组合成一个尽量大的联通块。
2、理想状态:颜色尽可能少,同色块尽可能是连接在一起的。这个主要是为了后来算法评估做准备。数学证明比较简单。
假设有5中颜色,每种颜色的数量为a,b,c,d,e,那么就有a+b+c+d+e=100,需要求a*a+b*b+c*c+d*d+e*e的最大值。取值范围[0~100],所以,当某一个颜色是100,最大。同理,同一个颜色的色块链接在一起价值最大。
有了这些准备,我们再来看算法:
当给定一个图形时:我们能够知道如下价格关键数据
1、图形中有多少个联通块。
2、图形中色块的完美值:各个色块的平方和。
3、由上一个图形状态转换到当前图形状态,已经产生的价值。
当我们拿到一个图形,通过分析会得到N个联通块,每一个联通块消失都会产生一种新的视图。就有N种情况。在这N中情况中,我们会选择评估值最高的去尝试(贪心嘛,总是为了得到最大值),于是就开始了递归查询。
程序设计:
1、一个视图类,用来保存视图的各种数据
2、视图帮助类,用来计算分析视图的,(当然完全可以放在视图类里面)
3、视图管理类,用来处理算法,筛选最优视图去处理,并且调度并行任务。
视图类GameVIew
</pre> <pre code_snippet_id="1596212" snippet_file_name="blog_20160303_2_8130802" name="code" class="csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BlockGame
{
public class GameView
{
public GameView()
{
State = 0;
}
/// <summary>
/// 0:未检测过
/// 1:
/// </summary>
public int State
{
get; set;
}
public GameView Parent
{
get; set;
}
public int Col
{
get; set;
}
public int Row
{
get; set;
}
public int Color
{
get; set;
}
public int[,] ViewData
{
get; set;
}
public string ViewDataString
{
get; set;
}
/// <summary>
/// 转换到当前视图的累计分数
/// </summary>
public int PreScore
{
get; set;
}
/// <summary>
/// 从上一个视图转换到当前视图的分数
/// </summary>
public int StepScore
{
get; set;
}
/// <summary>
/// 视图的评估值=当前值+视图完美值
/// </summary>
public int AppraiseScore
{
get; set;
}
/// <summary>
/// 当前视图的完美值
/// </summary>
public int PerfectScore
{
get;set;
}
}
}
帮助类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
namespace BlockGame
{
public class GameViewHepler
{
public void CalcPerfectScore(GameView view)
{
int[] cs = new int[view.Color];
int c = 0;
for (int x = 0; x < view.Row; x++)
{
for (int y = 0; y < view.Col; y++)
{
c = view.ViewData[x, y];
if (c != 0)
{
cs[c-1]++;
}
}
}
int perfectScore = 0;
for (int i = 0; i < cs.Length; i++)
{
perfectScore += cs[i] * cs[i];
}
view.PerfectScore = perfectScore;
}
public void CalcAppraiseScore(GameView view)
{
view.AppraiseScore = view.PreScore + view.PerfectScore;
}
/// <summary>
/// 初始化视图ViewDataString属性
/// </summary>
/// <param name="view"></param>
public void CalcViewDataString(GameView view)
{
StringBuilder s = new StringBuilder();
for (int x = 0; x < view.Row; x++)
{
for (int y = 0; y < view.Col; y++)
{
s.Append(view.ViewData[x, y].ToString() + ",");
}
}
view.ViewDataString = s.ToString();
}
/// <summary>
/// 由字符串初始化GameView
/// GameView已经被正确创建Row,Col,Color,PreScore,StepScore,Parent属性
/// 随后初始化其他属性:ViewData,ViewDataString,PerfectScore,AppraiseScore,
/// </summary>
/// <param name="view"></param>
/// <param name="s"></param>
public void InitViewDataByString(GameView view,string s)
{
#region 初始化数据部分
string[] strs = s.Split(',');
for (int x = 0; x < view.Row; x++)
{
for (int y = 0; y < view.Col; y++)
{
int c = Convert.ToInt32(strs[x * view.Col + y]);
view.ViewData[x, y] = c;
}
}
#endregion
view.ViewDataString = s;
CalcPerfectScore(view);
CalcAppraiseScore(view);
}
#region 计算有多少个联通块
/// <summary>
/// 计算有多少个联通块
/// </summary>
/// <param name="view"></param>
/// <returns></returns>
public List<List<Point>> CalcBlocks(GameView view)
{
int[,] usedView = new int[view.Row, view.Col];
List<List<Point>> ViewBlocks = new List<List<Point>>();
for (int x = 0; x < view.Row; x++)
{
for (int y = 0; y < view.Col; y++)
{
if (usedView[x, y] == 0)
{
//没有被使用过
int c = view.ViewData[x, y];
if (c > 0)
{
usedView[x, y] = 1;
List<Point> block = new List<Point>();
block.Add(new Point(x, y));
analyseNext(c, x, y, block, view, usedView);
if (block.Count == 1)
{
//只有一个块的,不进入
continue;
}
ViewBlocks.Add( block);
}
}
}
}
return ViewBlocks;
}
private void analyseNext(int color, int x, int y, List<Point> block,GameView view,int[,] usedView)
{
if (x - 1 >= 0)
{
if (view.ViewData[x - 1, y] == color && usedView[x - 1, y] == 0)
{
block.Add(new Point(x - 1, y));
usedView[x - 1, y] = 1;
analyseNext(color, x - 1, y, block,view,usedView);
}
}
if (x + 1 < view.Row)
{
if (view.ViewData[x + 1, y] == color && usedView[x + 1, y] == 0)
{
block.Add(new Point(x + 1, y));
usedView[x + 1, y] = 1;
analyseNext(color, x + 1, y, block,view,usedView);
}
}
if (y - 1 >= 0)
{
if (view.ViewData[x, y - 1] == color && usedView[x, y - 1] == 0)
{
block.Add(new Point(x, y - 1));
usedView[x, y - 1] = 1;
analyseNext(color, x, y - 1, block, view, usedView);
}
}
if (y + 1 < view.Col)
{
if (view.ViewData[x, y + 1] == color && usedView[x, y + 1] == 0)
{
block.Add(new Point(x, y + 1));
usedView[x, y + 1] = 1;
analyseNext(color, x, y + 1, block, view, usedView);
}
}
}
#endregion
/// <summary>
/// 移除某个联通块,构建一个新的视图
/// </summary>
/// <param name="view"></param>
/// <param name="block"></param>
/// <returns></returns>
public GameView RemoveBlock(GameView view, List<Point> block)
{
#region Clone新视图
GameView v = new GameView()
{
Col = view.Col,
Row = view.Row,
Color = view.Color,
Parent = view,
PreScore = view.PreScore + block.Count * block.Count,
StepScore = block.Count * block.Count
};
v.ViewData = new int[v.Row, v.Col];
InitViewDataByString(v, view.ViewDataString);
#endregion
#region 移除
foreach (Point p in block)
{
v.ViewData[p.X, p.Y] = 0;
}
#endregion
ReBuildViewData(v);
CalcViewDataString(v);
CalcPerfectScore(v);
CalcAppraiseScore(v);
return v;
}
/// <summary>
/// 重构视图的数据部分,也就是移动后ViewData
/// </summary>
private void ReBuildViewData(GameView view)
{
for (int y = view.Col - 1; y >= 0; y--)
{
//是否需要向左移动
bool moveleft = true;
//从上向下找,是否有颜色快存在
bool hasColor = false;
//找到右侧可以平移的列
bool hasCol = false;
#region 掉落
for (int x = 0; x < view.Row; x++)
{
if (view.ViewData[x, y] != 0)
{
moveleft = false;
hasColor = true;
}
else
{
if (hasColor)
{
//开始下移
for (int i = x; i >= 0; i--)
{
if (i == 0)
{
view.ViewData[i, y] = 0;
}
else
{
if (view.ViewData[i - 1, y] == 0)
{
view.ViewData[i, y] = 0;
break;
}
else
{
view.ViewData[i, y] = view.ViewData[i - 1, y];
}
}
}
}
}
}
#endregion
#region 左移
if (moveleft)
{
if (y == view.Col - 1)
{
continue; ;
}
for (int i = 0; i < view.Row; i++)
{
if (view.ViewData[i, y + 1] != 0)
{
hasCol = true;
break;
}
}
if (hasCol)
{
for (int i = 0; i < view.Row; i++)
{
for (int j = y; j < view.Col; j++)
{
if (j == view.Col - 1)
{
view.ViewData[i, j] = 0;
}
else
{
view.ViewData[i, j] = view.ViewData[i, j + 1];
}
}
}
}
}
#endregion
}
}
}
}
管理类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Drawing;
using System.Diagnostics;
namespace BlockGame
{
public class GameViewManager
{
private int max;
private List<GameView> gameViewList;
private List<GameView> resultViewList;
private GameViewHepler hepler;
private object objlock = new object();
private Dictionary<string, int> taskDic;
private Action<int,long> completedEventHandler;
private long time;
public Action<int,long> Completed
{
set
{
completedEventHandler = value;
}
}
private void OnCompleted()
{
if (completedEventHandler != null)
{
completedEventHandler(max,time);
}
}
public GameViewManager()
{
gameViewList = new List<GameView>();
resultViewList = new List<GameView>();
hepler = new GameViewHepler();
max = 0;
taskDic = new Dictionary<string, int>();
}
/// <summary>
/// 分析一个GameView,并转换成下一步的若干个GameView
/// </summary>
/// <param name="view"></param>
private void analyseGameView(GameView view)
{
List<List<Point>> blocks = hepler.CalcBlocks(view);
if (blocks.Count == 0)
{
//此视图终结
resultViewList.Add(view);
return;
}
foreach (List<Point> block in blocks)
{
GameView v = hepler.RemoveBlock(view, block);
lock(objlock)
{
if (v.PreScore > max)
{
max = v.PreScore;
}
}
#region 判断是否存在
GameView evl=null;
lock(objlock)
{
evl = (from p in gameViewList
where p.ViewDataString == v.ViewDataString
select p).FirstOrDefault();
if (evl == null)
{
Console.WriteLine("添加新view");
gameViewList.Add(v);
}
else
{
Console.WriteLine("有相同view存在");
if (evl.PreScore < v.PreScore)
{
Console.WriteLine("有相同view存在,而且新的更优");
evl = v;
}
}
}
//Thread.Sleep(3000);
#endregion
#region 判断是否是优秀结果
//在选择的时候已经过滤了,所以,这里不用处理
//是不是删除更好?加快查找?但也有可能,删除后会再次加入
var bv = from p in gameViewList
where p.AppraiseScore <= max && p.State == 0
select p;
lock(objlock)
{
Console.WriteLine("将会淘汰{0}", bv.Count());
}
#endregion
//Console.WriteLine("执行完毕");
};
}
private Task analyseGameViewAsync(string taskid)
{
return Task.Run(()=>
{
bool flag = true;
while (flag)
{
GameView view=null;
lock (objlock)
{
view = (from p in gameViewList
where p.State == 0 && p.AppraiseScore >= max
orderby p.AppraiseScore descending
select p).FirstOrDefault();
if (view != null)
{
view.State = 1;
taskDic[taskid] = 1;
}
else
{
taskDic[taskid] = 0;
}
}
if (view == null)
{
//其他线程都完成了,整个任务完成,
bool completed = true;
lock(objlock)
{
foreach (KeyValuePair<string, int> kvp in taskDic)
{
if (kvp.Value == 1)
{
completed = false;
break;
}
}
}
if (completed)
{
flag = false;
}
}
else
{
Console.WriteLine("线程{0}处理一条数据", taskid);
analyseGameView(view);
}
}
OnCompleted();
});
}
public void AddTask(string taskid)
{
if (taskDic.ContainsKey(taskid))
{
throw new Exception("重复taskid");
}
lock(objlock)
{
taskDic.Add(taskid, 1);
}
/*
Stopwatch watch = new Stopwatch();
await analyseGameViewAsync(taskid);
*/
}
public async void StartTask()
{
List<Task> task = new List<Task>();
lock(objlock)
{
foreach (var taskid in taskDic)
{
Task t = analyseGameViewAsync(taskid.Key);
task.Add(t);
}
}
Stopwatch watch = new Stopwatch();
watch.Start();
await Task.WhenAll(task);
watch.Stop();
time = watch.ElapsedMilliseconds;
Console.WriteLine("共用时:{0}", watch.ElapsedMilliseconds);
OnCompleted();
}
public void AddFirstGameView(GameView view)
{
max = 0;
time = 0;
gameViewList.Clear();
resultViewList.Clear();
gameViewList.Add(view);
}
}
}
首先初始化第一个视图
int x = Convert.ToInt16(this.textBox1.Text);
int y = Convert.ToInt16(this.textBox2.Text);
int c = Convert.ToInt16(this.textBox3.Text);
gv = new GameView() { Row = x, Col = y, Color = c, PreScore = 0, StepScore = 0 };
gv.ViewData = new int[gv.Row, gv.Col];
string str = "";
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
Random r = new Random(Guid.NewGuid().GetHashCode());
int rc = r.Next(1, c + 1);
str += rc.ToString() + ",";
}
}
hepler.InitViewDataByString(gv, str);
开始计算任务
GameViewManager manager = new GameViewManager();
manager.AddFirstGameView(gv);
manager.Completed = new Action<int,long>(Show);
manager.AddTask("1");
manager.AddTask("2");
manager.AddTask("3");
manager.AddTask("4");
manager.StartTask();
程序运行效果图
源代码即下载地址:http://download.csdn.net/detail/mamihong/9452014
vs2015的