codepens/cpc-dropdown-slots/dist/script.js

64 lines
2.5 KiB
JavaScript

"use strict";
//1 in 81 chance to get any valid option, 1 in 729 to get a particular option
//16 in 81 chance to get only 2 in a row, 17 in 81 to get at least 2 in a row, 8 in 27 to get just 2 matching
//56 in 81 all different
//The tweet video was definitely faked, but can be seen winning here
//https://twitter.com/Osorpenke/status/1445191696715821058
let enabled = true;
const items = 9;
const wheels = [1, 2, 3].map((x) => document.querySelector(`#dropdown .dropdown .wheel${x}`));
const tag = document.querySelector(`#dropdown .tag`);
const dropdown = document.querySelector(`#dropdown .dropdown`);
const dropdown_wrapper = document.getElementById(`dropdown`);
const all_equal = ([head, ...tail] = []) => tail.every((x) => x == head);
const round_and_modulus_numbers = (numbers, mod) => numbers.map((x) => Math.round(x) % items);
const minimum_spins = 3;
const state_increment = (current, index) => (minimum_spins + Math.random()) * items //minimum spins with 0-1 extra
* ((index + 2) / 3)
//Increases spins for wheels that also take longer spinning
+ current;
const row_height = 60; //Each row is 48 pixels with 12 pixel transition
const background_position_value = (position) => Math.round(position) * row_height;
const background_position = (position) => `${background_position_value(position)}px`;
const before_every_spin = () => {
dropdown.classList.add(`show-gap`);
dropdown_wrapper.classList.remove(`valid`);
tag.classList.add(`disabled`);
};
const after_every_spin = (fn = () => { }) => {
fn();
tag.classList.remove(`disabled`);
enabled = true;
};
const run_after_spinning = (fn) => setTimeout(() => after_every_spin(fn), 5000);
const run_after_shaking = (fn) => setTimeout(fn, 500);
const spin = (state) => {
before_every_spin();
const next_state = state.map(state_increment);
wheels.forEach((el, i) => {
el.style.backgroundPositionY =
background_position(next_state[i]);
});
if (all_equal(round_and_modulus_numbers(next_state, items))) {
run_after_spinning(() => {
dropdown.classList.remove(`show-gap`);
dropdown_wrapper.classList.add(`valid`);
});
}
else {
run_after_spinning(() => {
dropdown_wrapper.classList.add(`shake`);
run_after_shaking(() => {
dropdown_wrapper.classList.remove(`shake`);
});
});
}
return next_state;
};
let state = [0, 0, 0];
tag.addEventListener(`click`, () => {
if (!enabled)
return;
enabled = false;
state = spin(state);
});