Goedemiddag,

Ik heb een multidimensional array hierin zitten 12 arrays elk met 6 verschillende nummers. Nu wil ik deze array controleren met een variabele die willekeurige nummers genereer. Wanneer 6 nummers in 1 van de 12 arrays overeenkomen wil ik dat de functie stopt en de array opslaan zodat weer gegeven kan worden op het scherm.
Nu had ik al het een en ander gevonden op internet. Maar ik kom nu dus in een infinite loop terecht.
Iemand een idee hoe ik dit zou kunnen oplossen en wat ik fout heb gedaan?

<?php
mt_srand((double)microtime() * 1000000);

//lege bingokaart maken
$bingokaart = [];

//functie bingokaart vullen
function kaart_maken(){
//rijen vullen met willekeurige nummers
for($rij=1; $rij<=6; $rij++){
$bingokaart[$rij] = []; //de rij initialiseren
for($num=1; $num<=6; $num++){
//nummer aanmaken, en meteen controleren of ie al in de rij zit
while(in_array($nummer = $rij . rand(0,9), $bingokaart[$rij]));
//voeg nummer toe aan array
$bingokaart[$rij][$num] = $nummer;
}
}

//bingokaart-array uitbreiden met horizontale en verticale rijen door de horrizontale rijen te
//kantelen
$new_bingokaart = array();
foreach($bingokaart as $key => $subarr) {
foreach ($subarr as $subkey => $subvalue) {
$new_bingokaart[$subkey][$key] = $subvalue;
}
}

//bingokaart nummers en tabel printen
echo "<table border='1px black solid'>";
for($i=1; $i<=6; $i++){
echo "<tr>";
for($x=1; $x<=6; $x++){
echo "<td>" . $bingokaart[$i][$x] . "</td>";
}
echo "</tr>";
}
echo "</table><br>";
return array_merge($bingokaart, $new_bingokaart);;
}

//bingokaart printen
$bingokaart = kaart_maken();

$bingo = false;
$getal = rand(10, 69);
$getrokken_getallen = array();

while(!$bingo){
while(in_array($getal, $getrokken_getallen));
$getrokken_getallen[] = $getal;

for($rij=1; $rij<=12; $rij++){
for($rij_nr=1; $rij_nr<=6; $rij_nr++){
if($bingokaart[$rij][$rij_nr] == $getal){
$bingokaart[$rij][0] += 1;
if($bingokaart[$rij][6] == 6){
print "Bingo";
$bingo = true;
}
}
}
}
}

?>

Alvast bedankt voor de hulp.

Groeten Mario
Al aan een break gedacht in je code? Hiermee kan je uit een loop ontsnappen.
Ideaal als deze in een iteratie opeens aan een voorwaarde voldoet.
Ja, die had ik inderdaad ook toegevoegd. Maar helaas nog steeds een infiniti loop. Heb de break op verschillende rijen gezet.
Op welk punt krijg jij een infinite loop?
$getal verandert nooit? Deze wordt maar 1x random getrokken want deze staat buiten wat voor loop dan ook?

De bingokaart is ook enorm complex opgezet, waarom maak je deze tweedimensionaal? Dit heeft tot gevolg dat je elke keer moet gaan zoeken in een meerdimensionaal array. Een eerste ingeving zou zijn om dan hier maar een lineaire lijst van te maken (wat op zich een goed idee is) maar dan moet je geen in_array gaan gebruiken want dat is nog steeds redelijk inefficiënt. Omdat de nummers alle uniek zijn zou je deze op de keys kunnen zetten, en dan kun je met isset() of array_key_exists() een veel snellere lookup doen.

En dan zou je nog eens naar de "beëindiging" kunnen kijken, dus het geval waarin een complete rij of kolom getrokken is.

EDIT: en naar de spelvorm, want blijkbaar zijn er meerdere uitvoeringen van wat doorgaat als "bingo". Misschien is het handig als je even teruggaat naar het functioneel ontwerp, en je daar stap voor stap beschrijft hoe het spel werkt. Een implementatie wordt dan waarschijnlijk een stuk eenvoudiger, omdat precies is voorgeschreven wat er dient te gebeuren.
Als eerst bedankt voor het reageren.

@Ariën dat is voor ook mij vraag. Is er een goeie manier van debugen of een programmeerprogramma om te debugen. Ik maak nu gebruik van Brackets om te programmeren.

@Thomas qua spelvorm moet ik me aan de regels houden van de opdracht. Dus in dit geval een bingokaart 6x6 met de getallen 10=>20 20=>30 enz die horizontaal getoond moeten worden.
Betreft opzet had ik zelf ook al het idee dat het anders kan. Echter weet ikzelf niet echt hoe. Hier ben ik net iets te vers voor.

De reden waarom ik gekozen heb voor een meerdimensionaal array is omdat ik uiteindelijk de rij die bingo veroorzaakt een kleur moet geven. Dus heb ik een for loop gemaakt die het getal in de arrays controller, en wanneer deze 6x voorkomt in 1 van de arrays, $bingo true retour moet geven.
Het debuggen is in het simpelste niets meer dan de waardes tussentijd op je scherm outputten met echo, print_r en/of var_dump. Er zijn ook extentions voor webservers zoals Xdebug om je script meer te debuggen en te profilen.
@Marios: het spel eindigt dus als er een rij en/of kolom is afgestreept correct?

Stel je nu de volgende situatie voor:
. . . . x .
. . . . x .
. . . . x .
x x x x o x
. . . . x .
. . . . x .

Stel dat alle x-en afgestreept zijn, en de "o" het volgende getal is, dan dien je dus zowel een rij als een kolom in te kleuren :).

Het volgende lijkt te werken:
<?php
mt_srand((double)microtime() * 1000000);

// note: $rows and $columns cannot exceed 10, unless you want to play hexadecimal bingo
function createCard($rows=6, $columns=6) {
    $card = [];
    for ($i=0; $i < $rows; $i++) {
        for ($j=0; $j < $columns; $j++) {
            while (array_key_exists($randomNumber = ($i+1) * 10 + rand(0, 9), $card));
            $card[$randomNumber] = false;
        }
    }
    dump(implode(', ', array_keys($card)));
    return $card;
}

function updateCard(&$card, $number) {
    if (isset($card[$number])) {
        $card[$number] = true;
    }
}

function checkCardForBingo($card, $rows=6, $columns=6) {
    $return = false;
    $cardPositions = array_keys($card); // index => number
    // check rows
    for ($i=0; $i < $rows; $i++) {
        $count = 0;
        for ($j=0; $j < $columns; $j++) {
            $nr = $cardPositions[$i*$rows+$j];
            $count = $count + $card[$nr]; // false = 0, true = 1
        }
        if ($count == $columns) { // full row
            dump('row '.$i);
            $return = true;
        }
    }
    // check columns
    for ($j=0; $j < $columns; $j++) {
        $count = 0;
        for ($i=0; $i < $rows; $i++) {
            $nr = $cardPositions[$i*$rows+$j];
            $count = $count + $card[$nr];
        }
        if ($count == $rows) { // full column
            dump('column '.$j);
            $return = true;
        }
    }
    return $return;
}

function drawNumber(&$drawnNumbers) {
    while (array_key_exists($number = rand(10, 69), $drawnNumbers));
    $drawnNumbers[$number] = true;
    dump('drawing '.$number);
    return $number;
}

// debugging
define('DEBUG_OUTPUT', true);

function escape($s) {
    return htmlspecialchars($s, ENT_QUOTES, 'UTF-8');
}

function dump($in) {
    if (DEBUG_OUTPUT === false) {
        return;
    }
    if (is_array($in)) {
        echo '<pre>'.escape(print_r($in, true)).'</pre>';
    } else {
        echo escape($in).'<br>';
    }
}

$card = createCard();
$drawnNumbers = [];
$bingo = false;

while ($bingo === false) {
    $number = drawNumber($drawnNumbers);
    updateCard($card, $number);
    $bingo = checkCardForBingo($card);
}
?>[end]

Merk op dat als je e.e.a. vangt in functies dat het daadwerkelijke "programma" ook vrij kort is en (zonder de bijbehorende implementatie) al redelijk goed gevolgd kan worden, alsof het een aantal lopende zinnen zijn:
zolang er geen bingo is
    trek een nummer
    streep deze af op de lijst
    controleer op bingo
herhaal
Bedankt voor je bericht. Inderdaad was ik even vergeten dat het natuurlijk mogelijk is om meerdere rijen bingo te krijgen. Ik ga hiermee aan de slag. Er zitten hier voor mij ook wat nieuwe codes in. Dus ga ik eerst kijken wat er hier gebeurt en waarom.

Groeten Mario
Het voornaamste nieuwe ding is de & (ampersand) voor sommige van de variabelen in de functie-definitie van updateCard() (&$card) en drawNumber() (&$drawnNumbers).

Normaal weet een functie niet van het bestaan van variabelen die buiten de functie vallen -enkele speciale gevallen zoals superglobals daargelaten-, de functie heeft normaal alleen te maken met parameters die aan de functie worden meegegeven of de variabelen die binnen de functie worden gedefiniëerd. Dit is dan ook meteen het gebied waarin de variabelen bekend (of "geldig") zijn, m.a.w. dit is de scope (het geldigheidsgebied).

Bij de parameters die worden meegegeven is normaal alleen de waarde(n) die ze meesturen relevant, als een parameter intern van waarde verandert gebeurt er verder niets met de waarde van de externe variabele:
<?php
function plusEen($in) {
    $in = $in + 1;
    echo $in.'<br>';
}

$test = 4;
plusEen($test); // geeft 5
echo $test; // geeft 4
?>

Dit heet "call by value".

Er zijn echter (ten minste?) twee uitzonderingen hier op: in de eerste plaats kun je aangeven dat een (simpele) variabele (string, boolean, array, integer etc.) wél behandeld moet worden alsof deze rechtstreeks aangesproken werd. Dit heet "call by reference". Wijzigingen in de verwijzing hebben dezelfde impact op het origineel. Een variabele kun je call by reference meegeven aan een functie door er een ampersand (&) voor te zetten:
<?php
function plusTwee(&$in) {
    $in = $in + 2;
    echo $in.'<br>';
}

$test = 4;
plusTwee($test); // geeft 6
echo $test; // geeft ook 6
?>

Om variabelen uit de globale scope (buiten de functies) te gebruiken binnen een functie kun je ook het keyword global gebruiken, maar dat kan nogal verwarrend werken, ook kunnen er dan potentieel botsingen in naamgevingen gaan ontstaan. Persoonlijk zou ik het global keyword niet gebruiken, vaak -als je dit nodig lijkt te hebben- zijn er andere (en waarschijnlijk betere) oplossingen mogelijk. Het gebruik van global is zoiets als ergens een tussenwand uitslopen, en die tussenwand zat er meestal om een reden in. De enige hoop die je kunt hebben is dat die tussenwand niet dragend was :p.

En dan zijn er nog objecten. Objecten zijn (tegenwoordig, want volgens mij is dat in het verleden niet altijd zo geweest) standaard call by reference.
<?php
function plusDrie(StdClass $test) {
    $test->number = $test->number + 3;
    echo $test->number.'<br>';
}

$myNumberThing = new StdClass();
$myNumberThing->number = 4;

plusDrie($myNumberThing); // levert 7
echo $myNumberThing->number;  // levert ook 7
?>

Je had uiteraard ook alles kunnen doen zonder dit call by reference geneuzel door het resultaat te retourneren en toe te kennen aan de variabele die je als parameter meegaf.

Het wordt natuurlijk (nog) interessant(er) als je de bingokaarten en trekkingen organiseert in objecten die interactie met elkaar hebben in een soort van gesimuleerd spel.

NB: als je vaak call by reference gebruikt (doorgaans in een procedurele setting) dan houdt dit in dat er sprake is van een soort van "variabelentoestand" (ook wel state genoemd) die bijgehouden en (meerdere toestandsveranderingen overbruggend) onthouden moet worden. Dit kan ook een indicatie zijn dat een overstap naar een object georiënteerde aanpak handig kan zijn, omdat objecten (van classes) bij uitstek geschikt zijn om een toestand vast te houden.
Goedemorgen,

Het heeft even geduurd maar goed. Ik kan hier zeker wat mee. Bedankt voor de goede uitleg zeker betreft ampersand. Ikzelf had inderdaad alles functie uitslagen in een variabele laten opslaan. Maar ik ben wel benieuwt dat wanneer ik de ampersand ga gebruiken, dit invloed kan hebben op mijn variabele wanneer ik deze verder gaat gebruiken/wijzigen in latere code, of houd deze variabele de aangepaste waarde?
Variabelen declareren in functies was trouwens ook nieuw voor mij.

Ik heb zelf nog wat vragen over je code die je geschreven had voornamelijk voor mijzelf om te zien of ik het begrijp. Ik heb de vraag in commentaar bij de regel gezet.

Vraag1:
<?php
function createCard($rows=6, $columns=6) {
$card = [];
for ($i=0; $i < $rows; $i++) {
for ($j=0; $j < $columns; $j++) {
while (array_key_exists($randomNumber = ($i+1) * 10 + rand(0, 9), $card));//klopt het dat hier gegeken word of het randomnummer voorkomt?
$card[$randomNumber] = false; //en hier wanneer het false is, de loop opnieuw uitvoeren net zolang todat de kaart gevuld is?
}
}
dump(implode(', ', array_keys($card)));
return $card;
}
?>

Vraag 2:
<?php
function checkCardForBingo($card, $rows=6, $columns=6) {
$return = false;
$cardPositions = array_keys($card); // index => number
// check rows
for ($i=0; $i < $rows; $i++) {
$count = 0;
for ($j=0; $j < $columns; $j++) {
$nr = $cardPositions[$i*$rows+$j];//waarom word hier vermenigvuldigd en opgeteld?
$count = $count + $card[$nr]; // false = 0, true = 1
}
if ($count == $columns) { // full row
dump('row '.$i);
$return = true;
}
}
?>

Vraag 3:
<?php
function drawNumber(&$drawnNumbers) { //Klopt het dat door hier gebruik te maken van een ampersand dat de array gevuld word met random nummers?
while (array_key_exists($number = rand(10, 69), $drawnNumbers));
$drawnNumbers[$number] = true;
dump('drawing '.$number);
return $number;
}
?>


Groeten Mario

Reageren