Всем привет! Пока я работал над своей последней статьей (Перемешивание значений массива в Vue 3), я создал серию демонстраций Генератора случайных чисел, которые в конечном итоге не вошли в число лучших. для финального поста. Одной из демонстраций, которую я изначально запланировал для этой публикации, было приложение для игровых автоматов Vue.js, которое предполагало случайный цикл по массиву значений. Позже, просматривая демонстрацию, я обнаружил проблему: при циклическом просмотре случайного набора значений слотов слоты заикались по крайней мере один раз в два цикла. Присмотревшись к журналу, стало ясно, что виновниками были повторяющиеся значения подряд:
Это беспокоило меня… поэтому я решил это исправить. После некоторых проб и ошибок и консультаций по StackOverflow я считаю, что у меня есть по крайней мере одно потенциальное решение. Давайте проверим это!
Для этой статьи см. компонент под названием IndexRepeatPrevention.vue в следующем репозитории:
Для начала поговорим о компоненте, который изначально выглядел так, когда я только начинал:
<template> <div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8"> <div class="px-4 py-6 sm:px-0"> <div class="flex items-center justify-center py-16"> <QuestionMarkCircleIcon v-if="slots.length < 1" class="w-96 h-96"/> <div v-else v-for="slot in slots" :key="slot.id" class="w-96 h-96 m-2"> <div class="flex justify-center items-center w-full h-full p-8 text-9xl rounded-md shadow-lg border-solid border-2 border-sky-500"> <!-- <img :src="slot.img"> --> {{ slot }} </div> </div> </div> <div class="flex justify-center"> <button @click="randomize" class="group relative w-48 flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> Randomize </button> </div> </div> </div> </template> <script setup> import { ref } from "@vue/reactivity"; import { onMounted } from "@vue/runtime-core"; import { QuestionMarkCircleIcon } from "@heroicons/vue/outline" const slots = ref([]) const numberArray = ref(Array.from({length: 9}, (e, i)=> i + 1)) const sleep = (milliseconds) => { return new Promise(resolve => setTimeout(resolve, milliseconds)) } const randomize = async () => { const list = numberArray.value.sort(() => Math.random() - 0.5) for (let i = 0; i < list.length; i++) { const index = Math.floor(Math.random() * list.length) await sleep(100) slots.value = list.filter(r => r === (index + 1)) console.log(slots.value) } } </script>
Приведенная выше функция рандомизации получает numberArray, а затем присваивает его списку после сортировки и рандомизации. Затем внутри цикла for мы создаем новый случайный индекс для каждого цикла. Исходный список затем фильтруется с использованием каждого вновь созданного индекса, а затем повторно назначается slots.value. Используя функцию sleep, мы можем замедлить цикл цикла, чтобы увидеть каждый отдельный результат, назначенный slots.value.
Эта функциональность работает с точки зрения генерации случайных последовательностей, но она не принимает во внимание возможность последовательного повторения случайных чисел. После некоторых онлайн-копаний и консультаций я реорганизовал функцию рандомизации следующим образом:
let prevIndex = null const generateRandIndex = max => { let index do { index = Math.floor(Math.random() * max) } while (index === prevIndex) prevIndex = index return index } const randomize = async () => { const list = numberArray.value.sort(() => Math.random() - 0.5) for (let i = 0; i < 10; i++) { const index = generateRandIndex(list.length) await sleep(100) slots.value = list.filter(r => r === index + 1) } }
Внутри функции рандомизации мы вызовем другую функцию с именем generateRandIndex(), которая использует цикл do-while для повторного создания индекса, если значение в заданном цикле совпадает с предыдущим.
Окончательная настройка скрипта должна выглядеть так:
<script setup> import { ref } from "@vue/reactivity"; import { onMounted } from "@vue/runtime-core"; import { QuestionMarkCircleIcon } from "@heroicons/vue/outline" const slots = ref([]) const numberArray = ref(Array.from({length: 9}, (e, i)=> i + 1)) const sleep = (milliseconds) => { return new Promise(resolve => setTimeout(resolve, milliseconds)) } let prevIndex = null const generateRandIndex = max => { let index do { index = Math.floor(Math.random() * max) } while (index === prevIndex) prevIndex = index return index } const randomize = async () => { const list = numberArray.value.sort(() => Math.random() - 0.5) for (let i = 0; i < 10; i++) { const index = generateRandIndex(list.length) await sleep(100) slots.value = list.filter(r => r === index + 1) console.log(slots.value) } } </script>
Давайте посмотрим, как теперь выглядит вывод:
Вот и все... никаких повторных правонарушителей!
Еще раз проверьте эту функциональность в компоненте IndexRepeatPrevention.vue в следующем репозитории:
На этом пока хватит статей о ГСЧ. Я работаю над некоторыми демонстрациями Vue + Supabase… так что следите за обновлениями!