Normalizing a board game notation

43 Views Asked by At

I have a board game notation for the game of Hnefatafl which I need to rotate clockwise. In the game of Hnefatafl we use a 11x11 board with files from A to K and ranks numbered from 1 to 11. So, here are the first three moves from the notation:

"1.k8-i8 g7-j7; 2.k5-j5 h6-h9; 3.k7-k9 f8-c8;"

After the rotation the notation must be like this:

"1.h1-h3 g5-g2; 2.e1-e2 f4-i4; 3.g1-i1 h6-h9;"

How can I rotate the board and normalize the notation by using a JavaScript function?

1

There are 1 best solutions below

0
nullromo On

When you rotate the board, you can see that anything that used to be in file A is now in rank 11; anything that was in file K is now in rank 1, etc.

In general, take the rank letter's ordinal position and subtract it from 11.

old file old file ascii value subtract 97 (ordinal position) new rank (11 - ordinal)
'a' 97 0 11
'b' 98 1 10
'c' 99 2 9
... ... ... ...
'k' 107 10 1

Likewise, the old ranks can get mapped in a similar way

old rank new file
1 a
2 b
3 c
...
11 k

So if your coordinates are of the form:

{
    file: 'a',
    rank: 11,
}

then you can just transform them using a function like this:

const transform = (oldSpace) => {
    return {
        rank: 11 - (oldSpace.file.charCodeAt(0) - 97)
        file: String.fromCharCode(oldSpace.rank + 96)
    };
};

Then you can just transform them to the new coordinate system.

console.log(transform({ file: 'k', rank: 8 })); // => h1
console.log(transform({ file: 'i', rank: 8 })); // => h3
console.log(transform({ file: 'g', rank: 7 })); // => g5
console.log(transform({ file: 'j', rank: 7 })); // => g2

Sample implementation

const transform = (oldSpace) => {
    const match = oldSpace.match(/^(?<file>\w)(?<rank>\d+)$/);
    const file = String.fromCharCode(Number(match.groups.rank) + 96);
    const rank = 11 - (match.groups.file.charCodeAt(0) - 97);
    return `${rank}${file}`;
};

const parseTurn = (turn) => {
    const match = turn.match(
        /^(?<turnNumber>\d)\.(?<first>\w\d+)-(?<second>\w\d+) (?<third>\w\d+)-(?<fourth>\w\d+)$/,
    );
    return {
        turnNumber: parseInt(turn, 10),
        first: match.groups.first,
        second: match.groups.second,
        third: match.groups.third,
        fourth: match.groups.fourth,
    };
};

const transformGame = (input) => {
    return input
        .split(';')
        .filter((turn) => {
            return Boolean(turn);
        })
        .map((turn) => {
            return parseTurn(turn.trim());
        })
        .map((turn) => {
            return {
                turnNumber: turn.turnNumber,
                first: transform(turn.first),
                second: transform(turn.second),
                third: transform(turn.third),
                fourth: transform(turn.fourth),
            };
        })
        .map((turn) => {
            return `${turn.turnNumber}.${turn.first}-${turn.second} ${turn.third}-${turn.fourth};`;
        })
        .join(' ');
};

const input = '1.k8-i8 g7-j7; 2.k5-j5 h6-h9; 3.k7-k9 f8-c8;';
console.log(input);
console.log(transformGame(input));

Output:

1.k8-i8 g7-j7; 2.k5-j5 h6-h9; 3.k7-k9 f8-c8;
1.1h-3h 5g-2g; 2.1e-2e 4f-4i; 3.1g-1i 6h-9h;