quarta-feira, 31 de julho de 2024

Trip about game

 

I wanted to share some thoughts, that’s way I published an almost finished game in the previous post.

The game I created was inspired by Professor Judea Pearl’s “The Book Of Why”, about Causal Inference. I’m still in chapter 4, because of other duties, and because, even though it’s a book for the layman, the professor, let’s say, respects the intelligence of the lay man a lot (maybe that’s what really smart people do).

 

Anyway, I’ll talk about causal inference in terms of Electricity, basic stuff.

We got these formulas:

 


 

In this images, there is no hierarchy, the formulas all have the same importance, right?

But think: you can’t keep voltage stable, then push the current to a higher level, causing the resistance to increase, right? No, there are actual causes and effects.

Because the real stuff is this:

 



So, imagine that a robot was trying to learn how to project an electrical installation by just collecting data from existing installations, maybe getting to the formulas as first presented here, with no causal model. How much data he would need to collect if he didn’t allow himself to say “There are individual mathematical one-way relations here”.?

 

I mean, how would he avoid making something that just wasn’t as precise and economical as it could be, if he doesn’t separate things in cause and effects?

 

So, I was inspired by Worlde (I even got stuff from a “How to code Wordle” article at code camp) and also by the Professor Judea’s book, and made this game.

Like, how long a “just relations, no cause” data collector would take to master this game, and how long a robot that knows “there are  individual mathematical one-way relations here” would?

Almost finished game

 If you want, copy all that is below, paste on notepad and save as anything.html

Then just go to windows explorer and click on the file you created!


<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

   

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>CauseNumber</title>

    <link rel="stylesheet" href="causenumber.css">

   

    

</head>

<style>

h1 {

 text-align: center;

}


body {

font-family: "Fonarto";

background-color: #fefed2;

}


@font-face {

    font-family: 'Fonarto';

   

    src: url('shaky-hand-some-comic.regular.otf')  format('truetype'), 

        

}


@font-face {

    font-family: 'FonartoMore';

   

    src: url('shaky-hand-some-comic.3d.otf')  format('truetype'), 

        

}


#Title {

font-family: "FonartoMore";

font-size: 3.5em;

}

#instruc {

font-size: 1.5em;

text-align: center;

width: 200;

display: block;

margin: auto;

align-items: center;

}


#game-board {

  display: flex;

  align-items: center;

  flex-direction: column;

  color: #202000;

}


.letter-box {

  border: 2px solid gray;

  border-radius: 3px;

  margin: 2px;

  font-size: 2.5rem;

  font-weight: 700;

  height: 3rem;

  width: 3rem;

  display: flex;

  justify-content: center;

  align-items: center;

  text-transform: uppercase;

}


.filled-box {

  border: 2px solid black;

}


.selected-box {

  border: 3px solid black;

}


.letter-row {

  display: flex;

}


.buttons {

  margin: 1rem 0;

  display: flex;

  flex-direction: column;

  align-items: center;

}


#keyboard-cont div {

  display: flex;

}


#upper_buttons div {

   display: flex;

}


.second-row {

  margin: 0.5rem 0;

}


.keyboard-button {

  font-size: 1.5rem;

  font-family: "Fonarto";

  padding: 0.5rem;

  margin: 0 2px;

  cursor: pointer;

  color: #202000;

  background-color: #f1b04c;

}


.keyboard-buttonC {

  font-size: 1rem;

  font-weight: 700;

  padding: 0.5rem;

  margin: 0 2px;

  cursor: pointer;

  width: 2em; 

  

}



#snackbar {

  visibility: hidden; /* Hidden by default. Visible on click */

  min-width: 250px; /* Set a default minimum width */

  margin-left: -125px; /* Divide value of min-width by 2 */

  background-color: #333; /* Black background color */

  color: #fff; /* White text color */

  text-align: center; /* Centered text */

  border-radius: 2px; /* Rounded borders */

  padding: 16px; /* Padding */

  position: fixed; /* Sit on top of the screen */

  z-index: 1; /* Add a z-index if needed */

  left: 50%; /* Center the snackbar */

  bottom: 50%; /* 30px from the bottom */

}


/* Show the snackbar when clicking on a button (class added with JavaScript) */

#snackbar.show {

  visibility: visible; /* Show the snackbar */

  /* Add animation: Take 0.5 seconds to fade in and out the snackbar.

  However, delay the fade out process for 2.5 seconds */

  -webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;

  animation: fadein 0.5s, fadeout 0.5s 2.5s;

}


/* Animations to fade the snackbar in and out */

@-webkit-keyframes fadein {

  from {bottom: 0; opacity: 0;}

  to {bottom: 50%; opacity: 1;}

}


@keyframes fadein {

  from {bottom: 0; opacity: 0;}

  to {bottom: 50%; opacity: 1;}

}


@-webkit-keyframes fadeout {

  from {bottom: 50%; opacity: 1;}

  to {bottom: 0; opacity: 0;}

}


@keyframes fadeout {

  from {bottom: 50%; opacity: 1;}

  to {bottom: 0; opacity: 0;}

}




</style>

<body>

    <h1 id="Title"> Cause Number </h1>

    

    <div id="upper_buttons" class="buttons">

<div class="first-row">

            <button class="keyboard-button">New Game</button>

            <button class="keyboard-button">Instructions</button>

           

        </div>

    </div>


    <div id="game-board">


    </div>


   <div id="keyboard-cont" class="buttons">

 

   

        <div class="second-row">

            <button class="keyboard-button">Del</button>

            <button class="keyboard-button">1</button>

            <button class="keyboard-button">2</button>

            <button class="keyboard-button">4</button>

    <button class="keyboard-button">8</button>

    <button class="keyboard-button">16</button>

            <button class="keyboard-button">Enter</button>

        </div>


    </div>



<div id="snackbar">Some text some message..</div>


<div>

<p id="instruc">

Instructions:

<br>

Click on the squares to enter the numbers.

Click twice to make it orange, if it helps thinking.

<br>

Every number that will appear below is the division of 2 other numbers on the row above,

<br>

always the big divided by the smaller.

<br>

No rule that every number will be used, 

<br>

or that one can't be used twice.

<br>

So, try to cause the numbers asked!

</p>


<script>



const NUMBER_OF_GUESSES = 5;

let guessesRemaining = NUMBER_OF_GUESSES;

let currentGuess = [];

let nextLetter = 0;

let numberNumber = 5;


let theTransforms = undefined;

let theGoalNumbers = undefined;


let theNumbers = [1, 2, 4, 8, 16];


var currentBox = undefined;


var theColor = "#febf7e"; //"#ff8533"

var wrongColor = "#6e0280";

var rightColor = "#03C03C";


var lastClickedTarget;


window.onload = function() {

initBoard();

}


function initBoard() {


setGame();


    let board = document.getElementById("game-board");


    for (let i = 0; i < NUMBER_OF_GUESSES*2; i++) {

        let row = document.createElement("div")

        row.className = "letter-row"

        

        for (let j = 0; j < numberNumber; j++) {

            let box = document.createElement("div")

            box.className = "letter-box"

            box.id = "" + i + j;

            row.appendChild(box)

        }


        board.appendChild(row)

if (i%2 != 0) row.style.visibility = "hidden";

    }

}


document.getElementById("keyboard-cont").addEventListener("click", (e) => {

    const target = e.target

    

    if (!target.classList.contains("keyboard-button")) {

        return

    }

    let key = target.textContent


    if (key === "Del") {

        key = "Backspace"

    } 

if (key != "  ") {

pressedButton(key);

} else {

clickColor(target);

}

    getInput(key);

})


document.getElementById("game-board").addEventListener("click", (e) => {

    const target = e.target

    

    window.console.log(target);

    if(!target.classList.contains("letter-box")) {

    window.console.log("nem pah");

    return;

    }

    let row = getCurrentRow();

    window.console.log("current row: " + row);

    var boxRowIndex = target.id[0];

    var boxRow = document.getElementsByClassName("letter-row")[boxRowIndex];

    window.console.log("ROW DO NEGOCIO : " + boxRow);

    changeColor(target);

    if (row != boxRow) {

    return;

    }

    currentBox = target;

    target.classList.add("selected-box");

    deselectOtherBoxes(boxRow, target);

    window.console.log("clicou no baguio");

    

    

})


function changeColor(target) {

if(lastClickedTarget != target) {

lastClickedTarget = target;

return;

}

lastClickedTarget = undefined;

window.console.log("cor do garotinho: " + target.style.backgroundColor);

if (target.style.backgroundColor == "") {

target.style.backgroundColor = theColor;

window.console.log("should change");

} else {

target.style.backgroundColor = "";

}

}


deselectOtherBoxes = function(boxRow, target) {

for(var i = 0; i < boxRow.children.length; i++) {

var child = boxRow.children[i];

if (child != target) {

child.classList.remove("selected-box");

}

}

}


document.getElementById("upper_buttons").addEventListener("click", (e) => {

    const target = e.target

    

    if (!target.classList.contains("keyboard-button")) {

        return

    }

    let key = target.textContent


    if (key === "Del") {

        key = "Backspace"

    } 

pressedButton(key);

 

    

})


clickColor = function(target) {

window.console.log("ai garotinhgo, clicou na cor");

}



pressedButton = function(theButton) {

window.console.log("you pressed button " + theButton);

if (theButton == "New Game") {

newGameAction();

}

 }

getInput = function(pressedKey) {

window.console.log("the key is " + pressedKey);


    if (pressedKey === "Backspace" && nextLetter !== 0) {

        deleteLetter()

        return

    }


    if (pressedKey === "Enter") {

        checkGuess()

        return

    }

    

   


   if(nextLetter != numberNumber && pressedKey !== "Backspace") {

   

    insertLetter(pressedKey);

   }

        

   

}


function deleteLetter () {

    let row = getCurrentRow();

    let box = row.children[nextLetter - 1]

    box.textContent = ""

    box.classList.remove("filled-box")

    currentGuess.pop()

    nextLetter -= 1

}


function insertLetter (pressedKey) {

/*

    if (nextLetter === numberNumber) {

        return

    }

*/

    

    pressedKey = pressedKey.toLowerCase()

let box = undefined;

  if (currentBox == undefined && !isRowFilled(getCurrentRow())) {

  let row = getCurrentRow();

    box = row.children[nextLetter]

 

  } else {

 

  box = currentBox;

  }

   

    if (currentBox == undefined) {

    return;

    }

   

    box.textContent = pressedKey

    box.classList.add("filled-box")

    box.classList.remove("selected-box")

    currentGuess.push(pressedKey)

  //  nextLetter += 1

}


function isRowFilled(row) {

var counted = 0;

for(var i = 0; i < row.children.length; i++) {

if(row.children[i].textContent != undefined) counted++;

}

window.console.log("checker counted: " + counted);

return counted == numberNumber;

}


function getCurrentRow() {

var rawIndex = NUMBER_OF_GUESSES - guessesRemaining;

var theIndex = rawIndex * 2;

return document.getElementsByClassName("letter-row")[theIndex];

}


function getNextRow() {

var rawIndex = NUMBER_OF_GUESSES - guessesRemaining;

var theIndex = rawIndex * 2 +1;

return document.getElementsByClassName("letter-row")[theIndex];

}




function talkToThem(stringText) {

// Get the snackbar DIV

  var x = document.getElementById("snackbar");

x.innerHTML = stringText;

  // Add the "show" class to DIV

  x.className = "show";


  // After 3 seconds, remove the show class from DIV

  setTimeout(function(){ x.className = x.className.replace("show", ""); }, 3000);

}


/******

NUMBER TRANSFORMATIONS

***************/


transformNumbers = function(numberArray, transGroup) {

var newNumbers = new Array();

for(var i = 0; i < numberNumber; i++) {

var numberTransf = transGroup.transformations[i];

var thisResult = getANumberTransform(numberArray, numberTransf);

newNumbers.push(thisResult);

}

return newNumbers;

}


getANumberTransform = function(oldNumbers, numberTransformation) {

var op1 = oldNumbers[numberTransformation.operand1];

var op2 = oldNumbers[numberTransformation.operand2];

if(op2 > op1) {

var hold = op1;

op1 = op2;

op2 = hold;

}

var result = op1 / op2;

return result;

}


function numberTransformationGroup() {

this.transformations = new Array();

for(var i = 0; i < numberNumber; i++) {

var newTransf = new numberTransformation();

this.transformations.push(newTransf);

}


function numberTransformation() {

this.operand1 = getOperand();

this.operand2 = getOperand();

while (this.operand1 == this.operand2) {

this.operand2 = getOperand();

}

}


function getOperand() {

var index = getRandomInt(numberNumber);

return index;

}






function getRandomInt(max) {

  return Math.floor(Math.random() * max);

}


/******

SETTING UP A GAME

**********/


function setGame() {

var haveGame = false;


while(!haveGame) {

theTransforms = new numberTransformationGroup();

theGoalNumbers = getGoalN(theTransforms);

if (theGoalNumbers.indexOf(16) < 0) {

haveGame = true;

}

}

window.console.log("THE GOAL Ns");

window.console.log(theGoalNumbers);

var nString = getNumberStrings(theGoalNumbers);

var titleH = document.getElementById("Title");

titleH.innerHTML = "Cause The Numbers " + nString;

}


function getGoalN(transGroup) {

var possibleNumbers = new Array();

for(var i = 0; i < numberNumber; i++) {

var index = getRandomInt(5);

var thisN = theNumbers[index];

possibleNumbers.push(thisN);

}

var goalNs = transformNumbers(possibleNumbers, transGroup);

return goalNs;

}


function getNumberStrings(numberArray) {

var theString = "";

for(var i = 0; i < numberArray.length; i++) {

theString += numberArray[i];

theString += "  ";

}

window.console.log("theString: ");

window.console.log(theString);

return theString;

}


/**********

PLAYING THE GAME

***********/


checkGuess = function() {

// alert("This is barely a game yet");


if (!isRowFilled(getCurrentRow())) {

        talkToThem("fill the numbers");

        return;

    }


var resulted = makeResult();

if (isGoalNumber(resulted)) {

dealWin();

}

guessesRemaining --;

nextLetter = 0;

currentBox = undefined;

}


function isGoalNumber(resulted) {

var isWin = true;

for(var i = 0; i < resulted.length; i++) {

if(resulted[i] != theGoalNumbers[i]) {

isWin = false;

}

}

return isWin;

}


function dealWin() {

window.console.log("seems you won");

changeLastRowColor();

guessesRemainig = 0;

talkToThem("CONGRATS!");

}


changeLastRowColor = function() {

var lastRow = getNextRow();

for(var i = 0; i < numberNumber; i++) {

let box = lastRow.children[i];

box.style.color = rightColor;

}

}


makeResult = function() {

var currentRow = getCurrentRow();

var thisNumbers = new Array();

for(var i = 0; i < numberNumber; i++) {

let box = currentRow.children[i];

var thisNumber = Number(box.textContent);

thisNumbers.push(thisNumber);

}

var transformedNumbers = transformNumbers(thisNumbers, theTransforms);

var nextRow = getNextRow();

for(var i = 0; i < numberNumber; i++) {

let box = nextRow.children[i];

var thisNumber = transformedNumbers[i];

box.textContent = thisNumber;

}

    nextRow.style.visibility = "visible";

    nextRow.style.color = wrongColor;


return transformedNumbers;

}


/****

ACTIONS

*****/


newGameAction = function() {

window.location.reload();

}



</script>



</body>

</html>