Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Match Scouting Phase System #12

Merged
merged 6 commits into from
Nov 20, 2024
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/app.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
/* Hide scrollbar for Chrome, Safari and Opera */
.no-scrollbar::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
.no-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
}
23 changes: 20 additions & 3 deletions src/lib/ActionInputStateMachine.svelte.ts
Original file line number Diff line number Diff line change
@@ -5,10 +5,27 @@ export class ActionInputVerifier {
private held_balloons: number = 0;
private held_totes: number = 0;

public get_held_tele(): { balloons: number; totes: number } {
return {
balloons: this.held_balloons,
totes: this.held_totes
};
}
public get_held_auto(): { bunnies: number; balloons: number; totes: number } {
return {
bunnies: this.held_bunnies,
balloons: this.held_balloons,
totes: this.held_totes
};
}

public verify_actions(action_data: AutoActionData[]) {
action_data
.reverse()
.forEach((action_data) => (action_data.ok = this.verify_new_action(action_data)));
action_data.forEach((action) => {
action.ok = this.verify_new_action(action);
this.held_totes = Math.max(this.held_totes, 0);
this.held_balloons = Math.max(this.held_balloons, 0);
this.held_bunnies = Math.max(this.held_bunnies, 0);
});
}

// Takes an action and returns if it's a legal one
6 changes: 3 additions & 3 deletions src/lib/components/Action.svelte
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
}: {
action_data: AutoActionData;
index: number;
shift: (index: number, change: number) => void;
shift: (index: number, change: -1 | 1) => void;
remove: (index: number) => void;
} = $props();

@@ -31,13 +31,13 @@
{/if}
<button
class="group-first:pointer-events-none group-first:opacity-30"
onclick={() => shift(index, -1)}
onclick={() => shift(index, 1)}
>
<MoveUp />
</button>
<button
class="group-last:pointer-events-none group-last:opacity-30"
onclick={() => shift(index, 1)}
onclick={() => shift(index, -1)}
>
<MoveDown />
</button>
33 changes: 25 additions & 8 deletions src/lib/components/Timeline.svelte
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
<script lang="ts">
import { ActionInputVerifier } from '$lib/ActionInputStateMachine.svelte';
import type { AutoActionData } from '$lib/types';
import type { AutoActionData, AutoHeldItems, TeleHeldItems } from '$lib/types';
import Action from './Action.svelte';

let {
actions = $bindable(),
held = $bindable(),
furthest_auto_index = $bindable(),
displaying = $bindable()
}: { actions: AutoActionData[]; displaying: boolean } = $props();
}: {
actions: AutoActionData[];
held: AutoHeldItems | TeleHeldItems;
furthest_auto_index: number;
displaying: boolean;
} = $props();

/// Determine if currying is the right solution or if we should use a binding
function remove(index: number) {
if (furthest_auto_index >= index) furthest_auto_index--;
actions.splice(index, 1);
verify();
}

function shift(index: number, change: number) {
let item = actions[index];
actions.splice(index, 1);
actions.splice(index + change, 0, item);
function shift(index: number, change: -1 | 1) {
//if (furthest_auto_index === index) furthest_auto_index += change;
//else if (furthest_auto_index === index + change) furthest_auto_index = index;

[actions[index], actions[index + change]] = [actions[index + change], actions[index]];
verify();
}

function verify() {
new ActionInputVerifier().verify_actions(actions);
const action_input_verifier = new ActionInputVerifier();
action_input_verifier.verify_actions(actions);
// TODO: Fix this horrible and jank solution
held = Object.hasOwn(held, 'bunnies')
? action_input_verifier.get_held_auto()
: action_input_verifier.get_held_tele();
}
const is_valid_timeline = $derived(actions.filter((action) => !action.ok).length === 0);
</script>
@@ -36,7 +50,7 @@
}}
>
<div
class="absolute inset-x-0 bottom-0 flex h-[50dvh] w-dvw flex-col items-center gap-3 rounded-t-lg bg-gunmetal p-3 text-white"
class="no-scrollbar absolute inset-x-0 bottom-0 flex h-[50dvh] w-dvw flex-col items-center gap-3 overflow-y-scroll rounded-t-lg bg-gunmetal p-3 text-white"
id="timeline"
>
{#each actions as _, i}
@@ -46,6 +60,9 @@
{remove}
{shift}
/>
{#if furthest_auto_index === actions.length - i - 1}
<hr />
azaleacolburn marked this conversation as resolved.
Show resolved Hide resolved
{/if}
{/each}
{#if actions.length === 0}
<h3 class="m-auto">No actions yet :3</h3>
6 changes: 6 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -91,6 +91,12 @@ export type BunnyAction =
| 'ScoreBunnyLow';
export type AutoAction = TeleAction | BunnyAction;

export type TeleHeldItems = {
balloons: number;
totes: number;
};
export type AutoHeldItems = TeleHeldItems & { bunnies: number };

// For state machine
export type ItemInputState = 'Intake' | 'Score' | 'Eject' | 'None';
export type TeleInputState = TeleAction | ItemInputState;
110 changes: 84 additions & 26 deletions src/routes/scout/[team_data]/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,46 +1,104 @@
<script lang="ts">
import type { TeamMatch, AutoActionData } from '$lib/types';
import type { TeamMatch, AutoActionData, AutoHeldItems, TeleActionData } from '$lib/types';
import Timeline from '$lib/components/Timeline.svelte';
import ActionInputs from './ActionInputs.svelte';
import AutoActionInputs from './AutoActionInputs.svelte';
import TeleActionInputs from './TeleActionInputs.svelte';
import type { PageData } from './$types';
import { ArrowRight, ArrowLeft } from 'lucide-svelte';
import { browser } from '$app/environment';

const { data }: { data: PageData } = $props();

const scout_id = browser ? (localStorage?.getItem('scout_id') ?? '') : '';

let actions: AutoActionData[] = $state([]);
let held: AutoHeldItems = $state({
bunnies: 0,
balloons: 0,
totes: 0
});
// The furthest index in actions that was made during auto
let furthest_auto_index = $state(0);

let skill = $state(0);
let broke = $state(false);
let died = $state(false);
let notes = $state('');

let timelineExtended = $state(false);
let gamePhase = $state('Auto') as 'Auto' | 'Tele' | 'Post';
let pageName = $state('');

const match: TeamMatch = $state({
id: 0,
scout_id,
team_key: data.team_key,
match_key: data.match_key,
skill: 3,
notes: '',
broke: false,
died: false,
auto_actions: [],
tele_actions: []
});
function phaseShiftRight() {
gamePhase = gamePhase === 'Auto' ? 'Tele' : gamePhase === 'Tele' ? 'Post' : 'Post'; // Last case should never happen
}
function phaseShiftLeft() {
gamePhase = gamePhase === 'Post' ? 'Tele' : gamePhase === 'Tele' ? 'Auto' : 'Auto'; // Last case should never happen
}

function submit() {
const auto_actions = actions.slice(0, furthest_auto_index + 1);
const tele_actions = actions.slice(furthest_auto_index + 1) as TeleActionData[]; // TODO: Add verification function to ensure that this always works
const match: TeamMatch = {
id: 0,
scout_id,
team_key: data.team_key,
match_key: data.match_key,
skill,
broke,
died,
notes,
auto_actions,
tele_actions
};
}
</script>

<div class="m-auto flex h-dvh max-w-md flex-col items-center gap-2 p-2">
<div class="flex w-full justify-between border-b-2 border-white/10 pb-2 font-semibold">
<span class="flex-grow">Team {data.team_key}</span>
<span class="flex-grow text-right">{pageName}</span>
<span class="">Team {data.team_key}</span>
{#if gamePhase !== 'Auto'}
<button onclick={phaseShiftLeft} class=""><ArrowLeft /></button>
awwpotato marked this conversation as resolved.
Show resolved Hide resolved
{/if}
<span class="text-right">{gamePhase}: {pageName}</span>
awwpotato marked this conversation as resolved.
Show resolved Hide resolved
{#if gamePhase === 'Post'}
<button class="rounded border pl-2 pr-2">Submit </button>
awwpotato marked this conversation as resolved.
Show resolved Hide resolved
{:else}
<button onclick={phaseShiftRight} class=""><ArrowRight /></button>
{/if}
</div>

<ActionInputs bind:actions bind:pageName />

<button
class="w-full border-t-2 border-white/10 pt-2 text-center font-semibold"
onclick={(e: Event) => {
e.stopPropagation();
timelineExtended = true;
}}>Show Timeline</button
>
<Timeline bind:actions bind:displaying={timelineExtended} />
{#if gamePhase === 'Auto'}
<AutoActionInputs bind:furthest_auto_index bind:held bind:actions bind:pageName />
<button
class="w-full border-t-2 border-white/10 pt-2 text-center font-semibold"
onclick={(e: Event) => {
e.stopPropagation();
timelineExtended = true;
}}>Show Timeline</button
>
<Timeline
bind:furthest_auto_index
bind:held
bind:actions
bind:displaying={timelineExtended}
/>
{:else if gamePhase === 'Tele'}
<TeleActionInputs bind:held bind:actions bind:pageName />
<button
class="w-full border-t-2 border-white/10 pt-2 text-center font-semibold"
onclick={(e: Event) => {
e.stopPropagation();
timelineExtended = true;
}}>Show Timeline</button
>
<Timeline
bind:furthest_auto_index
bind:held
bind:actions
bind:displaying={timelineExtended}
/>
{:else}
<div>Postmatch</div>
{/if}
</div>
Loading