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 {
data() {
return {
// Constants
LETTER_ANIMATION_DURATION: 0.3,
SHAKE_ANIMATION_DURATION: 0.3,
// Variables
words: [],
listen: true,
gridState: null,
rowsAnimations: null,
keyboardMask: null,
currentAttempt: 0,
@ -23,8 +33,7 @@
}
},
created() {
this.setupGame();
async created() {
window.addEventListener('keyup', (e) => {
if (e.key === 'Backspace') {
this.keyPress('Delete');
@ -34,6 +43,11 @@
this.keyPress(e.key.toUpperCase())
}
});
let req = await fetch('./mathematical-wordle-words-list.json');
this.words = await req.json();
this.setupGame();
},
components: {
GuessGrid,
@ -42,6 +56,33 @@
PopUp,
},
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() {
this.gridState = Array.from({length: 6}, () => {
return Array.from({length: 5}, () => {
@ -49,44 +90,26 @@
letter: '',
state: 'unset'
};
})
});
});
this.rowsAnimations = new Array(6).fill(false);
this.keyboardMask = {
'Q': 'unused',
'W': 'unused',
'E': 'unused',
'R': 'unused',
'T': 'unused',
'Y': 'unused',
'U': 'unused',
'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.keyboardMask = Object.fromEntries(
Array.from({length: 26}, (v, i) => [
String.fromCharCode(i + 65), 'unused'
])
);
this.keyboardMask['Enter'] = 'unused';
this.keyboardMask['Delete'] = 'unused';
console.log(this.keyboardMask);
this.currentAttempt = 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.won = false;
@ -125,6 +148,9 @@
this.overlayVisible = true;
},
keyPress(event) {
if (!this.listen) {
return;
}
if (event === "Delete") {
if(this.currentIndex > 0) {
this.currentIndex -= 1;
@ -133,19 +159,49 @@
}
} else if (event == "Enter") {
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] ];
for(let i = 0; i < 5; i++)
{
for(let i = 0; i < 5; i++) {
let letter = this.gridState[this.currentAttempt][i].letter;
for(let j = 0; j < 2; j++)
{
if (this.secretWords[j].includes(letter)) {
let matchType = this.secretWords[j][i] === letter;
matches[i] = [j, matchType];
for(let j = 0; j < 2; j++) {
if (wordsFlags[j][i] === letter) {
wordsFlags[j][i] = null;
matches[i] = [j, true];
}
}
}
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;
for(let i = 0; i < 5; i++) {
for(let j = 0; j < 5; j++) {
@ -155,27 +211,49 @@
}
}
// Update grid to tease result
for(let i = 0; i < 5; i++) {
if (matches[i][0] !== -1 && matches[i][1]) {
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]) {
this.gridState[this.currentAttempt][i].state = `misplaced-${oneWordMatch ? 'full' : 'half'}`;
this.keyboardMask[this.gridState[this.currentAttempt][i].letter] = 'misplaced';
} else {
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.currentIndex = 0;
this.currentAttempt += 1;
this.currentIndex = 0;
if (this.checkWin(matches, oneWordMatch)) {
this.resolveGame(true);
} else if (this.currentAttempt === 6) {
this.resolveGame(false);
}
if (this.checkWin(matches, oneWordMatch)) {
this.resolveGame(true);
} else if (this.currentAttempt === 6) {
this.resolveGame(false);
}
this.listen = true;
}, this.LETTER_ANIMATION_DURATION * 1000 * 5);
}
} else {
if (this.currentIndex < 5) {
@ -190,8 +268,8 @@
</script>
<template>
<div class="page">
<div class="interface">
<div class="page" :style="`--letter-animation-duration: ${LETTER_ANIMATION_DURATION}s; --shake-animation-duration: ${SHAKE_ANIMATION_DURATION}s`">
<div v-if="this.gridState !== null" class="interface">
<div class="header">
<div>Qwordle</div>
<div class="end">
@ -199,8 +277,8 @@
<div v-if="gameOver" class="material-icons-outlined" @click="overlayVisible = true">military_tech</div>
</div>
</div>
<GuessGrid :state="gridState" />
<Keyboard :mask="keyboardMask" @add="keyPress($event)" />
<GuessGrid :state="gridState" :rows-animations="rowsAnimations"/>
<Keyboard :mask="keyboardMask" @add="keyPress($event)" :listen="true"/>
</div>
<Overlay v-if="overlayVisible"
:secret-words="secretWords"
@ -250,8 +328,6 @@
--misplaced-cell-dark: #eab308;
--misplaced-cell-light: #facc15;
--wrong-cell: #334155;
--animation-duration: 0.3s;
}
* {

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

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

Loading…
Cancel
Save