数据结构

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*算法【拼图游戏】的更多相关文章

  1. 基于unity3d和leap motion的拼图游戏

    近期用unity3d引擎做了一个拼图游戏,会分几次写完,以此作为总结. 本文基本查找了网上能查到的全部资料作为參考.也算是大家节省了时间. 眼下仅仅完毕了拼图部分,leap motion手势控制部分会 ...

  2. 程序设计 之 C#实现《拼图游戏》 (下) 原理篇

    前言:在 http://www.cnblogs.com/labixiaohei/p/6698887.html 程序设计 之 C#实现<拼图游戏>(上),上传了各模块代码,而在本文中将详细剖 ...

  3. [Android]自己动手做个拼图游戏

    目标 在做这个游戏之前,我们先定一些小目标列出来,一个一个的解决,这样,一个小游戏就不知不觉的完成啦.我们的目标如下: 游戏全屏,将图片拉伸成屏幕大小,并将其切成若干块. 将拼图块随机打乱,并保证其能 ...

  4. 拼图游戏js

    实现算法: 1. JavaScript动态生成拼图:通过生成16个div,且除最后一个div不使用背景图片以外,其他div都设置拼图图片为背景.然后通过调整background-position来实现 ...

  5. iOS 滑块拼图游戏(Puzzle8)

    代码地址如下:http://www.demodashi.com/demo/11505.html 一.准备工作 先了解一个定义和定理 定义:在一个1,2,...,n的排列中,如果一对数的前后位置与大小顺 ...

  6. C#实现拼图游戏

    C#实现<拼图游戏> (下) 原理篇   前言:在 http://www.cnblogs.com/labixiaohei/p/6698887.html 程序设计 之 C#实现<拼图游 ...

  7. 利用Vue.js实现拼图游戏

    之前写过一篇<基于Vue.js的表格分页组件>的文章,主要介绍了Vue组件的编写方法,有兴趣的可以访问这里进行阅读:http://www.cnblogs.com/luozhihao/p/5 ...

  8. JavaScript拼图游戏

    今天是2016年最后一天上班了.最近几天都比较休闲,有时间空闲下来写写文档之类的. 2016过得真是快.感觉没做什么就过去了.想到之前想坚持每个月写一写博客都没坚持到.希望2017年可以吧. 无聊之余 ...

  9. SDL制作拼图游戏

    看完教程第三集后,好像自己能用这个来写一个简单的拼图游戏,第一次写出个带界面的游戏,好有成就感. 图片是自己慢慢截左上部分8个脸. #include <stdio.h> #include ...

  10. 拼图游戏(js,C#,java三种语言)

    <html> <head> <meta charset="utf-8"> <style type="text/css" ...

随机推荐

  1. python学习之路(14)

    通过列表生成式,我们可以直接创建一个列表.但是,受到内存限制,列表容量肯定是有限的.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素 ...

  2. springBoot 整合 mybatis 项目实战

    二.springBoot 整合 mybatis 项目实战   前言 上一篇文章开始了我们的springboot序篇,我们配置了mysql数据库,但是我们sql语句直接写在controller中并且使用 ...

  3. python环境下安装virtualenv,virtualenvwrapper

    在使用 Python 开发的过程中,工程一多,难免会碰到不同的工程依赖不同版本的库的问题: 亦或者是在开发过程中不想让物理环境里充斥各种各样的库,引发未来的依赖灾难. 此时,我们需要对于不同的工程使用 ...

  4. python实战,

    1.把日志状态码为200得请求记录下来 记录信息(ip,访问时间,请求资源) 封装函数再次调用,健壮性try except #coding=utf-8import redef  aclog(path, ...

  5. What is the most efficient way to deep clone an object in JavaScript?

    What is the most efficient way to deep clone an object in JavaScript? Reliable cloning using a libra ...

  6. Oracle_Windows server ORA-01031: insufficient privileges

    PS C:\Users\admin> sqlplus / as sysdba SQL*Plus: Release 11.2.0.1.0 Production on 星期二 9月 3 10:21: ...

  7. ListView 中图片错位的问题是如何产生的?

    图片错位问题的本质源于我们的 listview 使用了缓存 convertView,假设一种场景,一个 listview 一屏显示九个item,那么在拉出第十个 item 的时候,事实上该 item ...

  8. 第三章 SpringCloud之Eureka-Client服务提供者

    1.Eureka-Client简介 #################接下来开始程序啦########################## 1.pom.xml <?xml version=&qu ...

  9. ControlTemplate in WPF —— ListBox

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" x ...

  10. 阶段3 3.SpringMVC·_01.SpringMVC概述及入门案例_06.入门案例的流程总结

    配置了load-on-startup等于1 表示启动了服务器就会去创建DispatcherServlet 如果不配置load-on-startup为1 那么第一次发送请求才会去创建Dispatcher ...