码迷,mamicode.com
首页 > 其他好文 > 详细

还原拼图, 把妹收小弟神器, 让你逼格提高好几个档次.

时间:2015-06-08 19:29:42      阅读:136      评论:0      收藏:0      [点我收藏+]

标签:

技术分享

这里给链接: 自动拼图 http://pan.baidu.com/s/1sjoNv7f

其实呢, 也没多少技术含量. 当然, 我比较谦虚.

源码

  1 #include "Game.h"
  2 
  3 #include <map>
  4 
  5 static const auto PUZZLE_COUNT = 16;
  6 static const auto PUZZLE_WIDTH = WINDOW_WIDTH / PUZZLE_COUNT;
  7 static const auto PUZZLE_HEIGHT = WINDOW_HEIGHT / PUZZLE_COUNT;
  8 
  9 static const auto RAND_COUNT = 2000;
 10 
 11 inline bool operator <(const D2D1_POINT_2F &pos1, const D2D1_POINT_2F &pos2)
 12 {
 13     if (pos1.x == pos2.x)
 14     {
 15         return pos1.y < pos2.y;
 16     }
 17     return pos1.x < pos2.x;
 18 }
 19 
 20 enum EnumDirect {
 21     UP,
 22     RIGHT,
 23     DOWN,
 24     LEFT
 25 };
 26 
 27 namespace Utils {
 28     inline EnumDirect flipDirect(EnumDirect direct)
 29     {
 30         return direct == EnumDirect::UP ? EnumDirect::DOWN
 31             : direct == EnumDirect::DOWN ? EnumDirect::UP
 32             : direct == EnumDirect::LEFT ? EnumDirect::RIGHT
 33             : EnumDirect::LEFT;
 34     }
 35 }
 36 
 37 class Puzzle : public mmc::LImage {
 38 public:
 39     Puzzle(int x, int y, int width, int height, const std::wstring &filename) : LImage(filename)
 40     {
 41         _cliprc = D2D1::RectF(x * 1.0f, y * 1.0f, x + width * 1.0f, y + height * 1.0f);
 42     }
 43 
 44     ~Puzzle()
 45     {
 46 
 47     }
 48 
 49     virtual void doDraw(ID2D1RenderTarget *pRT, float opacity) override
 50     {
 51         auto pImg = getD2dBitmap();
 52         if (pImg)
 53         {
 54             pRT->DrawBitmap(pImg,
 55                 D2D1::RectF(0.0f, 0.0f, PUZZLE_WIDTH * 1.0f, PUZZLE_HEIGHT * 1.0f),
 56                 opacity, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, _cliprc);
 57         }
 58     }
 59 
 60 private:
 61     D2D1_RECT_F _cliprc;
 62 };
 63 
 64 class Game::impl {
 65 public:
 66     impl(Game *pGame) : _pGame(pGame)
 67     {
 68         srand(time(0));
 69     }
 70 
 71     ~impl()
 72     {
 73 
 74     }
 75 
 76     void init()
 77     {
 78         for (auto x = 0; x != PUZZLE_COUNT; ++x)
 79         {
 80             for (auto y = 0; y != PUZZLE_COUNT; ++y)
 81             {
 82                 auto pos = D2D1::Point2F(x * PUZZLE_WIDTH * 1.0f, y * PUZZLE_HEIGHT * 1.0f);
 83 
 84                 auto pChild = new Puzzle((int)pos.x, (int)pos.y, PUZZLE_WIDTH, PUZZLE_HEIGHT, L"res/img.png");
 85                 pChild->setParent(_pGame);
 86                 pChild->setPosition(pos.x, pos.y);
 87 
 88                 _posMap.insert(std::make_pair(pos, pChild));
 89             }
 90         }
 91 
 92         mmc::LRootWindow::getInstance()->redrawWindow();
 93 
 94         auto hWnd = mmc::LRootWindow::getInstance()->getWindowHandle();
 95         rand(RAND_COUNT);
 96     }
 97 
 98     void rand(u_int count)
 99     {
100         for (auto i = 0; i != count; ++i)
101         {
102             auto direct = EnumDirect(::rand() % 4);
103             if (next(direct))
104             {
105                 _directs.push(direct);
106             }
107         }
108         mmc::LRootWindow::getInstance()->redrawWindow();
109     }
110 
111     void next()
112     {
113         static auto isIgnore = [](EnumDirect direct, std::stack<EnumDirect> &directs) {
114             return Utils::flipDirect(direct) == directs.top();
115         };
116 
117         if (_directs.empty())
118         {
119             //rand(RAND_COUNT);
120             return;
121         }
122 
123         auto isOk = false;
124         auto direct = EnumDirect::UP;
125 
126         while (!_directs.empty() && !isOk)
127         {
128             isOk = true;
129             direct = _directs.top();
130             _directs.pop();
131 
132             if (!_directs.empty() && isIgnore(direct, _directs))
133             {
134                 _directs.pop();
135                 isOk = false;
136             }
137 
138             if (_directs.size() > 1 && isOk)
139             {
140                 auto direct2 = _directs.top();
141                 _directs.pop();
142                 if (isIgnore(direct2, _directs))
143                 {
144                     _directs.pop();
145                     _directs.push(direct);
146                     isOk = false;
147                 }
148                 else
149                 {
150                     _directs.push(direct2);
151                 }
152             }
153         }
154 
155         if (isOk)
156         {
157             next(Utils::flipDirect(direct));
158             mmc::LRootWindow::getInstance()->redrawWindow();
159         }
160     }
161 
162     void doDraw(ID2D1RenderTarget *pRT, float opacity) 
163     {
164 
165     }
166 
167     void doInput(UINT uMsg, WPARAM wParam, LPARAM lParam)
168     {
169         switch (uMsg)
170         {
171         case WM_CREATE:
172             {
173                 init();
174             }
175         break;
176         case WM_TIMER:
177             {
178                 if (wParam == 1001)
179                 {
180                     next();
181                     mmc::LRootWindow::getInstance()->redrawWindow();
182                 }
183             }
184             break;
185         case WM_KEYUP:
186             {
187                 if (wParam == VK_RETURN)
188                 {
189                     SetTimer(mmc::LRootWindow::getInstance()->getWindowHandle(), 1001, 16, nullptr);
190                 }
191             }
192             break;
193         }
194     }
195 private:
196     bool next(EnumDirect direct)
197     {
198         auto pGap = getGap();
199         auto pMoveObj = find(direct);
200         if (pMoveObj != nullptr)
201         {
202             swap(pMoveObj);
203         }
204         return pMoveObj != nullptr;
205     }
206 
207     mmc::LNode *find(EnumDirect direct)
208     {
209         auto pGap = getGap();
210         auto pos = pGap->getPosition();
211         switch (direct)
212         {
213             case EnumDirect::UP:
214                 pos.y += PUZZLE_HEIGHT;
215                 break;
216             case EnumDirect::RIGHT:
217                 pos.x -= PUZZLE_WIDTH;
218                 break;
219             case EnumDirect::DOWN:
220                 pos.y -= PUZZLE_HEIGHT;
221                 break;
222             case EnumDirect::LEFT:
223                 pos.x += PUZZLE_WIDTH;
224                 break;
225         }
226         auto iter = _posMap.find(pos);
227         return iter != std::end(_posMap) ? iter->second : nullptr;
228     }
229 
230     mmc::LNode *getGap()
231     {
232         return _pGame->getChilds().back();
233     }
234 
235     void swap(mmc::LNode *pNode)
236     {
237         auto pGap = getGap();
238         auto pos1 = pGap->getPosition();
239         auto pos2 = pNode->getPosition();
240         pNode->setPosition(pos1.x, pos1.y);
241         pGap->setPosition(pos2.x, pos2.y);
242 
243         _posMap.at(pos1) = pNode;
244         _posMap.at(pos2) = pGap;
245     }
246 
247     std::stack<EnumDirect>                    _directs;
248     std::map<D2D1_POINT_2F, mmc::LNode*>    _posMap;
249     Game *_pGame;
250 };
251 
252 Game::Game() : _pimpl(new impl(this))
253 {
254     
255 }
256 
257 Game::~Game()
258 {
259 
260 }
261 
262 void Game::doDraw(ID2D1RenderTarget *pRT, float opacity)
263 {
264     _pimpl->doDraw(pRT, opacity);
265 }
266 
267 void Game::doInput(UINT uMsg, WPARAM wParam, LPARAM lParam)
268 {
269     _pimpl->doInput(uMsg, wParam, lParam);
270 }

这里是最关键的代码, 里面用了一些我封装的dx库. 在我给的连接里有源码. 代码写的潦草, 大伙也不要见笑.

我没有加入用户控制的功能, 因为呢, 我不想加. 呵呵!

咱们说说这个程序的效果, 启动之后按下回车键, 然后眼睁睁看着就好了.

原理是这样的.

把图片切成若干块, 沿着x, y轴对称铺好.

然后将其位置"打乱", rand 这个这个函数实现了打乱的功能, 随机生成方向, 然后图块移动, 并且在移动生效之后记录方向. 重复 count 次结束.

 

这里有一个槽点, 如果你是一个急性子, 也许你就忽略了. 本作者估计在这里断句, 让你有时间发现槽点.

在打乱的时候保存了方向, 在还原的时候反方向走一遍就OK了. 哈哈哈哈哈, 就是这么简单.

 

但是, 这是不可能的.

这样做会导致一个看起来很傻逼的效果.

因为打乱是随机生成的, 也就是说极有可能出现生成 up, down, up, down, 这种方向.

那么在还原的时候就出现了, down, up, down, up.. 走了好几步, 位置都没变.

 

那如何解决这一问题, 参见 next(), 这个next 不带参数, 看仔细..

它的实现过程是:

1, 如果当前的方向跟下一个方向造成冲突, 那就把这2个方向pop掉.

2, 如果当前的方向跟下一个方向不造成冲突, 那就检测下一个方向跟下下一个方向是否造成冲突.

如果你是一个菜鸟, 同时很有想法, 那就跟我学做菜吧. 呵呵!

开个玩笑, 如果你是一个菜鸟, 同时很有想法, 你大概会觉得第二条有些莫名其妙.

如果有 down, left, right, up 这种情况.

down作为当前方向, 跟下一个方向 left 做比较, 明显不会造成冲突, 因此第一条是不成立的, down顺利执行.

left作为当前方向, 跟下一个方向right 做比较, 这里造成了冲突, 这2个方向都被pop, 接下来 up 成了当前方向.

up已经是最后一个方向或者跟下一个方向不造成冲突, 那它就被顺利执行了.

问题就来了, 前面执行了down, 这里又执行up, 那就移动了位置也没变化..

 

晒晒博主的背影

技术分享

还原拼图, 把妹收小弟神器, 让你逼格提高好几个档次.

标签:

原文地址:http://www.cnblogs.com/mmc1206x/p/4561647.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!