111 lines
3.1 KiB
Vue
111 lines
3.1 KiB
Vue
<template>
|
|
<div>
|
|
<TransitionGroup name="slide_up">
|
|
<div
|
|
class="mb-2 text-center"
|
|
v-for="(op, i) in operations"
|
|
:style="{
|
|
transitionDelay: `${transDelay * (operations.length - i)}ms`,
|
|
}"
|
|
:key="i">
|
|
<div class="inline-block relative text-xl">
|
|
<!-- OPERATION -->
|
|
<div
|
|
class="flex items-center"
|
|
:class="{ 'text-red-600': isOperationInvalid(op) }">
|
|
<!-- LEFT -->
|
|
<div class="w-[2.5em] border-b border-stone-600 transition-all">
|
|
{{ op.left?.value ?? ' ' }}
|
|
</div>
|
|
<!-- RIGHT -->
|
|
<div class="w-[2.5em] border-b border-stone-600 transition-all">
|
|
{{ op.operator ?? ' ' }}
|
|
</div>
|
|
|
|
<div class="w-[2.5em] border-b border-stone-600 transition-all">
|
|
{{ op.right?.value ?? ' ' }}
|
|
</div>
|
|
|
|
<!-- EQUALS -->
|
|
<div class="mx-4 border-none">
|
|
=
|
|
</div>
|
|
|
|
<!-- RESULT -->
|
|
<PlaquetteBox
|
|
:dynamic-size="true"
|
|
class="w-[3.2em] h-8 border-none">
|
|
<IconSad v-if="isOperationInvalid(op)" />
|
|
<span
|
|
v-else-if="
|
|
op.operator &&
|
|
op.left &&
|
|
op.right &&
|
|
isOperationResultValid(op)
|
|
">
|
|
{{ operate(op.operator, op.left.value, op.right.value) }}
|
|
</span>
|
|
<span v-else>?</span>
|
|
</PlaquetteBox>
|
|
|
|
<!-- UNDO -->
|
|
<button
|
|
class="ml-8"
|
|
@click="undoOperation(i)">
|
|
<IconUndo
|
|
class="text-stone-400"
|
|
:class="{
|
|
invisible: !canOperationBeDeleted(op),
|
|
}" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</TransitionGroup>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {
|
|
getEmptyOperation,
|
|
isOperationInvalid,
|
|
isOperationResultValid,
|
|
operate,
|
|
} from '@/algo'
|
|
import { operations, plaquettes } from '@/game-state'
|
|
import { GameState, gameState } from '@/globals'
|
|
import { Operation } from '@/types'
|
|
import IconUndo from '~icons/bx/bx-undo'
|
|
import IconSad from '~icons/ph/smiley-sad'
|
|
|
|
import PlaquetteBox from './common/PlaquetteBox.vue'
|
|
|
|
const transDelay = 100
|
|
|
|
function canOperationBeDeleted(op: Operation): boolean {
|
|
return !!op.left || !!op.right || !!op.operator
|
|
}
|
|
|
|
function undoOperation(index: number): void {
|
|
if (gameState.value !== GameState.Playing) return
|
|
const l = operations.length
|
|
for (let i = operations.length - 1; i >= index; --i) {
|
|
let popped: Operation
|
|
if (i === index) {
|
|
popped = operations[index]
|
|
setTimeout(() => {
|
|
operations[index] = getEmptyOperation()
|
|
}, transDelay * l)
|
|
}
|
|
else {
|
|
popped = operations.pop()!
|
|
}
|
|
if (popped?.left) popped.left.free = true
|
|
if (popped?.right) popped.right.free = true
|
|
if (popped.result) {
|
|
plaquettes.value = plaquettes.value.filter(p => p !== popped.result)
|
|
}
|
|
}
|
|
}
|
|
</script>
|