Skip to content

Commit

Permalink
feat: basic timeline warning system
Browse files Browse the repository at this point in the history
  • Loading branch information
azaleacolburn committed Nov 19, 2024
1 parent 2b5620f commit c3a8f0e
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 54 deletions.
52 changes: 35 additions & 17 deletions src/lib/ActionInputStateMachine.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { AutoAction, AutoInputState } from '$lib/types';
import type { AutoAction, AutoActionData, AutoInputState } from '$lib/types';

export class ActionInputStateMachine {
actionState: AutoInputState = $state('None') as AutoInputState;

held_bunnies: number = 0;
held_balloons: number = $state(0);
held_totes: number = $state(0);
held_scorables: number = $derived(this.held_balloons + this.held_bunnies);
held_ejectables: number = $derived(this.held_scorables + this.held_totes);
held_balloons: number = 0;
held_totes: number = 0;

/// Methods for adjusting the state (checked by user)
intake_piece() {
this.actionState = this.actionState === 'None' ? 'Intake' : this.actionState;
}
Expand All @@ -27,20 +26,39 @@ export class ActionInputStateMachine {
}

complete_action(success: boolean): AutoAction {
const action_data: AutoActionData = {
action: this.actionState as AutoAction,
success,
ok: true
};

if (this.new_action(action_data)) {
const ret = this.actionState.slice();
this.actionState = 'None';
return ret as AutoAction;
} else {
console.error('Illegal action, this is a bug');
// UB aqfter contract of state machine has been broken
return {} as unknown as AutoAction;
}
}

// Takes an action and returns if it's a legal one
public new_action(action_data: AutoActionData): boolean {
const success = action_data.success;
const action = action_data.action;
if (success) {
if (this.actionState.includes('IntakeBalloon')) this.held_balloons++;
else if (this.actionState.includes('IntakeBunny')) this.held_bunnies++;
else if (this.actionState.includes('IntakeTote')) this.held_totes++;
else if (this.actionState.includes('EjectBalloon')) this.held_balloons--;
else if (this.actionState.includes('EjectBunny')) this.held_bunnies--;
else if (this.actionState.includes('EjectTote')) this.held_totes--;
if (action.includes('IntakeBalloon')) this.held_balloons++;
else if (action.includes('IntakeBunny')) this.held_bunnies++;
else if (action.includes('IntakeTote')) this.held_totes++;
else if (action.includes('EjectBalloon')) this.held_balloons--;
else if (action.includes('EjectBunny')) this.held_bunnies--;
else if (action.includes('EjectTote')) this.held_totes--;
}
// Assume failed scoring is still ejecting
if (this.actionState.includes('ScoreBalloon')) this.held_balloons--;
else if (this.actionState.includes('ScoreBunny')) this.held_bunnies--;
if (action.includes('ScoreBalloon')) this.held_balloons--;
else if (action.includes('ScoreBunny')) this.held_bunnies--;

const ret = this.actionState.slice();
this.actionState = 'None';
return ret as AutoAction;
if (action.includes('Intake')) return true;
return this.held_balloons >= 0 && this.held_bunnies >= 0 && this.held_totes >= 0;
}
}
7 changes: 5 additions & 2 deletions src/lib/components/Action.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,18 @@
>
<span class="w-auto shrink text-clip">{action_data.action}</span>
<div class="flex shrink-0 flex-row content-center justify-end gap-4">
{#if !action_data.ok}
<span class="text-yellow-400">Warning</span>
{/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>
Expand Down
28 changes: 18 additions & 10 deletions src/lib/components/Timeline.svelte
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
<script lang="ts">
import { ActionInputStateMachine } from '$lib/ActionInputStateMachine.svelte';
import type { AutoActionData } from '$lib/types';
import Action from './Action.svelte';
let {
actions = $bindable(),
displaying = $bindable()
}: { actions: AutoActionData[]; displaying: boolean } = $props();
// let latestActions: AutoActionData[] = $derived(actions.toReversed().slice(0, 5));
const remove = (index: number) => {
/// Determine if currying is the right solution or if we should use a binding
function remove(index: number) {
actions.splice(index, 1);
};
verify();
}
const shift = (index: number, change: number) => {
function shift(index: number, change: number) {
let item = actions[index];
actions.splice(index, 1);
actions.splice(index + change, 0, item);
};
verify();
}
function verify() {
actions
.slice()
.reverse()
.forEach(() => {});
const action_state_machine = new ActionInputStateMachine();
actions.forEach((action) => {
action.ok = action_state_machine.new_action(action);
});
}
</script>

Expand All @@ -37,7 +40,12 @@
id="timeline"
>
{#each actions as _, i}
<Action action_data={actions[i]} index={i} {remove} {shift} />
<Action
action_data={actions[actions.length - i - 1]}
index={actions.length - i - 1}
{remove}
{shift}
/>
{/each}
{#if actions.length === 0}
<h3 class="m-auto">No actions yet :3</h3>
Expand Down
38 changes: 20 additions & 18 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,6 @@ export type User = {
};

/// Counts
export type AutoActionsTM = ActionsTM & {
bunny_intake_success: number;
bunny_intake_failure: number;
bunny_tote_success: number;
bunny_tote_failure: number;
bunny_low_success: number;
bunny_low_failure: number;
actions: AutoActionData[];
};

export type TeleActionsTM = ActionsTM & {
actions: TeleActionData[];
};

export type ActionsTM = {
id: number;
tote_intake_success: number;
Expand All @@ -44,6 +30,20 @@ export type ActionsTM = {
score_other_robot_failure: number;
};

export type AutoActionsTM = ActionsTM & {
bunny_intake_success: number;
bunny_intake_failure: number;
bunny_tote_success: number;
bunny_tote_failure: number;
bunny_low_success: number;
bunny_low_failure: number;
actions: AutoActionData[];
};

export type TeleActionsTM = ActionsTM & {
actions: TeleActionData[];
};

export type TeamMatch = {
id: number;
scout_id: string;
Expand All @@ -57,14 +57,16 @@ export type TeamMatch = {
tele_actions: TeleActionData[];
};

export type AutoActionData = {
action: AutoAction;
export type TeleActionData = {
action: TeleAction;
success: boolean;
ok: boolean;
};

export type TeleActionData = {
action: TeleAction;
export type AutoActionData = {
action: AutoAction;
success: boolean;
ok: boolean;
};

// Action Types
Expand Down
45 changes: 39 additions & 6 deletions src/routes/scout/ActionInputs.svelte
Original file line number Diff line number Diff line change
@@ -1,27 +1,60 @@
<script lang="ts">
import SuccessFail from '$lib/components/SuccessFail.svelte';
import type { AutoAction, AutoInputState, AutoActionData } from '$lib/types';
import { ActionInputStateMachine } from '$lib/ActionInputStateMachine.svelte';
let {
actions = $bindable(),
pageName = $bindable()
}: { actions: AutoActionData[]; pageName: string } = $props();
const action_state_machine = new ActionInputStateMachine();
let actionState: AutoInputState = $state('None') as AutoInputState;
let held_bunnies: number = $state(0);
let held_balloons: number = $state(0);
let held_totes: number = $state(0);
const held_scorables: number = $derived(held_balloons + held_bunnies);
const held_ejectables: number = $derived(held_scorables + held_totes);
function intake_piece() {
actionState = actionState === 'None' ? 'Intake' : actionState;
}
function score_piece() {
actionState = actionState === 'None' ? 'Score' : actionState;
}
function eject_piece() {
actionState = actionState === 'None' ? 'Eject' : actionState;
}
function score_bunny(where: 'Low' | 'ExternalTote' | 'InternalTote' | 'UncontrolledTote') {
actionState = `ScoreBunny${where}`;
}
function score_balloon(where: 'Low' | 'InternalTote' | 'ExternalTote' | 'UncontrolledTote') {
actionState = `ScoreBalloon${where}`;
}
function complete(success: boolean) {
// Assume that a failure means a note remains where it is
if (success) {
if (actionState.includes('IntakeBalloon')) held_balloons++;
else if (actionState.includes('IntakeBunny')) held_bunnies++;
else if (actionState.includes('IntakeTote')) held_totes++;
else if (actionState.includes('EjectBalloon')) held_balloons--;
else if (actionState.includes('EjectBunny')) held_bunnies--;
else if (actionState.includes('EjectTote')) held_totes--;
}
// Assume failed scoring is still ejecting
if (actionState.includes('ScoreBalloon')) held_balloons--;
else if (actionState.includes('ScoreBunny')) held_bunnies--;
const actionState = action_state_machine.complete_action();
const action: AutoActionData = {
action: actionState as AutoAction,
success: success
success: success,
ok: true
};
actions.unshift(action);
actions.push(action);
actionState = 'None';
}
const is_none_state: boolean = $derived(action_state_machine.actionState === 'None');
const is_none_state: boolean = $derived(actionState === 'None');
const is_intake_state: boolean = $derived(actionState === 'Intake');
const is_score_state: boolean = $derived(actionState === 'Score');
const is_eject_state = $derived(actionState === 'Eject');
Expand Down
1 change: 0 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"types": ["svelte"]
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
//
Expand Down

0 comments on commit c3a8f0e

Please sign in to comment.