convertPointsToShots = function(dataPointsClean) {
let data = [];
let currentMatch = -1;
let currentSetsPl1, currentSetsPl2, currentGamesPl1, currentGamesPl2, currentPointsPl1, currentPointsPl2;
let point, currentPoint, rally, pos, event, prevEvent, isPlayer1Shot, shouldSavePoint;
for (let p of dataPointsClean) {
shouldSavePoint = true;
if (p.matchId == currentMatch) {
currentPoint += 1;
} else {
currentMatch = p.matchId;
currentPoint = 1;
currentSetsPl1 = 0;
currentSetsPl2 = 0;
currentGamesPl1 = 0;
currentGamesPl2 = 0;
currentPointsPl1 = 0;
currentPointsPl2 = 0;
}
point = {
matchId: p.matchId,
pointNumber: currentPoint,
setsPlayer1: currentSetsPl1,
setsPlayer2: currentSetsPl2,
gamesPlayer1: currentGamesPl1,
gamesPlayer2: currentGamesPl2,
pointsPlayer1: currentPointsPl1,
pointsPlayer2: currentPointsPl2,
tiebreakPointNumber: p.tiebreakPointNumber,
isPlayer1Serving: !!p.isPlayer1Serving,
isPlayer1Winner: !!p.isPlayer1Winner,
isGameWinner: !!p.isGameWinner,
isSetWinner: !!p.isSetWinner,
events: []
};
if ((typeof p.rally1 !== 'string') || (p.rally1.length == 0)) {
return rally + ' - ' + pos + ' - missing_rally1 - ' + p.matchId + ' - ' + currentPoint;
}
if (['S', 'R', 'P', 'Q'].includes(p.rally1[0])) {
if ((p.rally1.length > 1) || p.rally2) {
return rally + ' - ' + pos + ' - penalties_no_data - ' + p.matchId + ' - ' + currentPoint;
}
switch (p.rally1[0]) {
case 'S':
point.events.push({ _eventName: 'server_point' });
shouldSavePoint = false;
break;
case 'R':
point.events.push({ _eventName: 'returner_point' });
shouldSavePoint = false;
break;
case 'P':
point.events.push({ _eventName: 'server_penalty' });
shouldSavePoint = false;
break;
case 'Q':
point.events.push({ _eventName: 'returner_penalty' });
shouldSavePoint = false;
break;
}
} else {
rally = p.rally1;
isPlayer1Shot = !!p.isPlayer1Serving;
pos = 0;
event = readServe(p);
if (typeof event === 'object') {
point.events.push(event);
} else {
return event;
}
if (event._eventName == 'serve_fault') {
rally = p.rally2;
pos = 0;
event = readServe(p);
if (typeof event === 'object') {
point.events.push(event);
} else {
return event;
}
}
if (event._eventName != 'serve_fault') {
if (['*', '#'].includes(rally[pos])) {
point.events.push({
_eventName: 'ace',
isUnreturnable: (rally[pos] == '#')
});
} else {
while ((pos < rally.length) && !['*', 'n', 'w', 'd', 'x', '!', 'C', 'e', '@', '#'].includes(rally[pos])) {
isPlayer1Shot = !isPlayer1Shot;
event = readShot(p);
if (typeof event === 'object') {
point.events.push(event);
} else {
return event;
}
}
event = {
isPlayer1: !!isPlayer1Shot
};
if (['*', 'n', 'w', 'd', 'x', '!', 'C', 'e'].includes(rally[pos])) {
switch (rally[pos]) {
case '*':
event._eventName = 'winner';
break;
case 'n':
event.errorType = 'net';
break;
case 'w':
event.errorType = 'wide';
break;
case 'd':
event.errorType = 'deep';
break;
case 'x':
event.errorType = 'wide_deep';
break;
case '!':
event.errorType = 'shank';
event.isShank = true;
break;
case 'C':
event._eventName = 'winner';
event.hasLostChallenge = true;
break;
case 'e':
event.errorType = 'unknown';
shouldSavePoint = false;
break;
}
pos += 1;
}
if (pos < rally.length) {
switch (rally[pos]) {
case '@':
event._eventName = 'error_unforced';
break;
case '#':
event._eventName = 'error_forced';
break;
}
}
if (event.hasOwnProperty('_eventName')) {
point.events.push(event);
} else if (event.hasOwnProperty('errorType')) {
event._eventName = 'error_unknown';
point.events.push(event);
} else {
shouldSavePoint = false;
}
}
}
}
if (shouldSavePoint) {
data.push(point);
}
if (p.isSetWinner) {
if (p.isPlayer1Winner) {
currentSetsPl1 += 1;
} else {
currentSetsPl2 += 1;
}
currentGamesPl1 = 0;
currentGamesPl2 = 0;
currentPointsPl1 = 0;
currentPointsPl2 = 0;
} else if (p.isGameWinner) {
if (p.isPlayer1Winner) {
currentGamesPl1 += 1;
} else {
currentGamesPl2 += 1;
}
currentPointsPl1 = 0;
currentPointsPl2 = 0;
} else {
if (p.isPlayer1Winner) {
currentPointsPl1 += 1;
} else {
currentPointsPl2 += 1;
}
}
}
function readServe(p) {
let ev = {
isPlayer1: !!isPlayer1Shot
};
while (rally[pos] == 'c') {
pos += 1;
}
let posServeStart = pos;
while (['4', '5', '6', '0', '+', '^', ';', 'n', 'w', 'd', 'x', 'g', '!', 'V', 'e'].includes(rally[pos])) {
switch (rally[pos]) {
case '4':
ev._eventName = 'serve_wide';
break;
case '5':
ev._eventName = 'serve_body';
break;
case '6':
ev._eventName = 'serve_middle';
break;
case '0':
ev._eventName = 'serve_unknown';
shouldSavePoint = false;
break;
case '+':
ev.courtPosition = 'approach';
break;
case '^':
ev.isDropVolley = true;
break;
case ';':
ev.hasClippedNet = true;
break;
case 'n':
ev.faultType = 'net';
break;
case 'w':
ev.faultType = 'wide';
break;
case 'd':
ev.faultType = 'deep';
break;
case 'x':
ev.faultType = 'wide-deep';
break;
case 'g':
ev.faultType = 'foot';
break;
case '!':
ev.faultType = 'shank';
ev.isShank = true;
break;
case 'V':
ev.faultType = 'time';
break;
case 'e':
ev.faultType = 'unknown';
break;
}
pos += 1;
}
if (pos == posServeStart) {
return rally + ' - ' + pos + ' - serve - ' + p.matchId + ' - ' + currentPoint;
}
if (ev.hasOwnProperty('faultType')) {
ev._eventName = 'serve_fault';
}
return ev;
}
function readShot(p) {
let ev = {
isPlayer1: !!isPlayer1Shot
};
switch (rally[pos]) {
case 'f':
ev._eventName = 'forehand';
break;
case 'b':
ev._eventName = 'backhand';
break;
case 'r':
ev._eventName = 'f_slice';
break;
case 's':
ev._eventName = 'b_slice';
break;
case 'v':
ev._eventName = 'f_volley';
break;
case 'z':
ev._eventName = 'b_volley';
break;
case 'o':
ev._eventName = 'f_smash';
break;
case 'p':
ev._eventName = 'b_smash';
break;
case 'u':
ev._eventName = 'f_drop';
break;
case 'y':
ev._eventName = 'b_drop';
break;
case 'l':
ev._eventName = 'f_lob';
break;
case 'm':
ev._eventName = 'b_lob';
break;
case 'h':
ev._eventName = 'f_half_volley';
break;
case 'i':
ev._eventName = 'b_half_volley';
break;
case 'j':
ev._eventName = 'f_swing_volley';
break;
case 'k':
ev._eventName = 'b_swing_volley';
break;
case 't':
ev._eventName = 'trick';
break;
case 'q':
ev._eventName = 'unknown';
shouldSavePoint = false;
break;
default:
return rally + ' - ' + pos + ' - shot_type - ' + p.matchId + ' - ' + currentPoint;
}
pos += 1;
while (['+', '-', '=', ';', '^', '!', '1', '2', '3', '7', '8', '9', '0'].includes(rally[pos])) {
switch (rally[pos]) {
case '+':
ev.courtPosition = 'approach';
break;
case '-':
ev.courtPosition = 'net';
break;
case '=':
ev.courtPosition = 'baseline';
break;
case ';':
ev.hasClippedNet = true;
break;
case '^':
ev.isDropVolley = true;
break;
case '!':
ev.isShank = true;
break;
case '1':
ev.shotDirection = 'forehand';
break;
case '2':
ev.shotDirection = 'middle';
break;
case '3':
ev.shotDirection = 'backhand';
break;
case '7':
ev.returnDepth = 'short';
break;
case '8':
ev.returnDepth = 'middle';
break;
case '9':
ev.returnDepth = 'deep';
break;
case '0':
if (ev.hasOwnProperty('shotDirection')) {
ev.returnDepth = 'unknown';
} else {
ev.shotDirection = 'unknown';
}
break;
}
pos += 1;
}
return ev;
}
return data;
}