Pirc Defense Trainer
Details
Author: | Mark |
Rating: | |
Difficulty: | Beginner |
Date: | 24th February 2021 |
Description: | A trainer to help you learn and memorize the major variations of the Pirc Defense. |
Code
add("1.e4 d6", "This is the Pirc Defense");
add("1.e4 d6 2.d4 Nf6 3.Nf3", "This is the Roscher Gambit");
add("1.e4 d6 2.d4 Nf6 3.Nc3 c6", "This is the Ufimtsev-Pytel Variation");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.Bc4", "This is the Holmov System");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.Be2 Bg7 5.g4", "This is the Chinese Variation");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.Be2 Bg7 5.h4", "This is the Bayonet Attack");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.g3", "This is the Sveshnikov System");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.Bg5", "This is the Byrne Variation");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.Be3 c6 5.Qd2", "This is the 150 Attack");
add("1.e4 d6 2.d4 Nf6 3.Nc3 Nbd7 4.f4 e5", "This is the Jansen Variation");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.Nf3", "This is the Two Knights System");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.Nf3 Bg7 5.h3", "This is the Schlechter Variation");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.Nf3 Bg7 5.Be2", "This is the Quiet System");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.f4", "This is the Austrian Attack");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.f4 Bg7 5.Bc4", "This is the Ljubojevic Variation");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.f4 Bg7 5.Nf3 c5", "This is the Austrian, Dragon Formation");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.f4 Bg7 5.Nf3 0-0 6.Be3", "This is the Kurajica Variation");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.f4 Bg7 5.Nf3 0-0 6.e5", "This is the Unzicker Attack");
add("1.e4 d6 2.d4 Nf6 3.Nc3 g6 4.f4 Bg7 5.Nf3 0-0 6.Bd3", "This is the Weiss Variation");
function add(line, name) {
let dict = (Window.dict || (Window.dict = {}));
let notes = (Window.notes || (Window.notes = {}));
let split = parseLine(line);
let temp = dict;
for (let move of split) {
if (temp[move] != undefined)
{
temp = temp[move];
}
else
{
temp[move] = {};
temp = temp[move];
}
}
temp.id = nextID();
notes[temp.id] = name;
}
function nextID() {
Window.nextInt = (Window.nextInt || 0) + 1;
return Window.nextInt;
}
function parseLine(line) {
line = line.replace("\r\n", " ");
line = line.replace(" ", " ");
let split = [];
let regex = /(?:(\d+)(?:\.+|…)\s?)([^\s]+)(?:\s(\w[^\s\.…]+))?/g;
let match = regex.exec(line);
do {
let moveIndex = parseInt(match[1]);
//set it relative to 0
moveIndex--;
if (moveIndex * 2 > split.length + 1) {
throw new Error();
}
split.push(match[2]);
if (match[3] != undefined) {
split.push(match[3]);
}
} while ((match = regex.exec(line)) !== null);
return split;
}
function buildList(list, dict) {
let notes = (Window.notes || (Window.notes = {}));
let keys = Object.keys(dict);
const index = keys.indexOf("id");
if (index > -1) {
keys.splice(index, 1);
}
switch (keys.length) {
case 0:
if (notes[dict.id] != undefined) {
list.push({
info: notes[dict.id]
});
notes[dict.id] = undefined;
}
break;
case 1:
let key = keys[0];
//we can add it directly
list.push(key);
if(notes[dict[key].id] != undefined) {
list.push({
info: notes[dict[key].id]
});
notes[dict[key].id] = undefined;
}
//and send the same list through for the submoves
buildList(list, dict[key]);
break;
default:
for (let key of keys) {
let subList = [];
subList.push(key);
if(notes[dict[key].id] != undefined) {
subList.push({
info: notes[dict[key].id]
});
notes[dict[key].id] = undefined;
}
list.push(subList);
buildList(subList, dict[key]);
}
break;
}
}
function sortMoves(moves) {
moves.sort(function(a, b) {
let aSource = sourceOfSan(a);
let bSource = sourceOfSan(b);
if(aSource.substr(0, 1) != bSource.substr(0, 1)) {
return aSource.charCodeAt(0) - bSource.charCodeAt(0);
}
if(aSource.substr(1, 1) != bSource.substr(1, 1)) {
return bSource.charCodeAt(1) - aSource.charCodeAt(1);
}
let aDest = destOfSan(a);
let bDest = destOfSan(b);
if(aDest.substr(0, 1) != bDest.substr(0, 1)) {
return aDest.charCodeAt(0) - bDest.charCodeAt(0);
}
if(aDest.substr(1, 1) != bDest.substr(1, 1)) {
return bDest.charCodeAt(1) - aDest.charCodeAt(1);
}
return 0;
});
}
let root = [];
buildList(root, Window.dict);
let targetMove = "";
onPieceClicked(function (squareName) {
if (typeof targetMove == "string") {
if (squareName == sourceOfSan(targetMove)) {
return true;
}
} else if (Array.isArray(targetMove)) {
for (let temp of targetMove) {
if (squareName == sourceOfSan(temp)) {
return true;
}
}
} else {
throw new Error();
}
if (targetMove == "") {
return false;
}
if (squareName == sourceOfSan(targetMove)) {
return true;
}
highlightSquareRed(squareName);
return false;
});
onMoveAttempted(function (san) {
if (typeof targetMove == "string") {
if (san == targetMove) {
current.index++;
setTimeout(next, 50);
return true;
}
} else if (Array.isArray(targetMove)) {
for (let temp of targetMove) {
if (san == temp) {
for (let i = current.index; i < current.length; i++) {
if (current[i][0] == san) {
current[i].parent = current;
current = current[i];
current.index = 1;
break;
}
}
setTimeout(next, 50);
return true;
}
}
} else {
throw new Error();
}
return false;
});
onNextClicked(function () {
showNextButton(false);
next();
});
function nextDelayed() {
setTimeout(next, 500);
}
function onUndoClicked() {
undo();
if (current.index > 0) {
current.index--;
if (current.index > 0 && current[current.index].info != undefined) {
current.index--;
}
}
if (current.index == 0) {
if (current.parent != undefined) {
current = current.parent;
} else {
//showButton("undo", false);
}
}
next();
}
let current = root;
current.index = 0;
let preInfo = "";
let flipped = false;
createButton("Flip", function () {
blackAtTop(flipped);
flipped = !flipped;
});
createButton("Undo", onUndoClicked);
showButton("Undo", false);
let undoButtonVisible = false;
function next() {
let showUndoButton = current != root || current.index > 0;
if (undoButtonVisible != showUndoButton) {
showButton("Undo", showUndoButton);
undoButtonVisible = showUndoButton;
}
if (preInfo != "") {
preInfo += "<br><br>";
}
if (current.index >= current.length) {
info(preInfo + "End of the line");
preInfo = "";
return;
}
let step = current[current.index];
if (typeof step == "string") {
if (isWhitesTurn()) {
info(preInfo + "White to play <b>" + currentMoveNumber() + "." + step + "</b>");
} else {
info(preInfo + "Black to play <b>" + currentMoveNumber() + "..." + step + "</b>");
}
targetMove = step;
preInfo = "";
} else if (Array.isArray(step)) {
///assume that the rest of the steps in the current array are also arrays
//i.e. different options from this point
let possibleSteps = [];
for (let i = current.index; i < current.length; i++) {
//assume that the first step in every array is a string
//otherwise it would be seperated out into an array at the previous level
possibleSteps.push(current[i][0]);
}
sortMoves(possibleSteps);
targetMove = possibleSteps;
if (isWhitesTurn()) {
possibleSteps = possibleSteps.map(x => "<li><b>" + currentMoveNumber() + "." + x + "</b></li>");
info(preInfo + "White can play: <ul>" + possibleSteps.join("") + "</ul>");
} else {
possibleSteps = possibleSteps.map(x => "<li><b>" + currentMoveNumber() + "..." + x + "</b></li>");
info(preInfo + "Black can play: <ul>" + possibleSteps.join("") + "</ul>");
}
preInfo = "";
} else {
if (step.info != undefined) {
preInfo = step.info;
current.index++;
next();
}
}
}
next();