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>

domingo, 4 de fevereiro de 2024

New Stuff in the Site: Mathematics & Puzzles with Hubbard the Cat

 

                I have put a new thing in my game website. It’s called “Mathematics & Puzzles with Hubbard the Cat”. As you can imagine, it’s small math lessons and puzzles related to it.

                Just like in this blog I am trying to share some knowledge about programming, by starting from very basic considerations and then builiding on it, which is going really slow, I konw, I decided to try the same with another subject that I love, Mathematics. Now I have two long projects that go slow. But who knows, I may live long, I’d like to try doing this and here I am.

                The user interface looks and works different from my previous games, because I wanted to make it feel like a magic book with activities. The original dream was an actual book, physical book, with a puzzle in the end of every little chapter and a QR code to play a mobile version of the puzzle, but I decided not to wait for that to happen and I am happy with how it looks in internet.

                As you may realized from my last games, I try to make it possible for play in mobile, but they do fit better on desktop. I’m prioritizing it for now. Happened naturaly.

                That’s it. I would like to talk about the set of the Real Numbers and it’s subsets, and basic mathematical operations, and then, who knows? Who knows how far it will go, but I like doing it.

                Hope you enjoy.

                The link to my site:

                http://lucidstreetgames.com/

                See ya.

quinta-feira, 16 de novembro de 2023

005 - The For Loop

 

            We have learned how to make a computer repeat an operation a lot of times until a certain condition is achieved, with the while loop. Now we are going to learn another way to make loops, the “for” loop, which is fact is even more widely used.

            To do so, let’s make a little program about investiment.

            We will tell the program how much are we investing each month, how much is the interest, and how many months we will wait the money to grow.

            Do this:

 

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

GLOBAL VARIABLES

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

 

var monthlyInv = 0;

var monthlyPercInt = 0;

var totalMonths = 0;

 

            The brackets and the asterisk are another way to turn text into comments, that is, make the computer pass through it without looking for code to execute. After you write “ /* ” then everything that follows is just texts for humans to read, until you close the comment with “ */ “. I made a lot of asterisks for aesthetic reasons.

            Anyway, the computer is going to ask the user what he needs to know.

 

 

/*********

The Program

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

 

window.onload = function( ) {

 askHowMuch();

 askHowLong();

 askInterest();

 

calculate(monthlyInv, totalMonths, monthlyPercInt);

 }

 

 

You can see where this is going, right? So, let’s define the functions:

 

askHowMuch = function () {

            monthlyInv = prompt("How much do you intend to invest each month?")

            if (isNaN(monthlyInv) ) {

                        alert("Invalid entry");

                        askHowMuch( );

            }

}

 

askHowLong = function () {

            totalMonths = prompt("For how many months would you invest?")

            if (isNaN(totalMonths) ) {

                        alert("Invalid entry");

                        askHowLong( );

            }

}

 

askInterest = function () {

            monthlyPercInt = prompt("How much percent is the monthly interest?")

            if (isNaN(askInterest) ) {

                        alert("Invalid entry");

                        askInterest( );

            }

}         

            We told the computer to display the texts (the questions) and to store the values the user types, in a variable.

            The conditional “if” is to check if the person really wrote a number. isNan means “is not a number”. We have no use for Strings (text) in this particular program so, if it is not a number, the computer asks again.

            Well, we got the numbers we need. Now the function that really makes it happen:

           

calculate = function( monthlyInv, totalMoths, monthlyPercInt ) {

            var sum = 0;

//this is the money you have, it will increase

            var increase = 1 + monthlyPercInt / 100

/*

For something to increase in 1 porcent, in fact you multiply it for 1.01.

2 percent, 1.02

And so on. It’s the number itself plus the percentage

*/

            Now we are finnaly putting the “for” loop.

           

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

 

             sum += monthlyInv;

              sum *= increase;

           

            }

           

            First, the for syntax:

            As you see, you give 3 parameters to the for loop: you give it a variable “i”, you say that the loop will go on as long as the condition “ i < totalMonths” is true, and then you say that at each iteration, “i” will be increased in 1.

Iteration: a repetition of na operation, usually coming closer to the result you want.

+= means that the variable, after the instruction, will be itself plus the number you are giving after it.

            Same, *= means it will be itself multiplied by the other number

 

            If I had writen:

            For ( x = 5; x < 10 ; 5+=2)

            It would take “x” (or any other name you give it), increase it by 2 each round of the loop (iteration) and go until x is no longer smaller than 10.

 

           

           

            alert (“At the end of “ + totalMonths + “ you will have “ + sum);

} // closing function calculator.

 

 

See? We changed the sum at each round based on the interest and in the end the program says the result.

Now we will “wrap” it into a simple html that does basically nothing. The “invest.html” file.

 

<!doctype html>

<html>

            <head>

                        <meta charset="utf-8">

                        <script src="investor.js"></script>

                        <title>Super investing Page</title>

            <head>

 

            <body>

                        <h1> Invest With Us </h1>

                        <p>

                        You will have super like advantages

                        </p>

            <body>

</html>

 

Here your Javascript file complete. Call it "investor.js".

 

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

GLOBAL VARIABLES

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

 

var monthlyInv = 0;

var monthlyPercInt = 0;

var totalMonths = 0;

 

/*********

The Program

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

 

window.onload = function( ) {

 askHowMuch();

 askHowLong();

 askInterest();

 

calculate(monthlyInv, totalMonths, monthlyPercInt);

 }

 

askHowMuch = function () {

            monthlyInv = prompt("How much do you intend to invest each month?")

            if (isNaN(monthlyInv) ) {

                        alert("Invalid entry");

                        askHowMuch( );

            }

}

 

askHowLong = function () {

            totalMonths = prompt("For how many months would you invest?")

            if (isNaN(totalMonths) ) {

                        alert("Invalid entry");

                        askHowLong( );

            }

}

 

askInterest = function () {

            monthlyPercInt = prompt("How much percent is the monthly interest?")

            if (isNaN(monthlyPercInt) ) {

                        alert("Invalid entry");

                        askInterest( );

            }

}

 

calculate = function( monthlyInv, totalMonths, monthlyPercInt ) {

            var sum = 0;

//this is the money you have, it will increase

            var increase = 1 + monthlyPercInt / 100

/*

For something to increase in 1 porcent, in fact you multiply it for 1.01.

2 percent, 1.02

And so on. It’s the number itself plus the percentage

*/

 

           

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

 

             sum += monthlyInv;

              sum *= increase;

           

            }

 

 

            alert ("At the end of " + totalMonths + " you will have " + sum);

} // closing function calculator.

 

 

            That’s it, friends. We are going to get rich.

 

URGENT CORRECTION at 10 february 2024:

Oh schaitz, it seems I made a mistake, and the program was giving a much lower result than the actual outcome of the investment. After studies, I found that Javascript was treating some numbers as texts. I inserted the lines in black bellow, that make the answer given by the user equal to itself converted to integer.

The updated code:

 

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

GLOBAL VARIABLES

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

 

var monthlyInv = 0;

var monthlyPercInt = 0;

var totalMonths = 0;

 

/*********

The Program

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

 

window.onload = function( ) {

 askHowMuch();

 askHowLong();

 askInterest();

 

calculate(monthlyInv, totalMonths, monthlyPercInt);

 }

 

askHowMuch = function () {

            monthlyInv = prompt("How much do you intend to invest each month?");

                monthlyInv = parseInt(monthlyInv);

            if (isNaN(monthlyInv) ) {

                        alert("Invalid entry");

                        askHowMuch( );

            }

}

 

askHowLong = function () {

            totalMonths = prompt("For how many months would you invest?");

                totalMonths = parseInt(totalMonths);

            if (isNaN(totalMonths) ) {

                        alert("Invalid entry");

                        askHowLong( );

            }

}

 

askInterest = function () {

            monthlyPercInt = prompt("How much percent is the monthly interest?");

                montlhyPercInt = parseInt(monthlyPercInt);

            if (isNaN(monthlyPercInt) ) {

                        alert("Invalid entry");

                        askInterest( );

            }

}

 

calculate = function( monthlyInv, totalMonths, monthlyPercInt ) {

            var sum = 0;

//this is the money you have, it will increase

            var increase = 1 + monthlyPercInt / 100

/*

For something to increase in 1 porcent, in fact you multiply it for 1.01.

2 percent, 1.02

And so on. It’s the number itself plus the percentage

*/

 

           

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

 

             sum += monthlyInv;

              sum *= increase;

           

            }

 

 

            alert ("At the end of " + totalMonths + " you will have " + sum);

 } // closing function calculator.

 

That's it. At least, if you used my fantastic tool to invest, in the end you got more money than I promised, not less! ;-)