You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ygdc/assets/js/views/xoi/logic.js

543 lines
14 KiB

2 months ago
import { computed } from "vue";
/////////////////////////////////////////
// Helper
/////////////////////////////////////////
2 months ago
function setPoints(page, set){
let points = [0, 0]; // need to get updated for more player
let ret;
const m = page.game.sets.length-1;
for (const i in page.game.sets) {
const set = page.game.sets[i];
const points = legPoints(page, set, set.legs[set.legs.length-1]);
const winner = getWinner(points, page.legs);
if (winner > -1)
points[winner] += 1;
else
return points;
if (set == set){
return points;
}
}
return points;
}
function legPoints(page, set, leg){
let points = [0, 0]; // need to get updated for more player
let ret;
const m = set.legs.length-1;
for (const i in set.legs) {
const l = set.legs[i];
if (l.visits[l.visits.length-1].toGo === undefined) {
return points;
}
if (l.visits[l.visits.length-1].toGo[0] == 0)
points[0] += 1;
else if (l.visits[l.visits.length-1].toGo[1] == 0)
points[1] += 1;
if (l == leg){
return points;
}
}
return points;
}
function newPlayerStats(player) {
return {
player: player.uuid,
average: [0, 0],
first9: [0, 0],
checkouts: [0, 0],
2 months ago
checkins: [0, 0],
checkinPoints: [],
2 months ago
checkoutPoints: [],
"60+": 0,
"100+": 0,
"140+": 0,
"180": 0
};
}
function addNewSetStats(stats, scorers) {
stats["sets"].push(newStats(scorers));
2 months ago
stats["sets"][0]["legs"] = [];
return stats;
}
function addNewLegStats(stats, scorers) {
stats["sets"].at(-1)["legs"].push(newStats(scorers));
2 months ago
return stats;
}
function newStats(scorers) {
2 months ago
const stats = {
stats: []
}
scorers.forEach((scorer) => {
scorer.member.forEach((player) => {
const n = newPlayerStats(player);
stats.stats.push(n);
});
2 months ago
});
return stats;
}
function newVisit(playerUUID, round) {
return {
player: playerUUID,
throws: [],
visit: round,
checkoutTries: 0,
2 months ago
checkinTries: 0,
2 months ago
numDarts: 0,
}
}
function clearLastVisit(page){
const set = page.game.sets[page.game.sets.length-1];
const leg = set.legs[set.legs.length-1];
const visit = leg.visits[leg.visits.length-1];
const ret = visit["throws"];
visit["throws"] = [];
visit["checkoutTries"] = 0;
visit["checkinTries"] = 0;
visit["numDarts"] = 0;
delete visit["sum"];
delete visit["toGo"];
return ret;
}
function getWinner(points, mode) {
const sorted = [...points].map((e,i) => [e,i]).sort((a, b) => b[0] - a[0]);
const k = points.length;
const sum = points.reduce((a,c) => a+c, 0);
if (sum < mode && sorted[0][0] <= mode/k){
// not over yet
return -1;
}
if (sorted[0][0] == sorted[1][0]){
// Draw
return -2;
}
// winner id
return sorted[0][1];
}
function addNewSet(page){
const set = page.game.sets[page.game.sets.length-1];
const k = player2scorer(page)[set.legs[0].visits[0].player];
const p = page.scorers[(k+1)%2].member[0].uuid;
page.game.sets.push({
// points: [...points],
legs: [{
points: Array(2).fill(0),
visits: [newVisit(p, 1)]
}]
});
}
function addNewLeg(page){
const set = page.game.sets[page.game.sets.length-1];
const leg = set.legs[set.legs.length-1];
const k = player2scorer(page)[leg.visits[0].player];
console.log(k, k+1);
const p = page.scorers[(k+1)%2].member[0].uuid;
page.game.sets[page.game.sets.length-1].legs.push({
// points: [...points],
visits: [newVisit(p, 1)]
});
}
/////////////////////////////////////////
// Exports
/////////////////////////////////////////
export function playerFromUUID(uuid, players){
return players[players.map((p) => p.uuid).indexOf(uuid)];
}
export const getFinalWinner = (page) => {
const points = setPoints(page, page.sets[page.sets.length-1]);
return getWinner(points, page.sets);
};
export function initStats(page) {
const stats = newStats(page.scorers);
stats.sets = [];
addNewSetStats(stats, page.scorers);
addNewLegStats(stats, page.scorers);
page.stats = stats;
2 months ago
}
export function initGame(page) {
page.game = {
sets: [{
points: new Array(2).fill(0),
2 months ago
legs: [{
points: new Array(2).fill(0),
visits: [newVisit(page.scorers[0].member[0].uuid, 1)]
2 months ago
}]
}]
}
}
function updateStats(page, visit){
const playerUUIDs = allPlayers(page).map((p) => p.uuid);
2 months ago
const k = playerUUIDs.indexOf(visit.player);
const todos = [page.stats["stats"][k]];
todos.push(page.stats["sets"].at(-1)["stats"][k]);
todos.push(page.stats["sets"].at(-1)["legs"].at(-1)["stats"][k]);
todos.forEach((value, i) => {
todos[i]["average"][0] += visit["sum"];
todos[i]["average"][1] += visit["numDarts"];
if (visit["visit"] < 4) {
todos[i]["first9"][0] += visit["sum"];
todos[i]["first9"][1] += visit["numDarts"];
}
if (visit["toGo"][k] == 0) {
todos[i]["checkouts"][0] += 1;
todos[i]["checkoutPoints"].push(visit["sum"]);
}
2 months ago
if (visit["checkinTries"] != 0 && visit["sum"] != 0) {
todos[i]["checkins"][0] += 1;
todos[i]["checkinPoints"].push(visit["sum"]);
}
2 months ago
todos[i]["checkouts"][1] += visit["checkoutTries"];
2 months ago
todos[i]["checkins"][1] += visit["checkinTries"];
2 months ago
if (visit["sum"] == 180) {
todos[i]["180"] += 1;
} else if (visit["sum"] >= 140) {
todos[i]["140+"] += 1;
} else if (visit["sum"] >= 100) {
todos[i]["100+"] += 1;
} else if (visit["sum"] >= 60) {
todos[i]["60+"] += 1;
}
});
}
function getNextPlayer(page, visit) {
2 months ago
const set = page.game.sets[page.game.sets.length-1];
const leg = set.legs[set.legs.length-1];
const offset = 1*(leg.visits[0].player == page.scorers[0].member[0].uuid);
const order = [];
for (let index = 0; index < page.scorers[0].member.length; index++) {
order.push(page.scorers[1-offset].member[index].uuid);
order.push(page.scorers[offset].member[index].uuid);
}
const nextid = (order.indexOf(visit.player)+1);
return [order[nextid%order.length], (nextid == order.length)];
2 months ago
}
export function player2scorer(page){
return Object.entries(page.scorers).reduce((result, [scorersId, scorer]) => {
// Use the map method to create an array of key-value pairs for each "member"
scorer.member.forEach(player => {
result[player.uuid] = parseInt(scorersId);
});
return result;
}, {});
2 months ago
}
export function allPlayers(page){
return Object.entries(page.scorers).reduce((result, [scorersId, scorer]) => {
return result.concat(scorer.member);
}, []);
2 months ago
}
export const formatDate = (d) => {
return `${d.getFullYear()}-${(d.getMonth()+1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')} ${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;
};
2 months ago
export function recalcStats(page){
// const set = page.game.sets[page.game.sets.length-1];
2 months ago
// const leg = set.legs[set.legs.length-1];
// const visit = leg.visits[leg.visits.length-1];
initStats(page);
const lastset = page.game["sets"].length-1;
page.game["sets"].forEach((set, i) => {
const lastleg = set.legs.length-1;
set.legs.forEach((leg, j) => {
const lastvisit = leg["visits"].length-1;
leg.visits.forEach((visit, k) => {
if (!(k == lastvisit && j == lastleg && i == lastset)) {
updateStats(page, visit);
}
if (k == lastvisit && j != lastleg) {
addNewLegStats(page.stats, page.scorers);
2 months ago
}
});
if (j == lastleg && i != lastset) {
addNewSetStats(page.stats, page.scorers);
2 months ago
}
});
});
}
export function removeLastVisit(page){
const set = page.game.sets[page.game.sets.length-1];
const leg = set.legs[set.legs.length-1];
// const visit = leg.visits[leg.visits.length-1];
2 months ago
// delete last visit.
leg["visits"].pop();
if (leg["visits"].length == 0){
set["legs"].pop();
if (set["legs"].length == 0){
page.game["sets"].pop();
if (page.game["sets"].length == 0){
initGame(page);
return;
}
}
}
// clearLastVisit
const ret = clearLastVisit(page);
recalcStats(page);
return ret;
}
2 months ago
export function storeVisit(page, throws, sum, numDarts, outTries, inTries=0) {
2 months ago
const set = page.game.sets[page.game.sets.length-1];
const leg = set.legs[set.legs.length-1];
const visit = leg.visits[leg.visits.length-1];
visit["numDarts"] = numDarts;
visit["throws"] = throws;
2 months ago
visit["checkoutTries"] = outTries;
visit["checkinTries"] = inTries;
2 months ago
visit["sum"] = sum
const k = player2scorer(page)[visit["player"]];
2 months ago
let toGo;
if (leg["visits"].length-2 < 0) {
toGo = Array(2).fill(page.modus);
2 months ago
} else {
toGo = [...leg["visits"][leg["visits"].length-2]["toGo"]];
}
const rest = toGo[k] - visit["sum"];
if (rest < 0 || (page.out == "Double" && rest == 1)) {
visit["sum"] = 0;
} else {
toGo[k] = rest;
}
visit["toGo"] = toGo;
2 months ago
if (page.in != "Straight" && page.modus == toGo[k] && visit["sum"] == 0) {
visit["checkinTries"] = 3;
}
2 months ago
// update stats
updateStats(page, visit);
let update = [];
if (rest != 0) {
// Normal case...next players turn
const [nextPlayer, newRound] = getNextPlayer(page, visit);
const nVisit = newVisit(nextPlayer, visit["visit"]+1*newRound);
2 months ago
leg.visits.push(nVisit);
}
else {
// rest == 0 leg finished
const newlegp = legPoints(page, set, leg);
let winner = getWinner(newlegp, page.legs);
if (winner == -1) {
// new Leg
addNewLeg(page);
addNewLegStats(page.stats, page.scorers);
2 months ago
} else {
// new set?
const newsetp = setPoints(page, set);
winner = getWinner(newsetp, page.sets);
if (winner == -1) {
// new Set
addNewSet(page);
addNewSetStats(page.stats, page.scorers);
addNewLegStats(page.stats, page.scorers);
2 months ago
} else {
// ask for continue or game over
if (winner == -2) {
page.stats["winner"] = "DRAW";
} else {
page.stats["winner"] = visit["player"];
}
page.enddate = formatDate(new Date(Date.now()));
return [newsetp, newlegp];
}
}
}
return false;
}
export function endGame(page){
// const set = page.game.sets[page.game.sets.length-1];
// const leg = set.legs[set.legs.length-1];
// const visit = leg.visits[leg.visits.length-1];
// const winner = getWinner(newsetp, page.sets);
// set["points"] = newsetp;
// leg["points"] = newlegp;
}
export function extension(page){
const set = page.game.sets[page.game.sets.length-1];
const leg = set.legs[set.legs.length-1];
page.enddate = undefined;
2 months ago
// leg["points"] = newlegp;
// new Leg
addNewLeg(page);
addNewLegStats(page.stats, page.scorers);
2 months ago
}
/////////////////////////////////////////
// GameProps
/////////////////////////////////////////
export function getGameProps(page, current_set, current_leg) {
const ret = {};
if (current_set === undefined) {
current_set = computed(() => {
if (page.game != undefined) {
return page.game.sets[page.game.sets.length - 1]
}
return undefined;
});
}
ret.current_set = current_set;
if (current_leg === undefined) {
current_leg = computed(() => {
if (current_set.value != undefined) {
return current_set.value.legs[current_set.value.legs.length - 1]
}
return undefined;
});
}
ret.current_leg = current_leg;
const current_toGo = computed(() => {
if (current_leg.value != undefined) {
if (current_leg.value.visits.length < 2) {
return [page.modus, page.modus]
} else {
const end = current_leg.value.visits[current_leg.value.visits.length - 1].toGo;
if (end) return end;
return current_leg.value.visits[current_leg.value.visits.length - 2].toGo;
}
}
return [0, 0]; // need to get updated for more player
});
ret.current_toGo = current_toGo;
const current_set_points = computed(() => {
if (current_set.value != undefined) {
return setPoints(page, current_set.value);
}
return undefined;
});
ret.current_set_points = current_set_points;
const current_leg_points = computed(() => {
if (current_set.value != undefined || current_leg.value != undefined) {
return legPoints(page, current_set.value, current_leg.value);
}
return undefined;
});
ret.current_leg_points = current_leg_points;
const current_scorer_idx = computed(() => {
if (current_leg.value != undefined) {
const len = current_leg.value.visits.length;
return player2scorer(page)[current_leg.value.visits[len - 1].player];
}
return undefined;
});
ret.current_scorer_idx = current_scorer_idx;
const breaks = computed(() => {
let b = [0,0];
for (const j in page.game.sets) {
const set = page.game.sets[j];
for (const i in set.legs) {
const l = set.legs[i];
if (l.visits[l.visits.length-1].toGo === undefined) {
return b;
}
if (l.visits[l.visits.length-1].toGo[0] == 0 && i%2 == 1)
b[0] += 1;
else if (l.visits[l.visits.length-1].toGo[1] == 0 && i%2 == 0)
b[1] += 1;
}
}
return b;
});
ret.breaks = breaks;
const getVal = (tr) => {
const val = tr.trim();
if (val == "") {
return 0;
}
if (val == "SB") {
return 25;
}
if (val == "DB") {
return 50;
}
if (val[0] == "S" || val[0] == "O" || val[0] == "I") {
return parseFloat(val.substring(1));
}
if (val[0] == "D") {
return 2 * parseFloat(val.substring(1));
}
if (val[0] == "T") {
return 3 * parseFloat(val.substring(1));
}
if (val[0] == "M") {
return 0;
} else {
// TODO: Check for Na
return parseFloat(val);
}
}
const verifySum = (sum) => {
if (sum > 180 || [179, 178, 176, 175, 173, 172, 169, 166, 163].indexOf(sum) > -1) {
return -1;
} else if (current_toGo.value[current_scorer_idx.value] - sum < 0) {
return -2;
} if (current_toGo.value[current_scorer_idx.value] - sum == 0) {
// bogey numbers
if (page.out == "Double" && (sum > 170 || [169, 168, 166, 165, 163, 162, 159].indexOf(sum) > -1)) {
return -1;
}
return 0;
} else if (current_toGo.value[current_scorer_idx.value] - sum <= 50) {
return 1;
} else if (page.in != "Straight" && current_toGo.value[current_scorer_idx.value] == page.modus && sum != 0) {
return 3;
}
return 2;
}
const checkVisit = (throws) => {
const tr = throws.split(",");
let sum = 0;
tr.forEach((t, i) => {
sum += getVal(t);
});
const res = verifySum(sum);
return [res, sum];
}
ret.checkVisit = checkVisit;
return ret;
}