diff --git a/tsconfig.json b/tsconfig.json index a7bfa18..32cf185 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,7 @@ { // https://v3.nuxtjs.org/concepts/typescript - "extends": "./.nuxt/tsconfig.json" + "extends": "./.nuxt/tsconfig.json", + "compilerOptions": { + "noUncheckedIndexedAccess": true + }, } diff --git a/utils/wbsc-eval.ts b/utils/wbsc-eval.ts index 98b737b..13ac484 100644 --- a/utils/wbsc-eval.ts +++ b/utils/wbsc-eval.ts @@ -186,14 +186,14 @@ function changeBatterSpecificAction () { if (isNaN(Number(posSelection[0]))) { posItem1.value = posSelection } else { - posItem1.value = posSelection[0] + posItem1.value = posSelection[0] || '1' } } if (fc === true) { const posItem2 = document.getElementById(groupID + '2') as HTMLInputElement posItem2.innerHTML = renderFCLocationOptions().join(' ') - posItem2.value = useEvalStore().getPosSelection(groupID)[1] + posItem2.value = useEvalStore().getPosSelection(groupID)[1] || 'Z' // for "HP" } const runTypeSelect = document.getElementById(inputB + inputRuntype) as HTMLInputElement @@ -320,7 +320,7 @@ function changeRunnerSpecificAction (group: string) { if (throwing === true) { const posItem2 = document.getElementById(groupID + '2') as HTMLInputElement posItem2.innerHTML = renderFCLocationOptions().join(' ') - posItem2.value = useEvalStore().getPosSelection(groupID)[1] + posItem2.value = useEvalStore().getPosSelection(groupID)[1] || 'Z' // for HP } disableExtraInput(group, out === true) @@ -692,7 +692,7 @@ function processInput (input: WBSCInput, batter: number): WBSCOutput { let notAddedYet = true const concurrentPlays = useEvalStore().concurrentPlays for (let i = 0; i < concurrentPlays.length; i += 1) { - if (concurrentPlays[i].batter === batter) { + if (concurrentPlays[i]?.batter === batter) { notAddedYet = false break } diff --git a/utils/wbsc-input.ts b/utils/wbsc-input.ts index 95cdfc8..3c66422 100644 --- a/utils/wbsc-input.ts +++ b/utils/wbsc-input.ts @@ -399,7 +399,7 @@ function getPosSelectionSelect (group: string, ord: number) { const posSelection = useEvalStore().getPosSelection(groupID) posItem.innerHTML = renderPlayerOptions().join(' ') if (posSelection.length > ord - 1) { - posItem.value = posSelection[ord - 1] + posItem.value = posSelection[ord - 1] || '1' } posItem.addEventListener('change', function () { diff --git a/utils/wbsc-json.ts b/utils/wbsc-json.ts index 243e23d..db409fe 100644 --- a/utils/wbsc-json.ts +++ b/utils/wbsc-json.ts @@ -151,7 +151,7 @@ function setInputs (input: WBSCInput) { posSelection.innerHTML = renderFCLocationOptions().join(' ') // default are player positions } } - posSelection.value = pos[i] + posSelection.value = pos[i] || '1' } } else { const hitSelection = document.getElementById(group + inputPosition + '1') as HTMLSelectElement diff --git a/utils/wbsc-output.ts b/utils/wbsc-output.ts index 4ad6e45..ea6c71f 100644 --- a/utils/wbsc-output.ts +++ b/utils/wbsc-output.ts @@ -42,9 +42,12 @@ function renderAction (battingOrder: number, clear: boolean, mainInput: WBSCInpu if (extraInput) { for (let i = 0; i < extraInput.length; i += 1) { - renderAction(battingOrder, false, extraInput[i]) - if (!extraInput[i].specAction.includes('N')) { - drawConnector(output.base, extraInput[i].output!.base) + const extInput = extraInput[i] + if (extInput) { + renderAction(battingOrder, false, extInput) + if (!extInput.specAction.includes('N')) { + drawConnector(output.base, extInput.output!.base) + } } } } @@ -742,13 +745,13 @@ function writeBatterIndicator (base: number) { const ctx = useCanvasStore().ctx if (ctx) { ctx.font = 'bold 20px Verdana' - ctx.fillText(useEvalStore().batter.toString(), coords[0].x, coords[0].y) + ctx.fillText(useEvalStore().batter.toString(), coords[0]?.x || 0, coords[0]?.y || 0) ctx.lineWidth = 3 ctx.beginPath() - ctx.moveTo(coords[1].x, coords[1].y) - ctx.lineTo(coords[2].x, coords[2].y) - ctx.lineTo(coords[3].x, coords[3].y) + ctx.moveTo(coords[1]?.x || 0, coords[1]?.y || 0) + ctx.lineTo(coords[2]?.x || 0, coords[2]?.y || 0) + ctx.lineTo(coords[3]?.x || 0, coords[3]?.y || 0) ctx.stroke() } else { createError('Canvas context not defined') @@ -764,202 +767,206 @@ function connectOutsIfNeeded () { const start = useEvalStore().outs[i] const end = useEvalStore().outs[i + 1] - const hOffset = useCanvasStore().hOffset - const lineHOffset = 20 - const vOffsetStart = (h1 - 8) * (start.batter - 1) - const vOffsetEnd = (h1 - 8) * (end.batter - 1) - - let startX = 0 - let startY = 0 - let endX = 0 - let endY = 0 - switch (start.base) { - case 4: - startX = hOffset + lineHOffset - startY = h1 - 36 + vOffsetStart - switch (end.base) { - case 4: - startX = hOffset + h2 / 4 - startY = h1 - 25 + vOffsetStart - endX = hOffset + h2 / 4 - endY = h2 + 25 + vOffsetEnd - break - case 3: - startX = hOffset + h2 / 2 - startY = h1 - 15 + vOffsetStart - endX = hOffset + h2 / 2 - endY = h2 - 47 + vOffsetEnd - break - case 2: - startX += 15 - startY += 15 - endX = hOffset + lineHOffset + 15 - endY = 37 + vOffsetEnd - break - case 1: - case 0: - endX = hOffset + lineHOffset - endY = h2 - 30 + vOffsetEnd - break - } - break - case 3: - startX = hOffset + lineHOffset - startY = h2 + 25 + vOffsetStart - if (end.base === 2) { - endX = hOffset + lineHOffset - endY = h2 / 2 + vOffsetEnd - } else { - endX = hOffset + lineHOffset - endY = h2 - 30 + vOffsetEnd - } - break - case 2: - startX = hOffset + lineHOffset - startY = h2 - 13 + vOffsetStart - endX = hOffset + lineHOffset - endY = h2 - 30 + vOffsetEnd - break - } - - const ctx = useCanvasStore().ctx - if (ctx) { - ctx.lineWidth = 6 - ctx.beginPath() - ctx.moveTo(startX, startY) - ctx.lineTo(endX, endY) - ctx.stroke() - } else { - createError('Canvas context not defined') - } - } - } -} - -// processed AFTER all sitations were rendered -// if play contains 2 or more actions that has to be marked as "concurrent" -// (e.g. KS+SB, BB+WP or SB+SB) -// we need to link them with double-sided arrow connector -function connectConcurrentPlaysIfNeeded () { - if (useEvalStore().concurrentPlays.length > 1) { - for (let i = 0; i < useEvalStore().concurrentPlays.length - 1; i += 1) { - const start = useEvalStore().concurrentPlays[i] - const end = useEvalStore().concurrentPlays[i + 1] - - // two outs are already connected - if (start.out === false || end.out === false) { + if (start && end) { const hOffset = useCanvasStore().hOffset - const lineHOffset = 30 + const lineHOffset = 20 const vOffsetStart = (h1 - 8) * (start.batter - 1) const vOffsetEnd = (h1 - 8) * (end.batter - 1) - const out = start.out === true - - const startNa = start.na === true - const endNa = end.na === true let startX = 0 let startY = 0 let endX = 0 let endY = 0 - let xHOffset = 0 switch (start.base) { case 4: - startY = h1 - 20 + vOffsetStart + startX = hOffset + lineHOffset + startY = h1 - 36 + vOffsetStart switch (end.base) { + case 4: + startX = hOffset + h2 / 4 + startY = h1 - 25 + vOffsetStart + endX = hOffset + h2 / 4 + endY = h2 + 25 + vOffsetEnd + break case 3: - if (out) { - startX = hOffset + (h2 - lineHOffset) - endX = hOffset + (h2 - lineHOffset) - endY = 25 + vOffsetEnd - } else { - startX = hOffset + h2 / 2 - endX = hOffset + h2 / 2 - if (end.out === true) { - endY = h2 / 2 + vOffsetEnd - } else { - endY = 25 + vOffsetEnd - } - } + startX = hOffset + h2 / 2 + startY = h1 - 15 + vOffsetStart + endX = hOffset + h2 / 2 + endY = h2 - 47 + vOffsetEnd break case 2: - startX = hOffset + (h2 - lineHOffset) - endX = hOffset + h2 + lineHOffset - endY = 25 + vOffsetEnd + startX += 15 + startY += 15 + endX = hOffset + lineHOffset + 15 + endY = 37 + vOffsetEnd break case 1: - startX = hOffset + (h2 - lineHOffset) - if (out) { - startY += 15 - } - endX = hOffset + h2 + lineHOffset - endY = h2 + 25 + vOffsetEnd - break case 0: - startX = hOffset + lineHOffset endX = hOffset + lineHOffset - endY = 25 + vOffsetEnd + endY = h2 - 30 + vOffsetEnd break } break case 3: - if (out) { - startY = h2 * 1.5 + vOffsetStart - xHOffset = h2 / 4 + startX = hOffset + lineHOffset + startY = h2 + 25 + vOffsetStart + if (end.base === 2) { + endX = hOffset + lineHOffset + endY = h2 / 2 + vOffsetEnd } else { - startY = h2 - (startNa ? -5 : 25) + vOffsetStart - } - switch (end.base) { - case 2: - startX = hOffset + h2 / 2 + xHOffset - endX = hOffset + h2 + (endNa ? 0 : lineHOffset) - endY = (endNa ? 0 : 25) + vOffsetEnd - break - case 1: - startX = hOffset + h2 / 2 + xHOffset - endX = hOffset + h2 + (endNa ? h2 / 2 : lineHOffset) - endY = h2 + (endNa ? -5 : 25) + vOffsetEnd - break - case 0: - startX = hOffset + lineHOffset - endX = hOffset + lineHOffset - endY = 25 + vOffsetEnd - break + endX = hOffset + lineHOffset + endY = h2 - 30 + vOffsetEnd } break case 2: - if (out) { - startX = hOffset + (h2 - lineHOffset) - startY = h2 + 45 + vOffsetStart - } else if (startNa) { - startX = hOffset + h2 - startY = 45 + vOffsetStart - } else { - startX = hOffset + (h1 - lineHOffset) - startY = h2 - 25 + vOffsetStart - } - switch (end.base) { - case 1: - if (out) { + startX = hOffset + lineHOffset + startY = h2 - 13 + vOffsetStart + endX = hOffset + lineHOffset + endY = h2 - 30 + vOffsetEnd + break + } + + const ctx = useCanvasStore().ctx + if (ctx) { + ctx.lineWidth = 6 + ctx.beginPath() + ctx.moveTo(startX, startY) + ctx.lineTo(endX, endY) + ctx.stroke() + } else { + createError('Canvas context not defined') + } + } + } + } +} + +// processed AFTER all sitations were rendered +// if play contains 2 or more actions that has to be marked as "concurrent" +// (e.g. KS+SB, BB+WP or SB+SB) +// we need to link them with double-sided arrow connector +function connectConcurrentPlaysIfNeeded () { + if (useEvalStore().concurrentPlays.length > 1) { + for (let i = 0; i < useEvalStore().concurrentPlays.length - 1; i += 1) { + const start = useEvalStore().concurrentPlays[i] + const end = useEvalStore().concurrentPlays[i + 1] + + if (start && end) { + // two outs are already connected + if (start.out === false || end.out === false) { + const hOffset = useCanvasStore().hOffset + const lineHOffset = 30 + const vOffsetStart = (h1 - 8) * (start.batter - 1) + const vOffsetEnd = (h1 - 8) * (end.batter - 1) + const out = start.out === true + + const startNa = start.na === true + const endNa = end.na === true + + let startX = 0 + let startY = 0 + let endX = 0 + let endY = 0 + let xHOffset = 0 + switch (start.base) { + case 4: + startY = h1 - 20 + vOffsetStart + switch (end.base) { + case 3: + if (out) { + startX = hOffset + (h2 - lineHOffset) + endX = hOffset + (h2 - lineHOffset) + endY = 25 + vOffsetEnd + } else { + startX = hOffset + h2 / 2 + endX = hOffset + h2 / 2 + if (end.out === true) { + endY = h2 / 2 + vOffsetEnd + } else { + endY = 25 + vOffsetEnd + } + } + break + case 2: + startX = hOffset + (h2 - lineHOffset) + endX = hOffset + h2 + lineHOffset + endY = 25 + vOffsetEnd + break + case 1: + startX = hOffset + (h2 - lineHOffset) + if (out) { + startY += 15 + } endX = hOffset + h2 + lineHOffset endY = h2 + 25 + vOffsetEnd - } else if (startNa) { - endX = hOffset + (h1 - h2 / 2) - endY = h2 + (endNa ? -5 : 15) + vOffsetEnd - } else { - endX = hOffset + (h1 - (endNa ? h2 / 2 : lineHOffset)) + break + case 0: + startX = hOffset + lineHOffset + endX = hOffset + lineHOffset + endY = 25 + vOffsetEnd + break + } + break + case 3: + if (out) { + startY = h2 * 1.5 + vOffsetStart + xHOffset = h2 / 4 + } else { + startY = h2 - (startNa ? -5 : 25) + vOffsetStart + } + switch (end.base) { + case 2: + startX = hOffset + h2 / 2 + xHOffset + endX = hOffset + h2 + (endNa ? 0 : lineHOffset) + endY = (endNa ? 0 : 25) + vOffsetEnd + break + case 1: + startX = hOffset + h2 / 2 + xHOffset + endX = hOffset + h2 + (endNa ? h2 / 2 : lineHOffset) endY = h2 + (endNa ? -5 : 25) + vOffsetEnd - } - break - case 0: - endX = hOffset + (h1 - lineHOffset) - endY = 25 + vOffsetEnd - break - } - break - } + break + case 0: + startX = hOffset + lineHOffset + endX = hOffset + lineHOffset + endY = 25 + vOffsetEnd + break + } + break + case 2: + if (out) { + startX = hOffset + (h2 - lineHOffset) + startY = h2 + 45 + vOffsetStart + } else if (startNa) { + startX = hOffset + h2 + startY = 45 + vOffsetStart + } else { + startX = hOffset + (h1 - lineHOffset) + startY = h2 - 25 + vOffsetStart + } + switch (end.base) { + case 1: + if (out) { + endX = hOffset + h2 + lineHOffset + endY = h2 + 25 + vOffsetEnd + } else if (startNa) { + endX = hOffset + (h1 - h2 / 2) + endY = h2 + (endNa ? -5 : 15) + vOffsetEnd + } else { + endX = hOffset + (h1 - (endNa ? h2 / 2 : lineHOffset)) + endY = h2 + (endNa ? -5 : 25) + vOffsetEnd + } + break + case 0: + endX = hOffset + (h1 - lineHOffset) + endY = 25 + vOffsetEnd + break + } + break + } - drawArrow(startX, startY, endX, endY, 6) - drawArrow(endX, endY, startX, startY, 6) + drawArrow(startX, startY, endX, endY, 6) + drawArrow(endX, endY, startX, startY, 6) + } } } } diff --git a/utils/wbsc-processor.ts b/utils/wbsc-processor.ts index b38bd57..a1260a9 100644 --- a/utils/wbsc-processor.ts +++ b/utils/wbsc-processor.ts @@ -161,7 +161,7 @@ function processAction () { // current batter is not known in the time of input evaluation (we don't forsee number of players involved) // therefore placeholder is being used and here is replaced with actual number for (let i = 0; i < inputs.length; i += 1) { - const output = inputs[i].output + const output = inputs[i]?.output if (output) { output.text1 = output.text1.replace('#b#', useEvalStore().batter.toString()) } @@ -299,12 +299,14 @@ function checkMultipleRunnerAdvances (inputArr: WBSCInput[]) { let advanceEncountered = false for (let i = 0; i < inputArr.length; i += 1) { const current = inputArr[i] - const action = current?.specAction - if (action === 'WP' || action === 'PB' || action === 'BK' || action === 'IP') { - if (advanceEncountered) { - current.specAction = action.toLowerCase() + if (current) { + const action = current.specAction + if (action === 'WP' || action === 'PB' || action === 'BK' || action === 'IP') { + if (advanceEncountered) { + current.specAction = action.toLowerCase() + } + advanceEncountered = true } - advanceEncountered = true } } } @@ -319,7 +321,7 @@ function removeDuplicateConnectors () { let runner12Advance = false let batterOut = false for (let i = 0; i < useEvalStore().outs.length; i += 1) { - const base = useEvalStore().outs[i].base + const base = useEvalStore().outs[i]?.base if (base === 4 || base === 3) { runner23Out = true } @@ -328,8 +330,8 @@ function removeDuplicateConnectors () { } } for (let i = 0; i < useEvalStore().concurrentPlays.length; i += 1) { - const base = useEvalStore().concurrentPlays[i].base - const out = useEvalStore().concurrentPlays[i].out + const base = useEvalStore().concurrentPlays[i]?.base + const out = useEvalStore().concurrentPlays[i]?.out if ((base === 3 || base === 2) && !out) { runner12Advance = true } diff --git a/utils/wbsc-validation.ts b/utils/wbsc-validation.ts index 495c3ab..f366de3 100644 --- a/utils/wbsc-validation.ts +++ b/utils/wbsc-validation.ts @@ -88,7 +88,7 @@ function checkPosSelection (selection: string) { if (selection.length > 2) { const alreadyEncounteredPositions = [false, false, false, false, false, false, false, false, false, false] for (let i = 0; i < selection.length - 1; i += 1) { - const current = parseInt(selection[i]) + const current = parseInt(selection[i] || '1') if (alreadyEncounteredPositions[current] === true) { validation = attachValidation(validation, useT('editor.validation.noMultipleAsist')) break @@ -143,7 +143,7 @@ function checkOutcome (inputs: WBSCInput[]) { validation = attachValidation(validation, useT('editor.validation.noAdvanceAfterOut')) } } - const maxReachedBase = reachedBases[reachedBases.length - 1] + const maxReachedBase = reachedBases[reachedBases.length - 1] || 0 const currentReachedBase = Math.max(output.base, output.errorTarget) if (currentReachedBase > maxReachedBase || (currentReachedBase === maxReachedBase && noAdvActions.includes(input.specAction))) { validation = attachValidation(validation, useT('editor.validation.advanceInOrder')) @@ -167,8 +167,8 @@ function checkOutcome (inputs: WBSCInput[]) { }) for (let i = 0; i < reachedBases.length - 1; i += 1) { - const reachedBase1 = reachedBases[i] - const reachedBase2 = reachedBases[i + 1] + const reachedBase1 = reachedBases[i] || 0 + const reachedBase2 = reachedBases[i + 1] || 0 if (reachedBase2 > reachedBase1) { validation = attachValidation(validation, useT('editor.validation.noPassingRunner'))