Task 529: .PDN File Format
Task 529: .PDN File Format
File Format Specifications for the .PDN File Format
The .PDN file format is the Portable Draughts Notation (PDN), a text-based standard for recording games of draughts (also known as checkers). It is analogous to the Portable Game Notation (PGN) for chess. The format consists of a series of key-value tags in square brackets (e.g., [Event "Tournament Name"]) followed by the sequence of moves and optional comments or variations. The official specification is PDN 3.0, which defines the syntax, tags, move notation, and parsing rules. The full specification can be found in the PDF document at https://wiegerw.github.io/pdn/pdf/pdn_standard.pdf. The format supports various draughts variants, board sizes, and additional metadata like initial positions via FEN.
- List of all the properties of this file format intrinsic to its file system:
The properties are the standard tags defined in the PDN specification. These are key-value pairs that provide metadata about the game. The core "Seven Tag Roster" (STR) tags are required in standard PDN files, while others are optional. Here is the complete list of common properties (tags) and their meanings:
- Event: The name of the tournament or match event.
- Site: The location of the event.
- Date: The starting date of the game (in YYYY.MM.DD format, with ? for unknown parts).
- Round: The playing round ordinal of the game (e.g., "1" or "3.2").
- White: The player or team playing with the white pieces.
- Black: The player or team playing with the black pieces.
- Result: The outcome of the game (e.g., "1-0" for white wins, "0-1" for black wins, "1/2-1/2" for draw, "*" for unfinished).
- GameType: Specifies the draughts variant, board size, notation type, etc. (e.g., "20" for international 10x10 draughts).
- FEN: The initial board position using Forsyth-Edwards Notation (FEN) for non-standard starting positions.
- SetUp: Indicates if a custom initial position is used via FEN (value "1" if yes).
- TimeControl: The time control rules (e.g., "40/1200" for 40 moves in 1200 seconds).
- Time: The local time when the game started (HH:MM:SS).
- UTCDate: The UTC date of the game (YYYY.MM.DD).
- UTCTime: The UTC time of the game (HH:MM:SS).
- Annotator: The name of the person who annotated the game.
- Publication: Information about where the game was published.
- Mode: The mode of play (e.g., "OTB" for over-the-board, "ICS" for internet chess server).
- Termination: The reason the game ended (e.g., "normal", "time forfeit", "rules infraction").
- PlyCount: The number of half-moves (ply) in the game.
These tags are followed by the move list (e.g., 1. 32-28 19-23 2. 37-32 14-19), optional comments in braces {}, and variations in parentheses ().
- Two direct download links for files of format .PDN:
- https://www.ffjd.fr/dataGames/games/1wk.team/2005/4_3_italie_inde.pdn
- https://onlinecheckerslibrary.com/pool/Russian/games/Abaulin.files/Abaulin.pdn
- Ghost blog embedded html javascript that allows a user to drag n drop a file of format .PDN and it will dump to screen all these properties.
The following is an HTML snippet with JavaScript that can be embedded in a Ghost blog post. It creates a drag-and-drop area. When a .PDN file is dropped, it reads the text, parses the tags using a regex, and displays the properties in a list on the screen.
- Python class that can open any file of format .PDN and decode read and write and print to console all the properties from the above list.
import re
class PDNHandler:
def __init__(self):
self.properties = {}
def read(self, filename):
with open(filename, 'r') as f:
text = f.read()
regex = r'\[(\w+)\s+"(.*?)"\]'
matches = re.findall(regex, text)
self.properties = {key: value for key, value in matches}
self.print_properties()
def print_properties(self):
print("PDN Properties:")
for key, value in self.properties.items():
print(f"{key}: {value}")
def write(self, filename, moves=''):
with open(filename, 'w') as f:
for key, value in self.properties.items():
f.write(f'[{key} "{value}"]\n')
f.write('\n' + moves + '\n*') # Add moves and terminator if provided
# Example usage:
# handler = PDNHandler()
# handler.read('example.pdn')
# handler.properties['Event'] = 'New Event'
# handler.write('new.pdn', '1. 32-28 19-23')
- Java class that can open any file of format .PDN and decode read and write and print to console all the properties from the above list.
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class PDNHandler {
private Map<String, String> properties = new HashMap<>();
public void read(String filename) throws IOException {
StringBuilder text = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = br.readLine()) != null) {
text.append(line).append("\n");
}
}
Pattern pattern = Pattern.compile("\\[(\\w+)\\s+\"(.*?)\"\\]");
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
properties.put(matcher.group(1), matcher.group(2));
}
printProperties();
}
public void printProperties() {
System.out.println("PDN Properties:");
for (Map.Entry<String, String> entry : properties.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
public void write(String filename, String moves) throws IOException {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(filename))) {
for (Map.Entry<String, String> entry : properties.entrySet()) {
bw.write("[" + entry.getKey() + " \"" + entry.getValue() + "\"]\n");
}
bw.write("\n" + moves + "\n*");
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// PDNHandler handler = new PDNHandler();
// handler.read("example.pdn");
// handler.properties.put("Event", "New Event");
// handler.write("new.pdn", "1. 32-28 19-23");
// }
}
- Javascript class that can open any file of format .PDN and decode read and write and print to console all the properties from the above list.
(Note: JavaScript in browser/Node; this example assumes Node.js with fs module for read/write. For browser, use FileReader as in part 3.)
const fs = require('fs');
class PDNHandler {
constructor() {
this.properties = {};
}
read(filename) {
const text = fs.readFileSync(filename, 'utf8');
const regex = /\[(\w+)\s+"(.*?)"\]/g;
let match;
while ((match = regex.exec(text)) !== null) {
this.properties[match[1]] = match[2];
}
this.printProperties();
}
printProperties() {
console.log('PDN Properties:');
for (const [key, value] of Object.entries(this.properties)) {
console.log(`${key}: ${value}`);
}
}
write(filename, moves = '') {
let content = '';
for (const [key, value] of Object.entries(this.properties)) {
content += `[${key} "${value}"]\n`;
}
content += `\n${moves}\n*`;
fs.writeFileSync(filename, content);
}
}
// Example usage:
// const handler = new PDNHandler();
// handler.read('example.pdn');
// handler.properties.Event = 'New Event';
// handler.write('new.pdn', '1. 32-28 19-23');
- C class that can open any file of format .PDN and decode read and write and print to console all the properties from the above list.
(Note: C doesn't have built-in classes, so this is a C++ class for simplicity.)
#include <iostream>
#include <fstream>
#include <string>
#include <regex>
#include <map>
class PDNHandler {
private:
std::map<std::string, std::string> properties;
public:
void read(const std::string& filename) {
std::ifstream file(filename);
std::string text((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
std::regex regex(R"(\[(\w+)\s+"(.*?)"\])");
std::sregex_iterator iter(text.begin(), text.end(), regex);
std::sregex_iterator end;
for (; iter != end; ++iter) {
properties[(*iter)[1].str()] = (*iter)[2].str();
}
printProperties();
}
void printProperties() {
std::cout << "PDN Properties:" << std::endl;
for (const auto& pair : properties) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
}
void write(const std::string& filename, const std::string& moves) {
std::ofstream file(filename);
for (const auto& pair : properties) {
file << "[" << pair.first << " \"" << pair.second << "\"]" << std::endl;
}
file << std::endl << moves << std::endl << "*";
}
};
// Example usage:
// int main() {
// PDNHandler handler;
// handler.read("example.pdn");
// handler.properties["Event"] = "New Event";
// handler.write("new.pdn", "1. 32-28 19-23");
// return 0;
// }