Hey guys:

I'm working on a chess program for comsci, and surprisingly, the pawn is the hardest piece to program.

If you're not familiar with chess, this is the basic move of the pawn:

If the pawn is in its initial position, it can move 2 spaces forward, however, subsequent moves can only be one space forward. Secondly, it captures oponents if they are exactly one space forward and one space left or right (one diagonal space) ahead of them.

I just need to figure out how to keep track of whether a piece has moved or not. I guess I can put an if statement somewhere that determines if the piece is in the starting location, but if a pawn moves to the other side of the board, it might be considered a starting location of the opponent's side. My head hurts...

Thanks for the help!

Dani AI

Generated

A few practical points that fill gaps in the thread and keep your design clean and testable.

As discovered, canMove should be a pure, read-only predicate — do not change piece state there. Leave rule-checking inside canMove (including double-step eligibility), and perform state changes only when a move is actually executed. A simple pattern: keep a mutable flag or counter inside the pawn class, but update it from the board-level move routine (or replace the pawn object with an updated copy). Example sketch:

class Pawn : public Piece {
  bool moved = false;           // track side-effect state
public:
  bool canMove(...) const;      // does NOT modify state
  void setMoved(bool v) { moved = v; } // called by Board when move completes
};

void Board::makeMove(Pos from, Pos to) {
  Piece* p = squares[from];
  if (p->canMove(from,to,*this)) {
    // handle captures / en passant / promotion
    squares[to] = squares[from];
    squares[from] = nullptr;
    squares[to]->setMoved(true);   // non-const update happens here
  }
}

Alternatives and caveats: you can avoid storing moved by deriving eligibility from color + current rank (initial-rank check). That is simpler and perfectly valid — just be explicit about which rank is the pawn's start for each color. For en passant you do need a time context: track the turn number or the ply when a pawn made a two-square jump (store a lastDoubleJumpTurn on the pawn or a board-level last-move record) so the capture is only legal immediately after that move.

If you use a 0..63 index or bitboards (as suggested), compute forward and diagonal offsets carefully and guard against file-wrap (moves that cross the a/h boundary). Finally, add unit tests covering: single move, double move from start, blocked double move, diagonal captures, en passant window, and promotion. Keeping checks pure and state updates centralized makes those tests simple.

Recommended Answers

All 4 Replies

Pawns only go forward. if they aren't in their home row, they've moved!

if that's a problem, put a move counter on them.
If count=0, they haven't moved. Even a bit will do the job!

Ok, that makes perfect sense... I added a bool to my code, just skim along to see the lines that are commented:

class Pawn : public Piece
{
public:
	static const char SYMBOL = 'P'; 
	Pawn (Colour newColour);
	virtual bool canMove (Position start, Position end, const Board & board) const;
private:	
	bool hasMoved; // HERE IS THE BOOL!
};


Pawn::Pawn (Colour newColour) : Piece (newColour, SYMBOL)
{
	hasMoved = false; // IT IS INITIALIZED AS FALSE HERE
}


bool Pawn::canMove (Position start, Position end, const Board & board) const
{

	if (hasMoved == false) // so initially, it should be false, and it should let u go twice
	{	
		if (fabs(end.getY() - start.getY()) <= 2 && fabs(end.getX() - start.getX()) == 0)
		{
			return true; // this just means it will allow the move
		}
	}
	else // this comes in effect when hasMoved is not true
	{
		if (fabs(end.getY() - start.getY()) <= 2 && fabs(end.getX() - start.getX()) == 0)
		{
			return true;
		}
	}
	hasMoved = true; // this should set it to false for all other moves
			
}

However, I get an error:

"error: assignment of data-member ‘Pawn::hasMoved’ in read-only structure"

So, it won't allow me to assign variables in member functions?

Never mind, the member function is const :(

Pieces don't need a color. They do need an identifier to indicate which color they are. A single bit would do. bit=1:White 0:Black

All piece go in all directions except for pawns which are unidirectional. You don't need an X,Y for position, a single byte will contain positions 0...63. Moving forward is +8, etc. If you need X,Y slot index easily turns into an x,y.

The nice thing is the chessboard is 8x8 whereas it is supported within 3 bits for each axis 2^3.

White is 8...15, Black is 48...55 White pawns move (+), black pawns move (-).

You may want to think about checkers first? But good luck!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.