A*算法【拼图游戏】
数据结构
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 拼图
{ /// <summary>
/// 空格移动的方向
/// </summary>
enum Direction
{
None,
Up,
Left,
Right,
Down
} /// <summary>
/// 解答
/// </summary>
enum Answer
{
/// <summary>
/// 不存在解答
/// </summary>
NotExist,
/// <summary>
/// 存在解答
/// </summary>
Exist,
/// <summary>
/// 在当前指定的搜索深度内不存在解答(需要扩大深度)
/// </summary>
NotExistInDepth
} /// <summary>
/// 局面状态信息
/// </summary>
class StateMsg
{
private int depth;
private Direction dir;
public int Depth
{
get { return depth; }
}
public Direction Dir
{
get { return dir; }
} public StateMsg(int depth, Direction dir)
{
this.depth = depth;
this.dir = dir;
}
} /// <summary>
/// 局面状态
/// </summary>
class State : StateMsg
{
private long code; /// <summary>
/// 棋盘的编码
/// </summary>
public long Code
{
get { return code; }
set { code = value; }
} public State(long code, int depth, Direction dir)
: base(depth, dir)
{
this.code = code;
}
}
}
Astar类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 拼图
{
class AStar
{ /// <summary>
/// ten[i]代表10的i次方
/// </summary>
private static readonly long[] tens = { , , , , , , , , , }; /// <summary>
/// 不是合理的编码
/// </summary>
private const int OutOfCode = -; /// <summary>
/// 标志是否找到目标状态的编码
/// </summary>
public const int WinnerCode = ; private Direction[][] dirs; private int startBoard;
private static int endBoard;
private static int[] endBoardArray; private int MaxDepth; private SortedList<long, StateMsg> openList;
private Dictionary<long, StateMsg> boardtable; private const long maxNodes = ; //至多搜索的结点数=最大局面状态数量:(9!)=362880; private long nodes;
private int same;
private float time;
private Direction[] result; /// <summary>
/// 已经访问的结点数量
/// </summary>
public long Nodes
{
get { return nodes; }
} /// <summary>
/// 重复访问相同结点的数量
/// </summary>
public int Same
{
get { return same; }
} public float Time
{
get { return time; }
} public static int N; /// <summary>
/// 最终结果
/// </summary>
public Direction[] Result
{
get { return result; }
} public AStar(int n)
{
N = n;
dirs = new Direction[n*n][];
if(n==)
{
dirs[] = new Direction[] { Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Left, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Right };
dirs[] = new Direction[] { Direction.Left, Direction.Right, Direction.Up };
dirs[] = new Direction[] { Direction.Up, Direction.Left };
}
else
{
dirs[] = new Direction[] { Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Left, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Right, Direction.Down }; dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down }; dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Right, Direction.Down }; dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down }; dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Right, Direction.Down }; dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Right, Direction.Down }; dirs[] = new Direction[] { Direction.Up, Direction.Left, Direction.Down };
dirs[] = new Direction[] { Direction.Up, Direction.Right };
dirs[] = new Direction[] { Direction.Left, Direction.Right, Direction.Up };
dirs[] = new Direction[] { Direction.Left, Direction.Right, Direction.Up };
dirs[] = new Direction[] { Direction.Left, Direction.Right, Direction.Up };
dirs[] = new Direction[] { Direction.Up, Direction.Left };
} } /// <summary>
/// 求与目标位置不同的个数(不计空格,因此返回值0~8)
/// </summary>
/// <param name="curboard"></param>
/// <returns></returns>
public static int Different(int curboard)
{
int t_start = curboard;
int emp_start = curboard % ;
int ev = ;
//写2个for是为了减少9个if
for (int i = N*N; i > emp_start; i--)
{
t_start /= ;
if (t_start % != endBoardArray[i])
ev++;
}
for (int i = emp_start - ; i >= ; i--)
{
t_start /= ;
if (t_start % != endBoardArray[i])
ev++;
}
return ev;
} public static int getBoard(long code)
{
return (int)(code % tens[]);
} private static int getEval(long code)
{
return (int)(code / tens[]);
} private static int getEmpIndex(long code)
{
return (int)(code % );
} private static long combinCode(int board, int eval)
{
long codehead = eval * tens[];
return codehead + board;
} /// <summary>
/// 改变局面(移动空格)
/// </summary>
/// <param name="code"></param>
/// <param name="dir"></param>
public static long change(long code, Direction dir)
{
int newboard;
int eval;
int num;
int t0;
long t1;
long t2;
switch (dir)
{
case Direction.Left:
newboard = getBoard(code) - ;
if (newboard == endBoard)
return WinnerCode;
eval = Different(newboard);
return combinCode(newboard, eval);
case Direction.Right:
newboard = getBoard(code) + ;
if (newboard == endBoard)
return WinnerCode;
eval = Different(newboard);
return combinCode(newboard, eval);
case Direction.Up:
num = getBoard(code);
t0 = N*N - num % + ;
t1 = num / tens[t0];
t2 = t1 % ;
t1 = t1 - t2 + (t2 % ) * + t2 / ;
t1 *= tens[t0];
newboard = (int)(t1 + ((num % tens[t0]) - N));
if (newboard == endBoard)
return WinnerCode;
eval = Different(newboard);
return combinCode(newboard, eval);
case Direction.Down:
num = getBoard(code);
t0 = N*N - num % + - N;//跟Up不同的地方
t1 = num / tens[t0];
t2 = t1 % ;
t1 = t1 - t2 + (t2 % ) * + t2 / ;//跟Up不同的地方
t1 *= tens[t0];
newboard = (int)(t1 + ((num % tens[t0]) + N));//跟Up不同的地方
if (newboard == endBoard)
return WinnerCode;
eval = Different(newboard);
return combinCode(newboard, eval);
}
return OutOfCode;
} /// <summary>
/// 恢复上一步的局面
/// </summary>
/// <param name="code"></param>
/// <param name="dir"></param>
public long unchange(long code, Direction dir)
{
return change(code, (Direction)( - dir));
} /// <summary>
/// 当找到目标时,从哈希表里找原来的路径
/// </summary>
/// <param name="endCode"></param>
/// <param name="depth"></param>
private void setResult(long endCode, Direction curDir, Direction lastDir, int depth)
{
long lastCode = endCode;
result = new Direction[depth];
result[depth - ] = curDir;
for (int i = depth - ; i >= ; i--)
{
if (boardtable.ContainsKey(lastCode))
{
result[i] = boardtable[lastCode].Dir;
lastCode = unchange(lastCode, result[i]);
}
else
return;
}
} //本算法的核心部分
#region 带Open表和HashTable的最好优先搜索(每次扩展Open表后都对Open表排序) /// <summary>
/// 扩展Open表
/// </summary>
/// <param name="board"></param>
/// <param name="depth"></param>
private bool extentOpenList(long code, Direction lastDir, int depth)
{
int empIndex = (int)(code % - );
int len_moves = dirs[empIndex].Length;
long newcode;
Direction dir = - lastDir;
for (int i = ; i < len_moves; i++)
if (dirs[empIndex][i] != dir)
{
newcode = change(code, dirs[empIndex][i]); //跟目标匹配,结束
if (newcode == WinnerCode)
{
setResult(code, dirs[empIndex][i], lastDir, depth);
return true;
}
if (newcode <= tens[])
throw new Exception("棋盘码修改错误! ");
if (newcode != OutOfCode)
{
if (!openList.ContainsKey(newcode))
{
if (!boardtable.ContainsKey(newcode))
openList.Add(newcode, new StateMsg(depth, dirs[empIndex][i]));
else
{
same++;
if (depth < boardtable[newcode].Depth)
{
boardtable.Remove(newcode);
openList.Add(newcode, new StateMsg(depth, dirs[empIndex][i]));
}
}
}
else
{
same++;
if (depth < openList[newcode].Depth)
openList[newcode] = new StateMsg(depth, dirs[empIndex][i]);
}
}
}
return false;
} /// <summary>
/// 带Open表和HashTable的最好优先搜索(每次扩展Open表后都对Open表排序)
/// </summary>
/// <returns></returns>
private int BestFirstSearch()
{
int depth = ;
Direction[] moves;
int board;
long newCode = combinCode(this.startBoard, );
int empIndex = getEmpIndex(newCode); moves = dirs[empIndex - ];
StateMsg data;
if (extentOpenList(newCode, Direction.None, depth))
return WinnerCode;
while (openList.Count > )
{
lock (this)
{
nodes++;
if (nodes >= maxNodes)
return -;
newCode = openList.Keys[];
board = getBoard(newCode);
data = openList[newCode];
if (data.Depth != )
{
depth = data.Depth;
if (board == endBoard)
{
return WinnerCode;
}
boardtable.Add(newCode, new StateMsg(depth, data.Dir));
openList.RemoveAt();
if (depth < MaxDepth)
if (extentOpenList(newCode, data.Dir, depth + ))
return WinnerCode;
}
}
}
return -;
} #endregion /// <summary>
/// 把一维数组的局面编码成一个整数的表示形式
/// </summary>
/// <param name="genBoard"></param>
/// <returns></returns>
public int ToIntBoard(int[] genBoard)
{
int board = ;
int emp = ;
for (int i = ; i < genBoard.Length; i++)
{
if (genBoard[i] != )
board = * board + genBoard[i];
else
emp = i + ;
}
return * board + emp;
} /// <summary>
/// 判断是否可以从初始状态到达目标状态(计算两个状态的逆序列,奇偶性相同的返回true)
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <returns></returns>
private bool ExistAns(int[] start, int[] end)
{
int sequence_start = , sequence_end = ;
for (int i = ; i < start.Length; i++)
{
if (start[i] != )
for (int j = i + ; j < start.Length; j++)
{
if (start[j] != && start[j] < start[i])
sequence_start++;
}
if (end[i] != )
for (int j = i + ; j < start.Length; j++)
{
if (end[j] != && end[j] < end[i])
sequence_end++;
}
}
return (sequence_start + sequence_end) % == ;
} /// <summary>
/// 初始化求解
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <param name="maxDepth"></param>
private void InitComp(int[] start, int[] end, int maxDepth)
{
nodes = ;
same = ;
MaxDepth = maxDepth;
result = null;
boardtable = new Dictionary<long, StateMsg>();
openList = new SortedList<long, StateMsg>();
//openStack = new Stack<State>();
//openQueue = new Queue<State>(); this.startBoard = ToIntBoard(start);
endBoard = ToIntBoard(end);
int t_end = endBoard;
int emp_end = endBoard % ;
endBoardArray = new int[N*N+];
endBoardArray[] = emp_end;
endBoardArray[emp_end] = ;
for (int i = N*N; i > emp_end; i--)
{
t_end /= ;
endBoardArray[i] = t_end % ;
}
for (int i = emp_end - ; i >= ; i--)
{
t_end /= ;
endBoardArray[i] = t_end % ;
}
} /// <summary>
/// 求解8数码问题
/// </summary>
/// <param name="start"></param>
/// <param name="end"></param>
/// <param name="maxDepth"></param>
/// <returns></returns>
public Answer Compute(int[] start, int[] end, int maxDepth)
{
if (!ExistAns(start, end))
return Answer.NotExist;
InitComp(start, end, maxDepth);
if (startBoard == endBoard)
return Answer.Exist;
long oldtime = System.DateTime.Now.Ticks;
int eval = ;
eval = BestFirstSearch();
time = (System.DateTime.Now.Ticks - oldtime) / 10000000.0f;
if (eval == WinnerCode)
return Answer.Exist;
return Answer.NotExistInDepth;
} }
}
A*算法【拼图游戏】的更多相关文章
- 基于unity3d和leap motion的拼图游戏
近期用unity3d引擎做了一个拼图游戏,会分几次写完,以此作为总结. 本文基本查找了网上能查到的全部资料作为參考.也算是大家节省了时间. 眼下仅仅完毕了拼图部分,leap motion手势控制部分会 ...
- 程序设计 之 C#实现《拼图游戏》 (下) 原理篇
前言:在 http://www.cnblogs.com/labixiaohei/p/6698887.html 程序设计 之 C#实现<拼图游戏>(上),上传了各模块代码,而在本文中将详细剖 ...
- [Android]自己动手做个拼图游戏
目标 在做这个游戏之前,我们先定一些小目标列出来,一个一个的解决,这样,一个小游戏就不知不觉的完成啦.我们的目标如下: 游戏全屏,将图片拉伸成屏幕大小,并将其切成若干块. 将拼图块随机打乱,并保证其能 ...
- 拼图游戏js
实现算法: 1. JavaScript动态生成拼图:通过生成16个div,且除最后一个div不使用背景图片以外,其他div都设置拼图图片为背景.然后通过调整background-position来实现 ...
- iOS 滑块拼图游戏(Puzzle8)
代码地址如下:http://www.demodashi.com/demo/11505.html 一.准备工作 先了解一个定义和定理 定义:在一个1,2,...,n的排列中,如果一对数的前后位置与大小顺 ...
- C#实现拼图游戏
C#实现<拼图游戏> (下) 原理篇 前言:在 http://www.cnblogs.com/labixiaohei/p/6698887.html 程序设计 之 C#实现<拼图游 ...
- 利用Vue.js实现拼图游戏
之前写过一篇<基于Vue.js的表格分页组件>的文章,主要介绍了Vue组件的编写方法,有兴趣的可以访问这里进行阅读:http://www.cnblogs.com/luozhihao/p/5 ...
- JavaScript拼图游戏
今天是2016年最后一天上班了.最近几天都比较休闲,有时间空闲下来写写文档之类的. 2016过得真是快.感觉没做什么就过去了.想到之前想坚持每个月写一写博客都没坚持到.希望2017年可以吧. 无聊之余 ...
- SDL制作拼图游戏
看完教程第三集后,好像自己能用这个来写一个简单的拼图游戏,第一次写出个带界面的游戏,好有成就感. 图片是自己慢慢截左上部分8个脸. #include <stdio.h> #include ...
- 拼图游戏(js,C#,java三种语言)
<html> <head> <meta charset="utf-8"> <style type="text/css" ...
随机推荐
- Eclipse 导入逆向工程
相关配置 生成 生产前 生成后
- POJ 2299 Ultra-QuickSort (树状数组 && 离散化)
题意 : 给出一个数n(n<500,000), 再给出n个数的序列 a1.a2.....an每一个ai的范围是 0~999,999,999 要求出当通过相邻两项交换的方法进行升序排序时需要交换 ...
- Linux压缩工具
一.gzip/gunzip/zcat gzip, gunzip, zcat - compress or expand files gzip [ option .... ] [ filenames .. ...
- classpath说明
概念解释: classpath : 即项目中WEB-INF下面的classes目录; 应用: [01] src路径下的文件在编译后会放到WEB-INF/classes路径下.默认的classpath是 ...
- 【转】diamond专题(二)– 核心原理介绍
特别提示:本人博客部分有参考网络其他博客,但均是本人亲手编写过并验证通过.如发现博客有错误,请及时提出以免误导其他人,谢谢!欢迎转载,但记得标明文章出处:http://www.cnblogs.com/ ...
- react native props上存在的属性,显示不存在
问题:类型“Readonly<{}> & Readonly<{ children?: ReactNode; }>”上不存在属性“navigation”.ts(2339) ...
- 说说 Activity、Intent、Service 是什么关系
他们都是 Android 开发中使用频率最高的类.其中 Activity 和 Service 都是 Android 四大组件之一.他俩都是Context 类的子类 ContextWrapper 的子类 ...
- JAVA基础面试汇总
一.基础知识:1.JVM.JRE和JDK的区别: JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性. java ...
- Promise.then链式调用
let a = new Promise((resolve,reject)=>{ resolve(1) }).then((r)=>{console.log(r)}).then(()=> ...
- 阶段3 2.Spring_09.JdbcTemplate的基本使用_4 JdbcTemplate的CRUD操作
复制demo起名3 保存 update delete selct 有这么多的重载方法 如何去定位 可变参数是JDK1.5版本之后才有的东西 RowMapper 实现RowMapper这个接口.然后实现 ...