205 lines
4.8 KiB
Vue
205 lines
4.8 KiB
Vue
<template>
|
|
<div>
|
|
<h1 class="mt-2 mb-4 text-3xl font-bold text-center">
|
|
ASMD
|
|
</h1>
|
|
<!-- Number to find -->
|
|
|
|
<NumberBox
|
|
class="aspect-square mx-auto mb-8 w-[3em] text-4xl"
|
|
:class="{
|
|
'text-green-400': difficultyLevel === 1,
|
|
'text-amber-400': difficultyLevel === 2,
|
|
'text-red-400': difficultyLevel === 3,
|
|
}">
|
|
{{ result }}
|
|
</NumberBox>
|
|
|
|
<!-- Plaquettes -->
|
|
<div
|
|
class="grid grid-cols-6 grid-rows-2 gap-2 justify-center px-2 mx-auto max-w-sm">
|
|
<TransitionGroup name="list">
|
|
<NumberBox
|
|
class="col-start-auto h-[1.8em] text-2xl"
|
|
:class="{ 'text-stone-600 border-stone-600': !item.free }"
|
|
@click="selectNumber(item)"
|
|
v-for="(item, i) in plaquettes"
|
|
:key="i">
|
|
{{ item.value }}
|
|
</NumberBox>
|
|
</TransitionGroup>
|
|
</div>
|
|
|
|
<!-- OPERATORS -->
|
|
<div class="flex gap-2 justify-center my-4">
|
|
<NumberBox
|
|
class="aspect-square w-[1.5em] text-2xl"
|
|
@click="selectOperator(item)"
|
|
v-for="(item, i) in operators"
|
|
:key="i">
|
|
{{ item }}
|
|
</NumberBox>
|
|
</div>
|
|
|
|
<div class="my-4 border-b" />
|
|
|
|
<div
|
|
class="mb-2 text-center"
|
|
v-for="(operation, i) in operations"
|
|
:key="i">
|
|
<div class="inline-block relative text-xl">
|
|
<!-- OPERATION -->
|
|
<div class="flex items-center">
|
|
<NumberBox class="w-[2.5em]">
|
|
{{ operation.left?.value ?? '?' }}
|
|
</NumberBox>
|
|
<NumberBox class="w-[2.5em] border-none">
|
|
{{ operation.operator ?? '' }}
|
|
</NumberBox>
|
|
|
|
<NumberBox class="w-[2.5em]">
|
|
{{ operation.right?.value ?? '?' }}
|
|
</NumberBox>
|
|
|
|
<!-- EQUALS -->
|
|
<NumberBox class="mx-4 border-none">
|
|
=
|
|
</NumberBox>
|
|
|
|
<!-- RESULT -->
|
|
<NumberBox class="w-[2.5em]">
|
|
<span
|
|
v-if="
|
|
operation.operator &&
|
|
operation.left &&
|
|
operation.right &&
|
|
isOperationValid(operation)
|
|
">
|
|
{{
|
|
operate(
|
|
operation.operator,
|
|
operation.left.value,
|
|
operation.right.value
|
|
)
|
|
}}
|
|
</span>
|
|
<span v-else>?</span>
|
|
</NumberBox>
|
|
|
|
<IconClose class="ml-8 rounded-full border" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style>
|
|
.list-enter-active,
|
|
.list-leave-active {
|
|
transition: all 0.5s ease;
|
|
}
|
|
.list-enter-from,
|
|
.list-leave-to {
|
|
opacity: 0;
|
|
transform: translateX(30px);
|
|
}
|
|
</style>
|
|
|
|
<script setup lang="ts">
|
|
import { computed, onMounted, reactive, ref } from 'vue'
|
|
|
|
import { isOperationValid, isSolvable, operate } from '@/algo'
|
|
import NumberBox from '@/components/common/NumberBox.vue'
|
|
import { pool } from '@/globals'
|
|
import { Operation, OperatorType, Plaquette } from '@/types'
|
|
import { randItem, randRange } from '@/utils'
|
|
import IconClose from '~icons/ph/x'
|
|
|
|
const operators = ['+', '-', '*', '/'] as const
|
|
|
|
const result = ref(0)
|
|
const plaquettes = ref<Plaquette[]>([])
|
|
|
|
const operations = ref<Operation[]>([])
|
|
pushEmptyOperation()
|
|
// pushEmptyOperation()
|
|
|
|
const currentOperation = computed(
|
|
() => operations.value[operations.value.length - 1],
|
|
)
|
|
|
|
function pushEmptyOperation(): void {
|
|
operations.value.push({
|
|
left: null,
|
|
right: null,
|
|
operator: null,
|
|
executed: false,
|
|
})
|
|
}
|
|
|
|
function selectNumber(p: Plaquette): void {
|
|
const op = currentOperation.value
|
|
if (!p.free) return
|
|
p.free = false
|
|
|
|
if (!op.left) {
|
|
op.left = p
|
|
}
|
|
else if (!op.right) {
|
|
op.right = p
|
|
}
|
|
|
|
if (
|
|
op.operator &&
|
|
op.right &&
|
|
op.left &&
|
|
isOperationValid(op) &&
|
|
!op.executed
|
|
) {
|
|
op.executed = true
|
|
plaquettes.value.push({
|
|
value: operate(op.operator, op.left.value, op.right.value),
|
|
free: true,
|
|
})
|
|
pushEmptyOperation()
|
|
}
|
|
}
|
|
|
|
function selectOperator(o: OperatorType): void {
|
|
currentOperation.value.operator = o
|
|
}
|
|
|
|
const difficultyLevel = randItem([1, 1, 1, 1, 1, 1, 2, 2, 2, 3])
|
|
|
|
onMounted(() => {
|
|
do {
|
|
// Find a problem
|
|
// result.value = randRange(101, 1000)
|
|
result.value = (() => {
|
|
switch (difficultyLevel) {
|
|
case 1:
|
|
return randRange(50, 100)
|
|
case 2:
|
|
return randRange(100, 250)
|
|
default:
|
|
return randRange(250, 1000)
|
|
}
|
|
})()
|
|
|
|
plaquettes.value = []
|
|
for (let i = 0; i < 6; ++i) {
|
|
const random = Math.floor(Math.random() * pool.length)
|
|
const el = pool.splice(random, 1)[0]
|
|
plaquettes.value.push({ value: el, free: true })
|
|
}
|
|
// Solve it
|
|
} while (
|
|
!isSolvable(
|
|
result.value,
|
|
plaquettes.value.map(p => p.value),
|
|
)
|
|
)
|
|
plaquettes.value.sort((a, b) => a.value - b.value)
|
|
})
|
|
</script>
|