From 6b8df5100b38ade7b91c679c0ecfac0ecb35adbc Mon Sep 17 00:00:00 2001 From: tanzhijian Date: Thu, 21 Dec 2023 21:17:28 +0800 Subject: [PATCH] refactor project --- auto-imports.d.ts | 2 - index.html | 2 +- public/favicon.png | Bin 0 -> 642 bytes src/api.ts | 100 ++++++++++++++++++++++++++ src/components/Match.vue | 49 ++++++------- src/composables/logic.ts | 149 --------------------------------------- src/models.ts | 134 +++++++++++++++++++++++++++++++++++ src/pages/index.vue | 30 ++++---- src/types.ts | 47 ++++++------ test/api.test.ts | 31 ++++++++ test/data.ts | 31 ++++++++ test/logic.test.ts | 39 ---------- test/models.test.ts | 69 ++++++++++++++++++ 13 files changed, 425 insertions(+), 258 deletions(-) create mode 100644 public/favicon.png create mode 100644 src/api.ts delete mode 100644 src/composables/logic.ts create mode 100644 src/models.ts create mode 100644 test/api.test.ts create mode 100644 test/data.ts delete mode 100644 test/logic.test.ts create mode 100644 test/models.test.ts diff --git a/auto-imports.d.ts b/auto-imports.d.ts index 1726cff..556a2e7 100644 --- a/auto-imports.d.ts +++ b/auto-imports.d.ts @@ -294,7 +294,6 @@ import { UnwrapRef } from 'vue' declare module 'vue' { interface ComponentCustomProperties { readonly EffectScope: UnwrapRef - readonly Game: UnwrapRef readonly asyncComputed: UnwrapRef readonly autoResetRef: UnwrapRef readonly computed: UnwrapRef @@ -576,7 +575,6 @@ declare module 'vue' { declare module '@vue/runtime-core' { interface ComponentCustomProperties { readonly EffectScope: UnwrapRef - readonly Game: UnwrapRef readonly asyncComputed: UnwrapRef readonly autoResetRef: UnwrapRef readonly computed: UnwrapRef diff --git a/index.html b/index.html index b708455..8bfa152 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - + Score Simulator diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..5102d6823b552e9850b01be4d17771377020ddbe GIT binary patch literal 642 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&Wd`_!xB_YV0QH2`^WXpSmf~FxLOgiGCLUWff3aMRtw!Xm76B&?#i~o2Z;8){ z*ckqN%A8FSjYnp_eqFD;;PJG7E0kG8uYU1TG;r28X}WwxTyaN7Ran9XC2i*Bo;C6Y z8YhijtmxcX&%SqhX3`4{&It^h6B=f+zqq6^y>!ze$JHroV|-S+v)!2|F(p6afZFi| zhjT*?2;1>mrhc&O;k@vn>!fDebUDF*L+h2=x$61_8QJQ@i*_71-@_5`;kQz|{tr!{ zdEc32FVdQ&MBb@0DckZd;kCd literal 0 HcmV?d00001 diff --git a/src/api.ts b/src/api.ts new file mode 100644 index 0000000..79be8a9 --- /dev/null +++ b/src/api.ts @@ -0,0 +1,100 @@ +import type { MatchTypes, MatchesTypes } from '~/types' +import { Frame, FrameTeam, Result, ResultTeam } from '~/models' + +export function selectMatches( + date: string, + matches: MatchesTypes, +): MatchTypes[] { + const selected = matches[date] + selected.sort((aMatch: MatchTypes, bMatch: MatchTypes) => { + const aDate = new Date(aMatch.utc_time) + const bDate = new Date(bMatch.utc_time) + if (aDate < bDate) + return -1 + if (aDate > bDate) + return 1 + return 0 + }) + return selected +} + +export class Game { + constructor(public match: MatchTypes) {} + + result = ref(new Result( + new ResultTeam(this.match.home.name), + new ResultTeam(this.match.away.name), + this.match.competition.name, + )) + + generateXG(mu: number, sigma = 0.1) { + // 使用逆变换法生成正态分布的随机数来得到 xg + // 标准差先使用一点假设的数值 + const u = Math.random() + const z + = Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * Math.random()) + + let xg = mu + sigma * z + if (xg <= 0) + xg = 0.01 + else if (xg > 1) + xg = 0.99 + + return xg + } + + attack(): Frame { + const frame = new Frame(new FrameTeam(), new FrameTeam()) + + const homeXGPerShot = this.match.home.xg / this.match.home.shots + const awayXGPerShot = this.match.away.xg / this.match.away.shots + const homeShotPercentage + = this.match.home.shots / (this.match.home.shots + this.match.away.shots) + const shotProbPerMinute + = (this.match.home.shots + this.match.away.shots) + / ((this.match.home.played + this.match.away.played) / 2) + / 90 + + if (Math.random() < shotProbPerMinute) { + if (Math.random() < homeShotPercentage) { + frame.home.shot = true + frame.home.xg = this.generateXG(homeXGPerShot) + if (Math.random() < homeXGPerShot) + frame.home.score = true + } + else { + frame.away.shot = true + frame.away.xg = this.generateXG(awayXGPerShot) + if (Math.random() < awayXGPerShot) + frame.away.score = true + } + } + + return frame + } + + play(fulltime: number = 90, delay: number = 100): void { + this.result.value.reset() + this.result.value.played = true + + const intervalId = setInterval(() => { + const frame = this.attack() + this.result.value.home.shots += +frame.home.shot + this.result.value.home.xg += frame.home.xg + this.result.value.home.score += +frame.home.score + this.result.value.away.shots += +frame.away.shot + this.result.value.away.xg += frame.away.xg + this.result.value.away.score += +frame.away.score + + if (frame.home.score) + this.result.value.home.goalMinutes.push(this.result.value.timing) + else if (frame.away.score) + this.result.value.away.goalMinutes.push(this.result.value.timing) + + this.result.value.timing += 1 + + if (this.result.value.timing >= fulltime) + clearInterval(intervalId) + }, delay) + } +} diff --git a/src/components/Match.vue b/src/components/Match.vue index ea4fa17..b2e3fb1 100644 --- a/src/components/Match.vue +++ b/src/components/Match.vue @@ -1,9 +1,9 @@