推箱子AI

10 篇文章 0 订阅
2 篇文章 0 订阅

转帖地址http://blog.csdn.net/alai04/archive/2006/05/31/765958.aspx

 

// ----------------------------------------------------------------------------
// SokoState_v1.cpp -- SokoState类的实现文件,第一版

#if 0

#include "SokoState_v1.h"
#include <iterator>
#include <string>
#include <memory>
#include <stdexcept>

using namespace std;

inline unsigned char SokoState::mapChar(Point p) const
{
    if (isWall(p))
        return CharWall;
    else if (isBox(p))
        return isDest(p) ? CharInDest : CharBox;
    else if (isSoko(p))
        return isDest(p) ? CharSokoInDest : CharSoko;
    else if (isDest(p))
        return CharDest;
    else
        return CharSpace;
}

void SokoState::checkSoko(stack<Point>& ps, Point p)
{
    if (isPureSpace(p))
    {
        map_[p.x_][p.y_] |= FlagSoko;
        ps.push(p);
    }
}

void SokoState::stateEq()
{
    int i, j;
    for (i = 1; i < rows_-1; i++)
    {
        for (j = 1; j < cols_-1; j++)
        {
            if (isSoko(Point(i, j))) break;
        }
        if (j < cols_-1) break;
    }
   
    stack<Point> points;
    Point p(i, j);
    points.push(p);

    while (!points.empty())
    {
        p = points.top();
        points.pop();
        checkSoko(points, p.up());
        checkSoko(points, p.down());
        checkSoko(points, p.left());
        checkSoko(points, p.right());
    }
}


bool SokoState::moveBox(SokoState& r, Point box, Point soko, Point nBox,
    char d) const
{
    if (!isSoko(soko) || !isSpace(nBox))
        return false;

    r = *this;
    for (int i = 0; i < r.rows_; i++)  //清除soko标志
    {
        for (int j = 0; j < r.cols_; j++)
        {
            r.map_[i][j] &= ~FlagSoko;
        }
    }
    r.map_[box.x_][box.y_] &= ~FlagBox;  //移动箱子
    r.map_[box.x_][box.y_] |= FlagSoko;
    r.map_[nBox.x_][nBox.y_] |= FlagBox;
    r.stateEq();
    r.steps_.push_back(SokoStep(box.x_, box.y_, d));
    return true;
}

 

void SokoState::nextStep(vector<SokoState>& vs) const
{
    SokoState newState;
    for (int i = 1; i < rows_-1; i++)
    {
        for (int j = 1; j < cols_-1; j++)
        {
            Point p(i, j);
            if (!isBox(p))
                continue;
            if (moveBox(newState, p, p.down(), p.up(), 'U'))
                vs.push_back(newState);
            if (moveBox(newState, p, p.up(), p.down(), 'D'))
                vs.push_back(newState);
            if (moveBox(newState, p, p.right(), p.left(), 'L'))
                vs.push_back(newState);
            if (moveBox(newState, p, p.left(), p.right(), 'R'))
                vs.push_back(newState);
        }
    }
}


bool SokoState::isTarget() const
{
    for (int i = 1; i < rows_-1; i++)
    {
        for (int j = 1; j < cols_-1; j++)
        {
            Point p(i, j);
            if (isDest(p) != isBox(p))
                return false;
        }
    }
    return true;
}


void SokoState::printAnswer(ostream& os) const
{
    copy(steps_.begin(), steps_.end(), ostream_iterator<SokoStep>(os, " "));
}


bool SokoState::operator< (const SokoState& other) const
{
    if (rows_ < other.rows_)
        return true;
    if (rows_ > other.rows_)
        return false;
    if (cols_ < other.cols_)
        return true;
    if (cols_ > other.cols_)
        return false;
    for (int i = 0; i < rows_; i++)
    {
        for (int j = 0; j < cols_; j++)
        {
            if (map_[i][j] < other.map_[i][j])
                return true;
            if (map_[i][j] > other.map_[i][j])
                return false;
        }
    }
    return false;
}

 

ostream& operator<< (ostream& os, const SokoState& s)
{
    for (int i = 0; i < s.rows_; i++)
    {
        for (int j = 0; j < s.cols_; j++)
        {
            os << s.mapChar(SokoState::Point(i, j));
        }
        os << "/n";
    }
    os << "------------------------" << endl;
    return os;
}


istream& operator>> (istream& is, SokoState& s)
{
    is >> s.rows_;
    if (s.rows_ < MIN_ROWS || s.rows_ > MAX_ROWS)
    {
        throw invalid_argument("rows of soko game error.");
    }
    is >> s.cols_;
    if (s.cols_ < MIN_COLS || s.cols_ > MAX_COLS)
    {
        throw invalid_argument("cols of soko game error.");
    }

    string str;
    getline(is, str);  // 滤过第一行的换行
    for (int i = 0; i < s.rows_; i++)
    {
        getline(is, str);
        for (int j = 0; j < s.cols_; j++)
        {
            s.map_[i][j] = 0;
            switch (str[j]) {
                case SokoState::CharBox :
                    s.map_[i][j] |= SokoState::FlagBox;
                    break;
                case SokoState::CharWall :
                    s.map_[i][j] |= SokoState::FlagWall;
                    break;
                case SokoState::CharSpace :
                    break;
                case SokoState::CharDest :
                    s.map_[i][j] |= SokoState::FlagDest;
                    break;
                case SokoState::CharInDest :
                    s.map_[i][j] |= SokoState::FlagDest | SokoState::FlagBox;
                    break;
                case SokoState::CharSoko :
                    s.map_[i][j] |= SokoState::FlagSoko;
                    break;
                case SokoState::CharSokoInDest :
                    s.map_[i][j] |= SokoState::FlagSoko | SokoState::FlagDest;
                    break;
                default :
                    throw invalid_argument(
                        string("char of soko game error: ") + str );
            }
        }
    }
    s.stateEq();
    return is;
}

 

// ----------------------------------------------------------------------------
// soko.cpp -- 推箱子主程序

#include <iostream>
//#include "BreadthFirstSearch.hpp"
#include "bfs.h"
#include "SokoState_v1.h"

using namespace std;

bool printAnswer(const SokoState& s)
{
    s.printAnswer(cout);
    cout << endl;
    return true;
}

/*
输入:

  9 9
WWWWWWWWW
WWWSSSWWW
WWSSSSSSW
WWIWIWISW
WWSWKBSWW
WWSWSWDWW
WSSSSSSWW
WSSSWSSWW
WWWWWWWWW

*/

int main(int argc, char *argv[])
{
    SokoState initState;
    cin >> initState;
    cout << initState;
    OrderCheckDup<SokoState> checkDup;
    int n = BreadthFirstSearch(initState, printAnswer, checkDup);
    if (n == 0)
    {
        cout << "No answer." << endl;
    }
 
    return 0;
}


//本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/alai04/archive/2006/05/31/765958.aspx

#endif

 

/*
在引入boost.Multi_index容器,我想有必要先整理一下DFS/BFS的代码。主要的修改是,
不再使用queue容器和stack容器,而用list容器来替换它们。原因是,queue和stack容器
会把已搜索过的结点删除掉,而我们如果要在容器内进行查重的话,就必须保留所有结点
,所以不能使用这两种容器。

一开始我也想过使用vector容器,不过由于我们最终的目标是Multi_index容器,它不能象
vector那样进行随机访问,它只能实现list容器的功能,为了便于向Multi_index过渡,最
终我还是选择了list。

没有了queue和stack,我们就要用一个iterator来区分list中那些已搜索与未搜索的结点。
我把已搜索和未搜索的结点分别放在list的两端,而这个iterator指向它们的分界线,即
iterator之前的结点为已搜索结点,之后的结点为未搜索结点。当我们需要取出下一个结
点来处理时,只要把iterator后移一下就可以了;对当前结点调用nextStep()所得到的下
一层结点,则要视DFS或BFS来决定如何插入list;如果是DFS,就把新得到的结点插入到
iterator的后面;如果是BFS,则把新的结点插入到list的后端;当iterator到达list的
末端时,则表示搜索结束。

为方便起见,我把DFS和BFS以及各种查重算法集中到一个.hpp文件,源码如下:


--------------------------------------------------------------------------------
*/

// Filename: bfs.h
#ifndef _BFS_DFS_HPP
#define _BFS_DFS_HPP

#pragma warning ( disable : 4786 )

#include <list>
#include <vector>
#include <set>
//#include <ext/hash_set>
//#include <hash_set>

using std::list;
using std::vector;
using std::set;
//using __gnu_cxx::hash_set;
//using __gnu_cxx::hash;


// 仿函式,用于不检查状态结点是否重复,搜索算法的两参数版本使用
// duplicate
template <class T>
struct NoCheckDup : std::unary_function<T, bool>
{
    bool operator() (const T&) const
    {
        return false;
    }
};

/*
// 仿函式,用hash_set容器检查状态结点是否重复
// 要求状态类提供operator==以及hash函数
template <class T, class HashFcn = hash<T> >
class HashCheckDup : std::unary_function<T, bool>
{
    typedef hash_set<T, HashFcn> Cont;
    Cont states_;
public:
    typedef typename Cont::hasher hasher;
    HashCheckDup(const hasher& hf) : states_(100, hf) {}
    bool operator() (const T& s)
    {
        if (states_.find(s) != states_.end())  // 状态已存在,重复
        {
            return true;
        }
        states_.insert(s);  // 状态未重复,记录该状态
        return false;
    }
};
*/

// 仿函式,用set容器检查状态结点是否重复
// 要求状态类提供operator<
template <class T>
class OrderCheckDup : std::unary_function<T, bool>
{
    typedef set<T> Cont;
    Cont states_;
public:
    bool operator() (const T& s)
    {
        typename Cont::iterator i = states_.find(s);
        if (i != states_.end())  // 状态已存在,重复
        {
            return true;
        }
        states_.insert(i, s);  // 状态未重复,记录该状态
        return false;
    }
};

// 仿函式,用vector容器检查状态结点是否重复,线性复杂度
// 要求状态类提供operator==
template <class T>
class SequenceCheckDup : std::unary_function<T, bool>
{
    typedef vector<T> Cont;
    Cont states_;
public:
    bool operator() (const T& s)
    {
        typename Cont::iterator i =
            find(states_.begin(), states_.end(), s);
        if (i != states_.end())  // 状态已存在,重复
        {
            return true;
        }
        states_.push_back(s);  // 状态未重复,记录该状态
        return false;
    }
};

template <class T1, class T2 >
int BreadthFirstSearch(const T1& initState, const T2& afterFindSolution)
// 两参数版本
// initState : 初始化状态,类T1应提供成员函数nextStep()和isTarget(),
//             nextStep()用vector<T1>返回下一步可能的所有状态,
//             isTarget()用于判断当前状态是否符合要求的答案;
// afterFindSolution : 仿函式,在找到一个有效答案后调用之,它接受一个const T1&,
//                     并返回一个Boolean值,true表示停止搜索,false表示继续找
// return : 找到的答案数量
{
    NoCheckDup<T1> noCheckDup;
    return BreadthFirstSearch(initState, afterFindSolution, noCheckDup);
}

template <class T1, class T2, class T3 >
int BreadthFirstSearch(const T1& initState, const T2& afterFindSolution,
    T3& checkDup)
// 三参数版本,前两个参数参考两参数版本说明
// checkDup :  仿函式,对于每一个下一步可能的状态调用之,它接受一个const T1&,
//             并返回一个Boolean值,true表示状态重复,false表示状态不重复
//             checkDup的缺省值是不进行检查,假定所有生成的状态均不会重复
// return : 找到的答案数量
{
    int n = 0;
    list<T1> states;
    states.push_back(initState);
    typename list<T1>::iterator head = states.begin();  // 指向下个搜索的结点

    vector<T1> nextStates;
    bool stop = false;
    while (!stop && head != states.end())
    {
        T1 s = *head;  // 搜索一个结点
        nextStates.clear();
        s.nextStep(nextStates);  // 从搜索点生成下一层结点
        for (typename vector<T1>::iterator i = nextStates.begin();
             i != nextStates.end(); ++i)
        {
            if (i->isTarget()) // 找到一个目标状态
            {
                ++n;
                if (stop = afterFindSolution(*i))  // 处理结果并决定是否停止
                {
                    break;
                }
            }
            else // 不是目标状态,判断是否放入搜索队列中
            {
                if (!checkDup(*i))  // 只将不重复的状态放入搜索队列
                {
                    states.push_back(*i);
                }
            }
        }
        ++head;  // 指针移到下一个元素
    }
    return n;
}

template <class T1, class T2 >
int DepthFirstSearch(const T1& initState, const T2& afterFindSolution)
// 两参数版本
// initState : 初始化状态,类T1应提供成员函数nextStep()和isTarget(),
//             nextStep()用vector<T1>返回下一步可能的所有状态,
//             isTarget()用于判断当前状态是否符合要求的答案;
// afterFindSolution : 仿函式,在找到一个有效答案后调用之,它接受一个const T1&,
//                     并返回一个Boolean值,true表示停止搜索,false表示继续找
// return : 找到的答案数量
{
    NoCheckDup<T1> noCheckDup;
    return DepthFirstSearch(initState, afterFindSolution, noCheckDup);
}

template <class T1, class T2, class T3 >
int DepthFirstSearch(const T1& initState, const T2& afterFindSolution,
    T3& checkDup)
// 三参数版本,前两个参数参考两参数版本说明
// checkDup :  仿函式,对于每一个下一步可能的状态调用之,它接受一个const T1&,
//             并返回一个Boolean值,true表示状态重复,false表示状态不重复
//             checkDup的缺省值是不进行检查,假定所有生成的状态均不会重复
// return : 找到的答案数量
{
    int n = 0;
    list<T1> states;
    states.push_back(initState);
    typename list<T1>::iterator head = states.begin();  // 指向下个搜索的结点

    vector<T1> nextStates;
    bool stop = false;
    while (!stop && head != states.end())
    {
        T1 s = *head;
        nextStates.clear();
        s.nextStep(nextStates);
        for (typename vector<T1>::iterator i = nextStates.begin();
             i != nextStates.end(); ++i)
        {
            if (i->isTarget()) // 找到一个目标状态
            {
                ++n;
                if (stop = afterFindSolution(*i))  // 处理结果并决定是否停止
                {
                    break;
                }
            }
            else  // 不是目标状态,判断是否放入搜索队列中
            {
                if (!checkDup(*i))  // 只将不重复的状态放入搜索队列
                {
                    typename list<T1>::iterator it = head;
                    states.insert(++it, *i);  // 插入到head的后面
                }
            }
        }
        ++head;
    }
    return n;
}

#endif

 

//--------------------------------------------------------------------------------


//源代码要使用GCC编译,其中使用了STL的扩展容器hash_set,如果使用其它编译环境,则需要修改相应的头文件和容器名字空间。


//本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/alai04/archive/2006/06/03/771432.aspx

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值