#Memory Game, delayed? reactivity

33 messages · Page 1 of 1 (latest)

wheat bay
#

To learn SolidJS I am converting a simple Memory game from jquery.
My problem is: User turn two Cards visible, when they do not match they should be turn around again. Only the last pressed card keeps reactivity, not the first flipped card.
How can this be solved?

lucid otter
#

Do you have some example code?

wheat bay
#

Sorry, I had failed to press enter

#

Testcase: Press on first and second card, it woks fine. Then press on the same cards again, only the second will behave correctly.

wheat bay
lucid otter
#

Sorry I won't download a zip file, could you just copy and paste the code from the relevant file here?

wheat bay
#

Sure!

#

import { createSignal,createResource, onMount, For, splitProps } from "solid-js";
import global, { Card } from './Global';

enum CardStyle { hidden, normal, greyed };

function GameCard(ACard : Card) {
const { cards, setCards, choosen, setChoosen, attempts,setAttempts, matched,setMatched } = global;
const [card] = splitProps(ACard,["name","image","text","id"])
const [style, setStyle] = createSignal(CardStyle.hidden);
const placeHolder = 'images/placeholder.png';

function ShowCardAs(card:Card, style:string = 'hidden') {
const cardId = card?.id?.toString();
const imgN = document.getElementById(cardId||"X");
if (imgN != null) {
imgN.className = style;
console.log('ShowCardAs(): ',cardId,' ',style);
} else {
console.log('not found image: ',cardId);
}
}

function checkForMatch() {
const firstCard = choosen()[0];
const secondCard = choosen()[1];
setChoosen([]);
console.log(---CheckForMatch() fc1: ${firstCard.name} ${firstCard.id}| fc2: ${secondCard.name} ${secondCard.id});

// Todo: Already matched cards, remove from reactivity

if (firstCard.id == secondCard.id) {
  console.log('Same-same card, not allowed!');
  setStyle(CardStyle.hidden); // Keeps reactivity
  // Hide(firstCard); // Fails on reactivity
}
else if (firstCard.name == secondCard.name) {
  console.log('You found a match! grey out cards');
  setMatched(matched()+1);
  // Keep image visible, but greyed
  ShowCardAs(firstCard,'greyed');
  ShowCardAs(secondCard,'greyed');
  // Overlay with text of Birds name?
} else {
  console.log('Wrong guess, turn cards!');
  ShowCardAs(firstCard); // *** This does not solve reactivity
  setStyle(CardStyle.hidden); // *** This works fine
//  ShowCardAs(secondCard);

// ** setCards(crds);
}
setAttempts(attempts()+1);
}

#

const flipCard = () => {
let choosenArr = choosen();
// Todo: Already matched cards, not touchable
console.log(=== flipCard() OnClick() ${card.id}, ${card.name} Len:${choosenArr.length});
if (choosenArr.length != 2) {
setStyle(CardStyle.normal); // setShowCard
let X = style();
console.log('Card Has Style(): '+X);
choosenArr.push(card);
setChoosen(choosenArr);
if (choosenArr.length == 2) {
setTimeout(checkForMatch,400);
}
}
}

const getClass = () => {
let cl = "";
const stil = style();
switch (stil) {
case CardStyle.hidden: { cl = cl + "hidden "; break; }
case CardStyle.normal: { cl = cl + "normal "; break; };
case CardStyle.greyed: { cl = cl + "greyed "; break; };
}
// if (greyed()) cl = cl + "ungreyed "; else cl = cl + "hidden ";
console.log(getClass() ${stil} class: ${cl});
return cl.trim();
}

return (
<>
<div class="box">
<img id={card.id?.toString()} onClick={flipCard} class={getClass()} src={ card.image } alt={card.text} />
</div>
</>
)
}

export default GameCard;

#

ShowCardAs() is dirtywork, so wehn correct solution is found it must be removed.

wheat bay
#

Was it to much code to dig into?

This is the building of the Board

    <For each={cards()}>{(card:Card, i) =>
      <GameCard name={card.name} image={card.image} text={card.text} id={card.id}></GameCard>
    }</For>
  </div>
languid jacinth
# wheat bay Was it to much code to dig into? This is the building of the Board ``` <div cl...

Hi janne, did you figure it out? I think is maybe better next time to upload your code to codesandbox, jsfiddle or something similar. It's a lot easier to debug running code then it is to debug text. The best would be if you could reproduce a simplified version of the problem in https://playground.solidjs.com/ Is also a good exercise, 99% of the time i figure out the bug while making the example-file.

wheat bay
languid jacinth
#

Ye i think u have to DoubleClick it!

wheat bay
#

Correct!👍

wheat bay
#

Is it not possible to load a json file via fetch()?
So I must declare the array in code?

languid jacinth
wheat bay
#

Mocked solved, images uploaded on another site, src= changed. But images will not be shown???
This is not working in game.
<img id="1" class="normal" src="http://birds.qip.se/images/knolsvan.jpg" alt="Knölsvan">

wheat bay
#

I get it working in Firefox with images, but not an any Webkit based browser.
https://playground.solidjs.com/anonymous/1d3de46a-c9b6-4cfe-a022-e0738fdfb318
Code is not cleaned up, but try to click on one card (will be shown) then a second card (shown) and if wrong cards they will be hidden again. Then click on the same first card again, nothing will happen. I have "hidden" it in a dirty non-reactive way. How do I solve this problem (keeping the first selected card reactive after hiding it again)?
Look in GameCard.tsx function checkForMatch() how to hide the firstCard!?

languid jacinth
#

hi 👋 sorry forgot this thread

#

i just looked at it, the reason why the images do not load in chrome is because there is something wrong w the https license of birds.qip.se and chrome is defaulting to https, while firefox still allows for http

#

that's a tricky bug! had to look in the network-tab for that.

#

and regarding the reactivity bug: my guess is it has to do with how you update card.state

#

this is not a valid way how to update a store

#

you get a linting error about it too: The reactive variable 'card' should not be reassigned or altered directly.

#

with createMutable you can just mutate the store as you want

#

the way how I approach a global store is by passing a readonly store, and then actions to manipulate that store, so card.state = CardStyle.normal would be written as an action in Global.ts: const setCardState = (id: number, state: CardStyle) => { setCards(id, "state", state); }; and then you could do in your code setCardState(card.id, CardStyle.normal)

#

this way the surface that can actually change your store is minimized, gives you a lot more control in comparison w createMutable

#

I couldn't get it to work tho, but I think the problem is a bit more in the overall game-logic.

languid jacinth