An array in a loop king of thing

I’m trying to do this thing:
Let say I have an array of 12 elements; each containing an integer.
I want to call a function. That function would get as parameter the place in the array. Then the function would read the value of this element in the array; let’s call it ‘nTime’. Set it to zero. And will increment by 1 the value contained in the next cells of the array for the ‘nTime’ given. Also if the next cell which value should be incremented is > to the number cells in the array then that value should be inscribed in the first cell of the array and so on. In a circle.

I’m trying to do that. I haven’t fully tested it yet but I think I’m trying to reinvent the wheel when a certainly easier solution exists:

Here is what I’ve done so far:

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Les Jeux Cornichons </title>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">


    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

    <style>
        table, th, td, tr {
          border: 2px solid;
          text-align: center;
          padding: 10px;
          cursor: pointer;
        }
        </style>
</head>

<body>
    <table style="width: 70%; margin-top: 10px; margin-left: 15%; font-size: 1.8em;">
        <tr style="text-align:center" >
            <th id="cell12" >4</th>
            <th id="cell11" >4</th>
            <th id="cell10" >4</th>
            <th id="cell9" >4</th>
            <th id="cell8" >4</th>
            <th id="cell7" >4</th>
        </tr>
        <tr>
            <th id="cell1" onclick="shiftCells(1)">4</th>
            <th id="cell2" onclick="shiftCells(2)">4</th>
            <th id="cell3" onclick="shiftCells(3)">4</th>
            <th id="cell4" onclick="shiftCells(4)">4</th>
            <th id="cell5" onclick="shiftCells(5)">4</th>
            <th id="cell6" onclick="shiftCells(6)">4</th>
        </tr>
    </table>
</body>

<script>

class classGroup {
        constructor(nbrPeas, occupied) {
            this.nbrPeas = 4;
            this.occupied = 'false';
            this.isFull = 'false';
        }
    }

    var myArray = [];

    for (var i = 1; i < 13; i++) {
        myArray[i] = new classGroup(4, 'false', 'false');
    }

    function shiftCells(callingCell){
        var byID
        var startLoop = callingCell + 1;
        var stopLoop = callingCell + myArray[callingCell].nbrPeas + 1;

        myArray[callingCell].nbrPeas = 0;


        for (var i = startLoop; i < stopLoop; i++) {
            if(myArray[i].isFull === 'false'){
                if (i < 13){
                    if ((myArray[i].nbrPeas + 1 < 12)){
                        myArray[i].nbrPeas = myArray[i].nbrPeas + 1;
                    }else{
                        myArray[i].isFull = 'true';
                        spillOverflow(i);
                        stopLoop = stopLoop + 1;
                    }
                }else{
                    myArray[i -12].nbrPeas = myArray[i -12].nbrPeas + 1;
                    spillOverflow(i);
                    stopLoop = stopLoop + 1;
                }
            }else{
                stopLoop = stopLoop + 1;
            }
        }

        for (var i = 1; i < 13; i++) {
            byID = 'cell' + i;
            document.getElementById(byID).innerText = myArray[i].nbrPeas;
            console.log(myArray[i].nbrPeas);
        }
    }

    function spillOverflow(cellNbr){
        var freeFound = false;
        var cellIncr = cellNbr + 1;

        while(freeFound === false){
            if(myArray[cellIncr].isFull === 'false'){
                freeFound = true;
                myArray[cellIncr].isFull = 'true';
            }else{
                cellIncr = cellIncr + 1;
            }
        }
    }
</script>

Working on the logic now only. Clicking on any cells at the bottom should work and gives expected values…

I hope I explain clearly enough :slightly_smiling_face:

Hi,

That sounds interesting. So that I can better understand the problem, could you give us a couple of examples of input and desired output.

1 Like

Should the increment of the next value, trigger a change of the value, so that you get some kind of endless loop?

It’s the base for a game for 2 players. 1 player has the lower row with 6 cases. The second player has the upper row with 6 case. When it’s his turn to play; the player click on a case (which will contain seeds or beans instead of numbers). Let say it’s the first move. At the beginning each player has 4 seeds in each of his cases. If I decide to click on the case number 5 for example. That case contains 4 seeds and each of the 4 seeds must be sowed one by one to the adjacent cases going counter clockwise. So from (on the screen)

[ 4 ] - [ 4 ] - [ 4 ] - [ 4 ] - [ 4 ] - [ 4 ]

[ 4 ] - [ 4 ] - [ 4 ] - [ 4 ] - [ 4 ] - [ 4 ]

I should get:

[ 4 ] - [ 4 ] - [ 4 ] - [ 5 ] - [ 5 ] - [ 5 ]

[ 4 ] - [ 4 ] - [ 4 ] - [ 4 ] - [ 0 ] - [ 5 ]

Then if the second player was to play is third case (keeping in mind that the first case of the opposite player is at the top to the right) I should obtain:

[ 5 ] - [ 5 ] - [ 5 ] - [ 0 ] - [ 5 ] - [ 5 ]

[ 5 ] - [ 5 ] - [ 4 ] - [ 4 ] - [ 0 ] - [ 5 ]

If now the first player was to play his last case it should give that:

[ 5 ] - [ 6 ] - [ 6 ] - [ 1 ] - [ 6 ] - [ 6 ]

[ 5 ] - [ 5 ] - [ 4 ] - [ 4 ] - [ 0 ] - [ 0 ]

Also a case can only have a maximum of 12 seeds. If the case is full it should be skipped and the seed sowed in the next case.
And so on.

Nope; just increasing the the values in the array. In the final those values will be seeds or beans to be displayed in the case…

Hi James;

Thanks for answer. The script is working so far I tested it. But maybe it exists a much more simpler way to achieve that. I’m a Sunday coder and there are plenty stuff I don’t know. :slight_smile:

Having a first Quick Look.

First of all. Do not mix your html with the JavaScript. Put your js in an own file and import in the html!

  • var is no longer used in modern JS. Use const and let instead.
  • I see no usage of „occupied“ in the whole code
  • I would not use a variable to check if the array is full. Instead I would make it a function
isFull()
{
     return myArray.size() >= MAXSIZE;
}

And define MAXSIZE at the top of the code,

const MAXSIZE = 12;

so you can easily change it if needed.
I would also use such defines for all other fix numbers like number of seeds at beginning of the game, number of cages for each player.

Hi;

Thank you.

„occupied“ will be used later. It’s a work on progress.
„isFull“ doesn’t indicate the maximum size of the array. But the maximum number allowed in any cell of the array. myArray[i].nbrPeas cannot exceed 12. But right I could use a const.

And you are right I use old stuff. I come from old time GW-BASIC and I’m just a Sunday coder trying to keep pace with the amazing modern stuff and have a little fun along. :slight_smile:

Note is taken for your advices. But it’s more about the functions I’m curious. I mean there are plenty functions of javascript I haven’t even the idea they exist. Among them there is not some smarter way to rewrite what I’m trying to do?

Hi,

Could you try this and let me know if it does what you want.

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Les Jeux Cornichons</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <style>
    table, th, td, tr {
      border: 2px solid;
      text-align: center;
      padding: 10px;
      cursor: pointer;
    }
    #gameBoard {
      width: 70%;
      margin-top: 10px;
      margin-left: 15%;
      font-size: 1.8em;
    }
  </style>
</head>
<body>
  <table id="gameBoard">
    <tr id="topRow">
      <td data-cell-id="12">4</td>
      <td data-cell-id="11">4</td>
      <td data-cell-id="10">4</td>
      <td data-cell-id="9">4</td>
      <td data-cell-id="8">4</td>
      <td data-cell-id="7">4</td>
    </tr>
    <tr id="bottomRow">
      <td data-cell-id="1">4</td>
      <td data-cell-id="2">4</td>
      <td data-cell-id="3">4</td>
      <td data-cell-id="4">4</td>
      <td data-cell-id="5">4</td>
      <td data-cell-id="6">4</td>
    </tr>
  </table>

  <script>
    // Add event listeners to the bottom row cells
    document.querySelectorAll('#bottomRow td').forEach(cell => {
      cell.addEventListener('click', () => {
        let cellId = Number(cell.getAttribute('data-cell-id'));
        let seeds = Number(cell.innerText);
        cell.innerText = 0;

        while (seeds > 0) {
          cellId = (cellId % 12) + 1; // Wrap around if greater than 12
          const nextCell = document.querySelector('[data-cell-id="' + cellId + '"]');
          if (nextCell) {
            nextCell.innerText = Number(nextCell.innerText) + 1;
          }
          seeds--;
        }
      });
    });
  </script>
</body>
</html>

I think I caught a bug in your implementation. If you load the page and then start clicking from left to right in the bottom row you eventually end up with this:

6-7-7-8-8-9
0-0-0-0-0-0

If I have understood what you are trying to do, this should be:

6-7-7-8-8-9
2-1-0-0-0-0

My version ends up with the bottom version.

1 Like

Thank you so much!!!

I had never tried clicking all cases from the left so didn’t catch the mistake.

Your version other than working perfectly is also what i was looking for: A smater way to implement it. I just copied/pasted and tried it. Going now to look more closely how you have done it. :+1:

1 Like

No problem. Let me know if you have any questions and I’ll be happy to explain.

Just GREAT :slightly_smiling_face:

I can after fill my myArray.nbrPeas with the values found in the cells.

But; as if it the case; the number of seeds/peas in one cell can not exceed 12. While seeding; if the added seed put the number of seeds contained in the cell to a number > 12 then that cell shouldn’t be seeded but the seed seeded to the next cell if < 12. So then if more seeds in the queue the next seed should be seeded in the cell next to the last one…

How you you do that?

In this case the distribution logic would need to be adjusted to skip cells that already have 12 seeds, while continuing the distribution to subsequent cells. Here’s how you might do that:

document.querySelectorAll('#bottomRow td').forEach(cell => {
  cell.addEventListener('click', () => {
    let cellId = Number(cell.getAttribute('data-cell-id'));
    let seeds = Number(cell.innerText);
    cell.innerText = 0;

    while (seeds > 0) {
      cellId = (cellId % 12) + 1; // Wrap around if greater than 12
      const nextCell = document.querySelector('[data-cell-id="' + cellId + '"]');

      // Skip cells if adding a seed would exceed 12
      if (nextCell && Number(nextCell.innerText) < 12) {
        nextCell.innerText = Number(nextCell.innerText) + 1;
        seeds--;
      }
    }
  });
});

Yep; so simple… I wish I could live in your brain my friend. :slightly_smiling_face:

Thanks for the help.

2 Likes

This works good and easy. But just curiousity: If you had tried to make it work manipulating the array instead of the DOM; was there a more easier way than mine?

I mean: There would be for sure :grinning: But how?

I’m not sure that an array is the best data structure to use because each cell needs more than just a number to represent its state. I would be tempted to use an array of objects:

const gameState = [
  { id: 1, seeds: 4 }, 
  { id: 2, seeds: 4 }, 
  { id: 3, seeds: 4 },
  { id: 4, seeds: 4 }, 
  { id: 5, seeds: 4 }, 
  { id: 6, seeds: 4 },
  { id: 7, seeds: 4 }, 
  { id: 8, seeds: 4 }, 
  { id: 9, seeds: 4 },
  { id: 10, seeds: 4 }, 
  { id: 11, seeds: 4 }, 
  { id: 12, seeds: 4 }
];

I could have a go at implementing this tomorrow if you like (I am off to bed now).

I agree; your solution is neat and it is a lot simpler to refresh the array afterwards.

Good night. :slight_smile:

This version moves the state out of the DOM and into the JavaScript.

  <table id="gameBoard">
    <tr id="topRow">
      <td data-cell-id="12"></td>
      <td data-cell-id="11"></td>
      <td data-cell-id="10"></td>
      <td data-cell-id="9"></td>
      <td data-cell-id="8"></td>
      <td data-cell-id="7"></td>
    </tr>
    <tr id="bottomRow">
      <td data-cell-id="1"></td>
      <td data-cell-id="2"></td>
      <td data-cell-id="3"></td>
      <td data-cell-id="4"></td>
      <td data-cell-id="5"></td>
      <td data-cell-id="6"></td>
    </tr>
  </table>

And:

const SEEDS = 4;
const SLOTS = 12;

const gameState = Array.from({ length: SLOTS }, (_, index) => ({
  id: index + 1,
  seeds: SEEDS
}));

function renderBoard() {
  document.querySelectorAll('[data-cell-id]').forEach((cell) => {
    const cellId = Number(cell.getAttribute('data-cell-id'));
    let cellData = gameState.find(state => state.id === cellId);
    cell.innerText = cellData.seeds;
  });
}

document.querySelectorAll('#bottomRow td').forEach(cell => {
  cell.addEventListener('click', () => {
    let cellId = Number(cell.getAttribute('data-cell-id')) - 1;
    let seeds = gameState[cellId].seeds;
    gameState[cellId].seeds = 0;

    while (seeds > 0) {
      cellId = (cellId + 1) % 12;

      if (gameState[cellId].seeds < 12) {
        gameState[cellId].seeds++;
        seeds--;
      }
    }

    renderBoard();
  });
});

renderBoard();

SLOTS is set to 12, but the script crashes if you change it. I did have a version where you could change the number of slots by altering this variable, but it increased the amount of code by a fair bit. Lemme know if you would like to see that.

Even if the version from James is nice, I would not prefer to do it directly in the DOM. Especially if it should become a game, which may grow in the future, the code becomes more and more hard to read and maintain. If you, for example, want to store the actual game status, you need to read all the data out of the DOM and store it into a format you can use for mass storage.

Also you are very limited with you logic to store all players in one array. and revers the order of player one and two in the array is confusing everyone to whom you did not explain it.
Also, what if you want to add another player?

I know, this may look over engineered but I would prefer to use all in classes and work with the newest JS ES6 modules instead. So my code would look something like that (Not tested, just written in editor:

config.mjs

export const gameConfig =
{
    "numberOfPlayers" : 2,
    "numberOfCellsPerPlayer" : 6,
    "numberOfInitialSeedsPerCell": 4,
    "maxNumberOfSeedsPerCell": 12
}

cell.mjs

import {gameConfig} from './config.mjs';

export class Cell
{
    actualSeedCount;

    constructor()
    {
        this.actualSeedCount = gameConfig.numberOfInitialSeedsPerCell;
    }
    
    addOneSeed()
    {
        if(this.actualSeedCount < gameConfig.maxNumberOfSeedsPerCell)
        {
            this.actualSeedCount++;
            return true;
        }
        return false;
    }
    
    reamoveAllSeeds()
    {
        this.actualSeedCount = 0;
    }
}

player.mjs

import {gameConfig} from './config.mjs';
import {Cell} from './cell.mjs';

export class Player
{
    cells = [];

    constructor()
    {
        for(let index = 0; index < gameConfig.numberOfCellsPerPlayer; index++)
            this.cells.push(new Cell());
    }
}

game.mjs

import {gameConfig} from './config.mjs';
import {Cell} from './cell.mjs';
import {Player} from './player.mjs'

export class Game
{
    players = [];

    constructor()
    {
        for(let index = 0; index < gameConfig.numberOfPlayers; index++)
            this.players.push(new Player());
    }

    makeAMove(playerId, cellId)
    {
        let seeds = players[playerId].cells[cellId].actualSeedCount;
        players[playerId].cells[cellId++].reamoveAllSeeds();
        while(seeds)
        {
            if(players[playerId % gameConfig.numberOfPlayers].cells[cellId % gameConfig.numberOfCellsPerPlayer].addOneSeed())
                seeds--;
            cellsId++;
            if(!cellId % gameConfig.numberOfCellsPerPlayer)
                playerId++;
        }
    }
}
1 Like

I had written some complicated code to put the values of the DOM in an array :laughing:

That works perfectly. :+1: Thanks to you I have now the ‘engine’ for my game; I will just now have to put some nice graphics in it save the game in data base for online play and it will be ready to go.

Thanks again for your time and effort James; it’s really appreciated. :+1: