functie stoppen wanneer array waardes overeenkomen

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Marios Achternaam

Marios Achternaam

22/07/2018 15:57:03
Quote Anchor link
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?

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?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
 
PHP hulp

PHP hulp

29/03/2024 06:05:03
 
- Ariën  -
Beheerder

- Ariën -

22/07/2018 16:00:22
Quote Anchor link
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.
 
Marios Achternaam

Marios Achternaam

22/07/2018 16:13:02
Quote Anchor link
Ja, die had ik inderdaad ook toegevoegd. Maar helaas nog steeds een infiniti loop. Heb de break op verschillende rijen gezet.
 
- Ariën  -
Beheerder

- Ariën -

22/07/2018 16:14:16
Quote Anchor link
Op welk punt krijg jij een infinite loop?
 
Thomas van den Heuvel

Thomas van den Heuvel

22/07/2018 19:14:23
Quote Anchor link
$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.
Gewijzigd op 23/07/2018 12:43:15 door Thomas van den Heuvel
 
Marios Achternaam

Marios Achternaam

23/07/2018 19:10:28
Quote Anchor link
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.
 
- Ariën  -
Beheerder

- Ariën -

23/07/2018 19:29:00
Quote Anchor link
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.
 
Thomas van den Heuvel

Thomas van den Heuvel

23/07/2018 23:31:01
Quote Anchor link
@Marios: het spel eindigt dus als er een rij en/of kolom is afgestreept correct?

Stel je nu de volgende situatie voor:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
. . . . 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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
zolang er geen bingo is
    trek een nummer
    streep deze af op de lijst
    controleer op bingo
herhaal
 
Marios Achternaam

Marios Achternaam

29/07/2018 12:35:13
Quote Anchor link
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
 
Thomas van den Heuvel

Thomas van den Heuvel

29/07/2018 15:35:59
Quote Anchor link
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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
<?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.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
<?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.
Gewijzigd op 29/07/2018 15:46:58 door Thomas van den Heuvel
 
Marios Achternaam

Marios Achternaam

10/08/2018 11:12:57
Quote Anchor link
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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
<?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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?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:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?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
 
Thomas van den Heuvel

Thomas van den Heuvel

10/08/2018 13:31:50
Quote Anchor link
//klopt het dat hier gegeken word of het randomnummer voorkomt?
Ja, zolang $randomNumber al voorkomt op de kaart zoeken we naar een nieuwe kandidaat, net zolang totdat we er een tegenkomen die er nog niet op staat. Deze voegen we dan toe en herhalen het proces totdat de hele kaart voorzien is van unieke nummers.

//en hier wanneer het false is, de loop opnieuw uitvoeren net zolang todat de kaart gevuld is?
Nee, dat is geen vergelijking, dat is een toekenning van een nog niet bestaand nummer ($randomNumber) aan de kaart. Deze sla ik op in de key, de value is false, die aangeeft dat het nummer nog niet afgestreept is. Als je een nieuwe kaart hebt/bouwt, is nog geen enkel nummer afgestreept. Ik sla $randomNumber op in de key zodat je dan heel snel (en efficiënt) dit nummer kunt inspecteren (en kunt afstrepen), en niet hoeft te gaan zoeken in $card met een in_array() operaties ofzo.

//waarom word hier vermenigvuldigd en opgeteld?
Ik maak er geen meerdimensionaal array van voor rijen en kolommen, maar zet de rijen achter elkaar. Elke kolom heeft dan een nieuwe "offset", namelijk de huidige rij, vermenigvuldigd met ... dat moet eigenlijk * $columns zijn denk ik, in plaats van $rows, waarschijnlijk :). Elke rij is namelijk $columns elementen lang.

//Klopt het dat door hier gebruik te maken van een ampersand dat de array gevuld word met random nummers?
$drawnNumbers (in de functie) is een parameter, deze representeert de variabele $drawnNumbers uit de globale scope (staat gedeclareerd op regel 79).

Het doel van deze parameter/variabele is dat je bijhoudt welke nummers al getrokken zijn. Bij het trekken van een nieuw nummer ga je ook hier weer net zolang door totdat je een nieuw nummber vindt. Deze wordt enerzijds toegevoegd aan de parameter in de functie, en daarmee aan de variabele $drawnNumbers uit de globable scope, en anderzijds geretourneerd via return.

Toegegeven, dat deze dezelfde naam hebben is wellicht verwarrend, maar doordat je de parameter aanroept met een ampersand wordt de variabele uit de globale scope (regel 79) dus direct aangesproken en kan deze dan ook rechtstreeks inhoudelijk worden aangepast. Normaal bestaan variabelen die je in een functie declareert niet buiten de functie, maar met een ampersand (of het keyword global, wat waarschijnlijk af te raden is) kun je een brug slaan tussen variabelen binnen de functie, en daarbuiten.

Het zou misschien zelfs nog handiger zijn als je hier objecten en klassen van maakt, want procedures (functies binnen een klasse) kunnen sowieso bij alle (eigen) klasse-variabelen.

EDIT: als ik zo in de gauwigheid kijk moeten er in de oorspronkelijke code misschien wat dingetjes worden aangepast:
- regel 30 $i*$rows moet $i*columns zijn
- ... hmm, dat wat het?
Het bovenstaande vormt trouwens geen probleem zolang de afmetingen van de kaart (rijen, kolommen) hetzelfde zijn.
Gewijzigd op 10/08/2018 14:02:40 door Thomas van den Heuvel
 
Marios Achternaam

Marios Achternaam

13/08/2018 19:38:38
Quote Anchor link
Bedankt voor het verduidelijken van mijn vragen. Heb hier zeker wat aan. Objecten en klassen heb ik nog niet gehad. Maar dit komt nog wel aan de orde. Ik ga hier weer mee aan de slag.

Groeten Mario
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.