/*************************************************************************** * Copyright (C) 2009 by Stefan Bühler * * stbuehler@web.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "toruschess.h" namespace toruschess { Move::Move(const Field* field, const Pos &from, const Pos &to) : m_from(from), m_to(to), m_prevFrom(field->place(from)), m_prevTo(field->place(to)), m_player(field->player(from)) { } static const int start_field[8][8] = { { -KNIGHT, -PAWN, -ROOK, 0, 0, 0, 0, 0 }, { -BISHOP, -KING, -QUEEN, 0, 0, 0, 0, 0 }, { -ROOK, -PAWN, -KNIGHT, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, ROOK, PAWN, KNIGHT, 0 }, { 0, 0, 0, 0, QUEEN, KING, BISHOP, 0 }, { 0, 0, 0, 0, KNIGHT, PAWN, ROOK, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } }; Field::Field() { memcpy(m_places, start_field, sizeof(start_field)); } void tryDirection(QList &moves, const Field *field, int thePlace, const Pos &from, int dx, int dy) { for (int d = 1; d < 8; d++) { Pos to = Pos(from.x() + d*dx, from.y() + d*dy); int toPlace = field->place(to); if (0 == toPlace) { // qDebug("move 1, %i", d); moves.push_back(Move(field, from, to)); /* move */ } else { if (0 > toPlace * thePlace) { // qDebug("beat 1, %i", d); moves.push_back(Move(field, from, to)); /* beat */ } else { // qDebug("hit friend, %i", d); } for (int c = 7; c > d; c--) { to = Pos(from.x() + c*dx, from.y() + c*dy); toPlace = field->place(to); if (0 == toPlace) { // qDebug("move 2, %i %i", d, c); moves.push_back(Move(field, from, to)); /* move */ } else if (0 > toPlace * thePlace) { // qDebug("beat 2, %i %i", d, c); moves.push_back(Move(field, from, to)); /* beat */ break; } else { // qDebug("hit friend, %i %i, (%i, %i) = %i", d, c, to.x(), to.y(), toPlace); break; } } break; } } } /* 7 == -1 mod 8, 6 == -2: but positive values are needed for (a + b) % 8 >= 0 */ typedef struct { int x, y; } move_delta; static const move_delta moves_pawn_walk[4] = { { 1, 0 }, { 0, 1 }, { 7, 0 }, { 0, 7 } }; static const move_delta moves_pawn_beat[4] = { { 1, 1 }, { 1, 7 }, { 7, 7 }, { 7, 1 } }; static const move_delta moves_knight[8] = { { 1, 2 }, { 1, 6 }, { 7, 2 }, { 7, 6 }, { 2, 1 }, { 2, 7 }, { 6, 1 }, { 6, 7 } }; static const move_delta moves_king[8] = { { 1, 1 }, { 1, 0 }, { 1, 7 }, { 0, 7 }, { 7, 7 }, { 7, 0 }, { 7, 1 }, { 0, 1 } }; static Pos operator + (const Pos &p, move_delta d) { return Pos(p.x() + d.x, p.y() + d.y); } QList Field::simpleValidMoves(const Pos &from) const { QList moves; int thePlace = place(from); Piece thePiece = (Piece) qAbs(thePlace); // qDebug("simpleValidMoves: %i", thePiece); switch (thePiece) { case NOPIECE: break; case PAWN: for (int i = 0; i < 4; i++) { if (0 == place(from + moves_pawn_walk[i])) { moves.push_back(Move(this, from, from + moves_pawn_walk[i])); } if (0 > thePlace * place(from + moves_pawn_beat[i])) { moves.push_back(Move(this, from, from + moves_pawn_beat[i])); } } break; case KNIGHT: for (int i = 0; i < 8; i++) { if (0 >= thePlace * place(from + moves_knight[i])) { moves.push_back(Move(this, from, from + moves_knight[i])); } } break; case BISHOP: tryDirection(moves, this, thePlace, from, 1, 1); tryDirection(moves, this, thePlace, from, 1, 7); break; case ROOK: tryDirection(moves, this, thePlace, from, 1, 0); tryDirection(moves, this, thePlace, from, 0, 1); break; case QUEEN: tryDirection(moves, this, thePlace, from, 1, 1); tryDirection(moves, this, thePlace, from, 1, 7); tryDirection(moves, this, thePlace, from, 1, 0); tryDirection(moves, this, thePlace, from, 0, 1); break; case KING: for (int i = 0; i < 8; i++) { if (0 >= thePlace * place(from + moves_king[i])) { moves.push_back(Move(this, from, from + moves_king[i])); } } break; } // qDebug("simpleValidMoves: found %i", moves.size()); return moves; } QList Field::validMoves(const Pos &from) const { QList moves = simpleValidMoves(from); int thePlace = place(from); Pos pking(0,0); /* find king */ for (int x = 0; x < 8; x++) for (int y = 0; y < 8; y++) { if (piece(Pos(x, y)) == KING && 0 < place(Pos(x, y)) * thePlace) { pking = Pos(x, y); goto foundking; } } return QList(); /* error, no king found */ foundking: QList resMoves; Field testField(*this); testField.place(from) = 0; bool movedKing = (from == pking); foreach(Move m, moves) { testField.place(m.to()) = thePlace; for (int x = 0; x < 8; x++) for (int y = 0; y < 8; y++) { Pos curp(x, y); if (0 > testField.place(curp) * thePlace && testField.simpleValidMoves(curp).contains(Move(&testField, curp, movedKing ? m.to() : pking))) { goto invalidmove; } } resMoves.push_back(m); invalidmove: testField.place(m.to()) = m.prevTo(); } return resMoves; } bool Field::validMove(const Move &m) const { QList moves = validMoves(m.from()); return moves.contains(m); } bool Field::move(const Move &m) { if (!validMove(m)) return false; place(m.from()) = 0; place(m.to()) = m.prevFrom(); return true; } bool Field::undo(const Move &m) { if (place(m.from()) != 0 || place(m.to()) != m.prevFrom()) return false; place(m.from()) = m.prevFrom(); place(m.to()) = m.prevTo(); return false; } Game::Game(QObject *parent) : QObject(parent), m_field(new Field()) { } Game::~Game() { delete m_field; } }