lila/ui/analyse/src/forecast/forecastCtrl.js

150 lines
3.6 KiB
JavaScript

var m = require('mithril');
var partial = require('chessground').util.partial;
module.exports = function(cfg, saveUrl) {
var forecasts = cfg.steps || [];
var loading = m.prop(false);
var keyOf = function(fc) {
return fc.map(function(step) {
return step.ply + ':' + step.uci;
}).join(',');
};
var contains = function(fc1, fc2) {
return fc1.length >= fc2.length && keyOf(fc1).indexOf(keyOf(fc2)) === 0;
};
var findStartingWithStep = function(step) {
return forecasts.filter(function(fc) {
return contains(fc, [step]);
});
};
var collides = function(fc1, fc2) {
var res = (function() {
for (var i = 0, max = Math.min(fc1.length, fc2.length); i < max; i++) {
if (fc1[i].uci !== fc2[i].uci) {
if (cfg.onMyTurn) return i !== 0 && i % 2 === 0;
return i % 2 === 1;
}
}
return true;
})();
return res;
};
var truncate = function(fc) {
if (cfg.onMyTurn)
return (fc.length % 2 !== 1 ? fc.slice(0, -1) : fc).slice(0, 30);
// must end with player move
return (fc.length % 2 !== 0 ? fc.slice(0, -1) : fc).slice(0, 30);
};
var isLongEnough = function(fc) {
return fc.length >= (cfg.onMyTurn ? 1 : 2);
};
var fixAll = function() {
// remove contained forecasts
forecasts = forecasts.filter(function(fc, i) {
return forecasts.filter(function(f, j) {
return i !== j && contains(f, fc)
}).length === 0;
});
// remove colliding forecasts
forecasts = forecasts.filter(function(fc, i) {
return forecasts.filter(function(f, j) {
return i < j && collides(f, fc)
}).length === 0;
});
};
fixAll();
var reloadToLastPly = function() {
loading(true);
m.redraw();
if (window.history.replaceState) window.history.replaceState(null, null, '#last');
location.reload();
};
var isCandidate = function(fc) {
fc = truncate(fc);
if (!isLongEnough(fc)) return false;
var collisions = forecasts.filter(function(f) {
return contains(f, fc);
});
if (collisions.length) return false;
return true;
};
var save = function() {
if (cfg.onMyTurn) return;
loading(true);
m.redraw();
m.request({
method: 'POST',
url: saveUrl,
data: forecasts
}).then(function(data) {
if (data.reload) reloadToLastPly();
else {
loading(false);
forecasts = data.steps || [];
}
});
};
var playAndSave = function(step) {
if (!cfg.onMyTurn) return;
loading(true);
m.redraw();
m.request({
method: 'POST',
url: saveUrl + '/' + step.uci,
data: findStartingWithStep(step).filter(function(fc) {
return fc.length > 1;
}).map(function(fc) {
return fc.slice(1);
})
}).then(function(data) {
if (data.reload) reloadToLastPly();
else {
loading(false);
forecasts = data.steps || [];
}
});
};
return {
addSteps: function(fc) {
fc = truncate(fc);
if (!isCandidate(fc)) return;
fc.forEach(function(step) {
delete step.variations;
});
forecasts.push(fc);
fixAll();
save();
},
isCandidate: isCandidate,
removeIndex: function(index) {
forecasts = forecasts.filter(function(fc, i) {
return i !== index;
});
save();
},
list: function() {
return forecasts;
},
truncate: truncate,
loading: loading,
onMyTurn: cfg.onMyTurn,
findStartingWithStep: findStartingWithStep,
playAndSave: playAndSave,
reloadToLastPly: reloadToLastPly
};
};