init
This commit is contained in:
13
.eslintignore
Normal file
13
.eslintignore
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/build
|
||||||
|
/.svelte-kit
|
||||||
|
/package
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# Ignore files for PNPM, NPM and YARN
|
||||||
|
pnpm-lock.yaml
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
31
.eslintrc.cjs
Normal file
31
.eslintrc.cjs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/** @type { import("eslint").Linter.Config } */
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:svelte/recommended',
|
||||||
|
'prettier'
|
||||||
|
],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
plugins: ['@typescript-eslint'],
|
||||||
|
parserOptions: {
|
||||||
|
sourceType: 'module',
|
||||||
|
ecmaVersion: 2020,
|
||||||
|
extraFileExtensions: ['.svelte']
|
||||||
|
},
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es2017: true,
|
||||||
|
node: true
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['*.svelte'],
|
||||||
|
parser: 'svelte-eslint-parser',
|
||||||
|
parserOptions: {
|
||||||
|
parser: '@typescript-eslint/parser'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
/build
|
||||||
|
/.svelte-kit
|
||||||
|
/package
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
.vercel
|
||||||
|
.output
|
||||||
|
vite.config.js.timestamp-*
|
||||||
|
vite.config.ts.timestamp-*
|
||||||
4
.prettierignore
Normal file
4
.prettierignore
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Ignore files for PNPM, NPM and YARN
|
||||||
|
pnpm-lock.yaml
|
||||||
|
package-lock.json
|
||||||
|
yarn.lock
|
||||||
8
.prettierrc
Normal file
8
.prettierrc
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"useTabs": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"printWidth": 100,
|
||||||
|
"plugins": ["prettier-plugin-svelte"],
|
||||||
|
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||||
|
}
|
||||||
1
README.md
Normal file
1
README.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
The code here is pretty gross. Was a quick hackathon type project, so if you're looking at this thinking it's worth investigating my skillz. Please don't
|
||||||
37
package.json
Normal file
37
package.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"name": "watlcalc",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite dev",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
|
"lint": "prettier --check . && eslint .",
|
||||||
|
"format": "prettier --write ."
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@fontsource/fira-mono": "^4.5.10",
|
||||||
|
"@neoconfetti/svelte": "^1.0.0",
|
||||||
|
"@sveltejs/adapter-auto": "^3.0.0",
|
||||||
|
"@sveltejs/kit": "^2.0.0",
|
||||||
|
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||||
|
"@types/eslint": "^8.56.0",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
||||||
|
"@typescript-eslint/parser": "^7.0.0",
|
||||||
|
"eslint": "^8.56.0",
|
||||||
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
"eslint-plugin-svelte": "^2.35.1",
|
||||||
|
"prettier": "^3.1.1",
|
||||||
|
"prettier-plugin-svelte": "^3.1.2",
|
||||||
|
"svelte": "^4.2.7",
|
||||||
|
"svelte-check": "^3.6.0",
|
||||||
|
"tslib": "^2.4.1",
|
||||||
|
"typescript": "^5.0.0",
|
||||||
|
"vite": "^5.0.3"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"@picocss/pico": "^2.0.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
2130
pnpm-lock.yaml
generated
Normal file
2130
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
13
src/app.d.ts
vendored
Normal file
13
src/app.d.ts
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// See https://kit.svelte.dev/docs/types#app
|
||||||
|
// for information about these interfaces
|
||||||
|
declare global {
|
||||||
|
namespace App {
|
||||||
|
// interface Error {}
|
||||||
|
// interface Locals {}
|
||||||
|
// interface PageData {}
|
||||||
|
// interface PageState {}
|
||||||
|
// interface Platform {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
||||||
12
src/app.html
Normal file
12
src/app.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
%sveltekit.head%
|
||||||
|
</head>
|
||||||
|
<body data-sveltekit-preload-data="hover">
|
||||||
|
<div style="display: contents">%sveltekit.body%</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
16
src/lib/images/github.svg
Normal file
16
src/lib/images/github.svg
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-3 -3 30 30">
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M12 2C6.47715 2 2 6.47715 2 12C2 17.5229 6.47715 22 12 22C17.5229 22 22 17.5229 22 12C22 6.47715 17.5229 2 12 2ZM0 12C0 5.3726 5.3726 0 12 0C18.6274 0 24 5.3726 24 12C24 18.6274 18.6274 24 12 24C5.3726 24 0 18.6274 0 12Z"
|
||||||
|
fill="rgba(0,0,0,0.7)"
|
||||||
|
stroke="none"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M9.59162 22.7357C9.49492 22.6109 9.49492 21.4986 9.59162 19.399C8.55572 19.4347 7.90122 19.3628 7.62812 19.1833C7.21852 18.9139 6.80842 18.0833 6.44457 17.4979C6.08072 16.9125 5.27312 16.8199 4.94702 16.6891C4.62091 16.5582 4.53905 16.0247 5.84562 16.4282C7.15222 16.8316 7.21592 17.9303 7.62812 18.1872C8.04032 18.4441 9.02572 18.3317 9.47242 18.1259C9.91907 17.9201 9.88622 17.1538 9.96587 16.8503C10.0666 16.5669 9.71162 16.5041 9.70382 16.5018C9.26777 16.5018 6.97697 16.0036 6.34772 13.7852C5.71852 11.5669 6.52907 10.117 6.96147 9.49369C7.24972 9.07814 7.22422 8.19254 6.88497 6.83679C8.11677 6.67939 9.06732 7.06709 9.73672 7.99999C9.73737 8.00534 10.6143 7.47854 12.0001 7.47854C13.386 7.47854 13.8777 7.90764 14.2571 7.99999C14.6365 8.09234 14.94 6.36699 17.2834 6.83679C16.7942 7.79839 16.3844 8.99999 16.6972 9.49369C17.0099 9.98739 18.2372 11.5573 17.4833 13.7852C16.9807 15.2706 15.9927 16.1761 14.5192 16.5018C14.3502 16.5557 14.2658 16.6427 14.2658 16.7627C14.2658 16.9427 14.4942 16.9624 14.8233 17.8058C15.0426 18.368 15.0585 19.9739 14.8708 22.6234C14.3953 22.7445 14.0254 22.8257 13.7611 22.8673C13.2924 22.9409 12.7835 22.9822 12.2834 22.9982C11.7834 23.0141 11.6098 23.0123 10.9185 22.948C10.4577 22.9051 10.0154 22.8343 9.59162 22.7357Z"
|
||||||
|
fill="rgba(0,0,0,0.7)"
|
||||||
|
stroke="none"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
1
src/lib/images/svelte-logo.svg
Normal file
1
src/lib/images/svelte-logo.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="107" height="128" viewBox="0 0 107 128"><title>svelte-logo</title><path d="M94.1566,22.8189c-10.4-14.8851-30.94-19.2971-45.7914-9.8348L22.2825,29.6078A29.9234,29.9234,0,0,0,8.7639,49.6506a31.5136,31.5136,0,0,0,3.1076,20.2318A30.0061,30.0061,0,0,0,7.3953,81.0653a31.8886,31.8886,0,0,0,5.4473,24.1157c10.4022,14.8865,30.9423,19.2966,45.7914,9.8348L84.7167,98.3921A29.9177,29.9177,0,0,0,98.2353,78.3493,31.5263,31.5263,0,0,0,95.13,58.117a30,30,0,0,0,4.4743-11.1824,31.88,31.88,0,0,0-5.4473-24.1157" style="fill:#ff3e00"/><path d="M45.8171,106.5815A20.7182,20.7182,0,0,1,23.58,98.3389a19.1739,19.1739,0,0,1-3.2766-14.5025,18.1886,18.1886,0,0,1,.6233-2.4357l.4912-1.4978,1.3363.9815a33.6443,33.6443,0,0,0,10.203,5.0978l.9694.2941-.0893.9675a5.8474,5.8474,0,0,0,1.052,3.8781,6.2389,6.2389,0,0,0,6.6952,2.485,5.7449,5.7449,0,0,0,1.6021-.7041L69.27,76.281a5.4306,5.4306,0,0,0,2.4506-3.631,5.7948,5.7948,0,0,0-.9875-4.3712,6.2436,6.2436,0,0,0-6.6978-2.4864,5.7427,5.7427,0,0,0-1.6.7036l-9.9532,6.3449a19.0329,19.0329,0,0,1-5.2965,2.3259,20.7181,20.7181,0,0,1-22.2368-8.2427,19.1725,19.1725,0,0,1-3.2766-14.5024,17.9885,17.9885,0,0,1,8.13-12.0513L55.8833,23.7472a19.0038,19.0038,0,0,1,5.3-2.3287A20.7182,20.7182,0,0,1,83.42,29.6611a19.1739,19.1739,0,0,1,3.2766,14.5025,18.4,18.4,0,0,1-.6233,2.4357l-.4912,1.4978-1.3356-.98a33.6175,33.6175,0,0,0-10.2037-5.1l-.9694-.2942.0893-.9675a5.8588,5.8588,0,0,0-1.052-3.878,6.2389,6.2389,0,0,0-6.6952-2.485,5.7449,5.7449,0,0,0-1.6021.7041L37.73,51.719a5.4218,5.4218,0,0,0-2.4487,3.63,5.7862,5.7862,0,0,0,.9856,4.3717,6.2437,6.2437,0,0,0,6.6978,2.4864,5.7652,5.7652,0,0,0,1.602-.7041l9.9519-6.3425a18.978,18.978,0,0,1,5.2959-2.3278,20.7181,20.7181,0,0,1,22.2368,8.2427,19.1725,19.1725,0,0,1,3.2766,14.5024,17.9977,17.9977,0,0,1-8.13,12.0532L51.1167,104.2528a19.0038,19.0038,0,0,1-5.3,2.3287" style="fill:#fff"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/lib/images/svelte-welcome.png
Normal file
BIN
src/lib/images/svelte-welcome.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 352 KiB |
BIN
src/lib/images/svelte-welcome.webp
Normal file
BIN
src/lib/images/svelte-welcome.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 113 KiB |
15
src/routes/+layout.svelte
Normal file
15
src/routes/+layout.svelte
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<script>
|
||||||
|
import '@picocss/pico';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<slot />
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
265
src/routes/+page.svelte
Normal file
265
src/routes/+page.svelte
Normal file
@@ -0,0 +1,265 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Game, type Score } from './interfaces';
|
||||||
|
export const ssr = false;
|
||||||
|
let games: Game[] = [new Game()];
|
||||||
|
let gameEditing = 0;
|
||||||
|
let scoreEditing = -1;
|
||||||
|
$: currentGameEditing = games[gameEditing];
|
||||||
|
$: currentScoreEditing = scoreEditing > -1 ? currentGameEditing.scores[scoreEditing] : null;
|
||||||
|
$: gamesNotEditing = games.filter(i => i !== currentGameEditing)
|
||||||
|
$: disableEditing = currentGameEditing.isComplete && scoreEditing === -1;
|
||||||
|
function isKill(score: Score | undefined | null) {
|
||||||
|
return score === "killHit6" || score === "killHit8" || score === "killMiss";
|
||||||
|
}
|
||||||
|
function addScore(score: Score) {
|
||||||
|
const targetGame = games[gameEditing];
|
||||||
|
targetGame.addScore(score);
|
||||||
|
games = [...games];
|
||||||
|
}
|
||||||
|
function replaceScore(score: Score) {
|
||||||
|
const targetGame = currentGameEditing;
|
||||||
|
targetGame.replaceScore(scoreEditing, score);
|
||||||
|
scoreEditing = -1;
|
||||||
|
games = [...games];
|
||||||
|
}
|
||||||
|
function setScore(score: Score) {
|
||||||
|
if (scoreEditing === -1) {
|
||||||
|
addScore(score);
|
||||||
|
} else {
|
||||||
|
replaceScore(score);
|
||||||
|
}
|
||||||
|
games = [...games];
|
||||||
|
}
|
||||||
|
function saveGame() {
|
||||||
|
if (!currentGameEditing.isComplete) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const lastGame = games[games.length - 1]
|
||||||
|
if(lastGame !== currentGameEditing) {
|
||||||
|
games = [...games];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
games = [...games, new Game()]
|
||||||
|
}
|
||||||
|
gameEditing = games.length - 1;
|
||||||
|
scoreEditing = -1;
|
||||||
|
}
|
||||||
|
function calculateAverage(gamesToCalculate: Game[]): number {
|
||||||
|
if(gamesToCalculate.length < 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const totalScore = gamesToCalculate.reduce((acc, g) => acc + g.totalScore, 0);
|
||||||
|
return totalScore / (gamesToCalculate.length);
|
||||||
|
}
|
||||||
|
function calculateRating(gamesToCalculate: Game[]): number {
|
||||||
|
const totalGames = gamesToCalculate.length;
|
||||||
|
|
||||||
|
if (totalGames === 0) {
|
||||||
|
return 0; // Return 0 if there are no completed games
|
||||||
|
}
|
||||||
|
|
||||||
|
const average = calculateAverage(gamesToCalculate);
|
||||||
|
const hitPercent = calculateHitPercentage(gamesToCalculate);
|
||||||
|
const killsHit = calculateKillsHit(gamesToCalculate);
|
||||||
|
|
||||||
|
// Apply weights and combine according to the formula
|
||||||
|
const rating = (average) * 8 + hitPercent * 500 + killsHit * 2;
|
||||||
|
|
||||||
|
return rating;
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateHitPercentage(games: Game[]): number {
|
||||||
|
const totalThrows = games.length * 10;
|
||||||
|
let totalHits = 0;
|
||||||
|
|
||||||
|
for (const game of games) {
|
||||||
|
for (const score of game.scores) {
|
||||||
|
if (score === 6 || score === 8 || score === 'killHit6' || score === 'killHit8') {
|
||||||
|
totalHits++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (totalHits / totalThrows); // Calculate hit percentage
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateKillsHit(games: Game[]): number {
|
||||||
|
let killsHit = 0;
|
||||||
|
|
||||||
|
for (const game of games) {
|
||||||
|
for (const score of game.scores) {
|
||||||
|
if (score === 'killHit6' || score === 'killHit8') {
|
||||||
|
killsHit++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return killsHit; // Calculate total kills hit
|
||||||
|
}
|
||||||
|
function totalKills(games: Game[]) {
|
||||||
|
return games.reduce((accum: number, current) => {
|
||||||
|
return current.stats.totalEightKills + current.stats.totalSixKills + accum;
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
function getLabelForScore(score: Score) {
|
||||||
|
if (typeof score === 'number') {
|
||||||
|
return score.toString();
|
||||||
|
}
|
||||||
|
switch (score) {
|
||||||
|
case 'killHit6':
|
||||||
|
return 'Kill 6';
|
||||||
|
case 'killHit8':
|
||||||
|
return 'Kill 8';
|
||||||
|
case 'killMiss':
|
||||||
|
return 'Miss';
|
||||||
|
case "drop":
|
||||||
|
return "Drop";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Home</title>
|
||||||
|
<meta name="description" content="Figure out ratings" />
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<h1 class="center">WATL rating simulator</h1>
|
||||||
|
<section>
|
||||||
|
<p>Current Game Score {currentGameEditing.totalScore}
|
||||||
|
</p>
|
||||||
|
<div class="flexrow">
|
||||||
|
{#each currentGameEditing.scores as score, scoreIndex}
|
||||||
|
<div>
|
||||||
|
{#if scoreIndex === scoreEditing}
|
||||||
|
<button
|
||||||
|
on:click={() => {
|
||||||
|
scoreEditing = -1;
|
||||||
|
}}>Cancel</button
|
||||||
|
>
|
||||||
|
{:else}
|
||||||
|
<button on:click={() => (scoreEditing = scoreIndex)}>{getLabelForScore(score)}</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
{#if currentGameEditing.isComplete}
|
||||||
|
<button on:click={saveGame}>Save Game</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing}
|
||||||
|
on:click={() => {
|
||||||
|
setScore(0);
|
||||||
|
}}>0</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing}
|
||||||
|
on:click={() => {
|
||||||
|
setScore(1);
|
||||||
|
}}>1</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing}
|
||||||
|
on:click={() => {
|
||||||
|
setScore(2);
|
||||||
|
}}>2</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing}
|
||||||
|
on:click={() => {
|
||||||
|
setScore(3);
|
||||||
|
}}>3</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing}
|
||||||
|
on:click={() => {
|
||||||
|
setScore(4);
|
||||||
|
}}>4</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing}
|
||||||
|
on:click={() => {
|
||||||
|
setScore(5);
|
||||||
|
}}>5</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing}
|
||||||
|
on:click={() => {
|
||||||
|
setScore(6);
|
||||||
|
}}>6</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing || (!currentGameEditing.KillEnabled && !isKill(currentScoreEditing))}
|
||||||
|
on:click={() => {
|
||||||
|
setScore('killHit6');
|
||||||
|
}}>{getLabelForScore('killHit6')}</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing || (!currentGameEditing.KillEnabled && !isKill(currentScoreEditing))}
|
||||||
|
on:click={() => {
|
||||||
|
setScore('killHit8');
|
||||||
|
}}>{getLabelForScore('killHit8')}</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing || (!currentGameEditing.KillEnabled && !isKill(currentScoreEditing))}
|
||||||
|
on:click={() => {
|
||||||
|
setScore('killMiss');
|
||||||
|
}}>{getLabelForScore('killMiss')}</button
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
disabled={disableEditing}
|
||||||
|
on:click={() => {
|
||||||
|
setScore('drop');
|
||||||
|
}}>{getLabelForScore('drop')}</button
|
||||||
|
>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<h2>Past Games</h2>
|
||||||
|
<p>Rating: {calculateRating(gamesNotEditing)} Average: {calculateAverage(gamesNotEditing)} total kills: {calculateKillsHit(gamesNotEditing)}</p>
|
||||||
|
<table class="striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Game</th>
|
||||||
|
<th>Score</th>
|
||||||
|
<th>Bulls</th>
|
||||||
|
<th>Kills 8</th>
|
||||||
|
<th>Kills 6</th>
|
||||||
|
<th>Drops</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{#each games as game, gameIndex}
|
||||||
|
{#if gameIndex !== gameEditing}
|
||||||
|
<tr>
|
||||||
|
<td>{gameIndex + 1}</td>
|
||||||
|
<td>{game.totalScore}</td>
|
||||||
|
<td>{game.stats.bulls}</td>
|
||||||
|
<td>{game.stats.totalEightKills}</td>
|
||||||
|
<td>{game.stats.totalSixKills}</td>
|
||||||
|
<td>{game.stats.drops}</td>
|
||||||
|
<td><button
|
||||||
|
on:click={() => {
|
||||||
|
gameEditing = gameIndex;
|
||||||
|
}}
|
||||||
|
>Edit</button></td>
|
||||||
|
</tr>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.center {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.flexrow {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 0.5rem;
|
||||||
|
min-height: 3.1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
76
src/routes/interfaces.ts
Normal file
76
src/routes/interfaces.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
export type Score = 8 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | "drop" | "killHit8" | "killHit6" | "killMiss";
|
||||||
|
export interface GameStats { totalSixKills: number; totalEightKills: number; killAttempts: number, drops: number, bulls: number}
|
||||||
|
export class Game {
|
||||||
|
public scores: Score[] = [];
|
||||||
|
public stats: GameStats = this.GenerateStats();
|
||||||
|
public addScore(score: Score) {
|
||||||
|
this.scores.push(score);
|
||||||
|
this.scores = [...this.scores]
|
||||||
|
this.stats = this.GenerateStats();
|
||||||
|
}
|
||||||
|
public removeScore(scoreNumber: number) {
|
||||||
|
this.scores.splice(scoreNumber, 1);
|
||||||
|
this.scores = [...this.scores]
|
||||||
|
this.stats = this.GenerateStats();
|
||||||
|
}
|
||||||
|
public replaceScore(scoreNumber: number, score: Score) {
|
||||||
|
this.scores[scoreNumber] = score;
|
||||||
|
this.scores = [...this.scores]
|
||||||
|
this.stats = this.GenerateStats();
|
||||||
|
}
|
||||||
|
public get isComplete() {
|
||||||
|
return this.scores.length === 10;
|
||||||
|
}
|
||||||
|
public convertScoreToNumber(score: Score): number {
|
||||||
|
if (score === 'killHit6') {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
if (score === 'killHit8') {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
if (score === 'killMiss') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (score === 'drop') {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
public get totalScore() : number {
|
||||||
|
return this.scores.reduce((acc: number, current) => {
|
||||||
|
return acc + this.convertScoreToNumber(current);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
public get KillEnabled() {
|
||||||
|
const stats = this.GenerateStats();
|
||||||
|
if(stats.killAttempts < 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(stats.killAttempts === 2 && stats.drops > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public GenerateStats(): { totalSixKills: number; totalEightKills: number; killAttempts: number, drops: number, bulls: number} {
|
||||||
|
const data = { totalSixKills: 0, totalEightKills: 0, killAttempts: 0, drops: 0, bulls: 0}
|
||||||
|
this.scores.forEach(score => {
|
||||||
|
if(score === 6) {
|
||||||
|
data.bulls += 1
|
||||||
|
}
|
||||||
|
if(score === "drop") {
|
||||||
|
data.drops += 1;
|
||||||
|
}
|
||||||
|
if( score === "killHit6" || score === "killHit8" || score === "killMiss") {
|
||||||
|
data.killAttempts += 1;
|
||||||
|
}
|
||||||
|
if(score === "killHit6") {
|
||||||
|
data.totalSixKills += 1;
|
||||||
|
}
|
||||||
|
if(score === "killHit8") {
|
||||||
|
data.totalEightKills += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
static/favicon.png
Normal file
BIN
static/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
3
static/robots.txt
Normal file
3
static/robots.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# https://www.robotstxt.org/robotstxt.html
|
||||||
|
User-agent: *
|
||||||
|
Disallow:
|
||||||
18
svelte.config.js
Normal file
18
svelte.config.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import adapter from '@sveltejs/adapter-auto';
|
||||||
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
|
||||||
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
|
const config = {
|
||||||
|
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
|
||||||
|
// for more information about preprocessors
|
||||||
|
preprocess: vitePreprocess(),
|
||||||
|
|
||||||
|
kit: {
|
||||||
|
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
|
||||||
|
// If your environment is not supported, or you settled on a specific environment, switch out the adapter.
|
||||||
|
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
|
||||||
|
adapter: adapter()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"extends": "./.svelte-kit/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"strict": true,
|
||||||
|
"moduleResolution": "bundler"
|
||||||
|
}
|
||||||
|
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||||
|
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
|
||||||
|
//
|
||||||
|
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||||
|
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||||
|
}
|
||||||
6
vite.config.ts
Normal file
6
vite.config.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [sveltekit()]
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user