最近在研究三消算法,我想试试在完全不借助网络资源的情况下搞定这个东西,所以有些地方可能不是最优的。

代码留此备忘。

1. 3x_desk_event.h

  1. 1 #pragma once
  2. 2
  3. 3 #ifndef __3X_DESK_EVENT_H_
  4. 4 #define __3X_DESK_EVENT_H_
  5. 5
  6. 6 #include "3x_desk_inc.h"
  7. 7 #include <vector>
  8. 8 #include <map>
  9. 9
  10. 10 /////////////////////// Event Action Datas ///////////////////////
  11. 11
  12. 12 #define StateEventCallBackT std::function<void(EAction, const __Event&)>
  13. 13
  14. 14 struct Action {};
  15. 15 struct Bonus : public Action
  16. 16 {
  17. 17 EBonusType _bonus = EBonusType::BONUS_None;
  18. 18 uint32_t _count = 0; //The max-count of line. {[3, 5]} & {0}
  19. 19 std::vector<Coord> _cleared;
  20. 20 };
  21. 21
  22. 22 struct Exchange : public Action
  23. 23 {
  24. 24 Coord _coordA;
  25. 25 Coord _coordB;
  26. 26 };
  27. 27
  28. 28 struct Replenish : public Action
  29. 29 {
  30. 30 std::vector<Coord> _news;
  31. 31 std::vector<Coord> _changed;
  32. 32 };
  33. 33
  34. 34 struct Refresh : public Action
  35. 35 {
  36. 36 std::vector<Coord> _src;
  37. 37 std::vector<Coord> _become;
  38. 38 };
  39. 39
  40. 40 struct Select : public Action
  41. 41 {
  42. 42 Coord _coord;
  43. 43 int _ex = 0;
  44. 44 };
  45. 45
  46. 46 struct NoneAction : public Action
  47. 47 {
  48. 48 public:
  49. 49 union __Act
  50. 50 {
  51. 51 public:
  52. 52 Exchange _exchange;
  53. 53 Select _select;
  54. 54 __Act()
  55. 55 {
  56. 56 new(&_exchange) Exchange;
  57. 57 new(&_select) Select;
  58. 58 }
  59. 59 ~__Act(){}
  60. 60 };
  61. 61
  62. 62 ~NoneAction()
  63. 63 {
  64. 64 switch (_type)
  65. 65 {
  66. 66 case EAction::ACTION_EXCHANGE:
  67. 67 _info._exchange.~Exchange();
  68. 68 break;
  69. 69
  70. 70 case EAction::ACTION_BONUS_BOMB:
  71. 71 _info._select.~Select();
  72. 72 break;
  73. 73
  74. 74 default:
  75. 75 break;
  76. 76 }
  77. 77 }
  78. 78
  79. 79 void Init(EAction t, Action* pAct)
  80. 80 {
  81. 81 if(t == EAction::ACTION_None)
  82. 82 return;
  83. 83
  84. 84 _type = t;
  85. 85
  86. 86 if(pAct == nullptr)
  87. 87 return;
  88. 88
  89. 89 switch (t)
  90. 90 {
  91. 91 case EAction::ACTION_EXCHANGE:
  92. 92 _info._exchange = *((Exchange*)pAct);
  93. 93 break;
  94. 94
  95. 95 case EAction::ACTION_BONUS_BOMB:
  96. 96 _info._select = *((Select*)pAct);
  97. 97 break;
  98. 98
  99. 99 default:
  100. 100 break;
  101. 101 }
  102. 102 }
  103. 103
  104. 104 inline EAction GetType() const noexcept { return _type; }
  105. 105 inline __Act GetInfo() const noexcept { return _info; }
  106. 106
  107. 107 private:
  108. 108 __Act _info;
  109. 109 EAction _type = EAction::ACTION_None;
  110. 110 };
  111. 111
  112. 112 /////////////////////// Event types ///////////////////////
  113. 113 template<EAction E> struct __action_type{};
  114. 114 template<> struct __action_type<EAction::ACTION_EXCHANGE>
  115. 115 {
  116. 116 using type = Exchange;
  117. 117 };
  118. 118 template<> struct __action_type<EAction::ACTION_BONUS>
  119. 119 {
  120. 120 using type = Bonus;
  121. 121 };
  122. 122 template<> struct __action_type<EAction::ACTION_REPLENISH>
  123. 123 {
  124. 124 using type = Replenish;
  125. 125 };
  126. 126 template<> struct __action_type<EAction::ACTION_REFRESH>
  127. 127 {
  128. 128 using type = Refresh;
  129. 129 };
  130. 130 template<> struct __action_type<EAction::ACTION_BONUS_BOMB>
  131. 131 {
  132. 132 using type = Bonus;
  133. 133 };
  134. 134 template<> struct __action_type<EAction::ACTION_None>
  135. 135 {
  136. 136 using type = NoneAction;
  137. 137 };
  138. 138 template<> struct __action_type<EAction::ACTION_FINAL>
  139. 139 {
  140. 140 using type = bool;
  141. 141 };
  142. 142
  143. 143 template<> struct __action_type<EAction::ACTION_BONUS_BOMB_INPUT>
  144. 144 {
  145. 145 using type = Select;
  146. 146 };
  147. 147
  148. 148 template<> struct __action_type<EAction::ACTION_EXCHANGE_INPUT>
  149. 149 {
  150. 150 using type = Exchange;
  151. 151 };
  152. 152
  153. 153 /////////////////////// Events ///////////////////////
  154. 154 struct __Event {};
  155. 155 template<EAction t> struct Event
  156. 156 : public __Event
  157. 157 {
  158. 158 public:
  159. 159 enum { _type = t };
  160. 160 Event(){}
  161. 161 ~Event(){};
  162. 162
  163. 163 public:
  164. 164 inline constexpr const EAction GetType() const { return t; }
  165. 165 typename __action_type<t>::type& Info() noexcept
  166. 166 {
  167. 167 return _info;
  168. 168 }
  169. 169
  170. 170 const typename __action_type<t>::type& GetInfo() const noexcept
  171. 171 {
  172. 172 return _info;
  173. 173 }
  174. 174
  175. 175 private:
  176. 176 typename __action_type<t>::type _info;
  177. 177 };
  178. 178
  179. 179
  180. 180
  181. 181 #endif

2.  3x_desk_inc.h

  1. 1 #pragma once
  2. 2
  3. 3 #ifndef __3X_DESK_INC_H_
  4. 4 #define __3X_DESK_INC_H_
  5. 5
  6. 6 #include <stdint.h>
  7. 7 #include <array>
  8. 8
  9. 9 enum EDeck : uint8_t
  10. 10 {
  11. 11 DECK_None ,
  12. 12 DECK_BLOCK ,
  13. 13 DECK_WALL ,
  14. 14 DECK_FREEZE ,
  15. 15 };
  16. 16
  17. 17 enum EElem : uint8_t
  18. 18 {
  19. 19 ELEM_None,
  20. 20 ELEM_A,
  21. 21 ELEM_B,
  22. 22 ELEM_C,
  23. 23 ELEM_D,
  24. 24 ELEM_E,
  25. 25 ELEM_F,
  26. 26 ELEM_G,
  27. 27 ELEM_H,
  28. 28 ELEM_I,
  29. 29 ELEM_J,
  30. 30
  31. 31 __ELEM_MAX_ ,
  32. 32 __ELEM_COUNT_ = __ELEM_MAX_ - 1
  33. 33 };
  34. 34
  35. 35 enum EAction
  36. 36 {
  37. 37 ACTION_None, //开始
  38. 38 ACTION_EXCHANGE, //交换
  39. 39 ACTION_BONUS, //消除
  40. 40 ACTION_REPLENISH, //充满
  41. 41 ACTION_REFRESH, //刷新/重排
  42. 42 ACTION_BONUS_BOMB, //特殊消除
  43. 43 ACTION_FINAL, //结束
  44. 44
  45. 45 //作为输入指令, 不进行类型偏特化,仅作为输入时的状态
  46. 46 ACTION_EXCHANGE_INPUT,
  47. 47 ACTION_BONUS_BOMB_INPUT,
  48. 48 };
  49. 49
  50. 50 enum EBonusType : uint32_t
  51. 51 {
  52. 52 __BONUS_BOMB_ = 0xB000,
  53. 53 BONUS_None = 0, //nothing
  54. 54 BONUS_ACROSS = (1 << 0), //---
  55. 55 BONUS_VERTICAL = (1 << 1), //|||
  56. 56 BONUS_CROSS = BONUS_ACROSS|BONUS_VERTICAL, // +++ / LLL
  57. 57 BONUS_BOMB_ACROSS = (__BONUS_BOMB_ | BONUS_ACROSS),
  58. 58 BONUS_BOMB_VERTICAL = (__BONUS_BOMB_ | BONUS_VERTICAL),
  59. 59 BONUS_BOMB_CROSS = (__BONUS_BOMB_ | BONUS_CROSS),
  60. 60 BONUS_BOMB_BY_SELECT = (__BONUS_BOMB_ | 0xFE),
  61. 61 BONUS_BOMB_CLEAR = (__BONUS_BOMB_ | 0xFF),
  62. 62
  63. 63 };
  64. 64
  65. 65 using Axis = int; //signed intager must!
  66. 66 enum AxisType { AxisX, AxisY };
  67. 67
  68. 68 struct Coord
  69. 69 {
  70. 70 Coord(Axis x, Axis y)
  71. 71 : _x(x), _y(y)
  72. 72 {}
  73. 73
  74. 74 Coord(Axis x, Axis y, EElem e)
  75. 75 : _x(x), _y(y), _e(e)
  76. 76 {}
  77. 77
  78. 78 Coord() : Coord(0, 0)
  79. 79 {}
  80. 80
  81. 81 Coord& operator()(Axis x, Axis y)
  82. 82 {
  83. 83 _x = x, _y = y;
  84. 84 return *this;
  85. 85 }
  86. 86
  87. 87 bool operator< (const Coord& r)
  88. 88 {
  89. 89 return _x < r._x ? true : _y < r._y;
  90. 90 }
  91. 91
  92. 92 bool operator==(const Coord& r)
  93. 93 {
  94. 94 return _x == r._x && _y == r._y;
  95. 95 }
  96. 96
  97. 97 Axis _x = 0, _y = 0;
  98. 98
  99. 99 //@notice: This value is uarely used.
  100. 100 EElem _e = EElem::ELEM_None;
  101. 101 };
  102. 102
  103. 103
  104. 104 #endif

3. 3x_desk_state.h

  1. 1 /**
  2. 2 * @file 3x_desk_state.h
  3. 3 * @author EvenOyan
  4. 4 * @brief 三消游戏的状态机,
  5. 5 * 一共分为 开始、交换、消除、下落、刷新、结束 6个状态,
  6. 6 * 每个状态都在执行属于自己的事情,
  7. 7 * @notice: 此状态机的实现稍为复杂,
  8. 8 * 使用了大量的模版特化,静态判断,宏替换,
  9. 9 * 在试图更改此代码时,务必注意细节,
  10. 10 *
  11. 11 * @version 0.3
  12. 12 * @date 2021-02
  13. 13 *
  14. 14 * @copyright Copyright (c) 2021
  15. 15 *
  16. 16 */
  17. 17
  18. 18 #pragma once
  19. 19
  20. 20 #ifndef __3X_DESK_STATE_H
  21. 21 #define __3X_DESK_STATE_H
  22. 22
  23. 23 #include "3x_desk.h"
  24. 24
  25. 25 #include "../../stdinc/lc_random.h"
  26. 26 #include "../../stdinc/lc_singleton.h"
  27. 27
  28. 28 #include <functional>
  29. 29 #include <unordered_set>
  30. 30
  31. 31 /////////////////////// Defines ///////////////////////
  32. 32
  33. 33 #define InputFuncBegin(state)\
  34. 34 template<EAction action> \
  35. 35 void __3x_state<state>::Input(Desk* pDesk, const Event<action>& in, const StateEventCallBackT& cb){\
  36. 36 if(pDesk == nullptr) return;
  37. 37
  38. 38 #define UpdateFuncBegin(state)\
  39. 39 template<EAction action> \
  40. 40 void __3x_state<state>::Update(Desk* pDesk, const Event<action>& in, const StateEventCallBackT& cb){\
  41. 41 if(pDesk == nullptr) return;
  42. 42
  43. 43 #define FuncEnd() }
  44. 44
  45. 45 #define __IUpdate(ev)\
  46. 46 Update<stateB>(pDesk, ev, cb)
  47. 47
  48. 48 #define __IGoTo(stateB, ev)\
  49. 49 __3x_state<stateB>::Input<(EAction)_state>(pDesk, ev, cb); \
  50. 50
  51. 51 #define Start_3x_State(pDesk, stateB, ev, fc)\
  52. 52 __3x_state<EAction::ACTION_None>::Input<stateB>(pDesk, ev, fc);
  53. 53
  54. 54 //e.g.: state A->B->C => B.Input(A); C = B.Update();
  55. 55 #define __StateClassDefine(state) \
  56. 56 template<> \
  57. 57 class __3x_state<state> \
  58. 58 : public Singleton<__3x_state<state> > \
  59. 59 { \
  60. 60 public: \
  61. 61 __3x_state(token){} \
  62. 62 \
  63. 63 private: \
  64. 64 enum { _state = state }; \
  65. 65 \
  66. 66 public: \
  67. 67 template<EAction action> /*输入状态*/\
  68. 68 static void Input(Desk* pDesk, const Event<action>& in/*输入参数*/, const StateEventCallBackT& cb);\
  69. 69 template<EAction action> /*输入状态*/\
  70. 70 static void Update(Desk* pDesk, const Event<action>& in/*输入参数*/, const StateEventCallBackT& cb);\
  71. 71 \
  72. 72 };
  73. 73
  74. 74 //used at 'input'
  75. 75 #define __StateAccept(stateA)\
  76. 76 if constexpr(stateA == action) { __3x_state<(EAction)_state>::Update<stateA>(pDesk, in, cb); return; }
  77. 77
  78. 78 /////////////////////// State Graph ///////////////////////
  79. 79 template<EAction E>class __3x_state {};
  80. 80 template<> class __3x_state<EAction::ACTION_None>;
  81. 81 template<> class __3x_state<EAction::ACTION_EXCHANGE>;
  82. 82 template<> class __3x_state<EAction::ACTION_BONUS_BOMB>;
  83. 83 template<> class __3x_state<EAction::ACTION_BONUS>;
  84. 84 template<> class __3x_state<EAction::ACTION_REPLENISH>;
  85. 85 template<> class __3x_state<EAction::ACTION_REFRESH>;
  86. 86 template<> class __3x_state<EAction::ACTION_FINAL>;
  87. 87
  88. 88 __StateClassDefine(EAction::ACTION_EXCHANGE);
  89. 89 __StateClassDefine(EAction::ACTION_BONUS_BOMB);
  90. 90 __StateClassDefine(EAction::ACTION_None);
  91. 91 __StateClassDefine(EAction::ACTION_BONUS);
  92. 92 __StateClassDefine(EAction::ACTION_REPLENISH);
  93. 93 __StateClassDefine(EAction::ACTION_REFRESH);
  94. 94 __StateClassDefine(EAction::ACTION_FINAL);
  95. 95
  96. 96 #include "3x_desk_state.inl"
  97. 97
  98. 98 #endif

4. 3x_desk_state.inl

  1. #include <iostream>
  2. #include <unordered_set>
  3. //////////////////////////////////////////////////////////////////////////////////////////
  4. InputFuncBegin(EAction::ACTION_None)
  5. //开始状态,
  6. __StateAccept(EAction::ACTION_EXCHANGE_INPUT);
  7. __StateAccept(EAction::ACTION_BONUS_BOMB_INPUT);
  8. FuncEnd()
  9.  
  10. UpdateFuncBegin(EAction::ACTION_None)
  11. Event<EAction::ACTION_None> ev;
  12. if(in.GetType() == EAction::ACTION_EXCHANGE_INPUT)
  13. {
  14. std::cout << "exchange input: " << in.GetInfo()._coordA._x << in.GetInfo()._coordA._y << in.GetInfo()._coordB._x << in.GetInfo()._coordB._y<< std::endl;
  15. ev.Info().Init(EAction::ACTION_EXCHANGE, (Action*)&(in.GetInfo()));
  16. __IGoTo(EAction::ACTION_EXCHANGE, ev);
  17. return;
  18. }
  19.  
  20. if(in.GetType() == EAction::ACTION_BONUS_BOMB_INPUT)
  21. {
  22. ev.Info().Init(EAction::ACTION_BONUS_BOMB, (Action*)&(in.GetInfo()));
  23. __IGoTo(EAction::ACTION_BONUS_BOMB, ev);
  24. return;
  25. }
  26.  
  27. FuncEnd()
  28.  
  29. //////////////////////////////////////////////////////////////////////////////////////////
  30. InputFuncBegin(EAction::ACTION_FINAL)
  31. __StateAccept(EAction::ACTION_REFRESH);
  32. FuncEnd()
  33.  
  34. UpdateFuncBegin(EAction::ACTION_FINAL)
  35. Event<EAction::ACTION_FINAL> ev;
  36. cb(EAction::ACTION_FINAL, ev); //响应 final 状态
  37. FuncEnd()
  38.  
  39. //////////////////////////////////////////////////////////////////////////////////////////
  40. InputFuncBegin(EAction::ACTION_EXCHANGE)
  41. std::cout << "exchange input function " << std::endl;
  42. __StateAccept(EAction::ACTION_None);
  43. FuncEnd()
  44.  
  45. UpdateFuncBegin(EAction::ACTION_EXCHANGE)
  46. //仅接受初始状态,在交换过后需要进入‘消除’状态
  47. //在当前状态直接判断是否可以消除,可以简化许多操作
  48. //所以在此,仅当可以消除时,才可以进入下一个状态
  49.  
  50. if(in.GetType() != EAction::ACTION_None)
  51. {
  52. std::cout << "in.GetType() != EAction::ACTION_None " << std::endl;
  53. return;
  54. }
  55.  
  56. const auto& act = in.GetInfo().GetInfo()._exchange;
  57.  
  58. //尝试交换
  59. if(!pDesk->Exchange(act._coordA, act._coordB))
  60. {
  61. std::cout << "!pDesk->Exchange(act._coordA, act._coordB)) " << std::endl;
  62. return;
  63. }
  64.  
  65. if(pDesk->IsInBonus(act._coordA)
  66. || pDesk->IsInBonus(act._coordB) )
  67. {
  68. std::cout << "can bonus." << std::endl;
  69. //只有可消除才会响应交换事件,进入Bonus状态
  70. Event<EAction::ACTION_EXCHANGE> ev;
  71. ev.Info()._coordA = act._coordA;
  72. ev.Info()._coordA._e = pDesk->get<EElem>(act._coordA._x, act._coordA._y);
  73. ev.Info()._coordB = act._coordB;
  74. ev.Info()._coordB._e = pDesk->get<EElem>(act._coordB._x, act._coordB._y);
  75. cb(EAction::ACTION_EXCHANGE, ev);
  76. __IGoTo(EAction::ACTION_BONUS, ev);
  77. return ;
  78. }
  79. else
  80. {
  81. //发现交换过后并不能消除,还原
  82. std::cout << "can not bonus." << std::endl;
  83. pDesk->Exchange(act._coordA, act._coordB);
  84. return ;
  85. }
  86. return ;
  87.  
  88. FuncEnd()
  89.  
  90. //////////////////////////////////////////////////////////////////////////////////////////
  91. InputFuncBegin(EAction::ACTION_BONUS)
  92. if(in.GetType() != action)
  93. return;
  94. //接受‘交换’和‘充满’两个状态,
  95. __StateAccept(EAction::ACTION_EXCHANGE);
  96. __StateAccept(EAction::ACTION_REPLENISH);
  97. FuncEnd()
  98.  
  99. UpdateFuncBegin(EAction::ACTION_BONUS)
  100. //1. Check the 'Event& in',
  101. // 1.1 If the action is 'ACTION_EXCHANGE', check bonus is can do or not.
  102. // 1.1.1 If not, reduce reversive, return FALSE(-1).
  103. // 1.1.2 If can do, do bonus.
  104. // 1.2 If the action is 'NoneAction', SPECIAL-SKILLs perhaps...[?]
  105.  
  106. //2. Do bonus,
  107. // 2.1 If bonus is happend, return 1, or return 2.
  108. std::vector<Coord> changes;
  109. const auto& act = in.GetInfo();
  110. //上个阶段是“交换”
  111. if constexpr(action == EAction::ACTION_EXCHANGE)
  112. {
  113. changes.push_back(act._coordA);
  114. changes.push_back(act._coordB);
  115. }
  116. //上一个阶段是“补充”,需要计算补充而来的新元素是否可以消除
  117. else if(action == EAction::ACTION_REPLENISH)
  118. {
  119. changes = act._changed;
  120. }
  121.  
  122. bool isBonus = false; //消除事件是否发生
  123. std::vector<Coord> cleared; //如果消除事件发生,被消除的坐标
  124. std::vector<Coord> bonusUnit;
  125. std::unordered_set<int> signTotal; //
  126.  
  127. for (const auto& coord : changes)
  128. {
  129. if(signTotal.find(pDesk->CoordToNum(coord)) != signTotal.end())
  130. continue;
  131.  
  132. std::unordered_set<int> sign;
  133.  
  134. int bonusType = EBonusType::BONUS_None;
  135. std::vector<Coord> bonus; //There are coord with elem-type. It's chche.
  136. int count = 0, maxCountLine = 0;
  137. bonusType |= (int)(pDesk->Bonus(coord, bonus, count));
  138. maxCountLine = std::max(maxCountLine, count);
  139.  
  140. if(bonusType == EBonusType::BONUS_None)
  141. continue;
  142.  
  143. std::vector<int> stack;
  144. //to stack
  145. for(const Coord& b : bonus)
  146. stack.push_back(pDesk->CoordToNum(b));
  147.  
  148. bonus.clear();
  149.  
  150. while(!stack.empty())
  151. {
  152. int num = stack.back();
  153. stack.pop_back();
  154. if(sign.find(num) != sign.end())
  155. continue;
  156.  
  157. sign.insert(num);
  158.  
  159. Coord next = pDesk->NumToCoord(num);
  160. bonusUnit.push_back(next);
  161.  
  162. bonusType |= pDesk->Bonus(next, bonus, count);
  163. maxCountLine = std::max(maxCountLine, count);
  164.  
  165. for(const Coord& b : bonus)
  166. stack.push_back(pDesk->CoordToNum(b));
  167. }
  168.  
  169. if(bonusType != EBonusType::BONUS_None)
  170. {
  171. isBonus = true;
  172.  
  173. Event<EAction::ACTION_BONUS> cbEvent;
  174. cbEvent.Info()._bonus = (EBonusType)bonusType;
  175. cbEvent.Info()._cleared = bonusUnit;
  176. cbEvent.Info()._count = maxCountLine;
  177. cb(EAction::ACTION_BONUS, cbEvent); //事件响应:每一个单元的消除都会执行一次事件响应,与次数无关
  178.  
  179. for (const auto& bu : bonusUnit)
  180. signTotal.insert(pDesk->CoordToNum(bu));
  181. }
  182.  
  183. cleared.insert(cleared.end(), bonusUnit.begin(), bonusUnit.end());
  184. bonusUnit.clear();
  185.  
  186. ///////////////////////////////////////////////////////////
  187. // //bonus happen.
  188. // std::vector<Coord> bonus; //There are coord with elem-type.
  189. // int count = 0;
  190. // //尝试消除,不真正更改棋盘
  191. // //返回值 bonus 携带元素类型,
  192. // EBonusType t = pDesk->Bonus(coord, bonus, count);
  193. // if(bonus.empty())
  194. // continue; //It's have no bonus.
  195.  
  196. // {
  197. // //in cache
  198. // for(const auto& c : bonus)
  199. // cache[pDesk->CoordToNum(c)] = c;
  200. // }
  201.  
  202. // isBonus = true;
  203.  
  204. // Event<EAction::ACTION_BONUS> cbEvent;
  205. // cbEvent.Info()._bonus = t;
  206. // cbEvent.Info()._cleared = bonus;
  207. // cbEvent.Info()._count = count;
  208. // cb(EAction::ACTION_BONUS, cbEvent); //事件响应:每一个单元的消除都会执行一次事件响应,与次数无关
  209. }
  210.  
  211. Event<EAction::ACTION_BONUS> ev;
  212. if(isBonus)
  213. {
  214. //set block.
  215. for (auto&& each : cleared)
  216. pDesk->get<EElem>(each._x, each._y) = EElem::ELEM_None;
  217.  
  218. //Next state is 'ACTION_REPLENISH'.
  219. ev.Info()._cleared = cleared;
  220. __IGoTo(EAction::ACTION_REPLENISH, ev);
  221.  
  222. //////////////////////test
  223. for (size_t i = 0; i < pDesk->_height; i++)
  224. {
  225. for (size_t j = 0; j < pDesk->_width; j++)
  226. {
  227. std::cout << (int)(pDesk->get<EElem>(j, i)) << " ";
  228. }
  229. std::cout << std::endl;
  230. }
  231. std::cout << std::endl;
  232. //////////////////////
  233.  
  234. return; // 已经成功执行了消除操作,进入‘充满’状态;
  235. }
  236. else
  237. {
  238. //Next state is 'ACTION_REFRESH'.
  239. __IGoTo(EAction::ACTION_REFRESH, ev);
  240. return; // 没有发生消除事件,进入‘判断重排’状态;
  241. }
  242.  
  243. return; //发生未知错误,状态机停止此刻,不阻塞,不更新
  244.  
  245. FuncEnd()
  246.  
  247. //////////////////////////////////////////////////////////////////////////////////////////
  248. InputFuncBegin(EAction::ACTION_REPLENISH)
  249. //仅接受‘bonus’状态,更新本状态后,再次进入‘bonus’状态,
  250. //开始进入好运连续消除的状态循环
  251. __StateAccept(EAction::ACTION_BONUS);
  252. __StateAccept(EAction::ACTION_BONUS_BOMB);
  253. FuncEnd()
  254.  
  255. UpdateFuncBegin(EAction::ACTION_REPLENISH)
  256. const auto& act = in.GetInfo();
  257.  
  258. std::set<Axis> xs;
  259. std::unordered_map<Axis, Axis> changed; //x:y
  260.  
  261. for (const auto& each : act._cleared)
  262. {
  263. xs.insert(each._x);
  264.  
  265. //changed
  266. //only insert y-max for each x.
  267. auto it = changed.find(each._x);
  268. if(it == changed.end() || it->second < each._y)
  269. changed[each._x] = each._y;
  270. }
  271.  
  272. Event<EAction::ACTION_REPLENISH> ev;
  273. for(const auto[x, y] : changed)
  274. {
  275. for(Axis i = y; i >= 0; --i)
  276. {
  277. ev.Info()._changed.emplace_back(x, i);
  278. }
  279. }
  280.  
  281. std::vector<Coord> newCoords;
  282. for (Axis x : xs)
  283. {
  284. std::vector<EElem>& eachX = pDesk->getcolume<EElem>(x);
  285. int blockCnt = 0,
  286. lastBlock = -1; //b
  287. for (Axis i = eachX.size() - 1; i >= 0; --i) //i
  288. {
  289. if(eachX[i] == EElem::ELEM_None)
  290. {
  291. blockCnt++;
  292.  
  293. /**
  294. * -------1. find 'b', it's block
  295. * x
  296. * o
  297. * x
  298. * x <- b
  299. * o
  300. * -------
  301. */
  302. if(lastBlock == -1)
  303. lastBlock = i;
  304. continue;
  305. }
  306.  
  307. /**
  308. * -------2. find 'i', it's not block.
  309. * x
  310. * o <- i
  311. * x
  312. * x <- b
  313. * o
  314. * -------
  315. */
  316. if(lastBlock > -1 && eachX[i] != EElem::ELEM_None)
  317. {
  318. /**
  319. * -------3. swap
  320. * x
  321. * x <- i
  322. * x
  323. * o <- b
  324. * o
  325. * -------
  326. */
  327. std::swap(eachX[lastBlock], eachX[i]);
  328.  
  329. /**
  330. * -------4. reset 'b'
  331. * x
  332. * x <- i
  333. * x <- b
  334. * o
  335. * o
  336. * -------
  337. */
  338. lastBlock--;
  339. continue;
  340. }
  341. }
  342.  
  343. for (size_t i = 0; i < blockCnt; i++)
  344. newCoords.emplace_back(x, i, pDesk->GetRandomElem());
  345. }
  346.  
  347. for(auto&& neweach : newCoords)
  348. {
  349. pDesk->set<EElem>(neweach._x, neweach._y, neweach._e);
  350. }
  351.  
  352. ev.Info()._news = newCoords;
  353. cb(EAction::ACTION_REPLENISH, ev);
  354. __IGoTo(EAction::ACTION_BONUS, ev);
  355.  
  356. FuncEnd()
  357.  
  358. //////////////////////////////////////////////////////////////////////////////////////////
  359. InputFuncBegin(EAction::ACTION_REFRESH)
  360. //仅接受‘bonus’状态,
  361. //在‘bonus’状态没有成功时,输入此状态,
  362. //更新之后,进入‘结束’状态
  363. //所以,务必保证此状态更新之后,不会导致存在可消除的情况
  364. __StateAccept(EAction::ACTION_BONUS);
  365. FuncEnd()
  366.  
  367. UpdateFuncBegin(EAction::ACTION_REFRESH)
  368. Event<EAction::ACTION_REFRESH> ev;
  369. if(!pDesk->IsDead())
  370. {
  371. __IGoTo(EAction::ACTION_FINAL, ev);
  372. return;
  373. }
  374.  
  375. std::vector<Coord> recordA, becomeB;
  376. pDesk->Refresh(recordA, becomeB);
  377. ev.Info()._src = recordA;
  378. ev.Info()._become = becomeB;
  379. cb(EAction::ACTION_REFRESH, ev);
  380. __IGoTo(EAction::ACTION_FINAL, ev);
  381. FuncEnd()
  382.  
  383. //////////////////////////////////////////////////////////////////////////////////////////
  384.  
  385. //特殊消除,具体需求为:
  386. // 消除 N 个某种颜色的元素
  387. InputFuncBegin(EAction::ACTION_BONUS_BOMB)
  388. //存在执行消除事件的情况,进入‘充满’状态
  389. //特殊情况:棋盘中不存在所谓的“某种颜色”,消除未被执行
  390. __StateAccept(EAction::ACTION_None);
  391. FuncEnd()
  392.  
  393. UpdateFuncBegin(EAction::ACTION_BONUS_BOMB)
  394. if(in.GetType() != EAction::ACTION_BONUS_BOMB)
  395. return;
  396.  
  397. const auto& act = in.GetInfo();
  398.  
  399. const Coord& coord = act.GetInfo()._select._coord;
  400. EElem e = pDesk->get<EElem>(coord._x, coord._y);
  401. if(e == EElem::ELEM_None)
  402. return; //error
  403.  
  404. int i = 0;
  405. std::vector<Coord> bonus;
  406. pDesk->foreach<EElem>([&](Axis x, Axis y, const EElem& each) -> bool
  407. {
  408. if(each != e)
  409. return true;
  410.  
  411. pDesk->get<EElem>(x, y) = EElem::ELEM_None;
  412. ++i;
  413. bonus.emplace_back(x, y, each);
  414. return true;
  415. });
  416.  
  417. Event<EAction::ACTION_BONUS_BOMB> ev;
  418. if(i == 0)
  419. {
  420. cb(EAction::ACTION_BONUS_BOMB, ev);
  421. __IGoTo(EAction::ACTION_REFRESH, ev);
  422. return;
  423. }
  424.  
  425. ev.Info()._bonus = EBonusType::BONUS_BOMB_BY_SELECT;
  426. ev.Info()._cleared = bonus;
  427. ev.Info()._count = i;
  428.  
  429. cb(EAction::ACTION_BONUS_BOMB, ev);
  430. __IGoTo(EAction::ACTION_REPLENISH, ev);
  431.  
  432. FuncEnd()

5.  3x_desk.h

  1. 1 #pragma once
  2. 2
  3. 3 #ifndef __LC_3X_DESK_H_
  4. 4 #define __LC_3X_DESK_H_
  5. 5
  6. 6 #include <array>
  7. 7 #include <vector>
  8. 8 #include <functional>
  9. 9 #include <unordered_map>
  10. 10 #include <set>
  11. 11 #include "lc_random.h"
  12. 12 #include <bitset>
  13. 13 #include "../__lc_component.h"
  14. 14 #include "3x_desk_event.h"
  15. 15
  16. 16
  17. 17 class Desk
  18. 18 {
  19. 19 public:
  20. 20 struct ElemWeight
  21. 21 {
  22. 22 EElem _ele;
  23. 23 int _weight = 0;
  24. 24 };
  25. 25
  26. 26 struct TryBonusInfo
  27. 27 {
  28. 28 int _count = 0;
  29. 29 EElem _elem = EElem::ELEM_None;
  30. 30 std::vector<Coord> _bouns;
  31. 31 Coord _coordA;
  32. 32 Coord _coordB;
  33. 33 };
  34. 34
  35. 35 public:
  36. 36 Desk() = delete;
  37. 37 Desk(Axis w, Axis h);
  38. 38
  39. 39 ~Desk(){}
  40. 40
  41. 41 template<typename T, typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type* = nullptr >
  42. 42 void foreach(std::function<bool(Axis x, Axis y, T& e)> && cb);
  43. 43
  44. 44 template<typename T, typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type* = nullptr >
  45. 45 void foreach(std::function<bool(Axis x, Axis y, const T& e)> && cb) const;
  46. 46
  47. 47 template<typename T, typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type* = nullptr >
  48. 48 T& get(Axis x, Axis y);
  49. 49
  50. 50 template<typename T, typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type* = nullptr >
  51. 51 T get(Axis x, Axis y) const;
  52. 52
  53. 53 template<typename T, typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type* = nullptr >
  54. 54 bool set(Axis x, Axis y, T e);
  55. 55
  56. 56 template<typename T, typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type* = nullptr >
  57. 57 std::vector<T>& getcolume(Axis x);
  58. 58
  59. 59 inline bool IsValidCoord(Axis x, Axis y) const noexcept;
  60. 60 bool IsFreeCoord(Axis x, Axis y) const;
  61. 61
  62. 62 bool IsNeighbour(const Coord& coordA, const Coord& coordB) const;
  63. 63
  64. 64 inline int CoordToNum(const Coord& coordA) const noexcept { return coordA._y * _width + coordA._x; }
  65. 65 inline Coord NumToCoord(int num) const noexcept {Axis x = num % _width; Axis y = num / _width; return { x, y, get<EElem>(x, y) }; };
  66. 66
  67. 67 public:
  68. 68 void Init(const std::vector<ElemWeight>& weight);
  69. 69 bool IsDead() const;
  70. 70
  71. 71 //This function is a blur check.
  72. 72 //If it returns true then bonus must be available,
  73. 73 //and not necessarily if it returns false.
  74. 74 bool IsCanBonus(const Coord& coord, bool isAccurate = false) const; //@CHECK-RES:1
  75. 75
  76. 76 bool IsInBonus(const Coord& coord) const; //@CHECK-RES:1
  77. 77 inline bool IsElemEqual(Axis x, Axis y, EElem e) const noexcept; //@CHECK-RES:1
  78. 78
  79. 79 public:
  80. 80 bool IsCanExchange(const Coord& coordA, const Coord& coordB, bool isForce = false) const;
  81. 81 void DoExchange(const Coord& coordA, const Coord& coordB, const StateEventCallBackT& cb, bool isForce = false);
  82. 82
  83. 83 //则仅仅尝试计算,不真正执行消除而导致的更改棋盘。
  84. 84 EBonusType Bonus(const Coord& coordA, std::vector<Coord>& out, int& maxCountLine) const;
  85. 85
  86. 86 int FindBonus(std::vector<TryBonusInfo>& out, bool isBest = false);
  87. 87
  88. 88 EElem GetRandomElem() const;
  89. 89
  90. 90 //@return Is function 'ResetDesk' called?
  91. 91 bool Refresh(std::vector<Coord>& recordA, std::vector<Coord>& becomeB, int times = 0);
  92. 92 bool Exchange(const Coord& coordA, const Coord& coordB, bool isForce = false); //@CHECK-RES:1
  93. 93
  94. 94 //private:
  95. 95 void ResetWeight(const std::vector<ElemWeight>& weight);
  96. 96 void ResetDesk(); //@CHECK-RES:01
  97. 97
  98. 98 template<AxisType AT>
  99. 99 std::bitset<5> BonusSign(const Coord & coord) const; //@CHECK-RES:01
  100. 100
  101. 101 bool IsBonusBySign(const std::bitset<5>& sign) const; //@CHECK-RES:1
  102. 102
  103. 103 template<AxisType AT>
  104. 104 std::bitset<5> TestSign(Coord&& coord) const; //@CHECK-RES:1
  105. 105
  106. 106 bool FindNeverBonusCoordWith(EElem e, Coord& out, uint64_t startWith = 0) const;
  107. 107 void TestNonBonusWith(Coord coord, std::set<EElem>& out) const;
  108. 108
  109. 109 public:
  110. 110
  111. 111
  112. 112 //private:
  113. 113 Axis _width = 0;
  114. 114 Axis _height = 0;
  115. 115
  116. 116 std::vector< //w
  117. 117 std::vector<EElem> //h
  118. 118 > _eles;
  119. 119
  120. 120 std::vector<
  121. 121 std::vector<EDeck>
  122. 122 > _decks;
  123. 123
  124. 124 //std::unordered_map<EElem, int> _pool;
  125. 125 RandomItem<ElemWeight> _randPool;
  126. 126 };
  127. 127
  128. 128 #include "3x_desk.inl"
  129. 129
  130. 130 #endif

6. 3x_desk.cpp

  1. 1 #include "3x_desk.h"
  2. 2 #include "3x_desk_state.h"
  3. 3 #include "inc.h"
  4. 4 #include "lc_logmgr.h"
  5. 5 #include "custom/CFG_CTM_Elem.h"
  6. 6 #include <algorithm>
  7. 7
  8. 8 Desk::Desk(Axis w, Axis h)
  9. 9 : _width(w)
  10. 10 , _height(h)
  11. 11 {
  12. 12 if(w < 5 || h < 5)
  13. 13 {
  14. 14 LogPrint("ERROR", "The Desk height or width too less. W: ", w, "; H: ", h);
  15. 15 return;
  16. 16 }
  17. 17
  18. 18 _eles.resize(w);
  19. 19 for (auto& eachW : _eles)
  20. 20 {
  21. 21 eachW.resize(h);
  22. 22 for(EElem& eachH : eachW)
  23. 23 eachH = EElem::ELEM_None;
  24. 24 }
  25. 25
  26. 26 _decks.resize(w);
  27. 27 for (auto& eachW : _decks)
  28. 28 {
  29. 29 eachW.resize(h);
  30. 30 for(EDeck& eachH : eachW)
  31. 31 eachH = EDeck::DECK_BLOCK;
  32. 32 }
  33. 33
  34. 34 std::vector<ElemWeight> pool;
  35. 35 const int defaultW = 2310;
  36. 36 for (uint8_t i = (uint8_t)EElem::ELEM_None + 1; i <= (uint8_t)EElem::ELEM_None + CFG_ELEM.Size(); i++)
  37. 37 {
  38. 38 EElem e = EElem(i);
  39. 39 pool.push_back({e, defaultW});
  40. 40 }
  41. 41
  42. 42 Init(pool);
  43. 43 }
  44. 44
  45. 45 void Desk::ResetWeight(const std::vector<ElemWeight>& weight)
  46. 46 {
  47. 47 _randPool.Init(weight, [](const ElemWeight& item)->int{ return item._weight; });
  48. 48 }
  49. 49
  50. 50 bool Desk::IsFreeCoord(Axis x, Axis y) const
  51. 51 {
  52. 52 if(!IsValidCoord(x, y))
  53. 53 return false;
  54. 54
  55. 55 EDeck deck = get<EDeck>(x, y);
  56. 56 return !(deck == EDeck::DECK_WALL || deck == EDeck::DECK_FREEZE);
  57. 57 }
  58. 58
  59. 59 bool Desk::IsNeighbour(const Coord& coordA, const Coord& coordB) const
  60. 60 {
  61. 61 if(!(IsValidCoord(coordA._x, coordA._y)
  62. 62 && IsValidCoord(coordB._x, coordB._y))
  63. 63 ) return false;
  64. 64
  65. 65 return
  66. 66 (coordA._x == coordB._x && std::abs(coordA._y - coordB._y) == 1)
  67. 67 || (coordA._y == coordB._y && std::abs(coordA._x - coordB._x) == 1) ;
  68. 68 }
  69. 69
  70. 70 bool Desk::IsInBonus(const Coord& coord) const
  71. 71 {
  72. 72 if(!IsValidCoord(coord._x, coord._y))
  73. 73 return false;
  74. 74
  75. 75 return IsBonusBySign(BonusSign<AxisType::AxisX>(coord))
  76. 76 || IsBonusBySign(BonusSign<AxisType::AxisY>(coord));
  77. 77 }
  78. 78
  79. 79 bool Desk::IsBonusBySign(const std::bitset<5>& sign) const
  80. 80 {
  81. 81 if(!sign[2])
  82. 82 return false;
  83. 83
  84. 84 return (sign[0] && sign[1])
  85. 85 ||(sign[3] && sign[4])
  86. 86 || (sign[1] && sign[3]);
  87. 87 }
  88. 88
  89. 89 bool Desk::IsDead() const
  90. 90 {
  91. 91 bool ret = true;
  92. 92 foreach<EElem>([this, &ret](Axis x, Axis y, const EElem& e) -> bool
  93. 93 {
  94. 94 if(e == EElem::ELEM_None)
  95. 95 return true;
  96. 96
  97. 97 if(IsInBonus({x, y}) || IsCanBonus({x, y}))
  98. 98 {
  99. 99 ret = false;
  100. 100 return false;
  101. 101 }
  102. 102 return true;
  103. 103 });
  104. 104
  105. 105 return ret;
  106. 106 }
  107. 107
  108. 108 inline bool Desk::IsElemEqual(Axis x, Axis y, EElem e) const noexcept
  109. 109 {
  110. 110 return IsValidCoord(x, y)
  111. 111 && (e != EElem::ELEM_None)
  112. 112 && (get<EElem>(x, y) == e)
  113. 113 ;
  114. 114 }
  115. 115
  116. 116 bool Desk::IsCanBonus(const Coord& coord, bool isAccurate) const
  117. 117 {
  118. 118 bool isCan = false;
  119. 119 const EElem e = get<EElem>(coord._x, coord._y);
  120. 120
  121. 121 {
  122. 122 /**
  123. 123 * 3.
  124. 124 * X P X
  125. 125 * P X P
  126. 126 * X C X
  127. 127 * X C X
  128. 128 * P X P
  129. 129 * X P X
  130. 130 */
  131. 131
  132. 132 for (Axis i = coord._y - 1; i < coord._y + 1; i++)
  133. 133 {
  134. 134 if(i == coord._y)
  135. 135 continue;
  136. 136
  137. 137 if(!IsElemEqual(coord._x, i, e))
  138. 138 continue;
  139. 139
  140. 140 Axis x1, x2, x3
  141. 141 , y1, y2, y3, y4;
  142. 142 x1 = coord._x - 1;
  143. 143 x2 = coord._x + 1;
  144. 144 x3 = coord._x;
  145. 145
  146. 146 Axis ymin = std::min(coord._y, i);
  147. 147 Axis ymax = std::max(coord._y, i);
  148. 148
  149. 149 y1 = ymin - 1;
  150. 150 y2 = ymax + 1;
  151. 151 y3 = ymin - 2;
  152. 152 y4 = ymax + 2;
  153. 153
  154. 154 isCan = IsElemEqual(x1, y1, e)
  155. 155 || IsElemEqual(x1, y2, e)
  156. 156 || IsElemEqual(x2, y1, e)
  157. 157 || IsElemEqual(x2, y2, e)
  158. 158 || IsElemEqual(x3, y3, e)
  159. 159 || IsElemEqual(x3, y4, e);
  160. 160 }
  161. 161
  162. 162 if(isCan)
  163. 163 return true;
  164. 164 }
  165. 165
  166. 166 {
  167. 167 /**
  168. 168 * 2.
  169. 169 * X P X X P X
  170. 170 * P X C C X P
  171. 171 * X P X X P X
  172. 172 */
  173. 173
  174. 174 for (Axis i = coord._x - 1; i < coord._x + 1; i++)
  175. 175 {
  176. 176 if(i == coord._x)
  177. 177 continue;
  178. 178
  179. 179 if(!IsElemEqual(i, coord._y, e))
  180. 180 continue;
  181. 181
  182. 182 Axis x1, x2, x3, x4
  183. 183 , y1, y2, y3;
  184. 184 Axis xmin = std::min(i, coord._x);
  185. 185 Axis xmax = std::max(i, coord._x);
  186. 186
  187. 187 x1 = xmin - 1;
  188. 188 x2 = xmax + 1;
  189. 189 x3 = xmin - 2;
  190. 190 x4 = xmax + 2;
  191. 191
  192. 192 y1 = coord._y - 1;
  193. 193 y2 = coord._y + 1;
  194. 194 y3 = coord._y;
  195. 195
  196. 196 isCan = IsElemEqual(x1, y1, e)
  197. 197 || IsElemEqual(x1, y2, e)
  198. 198 || IsElemEqual(x2, y1, e)
  199. 199 || IsElemEqual(x2, y2, e)
  200. 200 || IsElemEqual(x3, y3, e)
  201. 201 || IsElemEqual(x4, y3, e);
  202. 202 }
  203. 203
  204. 204 if(isCan)
  205. 205 return true;
  206. 206 }
  207. 207
  208. 208 {
  209. 209 /**
  210. 210 * 1.
  211. 211 * P X P
  212. 212 * X C X
  213. 213 * P X P
  214. 214 */
  215. 215
  216. 216 static const Coord edge[2] = {{-1, -1}, {1, 1}};
  217. 217 for (size_t i = 0; i < 2; i++)
  218. 218 {
  219. 219 const Coord& edgei = edge[i];
  220. 220 Coord cur(edgei._x + coord._x, edgei._y + coord._y);
  221. 221 if(!IsElemEqual(cur._x, cur._y, e))
  222. 222 continue;
  223. 223
  224. 224 else //found one.
  225. 225 {
  226. 226 //check x
  227. 227 cur._x = cur._x + -2 * edgei._x;
  228. 228 if(!IsElemEqual(cur._x, cur._y, e))
  229. 229 {
  230. 230 //check y
  231. 231 cur._y = cur._y + -2 * edgei._y;
  232. 232
  233. 233 //finding two.
  234. 234 isCan = IsElemEqual(cur._x, cur._y, e);
  235. 235 }
  236. 236 else
  237. 237 isCan = true;
  238. 238
  239. 239
  240. 240 }
  241. 241 }
  242. 242
  243. 243 if(isCan)
  244. 244 return true;
  245. 245 }
  246. 246
  247. 247 if(!isAccurate)
  248. 248 return false;
  249. 249
  250. 250 {
  251. 251 /**
  252. 252 * 4.
  253. 253 * P P X P P
  254. 254 * X X C X X
  255. 255 * P P X P P
  256. 256 */
  257. 257
  258. 258 //check line
  259. 259 std::bitset<5> signs[4] =
  260. 260 {
  261. 261 TestSign<AxisType::AxisX>({coord._x, coord._y - 1, e}),
  262. 262 TestSign<AxisType::AxisX>({coord._x, coord._y + 1, e}),
  263. 263 TestSign<AxisType::AxisY>({coord._x - 1, coord._y, e}),
  264. 264 TestSign<AxisType::AxisY>({coord._x + 1, coord._y, e})
  265. 265 };
  266. 266 for (size_t i = 0; i < 4; i++)
  267. 267 {
  268. 268 if(IsBonusBySign(signs[i]))
  269. 269 return true;
  270. 270 }
  271. 271
  272. 272 }
  273. 273
  274. 274 return false;
  275. 275 }
  276. 276
  277. 277 EElem Desk::GetRandomElem() const
  278. 278 {
  279. 279 auto* pItem = _randPool.Get();
  280. 280 if(pItem == nullptr)
  281. 281 return EElem::ELEM_None;
  282. 282 return pItem->_ele;
  283. 283 }
  284. 284
  285. 285 bool Desk::Refresh(std::vector<Coord>& recordA, std::vector<Coord>& becomeB, int times)
  286. 286 {
  287. 287 if(times >= 10)
  288. 288 {
  289. 289 ResetDesk();
  290. 290 return true;
  291. 291 }
  292. 292
  293. 293 const uint32_t total = _width * _height;
  294. 294 recordA.reserve(total);
  295. 295 becomeB.reserve(total);
  296. 296 for (size_t i = 0; i < total - 2; i++)
  297. 297 {
  298. 298 Axis x1 = i % _width;
  299. 299 Axis y1 = i / _width;
  300. 300
  301. 301 std::set<EElem> nonBonus;
  302. 302 TestNonBonusWith(Coord(x1, y1), nonBonus);
  303. 303 if(nonBonus.empty())
  304. 304 return Refresh(recordA, becomeB, times + 1);
  305. 305
  306. 306 bool isFound = false;
  307. 307 for(EElem nonEle : nonBonus)
  308. 308 {
  309. 309 Coord found;
  310. 310 if(!FindNeverBonusCoordWith(nonEle, found, i + 1))
  311. 311 continue;
  312. 312
  313. 313 isFound = true;
  314. 314 std::swap(_eles[x1][y1], _eles[found._x][found._y]);
  315. 315 recordA.push_back({x1, y1});
  316. 316 becomeB.push_back(found);
  317. 317 break;
  318. 318 }
  319. 319
  320. 320 if(!isFound)
  321. 321 return Refresh(recordA, becomeB, times + 1);
  322. 322 }
  323. 323
  324. 324 if(IsDead())
  325. 325 return Refresh(recordA, becomeB, times + 1);
  326. 326
  327. 327 return false;
  328. 328 }
  329. 329
  330. 330 //寻找一个坐标 out,这个坐标若是被设置成 e, 则不会被成为 InBonus.
  331. 331 //@return Is found.
  332. 332 bool Desk::FindNeverBonusCoordWith(EElem e, Coord& out, uint64_t startWith) const
  333. 333 {
  334. 334 const uint32_t total = _width * _height;
  335. 335 if(startWith >= total)
  336. 336 startWith = 0;
  337. 337
  338. 338 bool ret = false;
  339. 339 uint64_t r = RandomAvg::Instance().Get(startWith, total);
  340. 340 loop_start_by(startWith, total, r, [&](int64_t i)
  341. 341 {
  342. 342 Axis x1 = i % _width;
  343. 343 Axis y1 = i / _width;
  344. 344
  345. 345 auto sign1x = TestSign<AxisType::AxisX>({x1, y1, e});
  346. 346 if(IsBonusBySign(sign1x))
  347. 347 return true;
  348. 348
  349. 349 auto sign1y = TestSign<AxisType::AxisY>({x1, y1, e});
  350. 350 if(IsBonusBySign(sign1y))
  351. 351 return true;
  352. 352
  353. 353 out(x1, y1);
  354. 354 ret = true;
  355. 355 return false;
  356. 356 });
  357. 357
  358. 358 return ret;
  359. 359 }
  360. 360
  361. 361 //判断 coord 位置的元素,接受哪些元素类型(out)才不会成为 InBonus。
  362. 362 void Desk::TestNonBonusWith(Coord coord, std::set<EElem>& out) const
  363. 363 {
  364. 364 if(!IsValidCoord(coord._x, coord._y))
  365. 365 return;
  366. 366
  367. 367 for(uint8_t i = (uint8_t)EElem::ELEM_None + 1; i <= (uint8_t)EElem::ELEM_None + CFG_ELEM.Size(); ++i)
  368. 368 {
  369. 369 EElem e = (EElem)i;
  370. 370 auto sign1x = TestSign<AxisType::AxisX>({coord._x, coord._y, e});
  371. 371 if(IsBonusBySign(sign1x))
  372. 372 continue;
  373. 373
  374. 374 auto sign1y = TestSign<AxisType::AxisY>({coord._x, coord._y, e});
  375. 375 if(IsBonusBySign(sign1y))
  376. 376 continue;
  377. 377
  378. 378 out.insert(e);
  379. 379 }
  380. 380 }
  381. 381
  382. 382 void Desk::ResetDesk()
  383. 383 {
  384. 384 const uint32_t total = _width * _height;
  385. 385 std::vector<bool> symbol; //标识
  386. 386 symbol.resize(total, false);
  387. 387
  388. 388 //为了保证生成的棋盘不是一个死局,
  389. 389 //那么就在它还是一个空棋盘的时候,在随机位置 r 设置一个可以消除的情况,
  390. 390 //并将标识设置为 true
  391. 391 {
  392. 392 uint64_t r = RandomAvg::Instance().Get(0, total);
  393. 393 Axis x2 = r % _width;
  394. 394 Axis y2 = r / _width;
  395. 395
  396. 396 //为了后面的处理简单,则保证随机的位置 r 不在棋盘的边缘
  397. 397 //至少空余 2 个位置
  398. 398 x2 = x2 % ((_width - 2) - 2) + 2;
  399. 399 y2 = y2 % ((_height - 2) - 2) + 2;
  400. 400
  401. 401 //随机一个种类的元素
  402. 402 uint64_t rElem = _randPool.Get()->_ele;
  403. 403 _eles[x2][y2] = (EElem)rElem;
  404. 404 _eles[x2][y2 - 1] = (EElem)rElem;
  405. 405 _eles[x2 + 1][y2 + 1] = (EElem)rElem;
  406. 406 symbol[y2 * _width + x2] = true;
  407. 407 symbol[(y2 - 1) * _width + x2] = true;
  408. 408 symbol[(y2 + 1) * _width + (x2 + 1)] = true;
  409. 409 }
  410. 410
  411. 411 //开始初始化棋盘
  412. 412 for (uint32_t i = 0; i < total; i++)
  413. 413 {
  414. 414 const Axis x1 = i % _width;
  415. 415 const Axis y1 = i / _width;
  416. 416
  417. 417 if(symbol[i])
  418. 418 continue;
  419. 419
  420. 420 bool isSet = false;
  421. 421 //随机每个格子
  422. 422 uint64_t r = _randPool.Get()->_ele;
  423. 423 //此循环的意义在于,若是随机的元素 r 被设置后,导致了存在可消除的情况,
  424. 424 //那么则采用其他元素类型 [[unlikely]]
  425. 425 loop_start_by((int64_t)EElem::ELEM_None + 1, (int64_t)EElem::ELEM_None + CFG_ELEM.Size() + 1, r, [&](int64_t ie) -> bool
  426. 426 {
  427. 427 EElem e = (EElem)ie;
  428. 428
  429. 429 //测试位置(x1, y1)若是被设置了元素 e,
  430. 430 auto sign1x = TestSign<AxisType::AxisX>({x1, y1, e});
  431. 431 //是否可以消除,
  432. 432 if(IsBonusBySign(sign1x))
  433. 433 return true; //如果可消除,则 continue.
  434. 434
  435. 435 auto sign1y = TestSign<AxisType::AxisY>({x1, y1, e});
  436. 436 if(IsBonusBySign(sign1y))
  437. 437 return true;
  438. 438
  439. 439 _eles[x1][y1] = e;
  440. 440 symbol[i] = true;
  441. 441 isSet = true;
  442. 442
  443. 443 return false;
  444. 444 });
  445. 445
  446. 446 //如果所有元素的测试均未通过,则重新初始化棋盘,
  447. 447 //在棋盘大小以及元素种类个数设置合理的情况下,这种情况几乎不可能发生
  448. 448 //在 8x8 的棋盘,并最多存在6种不同元素情况下,经过 3x50W 次测试,没有命中
  449. 449 if(!isSet)
  450. 450 {
  451. 451 ResetDesk();
  452. 452 break;
  453. 453 }
  454. 454
  455. 455 }
  456. 456
  457. 457 }
  458. 458
  459. 459 bool Desk::IsCanExchange(const Coord& coordA, const Coord& coordB, bool isForce) const
  460. 460 {
  461. 461 if(IsElemEqual(coordA._x, coordA._y, get<EElem>(coordB._x, coordB._y)))
  462. 462 {
  463. 463 return false;
  464. 464 }
  465. 465
  466. 466 if(!isForce && !IsNeighbour(coordA, coordB))
  467. 467 {
  468. 468 return false;
  469. 469 }
  470. 470
  471. 471 if(isForce && IsValidCoord(coordA._x, coordA._y) && IsValidCoord(coordB._x, coordB._y))
  472. 472 {
  473. 473 return false;
  474. 474 }
  475. 475
  476. 476 if(!(IsFreeCoord(coordA._x, coordA._y) && IsFreeCoord(coordB._x, coordB._y)))
  477. 477 {
  478. 478 return false;
  479. 479 }
  480. 480
  481. 481 return true;
  482. 482 }
  483. 483
  484. 484 bool Desk::Exchange(const Coord& coordA, const Coord& coordB, bool isForce)
  485. 485 {
  486. 486 if(!IsCanExchange(coordA, coordB, isForce))
  487. 487 return false;
  488. 488
  489. 489 std::swap(_eles[coordA._x][coordA._y], _eles[coordB._x][coordB._y]);
  490. 490 return true;
  491. 491 }
  492. 492
  493. 493 void Desk::Init(const std::vector<ElemWeight>& weight)
  494. 494 {
  495. 495 ResetWeight(weight);
  496. 496 ResetDesk();
  497. 497 }
  498. 498
  499. 499 EBonusType Desk::Bonus(const Coord& coordA, std::vector<Coord>& out, int& maxCountLine) const
  500. 500 {
  501. 501 if(!IsValidCoord(coordA._x, coordA._y))
  502. 502 return EBonusType::BONUS_None;
  503. 503
  504. 504 EElem e = get<EElem>(coordA._x, coordA._y);
  505. 505 if(e == EElem::ELEM_None)
  506. 506 return EBonusType::BONUS_None;
  507. 507
  508. 508 EBonusType ret = EBonusType::BONUS_None;
  509. 509 bool isA = false, isV = false; // 横向/纵向是否存在消除
  510. 510 int cA = 0, cV = 0; // 横向/纵向消除数量
  511. 511
  512. 512 std::vector<Coord> outA, outV;
  513. 513 ///判断横向消除
  514. 514 {
  515. 515 //0,1,2,3,4 这 5 个元素以 2 位置为判断点,相同元素标识位为 1
  516. 516 std::bitset<5> signX = TestSign<AxisType::AxisX>({coordA._x, coordA._y, e});
  517. 517 for (size_t i = 1; i >= 0; i--) //<<-- //判断点的左侧两个元素 1, 0
  518. 518 {
  519. 519 if(signX[i])
  520. 520 {
  521. 521 Axis x = coordA._x + i - 2,
  522. 522 y = coordA._y;
  523. 523
  524. 524 //@Notice 需要设置点位置的元素类型,尽可能使返回值充分
  525. 525 outA.emplace_back(x, y, e);
  526. 526 }
  527. 527 else break; //顺序判断,一旦存在不相同,则立即退出
  528. 528 }
  529. 529
  530. 530 //加入判断点本身
  531. 531 outA.push_back(Coord(coordA._x, coordA._y, e));
  532. 532
  533. 533 for (size_t i = 3; i < 5; i++) //-->> //判断点的右侧两个元素 3, 4
  534. 534 {
  535. 535 if(signX[i])
  536. 536 {
  537. 537 Axis x = coordA._x + i - 2,
  538. 538 y = coordA._y;
  539. 539
  540. 540 outA.emplace_back(x, y, e);
  541. 541 }
  542. 542
  543. 543 else break;
  544. 544 }
  545. 545 }
  546. 546
  547. 547 ///判断纵向消除
  548. 548 {
  549. 549 std::bitset<5> signY = BonusSign<AxisType::AxisY>(coordA);
  550. 550 for (size_t i = 1; i >= 0; i--) //<<--
  551. 551 {
  552. 552 if(signY[i])
  553. 553 {
  554. 554 Axis x = coordA._x,
  555. 555 y = coordA._y + i - 2;
  556. 556 outV.emplace_back(x, y, e);
  557. 557 }
  558. 558 else break;
  559. 559 }
  560. 560
  561. 561 //判断点不可以包含两次
  562. 562 if(outA.size() < 3) outV.push_back(Coord(coordA._x, coordA._y, e));
  563. 563
  564. 564 for (size_t i = 3; i < 5; i++) //-->>
  565. 565 {
  566. 566 if(signY[i])
  567. 567 {
  568. 568 Axis x = coordA._x,
  569. 569 y = coordA._y + i - 2;
  570. 570 outV.emplace_back(x, y, e);
  571. 571 }
  572. 572
  573. 573 else break;
  574. 574 }
  575. 575 }
  576. 576
  577. 577 //执行横向消除
  578. 578 cA = outA.size();
  579. 579 if(cA >= 3) //大于等于 3 个可消除
  580. 580 {
  581. 581 isA = true;
  582. 582 for (auto& each : outA)
  583. 583 out.push_back(each);
  584. 584 }
  585. 585
  586. 586 //执行纵向消除
  587. 587 cV = outV.size();
  588. 588 if(cV >= 3 || (isA && outV.size() >= 2))
  589. 589 {
  590. 590 isV = true;
  591. 591 for (const auto& each : outV)
  592. 592 out.push_back(each);
  593. 593 }
  594. 594
  595. 595 //判断消除形状
  596. 596 maxCountLine = std::max(cA, cV);
  597. 597 if(isV && isA) return EBonusType::BONUS_CROSS; //十字形消除(T / L)
  598. 598 if(isA) return EBonusType::BONUS_ACROSS; //横向消除
  599. 599 if(isV) return EBonusType::BONUS_VERTICAL; //纵向消除
  600. 600 return EBonusType::BONUS_None;
  601. 601 }
  602. 602
  603. 603 int Desk::FindBonus(std::vector<TryBonusInfo>& out, bool isBest)
  604. 604 {
  605. 605 std::array<Coord, 4> side = { Coord{-1, 0}, Coord{1, 0}, Coord{0, -1}, Coord{0, 1} };
  606. 606
  607. 607 std::vector<Coord> bonus;
  608. 608 int count = 0;
  609. 609 int tmp = 0;
  610. 610 foreach<EElem>([&](Axis x, Axis y, const EElem& e)->bool
  611. 611 {
  612. 612 TryBonusInfo info;
  613. 613 Coord coordA(x, y, e); //the coordA is checked point.
  614. 614 for (size_t i = 0; i < side.size(); i++)
  615. 615 {
  616. 616 Axis bx = x + side[i]._x;
  617. 617 Axis by = y + side[i]._y;
  618. 618
  619. 619 if(!IsValidCoord(bx, by))
  620. 620 continue;
  621. 621
  622. 622 EElem be = get<EElem>(bx, by);
  623. 623 if(be == e)
  624. 624 continue;
  625. 625
  626. 626 Coord coordB(bx, by, be);
  627. 627 bonus.clear();
  628. 628
  629. 629 bool isExchange = Exchange(coordA, coordB, false);
  630. 630 if(!isExchange)
  631. 631 continue;
  632. 632
  633. 633 EBonusType bonusType = Bonus(coordA, bonus, tmp);
  634. 634 if(bonusType == EBonusType::BONUS_None)
  635. 635 {
  636. 636 Exchange(coordA, coordB, false);
  637. 637 continue;
  638. 638 }
  639. 639
  640. 640 const size_t s = bonus.size();
  641. 641
  642. 642 info._bouns = bonus;
  643. 643 info._count = s;
  644. 644 info._elem = bonus.front()._e;
  645. 645 info._coordA = coordA;
  646. 646 info._coordB = coordB;
  647. 647
  648. 648 if(!isBest)
  649. 649 {
  650. 650 out.push_back(info);
  651. 651 Exchange(coordA, coordB, false);
  652. 652 continue;
  653. 653 }
  654. 654
  655. 655 if(s > count)
  656. 656 {
  657. 657 out.clear();
  658. 658 out.push_back(info);
  659. 659
  660. 660 count = s;
  661. 661 }
  662. 662 else if(s == count && s > 0)
  663. 663 {
  664. 664 out.push_back(info);
  665. 665 }
  666. 666
  667. 667 Exchange(coordA, coordB, false);
  668. 668 }
  669. 669
  670. 670 return true;
  671. 671 });
  672. 672
  673. 673 return count;
  674. 674 }
  675. 675
  676. 676 ///////////////////////
  677. 677
  678. 678 void Desk::DoExchange(const Coord& coordA, const Coord& coordB, const StateEventCallBackT& cb, bool isForce)
  679. 679 {
  680. 680 Event<EAction::ACTION_EXCHANGE_INPUT> ev;
  681. 681 ev.Info()._coordA = coordA;
  682. 682 ev.Info()._coordB = coordB;
  683. 683 Start_3x_State(this, EAction::ACTION_EXCHANGE_INPUT, ev, cb);
  684. 684 }

7. 3x_desk.inl

  1. 1 template<typename T,
  2. 2 typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type*
  3. 3 >
  4. 4 void Desk::foreach(std::function<bool(Axis w, Axis h, T& e)> && cb)
  5. 5 {
  6. 6 for (Axis j = 0; j < _width; j++)
  7. 7 {
  8. 8 for (Axis i = 0; i < _height; i++)
  9. 9 {
  10. 10 bool is = false;
  11. 11 if constexpr(std::is_same<T, EElem>::value)
  12. 12 is = cb(j, i, _eles[j][i]);
  13. 13 else if(std::is_same<T, EDeck>::value)
  14. 14 is = cb(j, i, _decks[j][i]);
  15. 15 else break;
  16. 16
  17. 17 if(!is) break;
  18. 18 }
  19. 19 }
  20. 20
  21. 21 return;
  22. 22 }
  23. 23
  24. 24 template<typename T, typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type* >
  25. 25 void Desk::foreach(std::function<bool(Axis w, Axis h, const T& e)> && cb) const
  26. 26 {
  27. 27 for (Axis j = 0; j < _width; j++)
  28. 28 {
  29. 29 for (Axis i = 0; i < _height; i++)
  30. 30 {
  31. 31 bool is = false;
  32. 32 if constexpr(std::is_same<T, EElem>::value)
  33. 33 is = cb(j, i, _eles[j][i]);
  34. 34 else if(std::is_same<T, EDeck>::value)
  35. 35 is = cb(j, i, _decks[j][i]);
  36. 36 else break;
  37. 37
  38. 38 if(!is) break;
  39. 39 }
  40. 40 }
  41. 41 return;
  42. 42 }
  43. 43
  44. 44
  45. 45
  46. 46 template<typename T,
  47. 47 typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type*
  48. 48 >
  49. 49 T& Desk::get(Axis x, Axis y)
  50. 50 {
  51. 51 if constexpr(std::is_same<T, EElem>::value)
  52. 52 {
  53. 53 return _eles[x][y];
  54. 54 }
  55. 55
  56. 56 else if(std::is_same<T, EDeck>::value)
  57. 57 {
  58. 58 return _decks[x][y];
  59. 59 }
  60. 60 }
  61. 61
  62. 62 template<typename T,
  63. 63 typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type*
  64. 64 >
  65. 65 bool Desk::set(Axis x, Axis y, T e)
  66. 66 {
  67. 67 if(!IsValidCoord(x, y))
  68. 68 return false;
  69. 69
  70. 70 get<T>(x, y) = e;
  71. 71 return true;
  72. 72 }
  73. 73
  74. 74 template<typename T,
  75. 75 typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type*
  76. 76 >
  77. 77 T Desk::get(Axis x, Axis y) const
  78. 78 {
  79. 79 if constexpr(std::is_same<T, EElem>::value)
  80. 80 {
  81. 81 if(!IsValidCoord(x, y))
  82. 82 return EElem::ELEM_None;
  83. 83 return _eles[x][y];
  84. 84 }
  85. 85
  86. 86 else if(std::is_same<T, EDeck>::value)
  87. 87 {
  88. 88 if(!IsValidCoord(x, y))
  89. 89 return EDeck::DECK_None;
  90. 90 return _decks[x][y];
  91. 91 }
  92. 92 }
  93. 93
  94. 94 template<AxisType AT>
  95. 95 std::bitset<5> Desk::BonusSign(const Coord & coord) const
  96. 96 {
  97. 97 EElem e = get<EElem>(coord._x, coord._y);
  98. 98 if(e == EElem::ELEM_None)
  99. 99 return 0;
  100. 100
  101. 101 size_t i = 0;
  102. 102 std::bitset<5> ret;
  103. 103
  104. 104 if constexpr(AT == AxisType::AxisY)
  105. 105 {
  106. 106 for (Axis y = coord._y - 2; y <= coord._y + 2; y++, i++)
  107. 107 {
  108. 108 if(!IsValidCoord(coord._x, y))
  109. 109 {
  110. 110 ret[i] = 0;
  111. 111 continue;
  112. 112 }
  113. 113
  114. 114 ret[i] = get<EElem>(coord._x, y) == e ? 1 : 0;
  115. 115 }
  116. 116 return ret;
  117. 117 }
  118. 118
  119. 119 if constexpr(AT == AxisType::AxisX)
  120. 120 {
  121. 121 for (Axis x = coord._x - 2; x <= coord._x + 2; x++, i++)
  122. 122 {
  123. 123 if(!IsValidCoord(x, coord._y))
  124. 124 {
  125. 125 ret[i] = 0;
  126. 126 continue;
  127. 127 }
  128. 128 ret[i] = get<EElem>(x, coord._y) == e ? 1 : 0;
  129. 129 }
  130. 130 return ret;
  131. 131 }
  132. 132
  133. 133 return 0;
  134. 134 }
  135. 135
  136. 136 template<AxisType AT>
  137. 137 std::bitset<5> Desk::TestSign(Coord&& coord) const
  138. 138 {
  139. 139 EElem e = coord._e;
  140. 140 if(e == EElem::ELEM_None)
  141. 141 return 0;
  142. 142
  143. 143 size_t i = 0;
  144. 144 std::bitset<5> ret;
  145. 145
  146. 146 if constexpr(AT == AxisType::AxisY)
  147. 147 {
  148. 148 for (Axis y = coord._y - 2; y <= coord._y + 2; y++, i++)
  149. 149 {
  150. 150 if(!IsValidCoord(coord._x, y))
  151. 151 {
  152. 152 ret[i] = 0;
  153. 153 continue;
  154. 154 }
  155. 155
  156. 156 ret[i] = get<EElem>(coord._x, y) == e ? 1 : 0;
  157. 157 }
  158. 158 ret[2] = 1;
  159. 159 return ret;
  160. 160 }
  161. 161
  162. 162 if constexpr(AT == AxisType::AxisX)
  163. 163 {
  164. 164 for (Axis x = coord._x - 2; x <= coord._x + 2; x++, i++)
  165. 165 {
  166. 166 if(!IsValidCoord(x, coord._y))
  167. 167 {
  168. 168 ret[i] = 0;
  169. 169 continue;
  170. 170 }
  171. 171 ret[i] = get<EElem>(x, coord._y) == e ? 1 : 0;
  172. 172 }
  173. 173 ret[2] = 1;
  174. 174 return ret;
  175. 175 }
  176. 176
  177. 177 return 0;
  178. 178 }
  179. 179
  180. 180 template<typename T, typename std::enable_if<std::is_same<T, EElem>::value||std::is_same<T, EDeck>::value, T>::type* >
  181. 181 std::vector<T>& Desk::getcolume(Axis x)
  182. 182 {
  183. 183 if constexpr(std::is_same<T, EElem>::value )
  184. 184 return _eles[x];
  185. 185 else
  186. 186 return _decks[x];
  187. 187 }
  188. 188
  189. 189 inline bool Desk::IsValidCoord(Axis x, Axis y) const noexcept
  190. 190 {
  191. 191 return x < _width && y < _height && x >= 0 && y >= 0;
  192. 192 }

C++ 三消游戏基本实现的更多相关文章

  1. 消消乐、candy crush类三消游戏程序逻辑分析

    最近在开发一款类似消消乐的三消游戏,在碰到实现斜方向下落的时候卡住了很长时间.好几天没有思路,原本的思路是一次性预判多个宝石的一连串运动路径,运用缓动运动队列来实现宝石运动路径,例如 下落->滑 ...

  2. 三消游戏FSM状态机设计图

    三消游戏FSM状态机设计图 1) 设计FSM图 2) smc配置文件 ///////////////////////////////////////////////////////////////// ...

  3. cocos2d-x 3.2 它 三消游戏——万圣节大作战

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...

  4. Unity3d开发“类三消”游戏

    新建一个Project,导入图片素材和声音文件,把图片的Texture Type都修改为Sprite(2D and UI)[1].新建一个命名为Background的GameObject,为之添加背景 ...

  5. 最近用unity写三消游戏,mark一个准备用的unity插件,用来控制运动。

    http://www.pixelplacement.com/itween/index.php itween 听说还不错!

  6. cocos2d-x 消类游戏,类似Diamond dash 设计

    前几天刚刚在学习cocos2d-x,无聊之下自己做了一个类似Diamond dash的消类游戏,今天放到网上来和大家分享一下.我相信Diamond dash这个游戏大家都玩过,游戏的规则是这样的,有一 ...

  7. cocos2d 消除类游戏简单的算法 (一)

    1. 游戏视频演示 2.三消游戏我的理解 上面视频中的游戏.我做了2个星期时间,仅仅能算个简单Demo,还有bug.特效也差点儿没有.感觉三消游戏主要靠磨.越磨越精品. 市场上三消游戏已经超级多了.主 ...

  8. 游戏Demo(持续更新中...)

    格斗游戏 主要用于联系Unity的动画系统,并加入了通过检测按键触发不同的技能. WASD控制方向,AD为技能1,SW为技能2,右键跳跃,连续单机普通连招. 本来是要用遮罩实现跑动过程中的攻击动作,但 ...

  9. Unity三消算法

    消除算法图文详解 三消算法首要实现的就是找到所有三个或三个以上的可消除对象,但直接找到这些对象是不太现实的,所以我们要将需求拆分.可不可以先获取所有图案相连的对象,进而在获取三消对象,这个算法也是众多 ...

随机推荐

  1. [MongoDB知识体系] 一文全面总结MongoDB知识体系

    MongoDB教程 - Mongo知识体系详解 本系列将给大家构建MongoDB全局知识体系.@pdai MongoDB教程 - Mongo知识体系详解 知识体系 学习要点 学习资料 官网资料 入门系 ...

  2. ClickHouse元数据异常-MySQLHandlerFactory:Failed to read RSA key pair from server

    Clickhouse版本:20.3.6.40-2 clickhouse集群三个节点,一分片,三副本,三个节点数据完全一样 1. 问题描述 在使用连接工具操作时,发现其中一个节点连接拒绝,无法操作,另外 ...

  3. Nodejs学习笔记(2) 阻塞/非阻塞实例 与 Nodejs事件

    1. Node.js异步编程的特点 2. 阻塞与非阻塞的实例 2.1 阻塞代码实例 2.2 非阻塞代码实例 3. Node.js的事件驱动 4. 事件循环实例 1. Node.js异步编程的特点 参考 ...

  4. Linux 三剑客之 awk 实战详解教程

    我们知道 Linux 三剑客,它们分别是:grep.sed.awk.在前边已经讲过 grep 和 sed,没看过的同学可以直接点击阅读,今天要分享的是更为强大的 awk. sed 可以实现非交互式的字 ...

  5. ASP.NET Core与Redis搭建一个简易分布式缓存

    ​本文主要介绍了缓存的概念,以及如何在服务器内存中存储内容.今天的目标是利用IDistributedCache来做一些分布式缓存,这样我们就可以横向扩展我们的web应用程序. 在本教程中,我将使用Re ...

  6. 官方正式发布 Java 16

    前言 就在2021/03/16,官方正式发布了Java 16.我们可以下载使用Java 16了. 特性 向量API(孵化) 在运行期,Vector 表示向量计算可以可靠地编译成支持CPU架构上的最佳矢 ...

  7. 计算机图形学中使用Turbo C++画图步骤

    一.下载安装Turbo C++ 我安装的是Turbo C++ 3.2.2.0下载链接 二.画图 1.打开Turbo C++,点击右下角start turbo C++ 2.点击file ->new ...

  8. teprunner测试平台用例前置模块开发

    本文开发内容 现在正式进入测试相关功能开发.teprunner测试平台底层是pytest,中间层是tep,还没了解的朋友可以先看看tep的文章,整个平台的设计思路和后面用例的执行都会基于这个工具.te ...

  9. Android Studio 如何运行单个activity

    •写在前面 调试界面运行单个 Activity 可节省编译整个项目的时间提高效率: 本着提高效率的角度,特地上网百度相关知识: •解决方法 首先,在 AndroidManifest.xml 文件中,找 ...

  10. Android Studio 中的 button 无法使用 background 更改背景颜色

    •解决方案 res/values/themes.xml下的  <style name="Theme.HelloWorld" parent="Theme.Materi ...