pgnlib: a c++ library for PGN chess games

Tutorial - 6


6. Moves and pieces

Now we know how to get the moves, but what to do with them? What about some silly statistics?

For example we could want to know how many moves, from a file full of games, each type of piece does.

First of all we need to define a bunch of counters

int main(int argc, char *argv[])
{
    try
    {
        int ply_count = 0;
        int game_count = 0;
        std::map piece_move_counters;
        piece_move_counters["king"] = 0;
        piece_move_counters["queen"] = 0;
        piece_move_counters["rook"] = 0;
        piece_move_counters["bishop"] = 0;
        piece_move_counters["knight"] = 0;
        piece_move_counters["pawn"] = 0;
	...
    }
}

By this time you know all too well how to read games from file, get each single game, etc, so I am not going to repeat this code
again (you can find the complete code in the pgnlib tarball), let's go straight to the iteration over the move list ...

int main(int argc, char *argv[])
{
	...
        for (pgn::MoveList::iterator itr2 = movelist.begin(); itr2 != movelist.end(); itr2++)
        {
               // get white and black ply from each move and pass them on to update_piece_counters() routine,
               // along with all the counters.

               ply = itr2->white();
               udpate_piece_counters(piece_move_counters, ply);
               ply_count++;

               ply = itr2->black();
               if (!ply.valid()) break;
               udpate_piece_counters(piece_move_counters, ply);
               ply_count++;
        }
	...
}

... where, for each ply read, the counters get updated by the update_piece_counters() function:

update_piece_counters(std::map &counters, const pgn::Ply &ply)
{
	// a castle move is usually considered a king move
	if (ply.isLongCastle() || ply.isShortCastle())
	{
		counters["king"] += 1;
		return;
	}
	
	switch (ply.piece().letter())
	{
		 case 'K':
			counters["king"] += 1;
			break;
		 case 'Q':
			counters["queen"] += 1;
			break;
		 case 'R':
			counters["rook"] += 1;
			break;
		 case 'B':
			counters["bishop"] += 1;
			break;
		 case 'N':
			counters["knight"] += 1;
			break;
		 case 'P':
			counters["pawn"] += 1;
			break;
	}
}

The last step is to print out the final report.

int main(int argc, char *argv[])
{
	...
        // producing a report with number of moves played by each piece.
        //

        float percentage = 0.0;

        std::cout << std::endl;
        std::cout << "Game file                      : " << fname << std::endl;
        std::cout << std::endl;
        std::cout << "Total games processed          : " << game_count << std::endl;
        std::cout << "Total moves processed          : " << ply_count << std::endl;
        std::cout << std::endl;
        percentage = 100.0 / ply_count * piece_move_counters["king"];
        std::cout << "King moves processed           : " << piece_move_counters["king"] << " (" << percentage << "%)" << std::endl;

        percentage = 100.0 / ply_count * piece_move_counters["queen"];
        std::cout << "Queen moves processed          : " << piece_move_counters["queen"] << " (" << percentage << "%)" << std::endl;

        percentage = 100.0 / ply_count * piece_move_counters["rook"];
        std::cout << "Rook moves processed           : " << piece_move_counters["rook"] << " (" << percentage << "%)" << std::endl;

        percentage = 100.0 / ply_count * piece_move_counters["bishop"];
        std::cout << "Bishop moves processed         : " << piece_move_counters["bishop"] << " (" << percentage << "%)" << std::endl;

        percentage = 100.0 / ply_count * piece_move_counters["knight"];
        std::cout << "Knight moves processed         : " << piece_move_counters["knight"] << " (" << percentage << "%)" << std::endl;

        percentage = 100.0 / ply_count * piece_move_counters["pawn"];
        std::cout << "Pawn moves processed           : " << piece_move_counters["pawn"] << " (" << percentage << "%)" << std::endl;
        std::cout << std::endl;
}

And that's the outcome against a sample file containing 466 games.


Game file                      : ./games.pgn

Total games processed          : 466
Total moves processed          : 30647

King moves processed           : 3683 (12.0175%)
Queen moves processed          : 3405 (11.1104%)
Rook moves processed           : 4690 (15.3033%)
Bishop moves processed         : 4855 (15.8417%)
Knight moves processed         : 5523 (18.0213%)
Pawn moves processed           : 8491 (27.7058%)

Time to move on something a little more interesting.

[5. Give me the moves] [home page] [7. The Position class]

SourceForge.net Logo Valid HTML 4.01!