Caro-Kann Defense Trainer
Details
Author: | Mark |
Rating: | |
Difficulty: | Beginner |
Date: | 5th March 2021 |
Description: | A trainer to help you learn and memorize the major variations of the Caro-Kann Defense. |
Code
add("1.e4 c6", "This is the Caro-Kann Defense");
add("1.e4 c6 2.Bc4", "This is the Hillbilly Attack");
add("1.e4 c6 2.d3", "This is the Breyer Variation");
add("1.e4 c6 2.c4", "This is the Accelerated Panov Attack");
add("1.e4 c6 2.Nc3 d5 3.Qf3", "This is the Goldman Variation");
add("1.e4 c6 2.Nc3 d5 3.Nf3", "This is the Two Knights Variation");
add("1.e4 c6 2.Nc3 d5 3.Nf3 Bg4", "This is the Mindeno Variation");
add("1.e4 c6 2.Nc3 d5 3.Nf3 dxe4 4.Ng5", "This is the Hector Gambit");
add("1.e4 c6 2.d4 Nf6", "This is the Caro-Masi Defense");
add("1.e4 c6 2.d4 Na6 3.Nc3 Nc7", "This is the De Bruycker Defense");
add("1.e4 c6 2.d4 d5 3.f3", "This is the Maróczy");
add("1.e4 c6 2.d4 d5 3.Be3 dxe4", "This is the Mieses");
add("1.e4 c6 2.d4 d5 3.e5", "This is the Advance Variation");
add("1.e4 c6 2.d4 d5 3.e5 Bf5 4.g4", "This is the Bayonet Attack");
add("1.e4 c6 2.d4 d5 3.e5 Bf5 4.Nf3", "This is the Short Variation");
add("1.e4 c6 2.d4 d5 3.e5 Bf5 4.Nc3", "This is the an der Wiel Attack");
add("1.e4 c6 2.d4 d5 3.Nd2", "This is the Modern Variation");
add("1.e4 c6 2.d4 d5 3.Nd2 Qb6", "This is the Edinburgh Variation");
add("1.e4 c6 2.d4 d5 3.Nf3 dxe4 4.Ng5", "This is the Ulysses");
add("1.e4 c6 2.d4 d5 3.exd5", "This is the Exchange Variation");
add("1.e4 c6 2.d4 d5 3.exd5 cxd5 4.Bd3 Nc6 5.c3 Nf6 6.Bf4", "This is the Variation");
add("1.e4 c6 2.d4 d5 3.exd5 cxd5 4.c4", "This is the Panov-Botvinnik Attack");
add("1.e4 c6 2.d4 d5 3.exd5 cxd5 4.c4 Nf6 5.c5", "This is the Panov-Botvinnik Attack, Gunderam Attack");
add("1.e4 c6 2.d4 d5 3.exd5 cxd5 4.c4 Nf6 5.Nc3 Nc6 6.Bg5", "This is the Panov-Botvinnik Attack");
add("1.e4 c6 2.d4 d5 3.exd5 cxd5 4.c4 Nf6 5.Nc3 Nc6 6.Bg5 Qb6", "This is the Panov-Botvinnik Attack, Reifir (Spielmann) Variation");
add("1.e4 c6 2.d4 d5 3.exd5 cxd5 4.c4 Nf6 5.Nc3 Nc6 6.Bg5 dxc4 7.d5 Na5", "This is the Panov-Botvinnik Attack, Herzog Defense");
add("1.e4 c6 2.d4 d5 3.exd5 cxd5 4.c4 Nf6 5.Nc3 Nc6 6.Bg5 Qa5", "This is the Panov-Botvinnik Attack, Czerniak Variation");
add("1.e4 c6 2.d4 d5 3.exd5 cxd5 4.c4 Nf6 5.Nc3 e6 6.Bg5 Nc6", "This is the Panov, Carlsbad Line");
add("1.e4 c6 2.d4 d5 3.exd5 cxd5 4.c4 Nf6 5.Nc3 g6", "This is the Panov, Fianchetto Defense");
add("1.e4 c6 2.d4 d5 3.Nc3 g6", "This is the Gurgenidze System");
add("1.e4 c6 2.d4 d5 3.Nc3 g6 4.e5 Bg7 5.f4 h5", "This is the Gurgenidze System");
add("1.e4 c6 2.d4 d5 3.Nc3 b5", "This is the Gurgenidze Counter-Attack");
add("1.e4 c6 2.d4 d5 3.Nc3 Nf6", "This is the Campomanes");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.f3", "This is the Rasa-Studier Gambit");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Bc4", "This is the von Hennig");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Nf6", "This is the Knight");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Nf6 5.Bd3", "This is the Alekhine Gambit");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Nf6 5.Nxf6+ exf6", "This is the Tartakower Variation");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Nf6 5.Nxf6+ exf6 6.Bc4", "This is the Forgacs Variation");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Nf6 5.Nxf6+ gxf6", "This is the Nimzovich variation");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Nd7", "This is the Steinitz Variation");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Bf5", "This is the Classical Variation");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Bf5 5.Ng3 Bg6 6.f4", "This is the Maroczy Attack");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Bf5 5.Ng3 Bg6 6.Nh3", "This is the Flohr Variation");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Bf5 5.Ng3 Bg6 6.h4 h6 7.Nf3", "This is the Classical");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Bf5 5.Ng3 Bg6 6.h4 h6 7.Nf3 Nd7 8.h5", "This is the Spassky Variation");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Bf5 5.Ng3 Bg6 6.h4 h6 7.Nf3 Nd7 8.h5 Bh7 9.Bd3 Bxd3 10.Qxd3 e6 11.Bd2 Ngf6 12.O-O-O Be7", "This is the Lobron System");
add("1.e4 c6 2.d4 d5 3.Nc3 dxe4 4.Nxe4 Bf5 5.Ng3 Bg6 6.h4 h6 7.Nf3 Nd7 8.h5 Bh7 9.Bd3 Bxd3 10.Qxd3 e6 11.Bd2 Ngf6 12.O-O-O Bd6", "This is the Seirawan 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);
console.log(root);
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();