#ifndef SECONDO_ALGEBRAS_CHESS_POSITIONOPS_HPP #define SECONDO_ALGEBRAS_CHESS_POSITIONOPS_HPP #include #include #include #include #include #include "ternary_function.hpp" #include "Position.hpp" #include "Material.hpp" #include "Piece.hpp" #include "MoveOps.hpp" struct attackcount_op : std::binary_function< Position, Field, int > { int operator () ( const Position& pos, const Field& f ) const { int count = 0; // Count pawns attacks int row = f.row + ( pos.turn() == WHITE ? -1 : 1 ); if (pos[ Field(f.file - 1, row) ] == Piece(PT_PAWN, pos.turn()).get()) ++count; if (pos[ Field(f.file + 1, row) ] == Piece(PT_PAWN, pos.turn()).get()) ++count; // Count pieces attacks for( int pt = PT_KNIGHT; pt <= PT_KING; ++pt ) { position_t::board_t::moves_t dirs = pos.moves( PIECE_TYPE(pt) ); position_t::const_iterator it1 = pos.iter( f ); for( int d = 0; d < dirs.count; ++d ) { position_t::const_iterator it = it1; for( int i = 0; i < dirs.steps; ++i ) { it += dirs.moves[d]; if ( *it == NONE ) continue; if ( *it == Piece( PIECE_TYPE(pt), pos.turn() ).get() ) ++count; break; } } } return count; } }; struct protectcount_op : std::binary_function< Position, Field, int > { int operator () ( const Position& pos, const Field& f ) const { int count = 0; // Count pawns PIECE protecting = Piece( PT_PAWN, !pos.turn() ).get(); int row = f.row + ( pos.turn() == WHITE ? 1 : -1 ); if ( pos[ Field(f.file - 1, row) ] == protecting ) ++count; if ( pos[ Field(f.file + 1, row) ] == protecting ) ++count; // Count pieces for( int pt = PT_KNIGHT; pt <= PT_KING; ++pt ) { position_t::board_t::moves_t dirs = pos.moves( PIECE_TYPE(pt) ); position_t::const_iterator it1 = pos.iter( f ); for( int d = 0; d < dirs.count; ++d ) { position_t::const_iterator it = it1; for( int i = 0; i < dirs.steps; ++i ) { it += dirs.moves[d]; if ( *it == NONE ) continue; if ( *it == Piece( PIECE_TYPE(pt), !pos.turn() ).get() ) ++count; break; } } } return count; } }; struct move_generator { typedef std::vector< PlyT > moves_t; typedef moves_t::const_iterator iterator; move_generator( const Position& pos ) : pos_(pos) { generate_castlings( pos_ ); //typedef Position::const_iterator pos_iter; for( int row = 0; row < 8; ++row ) { for( int file = 0; file < 8; ++file ) { Field from( file, row ); Piece agent( pos_[from] ); if ( agent.get() < BLACK_PAWN || agent.get() > WHITE_KING || agent.color() != pos_.turn() ) continue; if ( agent.type() == PT_PAWN ) generate_pawn_moves( file, row, agent ); else if ( PT_KNIGHT <= agent.type() && agent.type() <= PT_KING ) generate_piece_moves( pos_, from, agent ); } } } Field find_king( COLOR color ) const { PIECE king = Piece( PT_KING, color ).get(); for( int i = 0; i < 64; ++i ) if ( pos_[ Field(i%8, i/8) ] == king ) return Field(i%8, i/8); throw std::runtime_error( "King not found" ); } iterator begin() const { return moves_.begin(); } iterator end() const { return moves_.begin(); } const PlyT& operator[]( int n ) const { return moves_[n]; } int size() const { return moves_.size(); } private: moves_t moves_; Position pos_; void add_move( const PlyT& p ) { Ply ply(p); delete apply_ply_op()( pos_, ply ); Field king_pos = find_king( !pos_.turn() ); if ( attackcount_op()( pos_, king_pos ) == 0 ) moves_.push_back( p ); delete revert_ply_op()( pos_, ply ); } void generate_piece_moves( const Position& pos_, const Field& from, const Piece& agent ) { position_t::board_t::moves_t dirs = pos_.moves( agent.type() ); for( int d = 0; d < dirs.count; ++d ) { position_t::const_iterator it = pos_.iter( from ); for( int i = 0; i < dirs.steps; ++i ) { it += dirs.moves[d]; if ( *it == UNDEFINED ) break; if ( *it != NONE && Piece(*it).color() == pos_.turn() ) break; Field to( pos_.field( it ) ); Piece captured( pos_[to] ); add_move( PlyT( from, to, agent.get(), pos_.state(), PLY_ORDINARY, captured.type() ) ); if ( *it != NONE ) break; } } } void generate_castlings( const Position& pos_ ) { int row = pos_.turn() == WHITE ? 0 : 7; if ( pos_.is_castling_possible( true, pos_.turn() ) && pos_[Field(3, row)] == NONE && pos_[Field(2, row)] == NONE && pos_[Field(1, row)] == NONE ) { PIECE agent = pos_[Field(4, row)]; add_move( PlyT(Field(4, row), Field(2, row), agent, pos_.state(), PLY_CASTLING ) ); } if ( pos_.is_castling_possible( false, pos_.turn() ) && pos_[Field(5, row)] == NONE && pos_[Field(6, row)] == NONE ) { Field from( 4, row ); Field to( 6, row ); PIECE agent = pos_[from]; add_move( PlyT( from, to, agent, pos_.state(), PLY_CASTLING ) ); } } void generate_pawn_moves( int file, int row, const Piece& agent ) { Field from( file, row ); int dest_row = row + ( pos_.turn() == WHITE ? 1 : -1 ); Field to( file, dest_row ); if ( pos_[ to ] == NONE ) { add_move( PlyT( from, to, agent.get(), pos_.state() ) ); if ( row == ( pos_.turn() == WHITE ? 1 : 6 ) ) { dest_row += pos_.turn() == WHITE ? 1 : -1; to = Field( file, dest_row ); if ( pos_[ to ] == NONE ) add_move( PlyT( from, to, agent.get(), pos_.state() ) ); } } dest_row = row + ( pos_.turn() == WHITE ? 1 : -1 ); generate_pawn_capture( from, Field( file - 1, dest_row ), agent ); generate_pawn_capture( from, Field( file + 1, dest_row ), agent ); } void generate_pawn_capture( const Field& from, const Field& to, const Piece& agent ) { Piece captured( pos_[to] ); if ( captured.get() == UNDEFINED ) return; if ( captured.get() == NONE ) { int to_row = pos_.turn() == WHITE ? 5 : 2; Field capture_f = Field( to.file, pos_.turn() == WHITE ? 4 : 3 ); if ( to.row == to_row && pos_.is_enpassant_possible() && Piece( pos_[capture_f] ) == Piece( PT_PAWN, !pos_.turn() ) && pos_.enpassant_file() == to.file ) { add_move( PlyT( from, to, agent.get(), pos_.state(), PLY_ENPASSANT, PT_PAWN ) ); } } else if ( captured.color() != pos_.turn() ) add_move( PlyT( from, to, agent.get(), pos_.state(), PLY_ORDINARY, captured.type() ) ); } }; struct pieces_op : std::unary_function< Position, Material* > { Material* operator () ( const Position& pos ) const { Material* m = new Material( DEFINED ); for( int i = 0; i < 64; ++i ) { Field field( i % 8, i / 8 ); PIECE piece = pos[field]; if ( piece >= BLACK_PAWN && piece <= WHITE_KING ) ++m->pieces[ piece - 2 ]; } return m; } }; struct moveNo_op : std::unary_function< Position, int > { int operator () ( const Position& p ) const { return p.move_number(); } }; struct checkmate_op : std::unary_function< Position, bool > { bool operator () ( const Position& pos ) const { move_generator gen( pos ); Field king_pos = gen.find_king( pos.turn() ); return protectcount_op()( pos, king_pos ) > 0 && gen.size() == 0; } }; struct stalemate_op : std::unary_function< Position, bool > { bool operator () ( const Position& pos ) const { move_generator gen( pos ); Field king_pos = gen.find_king( pos.turn() ); return protectcount_op()( pos, king_pos ) == 0 && gen.size() == 0; } }; struct includes_op : std::binary_function< Position, Position, bool > { bool operator () ( const Position& p1, const Position& p2 ) const { typedef Position::const_iterator Iter; for( Iter i1 = p1.begin(), i2 = p2.begin(); i1 != p1.end() && i2 != p2.end(); ++i1, ++i2 ) { if ( *i1 != *i2 && *i2 != NONE ) return false; } return true; } }; struct piececount_position_op : std::binary_function< Position, Piece, int > { int operator() ( const Position& pos, const Piece& piece ) const { PIECE p = piece.get(); return std::count_if( pos.begin(), pos.end(), p == boost::lambda::_1 ); } }; struct piececount_spos_op : std::binary_function< Position, CcString, int > { int operator() ( const Position& pos, const CcString& piece ) const { PIECE_TYPE pt = PT_UNDEFINED; try { pt = Piece::from_agent_type( piece.GetValue() ); } catch( const std::exception& ) { PIECE p = UNDEFINED; try { p = Piece::from_agent( piece.GetValue() ); } catch( const std::exception& ){ throw std::runtime_error( "Unknown Piece 1" ); } if ( p < NONE || p > WHITE_KING ) throw std::runtime_error( "Unknown Piece 2" ); return std::count_if( pos.begin(), pos.end(), p == boost::lambda::_1 ); } if ( pt < PT_NONE || pt > PT_KING ) throw std::runtime_error( "Unknown Piece 3" ); int sum = 0; for( int i = 0; i < 64; ++i ) if ( Piece( pos[Field(i%8, i/8)] ).type() == pt ) ++sum; return sum; } }; struct approx_position_op : std::binary_function< Position, Position, bool > { bool operator() ( const Position& p1, const Position& p2 ) const { return abs( p1.value_sum() - p2.value_sum() ) < 0.2; } }; struct posrange_op : ternary_function< Position, Field, Field, Position* > { Position* operator()( const Position& p, const Field& f1, const Field& f2 ) { Position* pos = new Position( EMPTY_POSITION ); for( int y = f1.row; y <= f2.row; ++y ) for( int x = f1.file; x <= f2.file; ++x ) (*pos)[ Field( x, y ) ] = p[ Field( x, y ) ]; return pos; } }; struct attacked_by_p_op : ternary_function< Position, Piece, Piece, bool > { bool operator()( const Position& pos, const Piece& p1, const Piece& p2 ) { Piece attacking = Piece( p2.type(), pos.turn() ); PIECE attacked = Piece( p1.type(), !pos.turn() ).get(); for( int i = 0; i < 64; ++i ) { Field f( i % 8, i / 8 ); if ( Piece( pos[f] ) == attacking ) { if ( p2.type() == PT_PAWN ) { int row = f.row + ( pos.turn() == WHITE ? 1 : -1 ); if ( pos[ Field(f.file - 1, row) ] == attacked ) return true; if ( pos[ Field(f.file + 1, row) ] == attacked ) return true; } else { /* Warning, sometimes the following code produces a memory error, i.e. the it will point after the valid data. */ position_t::board_t::moves_t dirs = pos.moves( p2.type() ); position_t::const_iterator it1 = pos.iter( f ); for( int d = 0; d < dirs.count; ++d ) { position_t::const_iterator it = it1; for( int i = 0; i < dirs.steps; ++i ) { it += dirs.moves[d]; if ( *it == NONE ) continue; if ( *it == attacked ) return true; } } } } } return false; } }; struct attacked_by_f_op : ternary_function< Position, Field, Piece, bool > { bool operator()( const Position& pos, const Field& f, const Piece& p ) { PIECE attacking = Piece( p.type(), pos.turn() ).get(); if ( p.type() == PT_PAWN ) { int row = f.row + ( pos.turn() == WHITE ? -1 : 1 ); if ( pos[ Field(f.file - 1, row) ] == attacking ) return true; if ( pos[ Field(f.file + 1, row) ] == attacking ) return true; return false; } position_t::board_t::moves_t dirs = pos.moves( p.type() ); position_t::const_iterator it1 = pos.iter( f ); for( int d = 0; d < dirs.count; ++d ) { position_t::const_iterator it = it1; for( int i = 0; i < dirs.steps; ++i ) { it += dirs.moves[d]; if ( *it == NONE ) continue; if ( *it == attacking ) return true; break; } } return false; } }; struct attacked_from_p_op : ternary_function< Position, Piece, Field, bool > { bool operator()( const Position& pos, const Piece& p, const Field& f ) { PIECE_TYPE attacking = Piece( pos[f] ).type(); if ( attacking < PT_PAWN || attacking > PT_KING ) return false; PIECE attacked = Piece( p.type(), !pos.turn() ).get(); // pawns attacks if ( attacking == PT_PAWN ) { int row = f.row + ( pos.turn() == WHITE ? -1 : 1 ); if ( pos[ Field(f.file - 1, row) ] == attacked ) return true; if ( pos[ Field(f.file + 1, row) ] == attacked ) return true; return false; } // pieces attacks position_t::board_t::moves_t dirs = pos.moves( attacking ); position_t::const_iterator it1 = pos.iter( f ); for( int d = 0; d < dirs.count; ++d ) { position_t::const_iterator it = it1; for( int i = 0; i < dirs.steps; ++i ) { it += dirs.moves[d]; if ( *it == NONE ) continue; if ( *it == attacked ) return true; break; } } return false; } }; struct attacked_from_f_op : ternary_function< Position, Field, Field, bool > { bool operator()( const Position& pos, const Field& f1, const Field& f2 ) { PIECE_TYPE attacking = Piece( pos[f2] ).type(); if ( attacking < PT_PAWN || attacking > PT_KING ) return false; // pawns attacks if ( attacking == PT_PAWN ) { int row = f2.row + ( pos.turn() == WHITE ? -1 : 1 ); if ( Field(f2.file - 1, row) == f1 ) return true; if ( Field(f2.file + 1, row) == f1 ) return true; return false; } // pieces attacks position_t::board_t::moves_t dirs = pos.moves( attacking ); position_t::const_iterator it1 = pos.iter( f2 ); for( int d = 0; d < dirs.count; ++d ) { position_t::const_iterator it = it1; for( int i = 0; i < dirs.steps; ++i ) { it += dirs.moves[d]; if ( pos.field( it ) == f1 ) return true; if ( *it == NONE ) continue; break; } } return false; } }; struct protected_by_p_op : ternary_function< Position, Piece, Piece, bool > { bool operator()( Position& pos, const Piece& p1, const Piece& p2 ) { pos.increment_turn(); bool result = attacked_by_p_op()( pos, p1, p2 ); pos.decrement_turn(); return result; } }; struct protected_by_f_op : ternary_function< Position, Field, Piece, bool > { bool operator()( Position& pos, const Field& f, const Piece& p ) { pos.increment_turn(); bool result = attacked_by_f_op()( pos, f, p ); pos.decrement_turn(); return result; } }; struct protected_from_p_op : ternary_function< Position, Piece, Field, bool > { bool operator()( Position& pos, const Piece& p, const Field& f ) { pos.increment_turn(); bool result = attacked_from_p_op()( pos, p, f ); pos.decrement_turn(); return result; } }; struct protected_from_f_op : ternary_function< Position, Field, Field, bool > { bool operator()( Position& pos, const Field& f1, const Field& f2 ) { pos.increment_turn(); bool result = attacked_from_f_op()( pos, f1, f2 ); pos.decrement_turn(); return result; } }; struct apply_move_op : ternary_function< Position, Field, Field, Position* > { Position* operator()( Position& pos, const Field& f1, const Field& f2 ) { // TODO Plausibilitaetspruefung, argument checking if ( pos[f1] != NONE ) { pos[f2] = pos[f1]; pos[f1] = NONE; } return new Position(pos); // TODO } }; struct pos_fields_op : std::unary_function< Position, std::pair > { pos_fields_op( const Position&, ListExpr type ) : index_(-1), type_(type){} std::pair operator()( const Position& pos ) { TupleType type( type_ ); if ( ++index_ < 64 ) { Tuple* result = new Tuple( new TupleType(type_) ); Field* field = new Field( index_ % 8, index_ / 8 ); result->PutAttribute( 0, field ); result->PutAttribute( 1, new Piece( pos[*field] ) ); return std::make_pair( true, result ); } return std::make_pair( false, new Tuple( new TupleType(type_) ) ); } static list_ostream type( ListExpr ) { return list_ostream() << ( list_ostream() << ChessBSymbol("Field") << ChessBSymbol("field") ) << ( list_ostream() << ChessBSymbol("Piece") << ChessBSymbol("piece") ); } private: int index_; ListExpr type_; }; struct tuple_t { tuple_t() : bp(NONE){} tuple_t( Piece sp_, Field sf_, Piece bp_, Field bf_, Piece ep_, Field ef_ ) : sp(sp_), bp(bp_), ep(ep_), sf(sf_), bf(bf_), ef(ef_){} Piece sp, bp, ep; Field sf, bf, ef; }; struct pos_moves_op : std::unary_function< Position, std::pair > { pos_moves_op( const Position& pos, ListExpr type ) : type_(type), gen_(pos), current_(-1){} std::pair operator()( const Position& ) { TupleType type( type_ ); if ( ++current_ < gen_.size() ) { const PlyT& ply = gen_[current_]; Tuple* result = new Tuple( new TupleType(type_) ); result->PutAttribute( 0, new Piece( ply.agent() ) ); result->PutAttribute( 1, new Field( ply.from() ) ); result->PutAttribute( 2, new Piece( ply.captured() ) ); result->PutAttribute( 3, new Field( ply.to() ) ); return std::make_pair( true, result ); } return std::make_pair( false, new Tuple( new TupleType(type_) ) ); } static list_ostream type( ListExpr ) { return list_ostream() << ( list_ostream() << ChessBSymbol("SPiece") << ChessBSymbol("piece") ) << ( list_ostream() << ChessBSymbol("SField") << ChessBSymbol("field") ) << ( list_ostream() << ChessBSymbol("EPiece") << ChessBSymbol("piece") ) << ( list_ostream() << ChessBSymbol("EField") << ChessBSymbol("field") ); } private: ListExpr type_; move_generator gen_; int current_; }; class p_moves_blocked_op; struct pos_moves_blocked_op : std::unary_function< Position, std::pair > { pos_moves_blocked_op( const Position& pos, ListExpr t ) : type_(t), current_(0) { int srow = pos.turn() == WHITE ? 1 : 6; int brow = pos.turn() == WHITE ? 2 : 5; int erow = pos.turn() == WHITE ? 3 : 4; Piece pawn = Piece( PT_PAWN, pos.turn() ); for( int file = 0; file < 8; ++file ) { Piece spiece = Piece( pos[ Field( file, srow ) ] ); Piece bpiece = Piece( pos[ Field( file, brow ) ] ); Piece epiece = Piece( pos[ Field( file, erow ) ] ); if ( spiece == pawn && bpiece.get() != NONE && epiece.color() != pos.turn() ) { tuples.push_back( tuple_t( spiece, Field( file, srow ), bpiece, Field( file, brow ), epiece, Field( file, erow ) ) ); } } for( int i = 0; i < 64; ++i ) { tuple_t t; t.sf = Field( i % 8, i / 8 ); t.sp = Piece( pos[t.sf] ); if ( t.sp.type() > PT_KNIGHT && t.sp.type() < PT_KING && t.sp.color() == pos.turn() ) { position_t::board_t::moves_t dirs = pos.moves( t.sp.type() ); position_t::const_iterator it1 = pos.iter( t.sf ); for( int d = 0; d < dirs.count; ++d ) { position_t::const_iterator it = it1; for( int i = 0; i < dirs.steps; ++i ) { it += dirs.moves[d]; if ( *it == UNDEFINED ) break; if ( t.bp == Piece( NONE ) ) { if ( *it != NONE ) { t.bp = Piece(*it); t.bf = pos.field(it); } continue; } if ( *it == NONE ) { t.ep = Piece(*it); t.ef = pos.field(it); tuples.push_back( t ); continue; } else if ( Piece(*it).color() != pos.turn() && Piece(*it).type() != PT_KING ) { t.ep = Piece(*it); t.ef = pos.field(it); tuples.push_back( t ); } t.bp = Piece(*it); t.bf = pos.field(it); } } } } } std::pair operator()( const Position& ) { TupleType type( type_ ); if ( current_ < tuples.size() ) { const tuple_t& t = tuples[ current_++ ]; Tuple* result = new Tuple( new TupleType(type_) ); result->PutAttribute( 0, new Piece(t.sp) ); result->PutAttribute( 1, new Field(t.sf) ); result->PutAttribute( 2, new Piece(t.bp) ); result->PutAttribute( 3, new Field(t.bf) ); result->PutAttribute( 4, new Piece(t.ep) ); result->PutAttribute( 5, new Field(t.ef) ); return std::make_pair( true, result ); } return std::make_pair( false, new Tuple( new TupleType(type_) ) ); } static list_ostream type( ListExpr ) { return list_ostream() << ( list_ostream() << ChessBSymbol("SPiece") << ChessBSymbol("piece") ) << ( list_ostream() << ChessBSymbol("SField") << ChessBSymbol("field") ) << ( list_ostream() << ChessBSymbol("BPiece") << ChessBSymbol("piece") ) << ( list_ostream() << ChessBSymbol("BField") << ChessBSymbol("field") ) << ( list_ostream() << ChessBSymbol("EPiece") << ChessBSymbol("piece") ) << ( list_ostream() << ChessBSymbol("EField") << ChessBSymbol("field") ); } private: ListExpr type_; std::vector< tuple_t > tuples; std::vector< tuple_t >::size_type current_; friend class p_moves_blocked_op; }; struct piece_moves_op : std::binary_function< Position, Piece, std::pair > { piece_moves_op( const Position& pos, const Piece& agent, ListExpr type ) : type_(type), gen_(pos), current_(-1){} std::pair operator()( const Position&, const Piece& agent ) { TupleType type( type_ ); while( ++current_ < gen_.size() ) { const PlyT& ply = gen_[current_]; if ( ply.agent() != agent ) continue; Tuple* result = new Tuple( new TupleType(type_) ); result->PutAttribute( 0, new Piece( ply.agent() ) ); result->PutAttribute( 1, new Field( ply.from() ) ); result->PutAttribute( 2, new Piece( ply.captured() ) ); result->PutAttribute( 3, new Field( ply.to() ) ); return std::make_pair( true, result ); } return std::make_pair( false, new Tuple( new TupleType(type_) ) ); } static list_ostream type( ListExpr ) { return list_ostream() << ( list_ostream() << ChessBSymbol("SPiece") << ChessBSymbol("piece") ) << ( list_ostream() << ChessBSymbol("SField") << ChessBSymbol("field") ) << ( list_ostream() << ChessBSymbol("EPiece") << ChessBSymbol("piece") ) << ( list_ostream() << ChessBSymbol("EField") << ChessBSymbol("field") ); } private: ListExpr type_; move_generator gen_; int current_; }; struct p_moves_blocked_op : std::binary_function< Position, Piece, std::pair > { p_moves_blocked_op( const Position& pos, const Piece& p, ListExpr t ) : type_(t), op_(pos, t){} std::pair operator()( const Position& pos, const Piece& piece ) { // TODO piece is undefined for some reason in // query wjc feed head[1] extract[elem] getposition[0] // piece_moves_blocked[Queen] consume; TupleType type( type_ ); while( op_.current_ < op_.tuples.size() ) { const tuple_t& t = op_.tuples[ op_.current_++ ]; if ( t.sp != piece ) continue; Tuple* result = new Tuple( new TupleType(type_) ); result->PutAttribute( 0, new Piece(t.sp) ); result->PutAttribute( 1, new Field(t.sf) ); result->PutAttribute( 2, new Piece(t.bp) ); result->PutAttribute( 3, new Field(t.bf) ); result->PutAttribute( 4, new Piece(t.ep) ); result->PutAttribute( 5, new Field(t.ef) ); return std::make_pair( true, result ); } return std::make_pair( false, new Tuple( new TupleType(type_) ) ); } static list_ostream type( ListExpr e ) { return pos_moves_blocked_op::type( e ); } private: ListExpr type_; pos_moves_blocked_op op_; }; #endif // SECONDO_ALGEBRAS_CHESS_POSITIONOPS_HPP