Alekhine's Defense Trainer
Details
Author: | Mark |
Rating: | |
Difficulty: | Beginner |
Date: | 23rd February 2021 |
Description: | A trainer to help you learn and memorize the major variations of the Alekhine's Defense. |
Code
add("1.e4 Nf6", "This is Alekhine's Defense");
add("1.e4 Nf6 2.d3", "This is the Maroczy Variation");
add("1.e4 Nf6 2.d4", "This is the Omega Gambit");
add("1.e4 Nf6 2.Bc4", "This is the Krejcik Variation");
add("1.e4 Nf6 2.Nc3 d5", "This is the Scandinavian Variation");
add("1.e4 Nf6 2.Nc3 d5 3.e5 Nfd7 4.e6", "This is the Spielmann Variation");
add("1.e4 Nf6 2.e5 Ne4", "This is the Mokele Mbembe (Buecker) Variation");
add("1.e4 Nf6 2.e5 Ng8", "This is the Alekhine: Brooklyn");
add("1.e4 Nf6 2.e5 Ng8 3.d4 Nc6 4.d5 Nb8", "This is the Brooklyn DefenSe");
add("1.e4 Nf6 2.e5 Nd5 3.b3", "This is the Welling Variation");
add("1.e4 Nf6 2.e5 Nd5 3.Bc4 Nb6 4.Bb3 c5 5.d3", "This is the Kmoch Variation");
add("1.e4 Nf6 2.e5 Nd5 3.Nc3", "This is the Saemisch Attack");
add("1.e4 Nf6 2.e5 Nd5 3.c4", "This is the Two Pawns Attack");
add("1.e4 Nf6 2.e5 Nd5 3.c4 Nb6 4.b3", "This is the Steiner Variation");
add("1.e4 Nf6 2.e5 Nd5 3.c4 Nb6 4.d4 d6 5.Nf3 Bg4 6.Be2 dxe5 7.Nxe5", "This is the Alekhine: Two Pawns (Alekhine)");
add("1.e4 Nf6 2.e5 Nd5 3.c4 Nb6 4.d4 d6 5.exd6 cxd6 6.h3 g6 7.Nf3", "This is the Alekhine: Two Pawns (Karpov)");
add("1.e4 Nf6 2.e5 Nd5 3.c4 Nb6 4.c5", "This is the Two Pawns' (Lasker's) Attack");
add("1.e4 Nf6 2.e5 Nd5 3.c4 Nb6 4.c5 Nd5 5.Bc4 e6 6.Nc3 d5", "This is the Two Pawns' Attack, Mikenas Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.b5", "This is the O'Sullivan Gambit");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.Bc4", "This is the Balogh Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.c4", "This is the Alekhine: Hunt");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.c4 Nb6 5.exd6", "This is the Exchange Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.c4 Nb6 5.f4", "This is the Four Pawns Attack");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.c4 Nb6 5.f4 g6", "This is the Four Pawns Attack, Fianchetto Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.c4 Nb6 5.f4 Bf5", "This is the Four Pawns Attack, Trifunovic Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.c4 Nb6 5.f4 g5", "This is the Four Pawns Attack, Planinc Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.c4 Nb6 5.f4 dxe5 6.fxe5 Bf5 7.Nc3 e6 8.Nf3 Be7 9.Be2 O-O 10.O-O f6", "This is the Four Pawns Attack, Korchnoi Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.c4 Nb6 5.f4 dxe5 6.fxe5 Nc6 7.Be3 Bf5 8.Nc3 e6 9.Nf3 Qd7 10.Be2 O-O-0 11.O-O Be7", "This is the Four Pawns Attack, Tartakower Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.c4 Nb6 5.f4 dxe5 6.fxe5 Nc6 7.Nf3 Bg4 8.e6 fxe6 9.c5", "This is the Four Pawns Attack, Ilyin-Genevsky Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 3.d6 4.c4 Nb6 5.f4 dxe5 6.fxe5 Bf5 7.Nc3 e6 8.Nf3 Bb4 9Bd3", "This is the Four Pawns Attack, Fahrni Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 d6 4.Nf3", "This is the Modern Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 d6 4.Nf3 4.Nb6", "This is the Modern, Schmid Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 d6 4.Nf3 4.dxe5", "This is the Modern, Larsen Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 d6 4.Nf3 4.g6", "This is the Modern, Alburt Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 d6 4.Nf3 4.g6 5.c4 Nb6 6.exd6 cxd6 7.h3 Bg7 8.Be2 O-O 9.Nc3 Nc6 10.O-O Bf5 11.Bf4", "This is the Modern, Karpov Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 d6 4.Nf3 4.g6 5.Bc4 Nb6 6.Bb3 Bg7 7.a4", "This is the Modern, Keres Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 d6 4.Nf3 Bg4 5.h3", "This is the Modern, Panov Variation");
add("1.e4 Nf6 2.e5 Nd5 3.d4 d6 4.Nf3 Bg4 5.c4 Nb6 6.d5", "This is the Modern, Vitolins Attack");
add("1.e4 Nf6 2.e5 Nd5 3.d4 d6 4.Nf3 Bg4 5.Be2 c6", "This is the Modern, Flohr 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();