推箱子源程序v1.1

回头看了看推箱子的源代码,里面有不少嵌套的for循环用于查找满足某个条件的位置,或者是对其进行处理。过多的嵌套for循环似乎与STL的精神相悖,于是想是否可以用迭代器和STL算法来替换这些嵌套的循环。

办法是:增加一个迭代器类SSiterator,保存某个SokoState对象中map_成员的位置,并提供operator++(前缀及后缀)、operator--前缀及后缀)、operator*、operator==、operator!=等操作符。为了方便SokoState的成员函数使用,还增加了四个成员函数up()、down()、left()、right()。

有了这个SSiterator,就可以对SokoState类进行修改了。修改包括:把MapFlag、MapChar、isXXX等移出SokoState类,以便于SSiterator使用;增加begin()和end()成员,返回表示起点和终点的迭代器对象;最后是用迭代器和STL算法来替换原有的for循环。最后,除了operator<<和operator>>的输入输出操作符之外,其它的for循环全部消失了。至于输入输出操作符,由于要处理换行符,所以还没有想以好办法来消除for循环。

用到的STL算法包括有:copy、transform、lexicographical_compare;还有compose2、ptr_fun等函数对象适配器。

不过,到完成后,与v1版本的运行效率比较了一下,有较大程序的性能损失,慢了约2-3倍。其实它们的算法是一样,不过v1.1中有很多迭代器对象的构造、复制、析构,导致了较多的开销。

以下贴出新的源代码,只有两个文件,soko主程序没有修改(除了#include),不再重复。

 

// SokoState_v1.1.h -- SokoState类的头文件,第一版

#ifndef _SOKOSTATE_H
#define _SOKOSTATE_H

#include <iostream>
#include <vector>
#include <stack>

using std::vector;
using std::stack;
using std::ostream;
using std::istream;

const int MIN_ROWS = 4;
const int MAX_ROWS = 16;
const int MIN_COLS = 4;
const int MAX_COLS = 16;

class SokoState;

struct SSiterator :
    public std::iterator<std::bidirectional_iterator_tag, unsigned char>
{
    SokoState* s_;
    int x_, y_;
    SSiterator(SokoState& s, int x, int y) : s_(&s), x_(x), y_(y) {}
    value_type& operator*() const;
    SSiterator& operator++();
    SSiterator& operator--();
    SSiterator operator++(int) {
        SSiterator tmp = *this;
        ++*this;
        return tmp;
    }
    SSiterator operator--(int) {
        SSiterator tmp = *this;
        --*this;
        return tmp;
    }
    bool operator==(const SSiterator& other) {
        return s_ == other.s_ && x_ == other.x_ && y_ == other.y_;
    }
    bool operator!=(const SSiterator& other) {
        return !operator==(other);
    }
    SSiterator up() {
        SSiterator tmp = *this;
        --(tmp.x_);
        return tmp;
    }
    SSiterator down() {
        SSiterator tmp = *this;
        ++(tmp.x_);
        return tmp;
    }
    SSiterator left() {
        SSiterator tmp = *this;
        --(tmp.y_);
        return tmp;
    }
    SSiterator right() {
        SSiterator tmp = *this;
        ++(tmp.y_);
        return tmp;
    }
    SSiterator& changeState(SokoState& s) {
        s_ = &s;
        return *this;
    }
};

class SokoState
{
public:
    SokoState() : rows_(0), cols_(0) {}
    void nextStep(vector<SokoState>&) const;
    bool isTarget() const;
    bool operator< (const SokoState& other) const;
    friend ostream& operator<< (ostream& os, const SokoState& s);
    friend istream& operator>> (istream& is, SokoState& s);
    void printAnswer(ostream& os) const;

private:
    typedef SSiterator iterator;
    friend struct SSiterator;
    iterator begin() const
        { return iterator(const_cast<SokoState&>(*this), 0, 0); }
    iterator end() const
        { return iterator(const_cast<SokoState&>(*this), rows_, 0); }

    struct SokoStep  //用于记录每一步箱子的移动
    {
        int x_;
        int y_;
        char d_;  // direction: R,L,U,D
        SokoStep(int x, int y , char d) : x_(x), y_(y), d_(d) {}
        friend ostream& operator<< (ostream& os, const SokoStep& s)
        {
            os << "[" << s.x_ << ", " << s.y_ << ", " << s.d_ << "]";
            return os;
        }
    };

    void moveBox(vector<SokoState>& vs, iterator iBox, iterator iSoko,
        iterator iNBox, char d) const;
    void checkSoko(stack<iterator>& ps, iterator it);
    void stateEq();

    int rows_, cols_;
    unsigned char map_[MAX_ROWS][MAX_COLS];
    vector<SokoStep> steps_;
};

#endif

 

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

#include <iterator>
#include <string>
#include <memory>
#include <ext/functional>
#include <stdexcept>
#include "SokoState_v1.1.h"

using namespace std;
using namespace __gnu_cxx;

enum MapChar {
    CharWall = 'W',         // Wall障碍物
    CharBox = 'B',          // Box箱子,不在目的地
    CharSpace = 'S',        // Space空地,没有任何东西
    CharDest = 'D',         // Dest目的地
    CharInDest = 'I',       // 已放在目的地上的箱子
    CharSoko = 'K',         // Soko推箱子的人,不在目的地
    CharSokoInDest = 'O',   // Soko推箱子的人,恰好在目的地
    CharError = 'E'         // 错误状态
};

enum MapFlag {
    FlagWall = 0x01,    // 是否障碍物
    FlagBox = 0x02,     // 是否有箱子
    FlagDest = 0x04,    // 是否目的地
    FlagSoko = 0x08     // 是否有人
};

inline bool isWall(unsigned char c) 
{
    return (c & FlagWall) != 0;
}

inline bool isBox(unsigned char c) 
{
    return (c & FlagBox) != 0;
}

inline bool isDest(unsigned char c) 
{
    return (c & FlagDest) != 0;
}

inline bool isSoko(unsigned char c) 
{
    return (c & FlagSoko) != 0;
}

inline bool isSpace(unsigned char c) 
{
    return !isWall(c) && !isBox(c);
}

inline bool isPureSpace(unsigned char c) 
{
    return isSpace(c) && !isSoko (c);
}

inline void setFlag(SSiterator it, MapFlag f)
{
    *it |= f;
}

inline void clearFlag(SSiterator it, MapFlag f)
{
    *it &= ~f;
}

inline unsigned char clearSokoFlag(unsigned char c)
{
    return c & ~FlagSoko;
}

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

SSiterator::value_type& SSiterator::operator*() const
{
    return s_->map_[x_][y_];
}

SSiterator& SSiterator::operator++()
{
    if (++y_ == s_->cols_)
    {
        y_ = 0;
        ++x_;
    }
    return *this;
}

SSiterator& SSiterator::operator--()
{
    if (--y_ < 0)
    {
        y_ = s_->cols_-1;
        --x_;
    }
    return *this;
}

void SokoState::checkSoko(stack<iterator>& ps, iterator it)
{
    if (isPureSpace(*it))
    {
        setFlag(it, FlagSoko);
        ps.push(it);
    }
}

void SokoState::stateEq()
{
    SSiterator it = find_if(begin(), end(), isSoko);
   
    stack<iterator> points;
    points.push(it);

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

void SokoState::moveBox(vector<SokoState>& vs, SSiterator iBox, SSiterator iSoko,
    SSiterator iNBox, char d) const
{
    if (!isSoko(*iSoko) || !isSpace(*iNBox))
        return;

    SokoState r = *this;
    transform(r.begin(), r.end(), r.begin(), clearSokoFlag);
    clearFlag(iBox.changeState(r), FlagBox);  //移动箱子
    setFlag(iBox, FlagSoko);
    setFlag(iNBox.changeState(r), FlagBox);   
    r.stateEq();
    r.steps_.push_back(SokoStep(iBox.x_, iBox.y_, d));
    vs.push_back(r);
}

void SokoState::nextStep(vector<SokoState>& vs) const
{
    iterator it = begin();
    while (it != end())
    {
        it = find_if(it, end(), isBox);
        if (it == end())
            break;
        moveBox(vs, it, it.down(), it.up(), 'U');
        moveBox(vs, it, it.up(), it.down(), 'D');
        moveBox(vs, it, it.right(), it.left(), 'L');
        moveBox(vs, it, it.left(), it.right(), 'R');
        ++it;
    }
}

bool SokoState::isTarget() const
{
    iterator it = find_if(begin(), end(),
        compose2(not_equal_to<bool>(), ptr_fun(isDest), ptr_fun(isBox)));
    return it == end();
}

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 rows_ < other.rows_;
    if (cols_ != other.cols_)
        return cols_ < other.cols_;
    return(lexicographical_compare(begin(), end(),
        other.begin(), other.end()));
}

ostream& operator<< (ostream& os, const SokoState& s)
{
    SSiterator it = s.begin();
    for (int i = 0; i < s.rows_; ++i)
    {
        transform(it, it.down(), ostream_iterator<char>(os, ""), mapChar);
        os << "/n";
        it = it.down();
    }
    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;
    SSiterator it = s.begin();
    getline(is, str);  // 滤过第一行的换行
    for (int i = 0; i < s.rows_; i++)
    {
        getline(is, str);
        for (int j = 0; j < s.cols_; j++, ++it)
        {
            *it = 0;
            switch (str[j]) {
                case CharBox :
                    setFlag(it, FlagBox);
                    break;
                case CharWall :
                    setFlag(it, FlagWall);
                    break;
                case CharSpace :
                    break;
                case CharDest :
                    setFlag(it, FlagDest);
                    break;
                case CharInDest :
                    setFlag(it, FlagDest);
                    setFlag(it, FlagBox);
                    break;
                case CharSoko :
                    setFlag(it, FlagSoko);
                    break;
                case CharSokoInDest :
                    setFlag(it, FlagSoko);
                    setFlag(it, FlagDest);
                    break;
                default :
                    throw invalid_argument(
                        string("char of soko game error: ") + str );
            }
        }
    }
    s.stateEq();
    return is;
}


 




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值