refactor(striscia): nuova struttura array-di-set, elimina storicoServizio

La striscia diventa un array di set: ogni elemento è { serv, r[] }
dove r è la sequenza di scorer ('home'|'guest') del set.

- Un rally = un elemento in r: minimo non-derivabile
- Tutti i set (passati e corrente) sono conservati nell'array
- Dal set corrente si derivano: punteggio, servizio, cambio palla, rotazione
- Dal set completo si derivano: vincitore (r.at(-1)), score finale (count)
- storicoServizio eliminato: l'undo legge l'entry precedente di r

DisplayPage calcola le strip visive (home/guest) tramite computed
da striscia.at(-1).r senza dati ridondanti nel modello.
This commit is contained in:
2026-05-12 13:49:47 +02:00
parent 5f9e37062c
commit c900153eed
4 changed files with 70 additions and 103 deletions
+1 -2
View File
@@ -224,7 +224,7 @@ export default {
visuStriscia: true,
modalitaPartita: "3/5",
sp: {
striscia: { home: [0], guest: [0] },
striscia: [{ serv: 'home', r: [] }],
servHome: true,
punt: { home: 0, guest: 0 },
set: { home: 0, guest: 0 },
@@ -233,7 +233,6 @@ export default {
home: ["1", "2", "3", "4", "5", "6"],
guest: ["1", "2", "3", "4", "5", "6"],
},
storicoServizio: [],
},
},
}
+22 -17
View File
@@ -92,16 +92,16 @@
<div class="striscia" v-if="state.visuStriscia">
<span class="striscia-nome text-bold">{{ state.sp.nomi.home }}</span>
<div class="striscia-items" ref="homeItems">
<div v-for="(h, i) in state.sp.striscia.home" :key="'sh'+i"
class="item" :class="{ 'item-vuoto': String(h).trim() === '' }">
{{ String(h) }}
<div v-for="(h, i) in stricciaStrip.home" :key="'sh'+i"
class="item" :class="{ 'item-vuoto': h === ' ' }">
{{ h }}
</div>
</div>
<span class="striscia-nome text-bold guest-striscia">{{ state.sp.nomi.guest }}</span>
<div class="striscia-items guest-striscia" ref="guestItems">
<div v-for="(h, i) in state.sp.striscia.guest" :key="'sg'+i"
class="item" :class="{ 'item-vuoto': String(h).trim() === '' }">
{{ String(h) }}
<div v-for="(h, i) in stricciaStrip.guest" :key="'sg'+i"
class="item" :class="{ 'item-vuoto': h === ' ' }">
{{ h }}
</div>
</div>
</div>
@@ -132,7 +132,7 @@ export default {
visuStriscia: true,
modalitaPartita: "3/5",
sp: {
striscia: { home: [0], guest: [0] },
striscia: [{ serv: 'home', r: [] }],
servHome: true,
punt: { home: 0, guest: 0 },
set: { home: 0, guest: 0 },
@@ -141,7 +141,6 @@ export default {
home: ["1", "2", "3", "4", "5", "6"],
guest: ["1", "2", "3", "4", "5", "6"],
},
storicoServizio: [],
},
},
}
@@ -192,23 +191,29 @@ export default {
this.ws = null
}
},
watch: {
'state.sp.striscia.home': {
deep: true,
handler() {
this.$nextTick(() => {
if (this.$refs.homeItems) this.$refs.homeItems.scrollLeft = this.$refs.homeItems.scrollWidth
})
computed: {
stricciaStrip() {
const currentSet = this.state.sp.striscia.at(-1)
if (!currentSet) return { home: [], guest: [] }
let h = 0, g = 0
const home = [], guest = []
for (const scorer of currentSet.r) {
if (scorer === 'home') { h++; home.push(h); guest.push(' ') }
else { g++; guest.push(g); home.push(' ') }
}
return { home, guest }
},
'state.sp.striscia.guest': {
},
watch: {
'state.sp.striscia': {
deep: true,
handler() {
this.$nextTick(() => {
if (this.$refs.homeItems) this.$refs.homeItems.scrollLeft = this.$refs.homeItems.scrollWidth
if (this.$refs.guestItems) this.$refs.guestItems.scrollLeft = this.$refs.guestItems.scrollWidth
})
}
}
},
},
methods: {
isMobile() {
+24 -51
View File
@@ -1,8 +1,3 @@
/**
* Logica di gioco condivisa per il segnapunti.
* Utilizzata sia dal server WebSocket sia dal client per l'anteprima locale.
*/
export function createInitialState() {
return {
order: true,
@@ -10,7 +5,7 @@ export function createInitialState() {
visuStriscia: true,
modalitaPartita: "3/5",
sp: {
striscia: { home: [0], guest: [0] },
striscia: [{ serv: 'home', r: [] }],
servHome: true,
punt: { home: 0, guest: 0 },
set: { home: 0, guest: 0 },
@@ -19,7 +14,6 @@ export function createInitialState() {
home: ["1", "2", "3", "4", "5", "6"],
guest: ["1", "2", "3", "4", "5", "6"],
},
storicoServizio: [],
},
}
}
@@ -31,22 +25,11 @@ export function checkVittoria(state) {
const setGuest = state.sp.set.guest
const totSet = setHome + setGuest
let isSetDecisivo = false
if (state.modalitaPartita === "2/3") {
isSetDecisivo = totSet >= 2
} else {
isSetDecisivo = totSet >= 4
}
const isSetDecisivo = state.modalitaPartita === "2/3" ? totSet >= 2 : totSet >= 4
const punteggioVittoria = isSetDecisivo ? 15 : 25
if (puntHome >= punteggioVittoria && puntHome - puntGuest >= 2) {
return true
}
if (puntGuest >= punteggioVittoria && puntGuest - puntHome >= 2) {
return true
}
if (puntHome >= punteggioVittoria && puntHome - puntGuest >= 2) return true
if (puntGuest >= punteggioVittoria && puntGuest - puntHome >= 2) return true
return false
}
@@ -59,16 +42,8 @@ export function applyAction(state, action) {
if (checkVittoria(s)) break
const cambioPalla = (team === "home") !== s.sp.servHome
s.sp.storicoServizio.push({ servHome: s.sp.servHome, cambioPalla })
s.sp.punt[team]++
if (team === "home") {
s.sp.striscia.home.push(s.sp.punt.home)
s.sp.striscia.guest.push(" ")
} else {
s.sp.striscia.guest.push(s.sp.punt.guest)
s.sp.striscia.home.push(" ")
}
s.sp.striscia.at(-1).r.push(team)
if (cambioPalla) {
s.sp.form[team].push(s.sp.form[team].shift())
@@ -79,23 +54,22 @@ export function applyAction(state, action) {
}
case "decPunt": {
if (s.sp.storicoServizio.length > 0) {
const tmpHome = s.sp.striscia.home.pop()
s.sp.striscia.guest.pop()
const statoServizio = s.sp.storicoServizio.pop()
const currentSet = s.sp.striscia.at(-1)
if (currentSet.r.length === 0) break
if (tmpHome === " ") {
s.sp.punt.guest--
if (statoServizio.cambioPalla) {
s.sp.form.guest.unshift(s.sp.form.guest.pop())
}
} else {
s.sp.punt.home--
if (statoServizio.cambioPalla) {
s.sp.form.home.unshift(s.sp.form.home.pop())
}
}
s.sp.servHome = statoServizio.servHome
const lastScorer = currentSet.r[currentSet.r.length - 1]
const prevServer = currentSet.r.length >= 2
? currentSet.r[currentSet.r.length - 2]
: currentSet.serv
const wasCambioPalla = lastScorer !== prevServer
currentSet.r.pop()
s.sp.punt[lastScorer]--
s.sp.servHome = prevServer === 'home'
if (wasCambioPalla) {
s.sp.form[lastScorer].unshift(s.sp.form[lastScorer].pop())
}
break
}
@@ -116,8 +90,8 @@ export function applyAction(state, action) {
s.sp.set[team]++
s.sp.punt.home = 0
s.sp.punt.guest = 0
s.sp.striscia = { home: [0], guest: [0] }
s.sp.storicoServizio = []
s.sp.servHome = team === 'home'
s.sp.striscia.push({ serv: team, r: [] })
s.sp.form = {
home: ["1", "2", "3", "4", "5", "6"],
guest: ["1", "2", "3", "4", "5", "6"],
@@ -128,7 +102,7 @@ export function applyAction(state, action) {
case "cambiaPalla": {
if (s.sp.punt.home === 0 && s.sp.punt.guest === 0) {
s.sp.servHome = !s.sp.servHome
s.sp.striscia = { home: [0], guest: [0] }
s.sp.striscia.at(-1).serv = s.sp.servHome ? 'home' : 'guest'
}
break
}
@@ -143,8 +117,7 @@ export function applyAction(state, action) {
home: ["1", "2", "3", "4", "5", "6"],
guest: ["1", "2", "3", "4", "5", "6"],
}
s.sp.striscia = { home: [0], guest: [0] }
s.sp.storicoServizio = []
s.sp.striscia = [{ serv: s.sp.servHome ? 'home' : 'guest', r: [] }]
break
}
+23 -33
View File
@@ -31,13 +31,10 @@ describe('Game Logic (gameState.js)', () => {
expect(state.sp.form.guest).toEqual(["1", "2", "3", "4", "5", "6"])
})
it('dovrebbe avere la striscia iniziale a [0]', () => {
expect(state.sp.striscia.home).toEqual([0])
expect(state.sp.striscia.guest).toEqual([0])
})
it('dovrebbe avere storico servizio vuoto', () => {
expect(state.sp.storicoServizio).toEqual([])
it('dovrebbe avere la striscia iniziale con un set vuoto', () => {
expect(state.sp.striscia).toHaveLength(1)
expect(state.sp.striscia[0].serv).toBe('home')
expect(state.sp.striscia[0].r).toEqual([])
})
it('dovrebbe avere modalità 3/5 di default', () => {
@@ -116,21 +113,19 @@ describe('Game Logic (gameState.js)', () => {
it('dovrebbe aggiornare la striscia per punto Home', () => {
const s = applyAction(state, { type: 'incPunt', team: 'home' })
expect(s.sp.striscia.home).toEqual([0, 1])
expect(s.sp.striscia.guest).toEqual([0, " "])
expect(s.sp.striscia.at(-1).r).toEqual(['home'])
})
it('dovrebbe aggiornare la striscia per punto Guest', () => {
const s = applyAction(state, { type: 'incPunt', team: 'guest' })
expect(s.sp.striscia.guest).toEqual([0, 1])
expect(s.sp.striscia.home).toEqual([0, " "])
expect(s.sp.striscia.at(-1).r).toEqual(['guest'])
})
it('dovrebbe registrare lo storico servizio', () => {
const s = applyAction(state, { type: 'incPunt', team: 'home' })
expect(s.sp.storicoServizio).toHaveLength(1)
expect(s.sp.storicoServizio[0]).toHaveProperty('servHome')
expect(s.sp.storicoServizio[0]).toHaveProperty('cambioPalla')
it('dovrebbe registrare scorer nella striscia', () => {
let s = applyAction(state, { type: 'incPunt', team: 'home' })
s = applyAction(s, { type: 'incPunt', team: 'guest' })
s = applyAction(s, { type: 'incPunt', team: 'home' })
expect(s.sp.striscia.at(-1).r).toEqual(['home', 'guest', 'home'])
})
it('non dovrebbe incrementare i punti dopo vittoria', () => {
@@ -185,7 +180,7 @@ describe('Game Logic (gameState.js)', () => {
it('dovrebbe ripristinare la striscia', () => {
const s1 = applyAction(state, { type: 'incPunt', team: 'home' })
const s2 = applyAction(s1, { type: 'decPunt' })
expect(s2.sp.striscia.home).toEqual([0])
expect(s2.sp.striscia.at(-1).r).toEqual([])
})
it('dovrebbe gestire undo multipli in sequenza', () => {
@@ -250,16 +245,17 @@ describe('Game Logic (gameState.js)', () => {
expect(s.sp.punt.guest).toBe(0)
})
it('dovrebbe resettare la striscia', () => {
state.sp.punt.home = 25
it('dovrebbe aggiungere un nuovo set vuoto alla striscia', () => {
const s = applyAction(state, { type: 'nuovoSet', team: 'home' })
expect(s.sp.striscia).toEqual({ home: [0], guest: [0] })
expect(s.sp.striscia).toHaveLength(2)
expect(s.sp.striscia.at(-1).r).toEqual([])
expect(s.sp.striscia.at(-1).serv).toBe('home')
})
it('dovrebbe resettare lo storico servizio', () => {
state.sp.storicoServizio = [{ servHome: true, cambioPalla: false }]
it('dovrebbe conservare il set precedente nella striscia', () => {
state.sp.striscia[0].r = ['home', 'guest', 'home']
const s = applyAction(state, { type: 'nuovoSet', team: 'home' })
expect(s.sp.storicoServizio).toEqual([])
expect(s.sp.striscia[0].r).toEqual(['home', 'guest', 'home'])
})
it('dovrebbe resettare le formazioni', () => {
@@ -664,17 +660,11 @@ describe('Game Logic (gameState.js)', () => {
expect(s.sp.form.guest).toEqual(["1", "2", "3", "4", "5", "6"])
})
it('dovrebbe resettare la striscia', () => {
state.sp.striscia = { home: [0, 1, 2, 3], guest: [0, " ", " ", 1] }
it('dovrebbe resettare la striscia a un set vuoto', () => {
state.sp.striscia = [{ serv: 'home', r: ['home', 'guest', 'home'] }, { serv: 'home', r: ['guest'] }]
const s = applyAction(state, { type: 'resetta' })
expect(s.sp.striscia.home).toEqual([0])
expect(s.sp.striscia.guest).toEqual([0])
})
it('dovrebbe resettare lo storico servizio', () => {
state.sp.storicoServizio = [{ servHome: true, cambioPalla: false }]
const s = applyAction(state, { type: 'resetta' })
expect(s.sp.storicoServizio).toEqual([])
expect(s.sp.striscia).toHaveLength(1)
expect(s.sp.striscia[0].r).toEqual([])
})
it('dovrebbe impostare visuForm a false', () => {