ICSAPI::parseVerbose is now used instead of VariantInfo::getVerboseMove.
[tagua/yd.git] / src / variants / ultima.cpp__
blob1692637fc04f6074ce943cc25eca292dcf40542c
1 #include "ultima.h"
2 #include "controllers/game.impl.h"
3 #include "controllers/examination.h"
4 #include "controllers/localexamination.h"
5 #include "controllers/editposition.impl.h"
6 #include "controllers/observedgame.h"
7 #include "controllers/editgame.impl.h"
8 #include "piecepoolwidget.h"
9 #include "variant.impl.h"
10 #include "graphicalinfo.impl.h"
11 #include "poolgraphicalinfo.impl.h"
12 #include "animator.impl.h"
13 #include "boardmanager.impl.h"
14 #include "moveserializer.impl.h"
15 #include <iostream>
17 using namespace std;
19 QString UltimaPiece::typeName() const {
20   switch (m_type) {
21   case King:
22     return "king";
23   case Withdrawer:
24     return "withdrawer";
25   case Coordinator:
26     return "coordinator";
27   case Chameleon:
28     return "chameleon";
29   case LongLeaper:
30     return "longleaper";
31   case Pawn:
32     return "pawn";
33   case Immobilizer:
34     return "immobilizer";
35   default:
36     return "";
37   }
40 QString UltimaPiece::typeSymbol(Type type) {
41   switch (type) {
42   case King:
43     return "K";
44   case Withdrawer:
45     return "W";
46   case Coordinator:
47     return "C";
48   case Chameleon:
49     return "X";
50   case LongLeaper:
51     return "L";
52   case Pawn:
53     return "P";
54   case Immobilizer:
55     return "I";
56   default:
57     return "";
58   }
61 bool UltimaPiece::canMove(UltimaMove& m, const UltimaPosition& position) const {
62   if (m_type == Chameleon) {
63     typedef map<Type, vector<Point> > Map;
64     Map possible_targets;
65     
66     bool valid = canMoveAs(m, position, m.targets, UltimaPiece::Chameleon);
67     
68     for (int i = 0; i < 7; i++) {
69       Type t = static_cast<Type>(i);
70       if (t != Chameleon) {
71         possible_targets[t] = vector<Point>();
72         bool keep_this = true;
73         if (!canMoveAs(m, position, possible_targets[t], t)) 
74           keep_this = false;
75         else {
76           if (possible_targets[t].size() == 0) {
77             if (position[m.to]) {
78               keep_this = true;
79               possible_targets[t].push_back(m.to);
80             }
81             else
82               keep_this = false;
83           }
84           else {
85             for (uint j = 0; j < possible_targets[t].size(); j++) {
86               Q_ASSERT(position[possible_targets[t][j]]);
87               if (position[possible_targets[t][j]]->type() != t) {
88                 keep_this = false;
89                 break;
90               }
91             }
92           }
93         }
94         
95         if (!keep_this) {
96           std::cout << "removing possible targets of type " << typeSymbol(t) << std::endl;
97           possible_targets.erase(t);
98         }
99       }
100     }
101     
102     for (Map::iterator i = possible_targets.begin();
103           i != possible_targets.end(); ++i) {
104       std::cout << "remaining targets of type " << typeSymbol(i->first) << std::endl;
105       valid = true;
106       copy(i->second.begin(),
107            i->second.end(),
108            back_insert_iterator<vector<Point> >(m.targets));
109     }
110     
111     return valid;
112   }
113   else 
114     return canMoveAs(m, position, m.targets, m_type);
117 bool UltimaPiece::checkPawnCapture(const UltimaPosition& position, const Point& p, 
118                                     const Point& direction, vector<Point>& targets) const {
119   Point opp = p + direction;
120   Point f = opp + direction;
121   
122   if (!position.valid(f)) return false;
123   if (position[opp] && position[opp]->color() != color()
124     && position[f] && position[f]->color() == color()) {
125     targets.push_back(opp);
126     return true;
127   }
128   else return false;
131 bool UltimaPiece::canMoveAs(const UltimaMove& m, const UltimaPosition& position, 
132                             vector<Point>& targets, Type actualType) const {
133   Point delta = m.to - m.from;
134   if (actualType == King)
135     // the king moves exactly like a chess king
136     return abs(delta.x) <= 1 && abs(delta.y) <= 1 && !sameColor(position[m.to]);
137   else {
138     PathInfo path = position.path(m.from, m.to);
139     if (path.valid() && !position[m.to]) {
140       
141       // a long leaper is the only one that can jump
142       if (actualType == LongLeaper) {
143         Point step = delta.normalizeInfinity();
144         // a long leaper move is pseudolegal if
145         // between from and to there are only
146         // opponent pieces, and they are not
147         // consecutive
148         bool last = false;
149         Point p = m.from;
150         while ((p += step) != m.to) {
151           if (position[p]) {
152             if (last || position[p]->color() == color()) return false;
153             targets.push_back(p);
154             last = true;
155           }
156           else last = false;
157         }
158         return true;
159       }
160       else {
161         if (!path.clear()) return false;
162         
163         switch (actualType) {
164         case Pawn:
165           // move like a rook
166           if (!path.parallel()) return false;
167           
168           // called specialized capture checks for each direction
169           checkPawnCapture(position, m.to, Point(1,0), targets);
170           checkPawnCapture(position, m.to, Point(0,1), targets);
171           checkPawnCapture(position, m.to, Point(-1,0), targets);
172           checkPawnCapture(position, m.to, Point(0,-1), targets);
173           break;
174           
175         case Coordinator:
176           {
177             // find king position
178             Point kingPos = position.findKing(m_color);
179             Q_ASSERT(kingPos != Point::invalid());
180             
181             // capture on the other vertices of the rectangle
182             // determined by m.to and kingPos
183             Point t1(m.to.x, kingPos.y);
184             Point t2(kingPos.x, m.to.y);
185             
186             if (position[t1] && position[t1]->color() != m_color)
187               targets.push_back(t1);
188             if (position[t2] && position[t2]->color() != m_color)
189               targets.push_back(t2);
190           }
191           break;
192         case Immobilizer:
193           // the immobilizer cannot capture
194           break;
195         case Withdrawer:
196           {
197             Point dir = delta.normalizeInfinity();
198             Point opp = m.from - dir;
199             if (position.valid(opp) && position[opp] && position[opp]->color() != color())
200               targets.push_back(opp);
201           }
202           break;
203         case Chameleon:
204           break;
205         default:
206           return false;
207         
208         }
209         
210         return true;
211       }
212       
213     }
214     
215     return false;
216   }  
219 bool UltimaPiece::equals(const UltimaPiece* other) const {
220   return other && m_color == other->m_color && m_type == other->m_type;
224 bool UltimaPiece::sameColor(const UltimaPiece* other) const {
225   return other && m_color == other->m_color;
228 UltimaPosition::UltimaPosition()
229 : m_turn(WHITE)
230 , m_board(8, 8) { };
232 UltimaPosition::~UltimaPosition() { }
234 #define SET_PIECE(i, j, color, type) \
235   m_board[Point(i,j)] = new Piece(color, UltimaPiece::type)
236 void UltimaPosition::setup() {
237   for (int i = 0; i < 8; i++) {
238     SET_PIECE(i, 1, BLACK, Pawn);
239     SET_PIECE(i, 6, WHITE, Pawn);
240   }
241   
242   SET_PIECE(0,0, BLACK, Coordinator);
243   SET_PIECE(1,0, BLACK, LongLeaper);
244   SET_PIECE(2,0, BLACK, Chameleon);
245   SET_PIECE(3,0, BLACK, Withdrawer);
246   SET_PIECE(4,0, BLACK, King);
247   SET_PIECE(5,0, BLACK, Chameleon);
248   SET_PIECE(6,0, BLACK, LongLeaper);
249   SET_PIECE(7,0, BLACK, Immobilizer);
251   SET_PIECE(0,7, WHITE, Immobilizer);
252   SET_PIECE(1,7, WHITE, LongLeaper);
253   SET_PIECE(2,7, WHITE, Chameleon);
254   SET_PIECE(3,7, WHITE, King);
255   SET_PIECE(4,7, WHITE, Withdrawer);
256   SET_PIECE(5,7, WHITE, Chameleon);
257   SET_PIECE(6,7, WHITE, LongLeaper);
258   SET_PIECE(7,7, WHITE, Coordinator);
259   
260   m_turn = WHITE;
262 #undef SET_PIECE
264 bool UltimaPosition::operator==(const UltimaPosition& other) const {
265   return m_turn == other.m_turn
266       && m_board == other.m_board;
269 UltimaPiece* UltimaPosition::operator[](const Point& p) const {
270   return m_board[p];
273 void UltimaPosition::setPiece(const Point& p, Piece* piece) {
274   delete m_board[p];
275   m_board[p] = piece;
278 Point UltimaPosition::findKing(Piece::Color color) const {
279   return m_board.find(UltimaPiece(color, UltimaPiece::King));
282 void UltimaPosition::dump() const { }
285 bool UltimaPosition::valid(const Point& p) const {
286   return m_board.valid(p);
289 bool UltimaPosition::testMove(Move& m) const {
290   return pseudolegal(m);
293 bool UltimaPosition::pseudolegal(Move& m) const {
294   if (!m.valid()) return false;
295   Q_ASSERT(valid(m.from));
296   Piece* piece = m_board[m.from];
297   Q_ASSERT(piece);
298   
299   if (m.from == m.to) return false;
300   
301   // a piece cannot move if it is near an opponent immobilizer
302   // or near a chameleon if it is an immobilizer
303   bool immobilized = false;
304   for (int i = -1; i <= 1; ++i)
305   for (int j = -1; j <= 1; ++j) {
306     Point p = m.from + Point(i,j);
307     if (!valid(p)) continue;
308     if (m_board[p]
309        && m_board[p]->color() != piece->color()) {
310       Piece::Type type = m_board[p]->type();
311       if (type == Piece::Immobilizer ||
312           (piece->type() == Piece::Immobilizer && type == Piece::Chameleon)) {
313         immobilized = true;
314         break;
315       }
316     }
317   }
318   if (immobilized) {
319     // an immobilized piece can move
320     // if an only if the move is a suicide
321     return m.to == Point::invalid();
322   }
324   if (piece->canMove(m, *this)) {
325     return true;
326   }
327   else return false;
330 void UltimaPosition::move(const Move& m) {
331   Q_ASSERT(m.valid());
332   
333   // remove targets
334   for (uint i = 0; i < m.targets.size(); i++)
335     if (m.targets[i] != Point::invalid()) setPiece(m.targets[i], 0);
336   
337   if (m.to == Point::invalid()) {
338     // suicide
339 //    setPiece(m.from, 0);
340     std::cout << "suicide on " << m.from << std::endl;
341   }
342   else {
343     // normal move
344     delete m_board[m.to];
345     m_board[m.to] = m_board[m.from];
346     m_board[m.from] = 0;
347   }
348   
349   switchTurn();
352 void UltimaPosition::switchTurn() {
353   m_turn = ChessPiece::oppositeColor(m_turn);
356 template class EditGameController<UltimaPosition>;