Aggiustata la questione di lettere multiple per lettera e corrette animazioni

main
Francesco Baldino 2 years ago
parent 846c7c7acc
commit d7faedce1e

@ -0,0 +1 @@
["MINUS","ZEROS","ROUND","THIRD","PROOF","EVENT","MATHS","CUBIC","MONAD","GAUSS","AXIOM","PRISM","CHORD","ANGLE","LITRE","MILES","VALUE","TABLE","HALVE","EXACT","LOCUS","QUART","ARRAY","SOLID","KITES","TRIAL","EMPTY","FIFTH","NINTH","DEPTH","BOOLE","FACES","TENTH","SLOPE","SIXTH","DELTA","SIGMA","LINES","EULER","FIFTY","SCALE","RULER","INDEX","OUNCE","FIRST","SPACE","MONIC","POINT","RIGHT","DIGIT","VALID","TIMES","KLEIN","TWICE","SIXES","METRE","STONE","BAYES","SEVEN","PLANE","CLOCK","THREE","CHAOS","ACUTE","UNITS","HARDY","COUNT","FORTY","TORUS","WIDTH","LOGIC","WILES","POWER","EIGHT","RANGE","PRIME","MODAL","TREND","THETA","CURVE","SIXTY","ERROR","TALLY","PLATO","UNION","KILOS","GRAPH","RATIO","CUBES","DOZEN","EQUAL","ALPHA","NODES","GROUP","ERDOS","KAPPA","LIMIT","ADDED","HERTZ","LATEX","CONIC","RINGS","BOUND","ROOTS","BOREL","ALEPH","SURDS","HELIX","APPEL","EDGES","GAMMA","POLAR","GODEL","FIELD","TUPLE","POLYA","BASIS","UPPER","LEMMA","PROVE","ORDER","SIDES","HASSE","SMALL","BRACE","KNUTH","AREAS","IDEAL","SPACE","DENSE","MODEL","LOWER","OVALS","NOISE","SOLVE","BAIRE","CHAIN","JULIA","FOCUS","KNOTS","DIRAC","HOLES","NORMS","REALS"]

@ -7,7 +7,17 @@
export default { export default {
data() { data() {
return { return {
// Constants
LETTER_ANIMATION_DURATION: 0.3,
SHAKE_ANIMATION_DURATION: 0.3,
// Variables
words: [],
listen: true,
gridState: null, gridState: null,
rowsAnimations: null,
keyboardMask: null, keyboardMask: null,
currentAttempt: 0, currentAttempt: 0,
@ -23,8 +33,7 @@
} }
}, },
created() { async created() {
this.setupGame();
window.addEventListener('keyup', (e) => { window.addEventListener('keyup', (e) => {
if (e.key === 'Backspace') { if (e.key === 'Backspace') {
this.keyPress('Delete'); this.keyPress('Delete');
@ -34,6 +43,11 @@
this.keyPress(e.key.toUpperCase()) this.keyPress(e.key.toUpperCase())
} }
}); });
let req = await fetch('./mathematical-wordle-words-list.json');
this.words = await req.json();
this.setupGame();
}, },
components: { components: {
GuessGrid, GuessGrid,
@ -42,6 +56,33 @@
PopUp, PopUp,
}, },
methods: { methods: {
generatePair() {
let words = [];
let validPair = false;
while (!validPair) {
let firstWord = this.words[Math.floor(Math.random() * this.words.length)];
let possibleSecondWords = []
for(let i = 0; i < this.words.length; i++) {
let validSecondWord = true;
for (let l = 0; l < firstWord.length; l++) {
if (this.words[i].includes(firstWord[l])) {
validSecondWord = false;
}
}
if (validSecondWord) {
possibleSecondWords.push(this.words[i]);
}
}
if (possibleSecondWords.length > 0) {
validPair = true;
words = [firstWord, possibleSecondWords[Math.floor(Math.random() * possibleSecondWords.length)]];
}
}
return words;
},
setupGame() { setupGame() {
this.gridState = Array.from({length: 6}, () => { this.gridState = Array.from({length: 6}, () => {
return Array.from({length: 5}, () => { return Array.from({length: 5}, () => {
@ -49,44 +90,26 @@
letter: '', letter: '',
state: 'unset' state: 'unset'
}; };
}) });
}); });
this.rowsAnimations = new Array(6).fill(false);
this.keyboardMask = { this.keyboardMask = Object.fromEntries(
'Q': 'unused', Array.from({length: 26}, (v, i) => [
'W': 'unused', String.fromCharCode(i + 65), 'unused'
'E': 'unused', ])
'R': 'unused', );
'T': 'unused', this.keyboardMask['Enter'] = 'unused';
'Y': 'unused', this.keyboardMask['Delete'] = 'unused';
'U': 'unused', console.log(this.keyboardMask);
'I': 'unused',
'O': 'unused',
'P': 'unused',
'A': 'unused',
'S': 'unused',
'D': 'unused',
'F': 'unused',
'G': 'unused',
'H': 'unused',
'J': 'unused',
'K': 'unused',
'L': 'unused',
'Z': 'unused',
'X': 'unused',
'C': 'unused',
'V': 'unused',
'B': 'unused',
'N': 'unused',
'M': 'unused',
'Enter': 'unused',
'Delete': 'unused',
};
this.currentAttempt = 0; this.currentAttempt = 0;
this.currentIndex = 0; this.currentIndex = 0;
this.secretWords = [ 'SNARK', 'ITCHY' ]; this.secretWords = this.generatePair();
console.log(this.secretWords);
console.log(this.secretWords[0]);
console.log(this.secretWords[1]);
this.gameOver = false; this.gameOver = false;
this.won = false; this.won = false;
@ -125,6 +148,9 @@
this.overlayVisible = true; this.overlayVisible = true;
}, },
keyPress(event) { keyPress(event) {
if (!this.listen) {
return;
}
if (event === "Delete") { if (event === "Delete") {
if(this.currentIndex > 0) { if(this.currentIndex > 0) {
this.currentIndex -= 1; this.currentIndex -= 1;
@ -133,19 +159,49 @@
} }
} else if (event == "Enter") { } else if (event == "Enter") {
if(this.currentIndex === 5) { if(this.currentIndex === 5) {
// Validate Word
let currentWord = "";
for(let i = 0; i < 5; i++) {
currentWord += this.gridState[this.currentAttempt][i].letter;
}
if(!this.words.includes(currentWord)) {
// Invalid attempt, signal error
this.listen = false;
this.rowsAnimations[this.currentAttempt] = true;
setTimeout(() => {
this.listen = true;
this.rowsAnimations[this.currentAttempt] = false;
}, this.SHAKE_ANIMATION_DURATION * 1000);
return;
}
// Calculate result
let wordsFlags = [ this.secretWords[0].split(''), this.secretWords[1].split('') ];
let matches = [ [-1,false], [-1,false], [-1,false], [-1,false], [-1,false] ]; let matches = [ [-1,false], [-1,false], [-1,false], [-1,false], [-1,false] ];
for(let i = 0; i < 5; i++)
{ for(let i = 0; i < 5; i++) {
let letter = this.gridState[this.currentAttempt][i].letter; let letter = this.gridState[this.currentAttempt][i].letter;
for(let j = 0; j < 2; j++) for(let j = 0; j < 2; j++) {
{ if (wordsFlags[j][i] === letter) {
if (this.secretWords[j].includes(letter)) { wordsFlags[j][i] = null;
let matchType = this.secretWords[j][i] === letter; matches[i] = [j, true];
matches[i] = [j, matchType]; }
}
}
for(let i = 0; i < 5; i++) {
let letter = this.gridState[this.currentAttempt][i].letter;
for(let j = 0; j < 2; j++) {
for(let k = 0; k < 5; k++) {
if(wordsFlags[j][k] === letter) {
wordsFlags[j][k] = null;
matches[i] = [j, false];
}
} }
} }
} }
let oneWordMatch = true; let oneWordMatch = true;
for(let i = 0; i < 5; i++) { for(let i = 0; i < 5; i++) {
for(let j = 0; j < 5; j++) { for(let j = 0; j < 5; j++) {
@ -155,27 +211,49 @@
} }
} }
// Update grid to tease result
for(let i = 0; i < 5; i++) { for(let i = 0; i < 5; i++) {
if (matches[i][0] !== -1 && matches[i][1]) { if (matches[i][0] !== -1 && matches[i][1]) {
this.gridState[this.currentAttempt][i].state = `correct-${oneWordMatch ? 'full' : 'half'}`; this.gridState[this.currentAttempt][i].state = `correct-${oneWordMatch ? 'full' : 'half'}`;
this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'correct';
} else if (matches[i][0] !== -1 && !matches[i][1]) { } else if (matches[i][0] !== -1 && !matches[i][1]) {
this.gridState[this.currentAttempt][i].state = `misplaced-${oneWordMatch ? 'full' : 'half'}`; this.gridState[this.currentAttempt][i].state = `misplaced-${oneWordMatch ? 'full' : 'half'}`;
this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'misplaced';
} else { } else {
this.gridState[this.currentAttempt][i].state = 'wrong'; this.gridState[this.currentAttempt][i].state = 'wrong';
this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'wrong';
} }
} }
this.listen = false;
// Resolve
setTimeout(() => {
for(let i = 0; i < 5; i++) {
if (matches[i][0] !== -1 && matches[i][1]) {
if(this.keyboardMask[this.gridState[this.currentAttempt][i].letter] === 'unused' ||
this.keyboardMask[this.gridState[this.currentAttempt][i].letter] === 'misplaced') {
this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'correct';
}
} else if (matches[i][0] !== -1 && !matches[i][1]) {
if(this.keyboardMask[this.gridState[this.currentAttempt][i].letter] === 'unused') {
this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'misplaced';
}
} else {
if(this.keyboardMask[this.gridState[this.currentAttempt][i].letter] === 'unused') {
this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'wrong';
}
}
}
this.currentAttempt += 1; this.currentAttempt += 1;
this.currentIndex = 0; this.currentIndex = 0;
if (this.checkWin(matches, oneWordMatch)) {
this.resolveGame(true); if (this.checkWin(matches, oneWordMatch)) {
} else if (this.currentAttempt === 6) { this.resolveGame(true);
this.resolveGame(false); } else if (this.currentAttempt === 6) {
} this.resolveGame(false);
}
this.listen = true;
}, this.LETTER_ANIMATION_DURATION * 1000 * 5);
} }
} else { } else {
if (this.currentIndex < 5) { if (this.currentIndex < 5) {
@ -190,8 +268,8 @@
</script> </script>
<template> <template>
<div class="page"> <div class="page" :style="`--letter-animation-duration: ${LETTER_ANIMATION_DURATION}s; --shake-animation-duration: ${SHAKE_ANIMATION_DURATION}s`">
<div class="interface"> <div v-if="this.gridState !== null" class="interface">
<div class="header"> <div class="header">
<div>Qwordle</div> <div>Qwordle</div>
<div class="end"> <div class="end">
@ -199,8 +277,8 @@
<div v-if="gameOver" class="material-icons-outlined" @click="overlayVisible = true">military_tech</div> <div v-if="gameOver" class="material-icons-outlined" @click="overlayVisible = true">military_tech</div>
</div> </div>
</div> </div>
<GuessGrid :state="gridState" /> <GuessGrid :state="gridState" :rows-animations="rowsAnimations"/>
<Keyboard :mask="keyboardMask" @add="keyPress($event)" /> <Keyboard :mask="keyboardMask" @add="keyPress($event)" :listen="true"/>
</div> </div>
<Overlay v-if="overlayVisible" <Overlay v-if="overlayVisible"
:secret-words="secretWords" :secret-words="secretWords"
@ -250,8 +328,6 @@
--misplaced-cell-dark: #eab308; --misplaced-cell-dark: #eab308;
--misplaced-cell-light: #facc15; --misplaced-cell-light: #facc15;
--wrong-cell: #334155; --wrong-cell: #334155;
--animation-duration: 0.3s;
} }
* { * {

@ -6,13 +6,23 @@
return { return {
}; };
}, },
props: ["state"] props: ["state", "rowsAnimations"]
}; };
</script> </script>
<template> <template>
<div class="guess-grid"> <div class="guess-grid">
<template v-for="i in 6"> <div v-for="i in 6" class="guess-row" :class="{'animate': rowsAnimations[i-1]}">
<div v-for="j in 5"
class="cell"
:class="state[i-1][j-1].state"
:style="`--index: ${j-1}`">
<div class="letter">
{{state[i-1][j-1].letter}}
</div>
</div>
</div>
<!-- <template v-for="i in 6">
<div v-for="j in 5" <div v-for="j in 5"
class="cell" class="cell"
:class="state[i-1][j-1].state" :class="state[i-1][j-1].state"
@ -22,7 +32,7 @@
{{state[i-1][j-1].letter}} {{state[i-1][j-1].letter}}
</div> </div>
</div> </div>
</template> </template> -->
</div> </div>
</template> </template>
@ -60,89 +70,114 @@
background-color: var(--cell-backgroud-color); background-color: var(--cell-backgroud-color);
} }
} }
@keyframes shake {
0% {
transform: translateX(0)
}
25% {
transform: translateX(-2%)
}
50% {
transform: translateX(2%)
}
75% {
transform: translateX(-2%)
}
100% {
transform: translateX(0)
}
}
.guess-grid { .guess-grid {
display: grid; display: flex;
gap: 0.2rem 0.2rem; flex-direction: column;
grid-template-columns: repeat(5, 1fr); gap: 0.2rem;
grid-auto-flow: row;
.cell { .guess-row {
width: 3.5rem;
height: 3.5rem;
display: flex; display: flex;
align-items: center; gap: 0.2rem;
justify-content: center;
border-radius: .25rem; &.animate {
border-width: 2px; animation: linear shake var(--shake-animation-duration);
border-style: solid; }
font-weight: 800;
font-size: 2.2rem;
.letter { .cell {
width: 3.5rem;
height: 3.5rem;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
transform: translateY(0.1em); border-radius: .25rem;
} border-width: 2px;
border-style: solid;
font-weight: 800;
font-size: 2.2rem;
&.unset { .letter {
border-color: var(--unset-cell-border); display: flex;
background-color: var(--background-color); align-items: center;
} justify-content: center;
&.set { transform: translateY(0.1em);
animation: linear grow 0.25s; }
border-color: var(--set-cell-border);
background-color: var(--background-color);
}
&:not(.unset):not(.set) { &.unset {
animation: linear flip var(--animation-duration) calc(var(--index) * var(--animation-duration)), step-end color-change calc(var(--index) * var(--animation-duration) + var(--animation-duration) / 2); border-color: var(--unset-cell-border);
&::before { background-color: var(--background-color);
animation: linear flip var(--animation-duration) calc(var(--index) * var(--animation-duration)), step-end color-change calc(var(--index) * var(--animation-duration) + var(--animation-duration) / 2); }
} &.set {
} animation: linear grow 0.25s;
&.wrong { border-color: var(--set-cell-border);
--cell-border-color: var(--wrong-cell); background-color: var(--background-color);
--cell-backgroud-color: var(--wrong-cell); }
border-color: var(--wrong-cell);
background-color: var(--wrong-cell);
}
&.misplaced-full {
border-color: var(--misplaced-cell-dark);
background-color: var(--misplaced-cell-dark);
}
&.misplaced-half {
border-color: var(--misplaced-cell-dark);
background-color: var(--wrong-cell);
position: relative;
z-index: 0;
&::before { &:not(.unset):not(.set) {
content: ''; animation: linear flip var(--letter-animation-duration) calc(var(--index) * var(--letter-animation-duration)), step-end color-change calc(var(--index) * var(--letter-animation-duration) + var(--letter-animation-duration) / 2);
background-color: var(--misplaced-cell-light); &::before {
position: absolute; animation: linear flip var(--letter-animation-duration) calc(var(--index) * var(--letter-animation-duration)), step-end color-change calc(var(--index) * var(--letter-animation-duration) + var(--letter-animation-duration) / 2);
inset: 0; }
left: 50%;
z-index: -1;
} }
} &.wrong {
&.correct-full { --cell-border-color: var(--wrong-cell);
border-color: var(--correct-cell-dark); --cell-backgroud-color: var(--wrong-cell);
background-color: var(--correct-cell-dark); border-color: var(--wrong-cell);
} background-color: var(--wrong-cell);
&.correct-half { }
border-color: var(--correct-cell-dark); &.misplaced-full {
background-color: var(--wrong-cell); border-color: var(--misplaced-cell-dark);
position: relative; background-color: var(--misplaced-cell-dark);
z-index: 0; }
&.misplaced-half {
border-color: var(--misplaced-cell-dark);
background-color: var(--wrong-cell);
position: relative;
z-index: 0;
&::before {
content: '';
background-color: var(--misplaced-cell-light);
position: absolute;
inset: 0;
left: 50%;
z-index: -1;
}
}
&.correct-full {
border-color: var(--correct-cell-dark);
background-color: var(--correct-cell-dark);
}
&.correct-half {
border-color: var(--correct-cell-dark);
background-color: var(--wrong-cell);
position: relative;
z-index: 0;
&::before { &::before {
content: ''; content: '';
background-color: var(--correct-cell-light); background-color: var(--correct-cell-light);
position: absolute; position: absolute;
inset: 0; inset: 0;
left: 50%; left: 50%;
z-index: -1; z-index: -1;
}
} }
} }
} }

@ -59,7 +59,7 @@
] ]
}; };
}, },
props: ["mask"], props: ["mask", "listen"],
methods: { methods: {
keyUp(event) { keyUp(event) {
console.log(event); console.log(event);
@ -69,7 +69,7 @@
</script> </script>
<template> <template>
<div class="keyboard-grid" @keyup="keyUp($event)"> <div class="keyboard-grid">
<template v-for="row in keyboard"> <template v-for="row in keyboard">
<div v-for="button in row.row" <div v-for="button in row.row"
class="cell" class="cell"
@ -83,6 +83,7 @@
<div class="letter"> <div class="letter">
{{button.letter}} {{button.letter}}
</div> </div>
<div class="cover"></div>
</div> </div>
</template> </template>
</div> </div>
@ -106,6 +107,7 @@
width: 30rem; width: 30rem;
.cell { .cell {
position: relative;
width: 100%; width: 100%;
height: 3.75rem; height: 3.75rem;
// background: var(--color); // background: var(--color);
@ -123,13 +125,19 @@
transform: translateY(0.1em); transform: translateY(0.1em);
} }
.cover {
position: absolute;
width: 100%;
height: 100%;
}
&.unused { &.unused {
background-color: var(--keyboard-unused); background-color: var(--keyboard-unused);
} }
&:not(.unused) { // &:not(.unused) {
animation: hide-color calc(5 * var(--animation-duration)); // animation: hide-color calc(5 * var(--animation-duration));
} // }
&.correct { &.correct {
background-color: var(--keyboard-correct); background-color: var(--keyboard-correct);
} }

Loading…
Cancel
Save