n0mbers/src/views/GameView.vue
2022-02-17 22:20:09 +01:00

221 lines
5.1 KiB
Vue

<template>
<AppHeader />
<!-- Number to find -->
<PlaquetteBox
class="p-1 mx-auto mb-4 w-fit"
:class="{
'text-blue-400': difficultyLevel === 1,
'text-purple-500': difficultyLevel === 2,
}">
<span class="text-4xl">{{ result }}</span>
</PlaquetteBox>
<!-- Start button -->
<!-- TODO: fix animation -->
<Transition name="zero_height">
<div
class="text-center"
v-if="gameState === GameState.Waiting">
<div>
Combinez les nombres imposés afin de trouver le résultat ci-dessus, ou
de vous en approcher le plus possible.<br>
Le compteur démarre quand vous cliquez sur le bouton.<br>Partagez vos
meilleurs temps !
</div>
<button
@click="startGame"
class="py-2 px-4 mt-4 btn">
{{ t('startGame') }}
</button>
</div>
</Transition>
<!-- PLAQUETTES -->
<PlaquettesList
:plaquettes="shownPlaquettes"
@click-number="selectNumber" />
<Transition name="slide_up">
<div v-if="gameIsRunning">
<!-- OPERATORS -->
<OperatorsList @click="selectOperator" />
<!-- Divider -->
<div class="my-4 mx-auto max-w-sm border-b" />
<!-- List of Operations -->
<OperationsList v-show="gameIsRunning" />
</div>
</Transition>
<Transition name="slide_up">
<div
v-if="isEndGame"
class="flex flex-row justify-evenly items-center mx-auto mt-8 max-w-sm">
<span
v-if="isResultPerfect"
v-html="t('endGame.victoryLabel')" />
<span
v-else
v-html="t('endGame.failureLabel')" />
<button
class="p-2 rounded border"
@click="reboot">
{{ t('playAgain') }}
</button>
</div>
</Transition>
</template>
<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute } from 'vue-router'
import {
getEmptyOperation,
isOperationReady,
isOperationResultValid,
isSolvable,
operate,
} from '@/algo'
import AppHeader from '@/components/AppHeader.vue'
import PlaquetteBox from '@/components/common/PlaquetteBox.vue'
import OperationsList from '@/components/OperationsList.vue'
import OperatorsList from '@/components/OperatorsList.vue'
import PlaquettesList from '@/components/PlaquettesList.vue'
import {
currentOperation,
gameIsRunning,
gameState,
isEndGame,
isResultPerfect,
operations,
plaquettes,
result,
} from '@/composables/game-state'
import { GameState, pools } from '@/globals'
import { OperatorType, Plaquette } from '@/types'
import { randItem, randRange } from '@/utils'
const { t } = useI18n() // call `useI18n`, and spread `t` from `useI18n` returning
/*
* Computed & refs
*/
const difficultyLevel = ref<1 | 2>(1)
const isDaily = computed(() => useRoute().name === 'daily')
const shownPlaquettes = computed(() =>
gameIsRunning.value ? plaquettes.value : [],
)
/*
* Watchers
*/
watch(
currentOperation,
op => {
if (isOperationReady(op) && isOperationResultValid(op) && !op.result) {
op.result = {
free: true,
value: operate(op.operator!, op.left!.value, op.right!.value),
}
if (operations.length < 5 && !isEndGame.value) {
plaquettes.value.push(op.result)
operations.push(getEmptyOperation())
}
}
},
{ deep: true },
)
function startGame(): void {
gameState.value = GameState.Loading
setTimeout(() => (gameState.value = GameState.Playing), 500)
}
function selectNumber(p: Plaquette): void {
if (isEndGame.value) return
const op = currentOperation.value
if (!p.free) return
if (!op.left) {
op.left = p
p.free = false
}
else if (!op.right) {
op.right = p
p.free = false
}
}
/*
* Functions
*/
function selectOperator(o: OperatorType): void {
if (isEndGame.value) return
currentOperation.value.operator = o
}
function reboot(): void {
gameState.value = GameState.Playing
do {
// Find a problem
// result.value = randRange(101, 1000)
difficultyLevel.value = randItem([1, 1, 1, 1, 2])
result.value = (() => {
switch (difficultyLevel.value) {
case 1:
return randRange(101, 1000)
case 2:
return randRange(101, 1000)
}
})()
// result.value = 29
// Reset Operations list
operations.splice(0)
operations.push(getEmptyOperation())
// Generate result and plaquettes
plaquettes.value = []
const poolCopy = [...pools[difficultyLevel.value]]
for (let i = 0; i < 6; ++i) {
const random = Math.floor(Math.random() * poolCopy.length)
const el = poolCopy.splice(random, 1)[0]
plaquettes.value.push({ value: el, free: true })
}
// plaquettes.value = [4, 8, 10, 25, 50, 100].map(value => ({
// free: true,
// value,
// }))
// Solve it
} while (
!isSolvable(
result.value,
plaquettes.value.map(p => p.value),
)
)
plaquettes.value.sort((a, b) => a.value - b.value)
}
/*
* Hooks
*/
onMounted(() => {
reboot()
gameState.value = GameState.Waiting
})
onUnmounted(() => {
gameState.value = GameState.Waiting
})
</script>