[RESOLU] comportement while

Petit nouveau ! | 3 Messages

19 mars 2017, 19:41

Bonjour,
je dois réaliser un distributeur de boisson comme exercice.

Pour rendre la monnaie je fais une boucle while mais ça ne fonctionne pas comme je le voudrais.

Le comportement est étrange et je ne me l'explique pas d'où mon message pour avoir une explication.
Pour exemple un Fanta moyen avec une pièce de 2 et une pièce de 1, la boucle saute.
Merci de m'éclairer.
Stef
$taille= array('Petite', 'Moyenne', 'Grande');
	
	$boisson['Coca']['Petite']=2;
	$boisson['Coca']['Moyenne']=2.4;
	$boisson['Coca']['Grande']=3;
	$slogan['Coca']='Always COOL';
	$image['Coca']='<img class="img-canette" src="images/coca.jpg" alt=""/>';
	
	$boisson['Fanta']['Petite']=2;
	$boisson['Fanta']['Moyenne']=2.5;
	$boisson['Fanta']['Grande']=3;
	$slogan['Fanta']='Eclate-toi avec FANTA';
	$image['Fanta']='<img class="img-canette" src="images/fanta.jpg" alt=""/>';
	
	$boisson['Icetea']['Petite']='Indisponibl';
	$boisson['Icetea']['Moyenne']=2.7;
	$boisson['Icetea']['Grande']=3.3;
	$slogan['Icetea']='Drink Positive';
	$image['Icetea']='<img class="img-canette" src="images/icetea.jpg" alt=""/>';
	
	$boisson['Kro']['Petite']='Indisponibl';
	$boisson['Kro']['Moyenne']=3.7;
	$boisson['Kro']['Grande']=4.3;
	$slogan['Kro']="Enfin une française qui est sûre d'arriver en demi";
	$image['Kro']='<img class="img-canette" src="images/kro.jpg" alt=""/>';
	
	$boisson['7up']['Petite']=1;
	$boisson['7up']['Moyenne']=2;
	$boisson['7up']['Grande']='Indisponibl';
	$slogan['7up']='Live life on the up';
	$image['7up']='<img class="img-canette" src="images/7up.jpg" alt=""/>';
	
	$boisson['Orangina']['Petite']=2;
	$boisson['Orangina']['Moyenne']=3.2;
	$boisson['Orangina']['Grande']='Indisponibl';
	$slogan['Orangina']='Shake the World';
	$image['Orangina']='<img class="img-canette" src="images/orangina.jpg" alt=""/>';
	
	$piece['2euro']=2;
	$piece['1euro']=1;
	$piece['50cents']=0.5;
	$piece['20cents']=0.2;
	$piece['10cents']=0.1;
	$piece['5cents']=0.05;
	$piece['2cents']=0.02;
	$piece['1cents']=0.01;
	
	
	$stock_piece['2euro']=4;
	$stock_piece['1euro']=2;
	$stock_piece['50cents']=0;
	$stock_piece['20cents']=1;
	$stock_piece['10cents']=1;
	$stock_piece['5cents']=5;
	$stock_piece['2cents']=5;
	$stock_piece['1cents']=5;
	
	
	if (isset($_POST['canette'])){
	
	
	    if ($boisson[$_POST['canette']][$_POST['taille']] == 'Indisponibl'){
echo "<div class='annonce-non'>";		
		echo "Désolé, nous n'avons plus de canette de ".$_POST['canette']." disponible dans cette taille";
echo "</div>";
	    }else{

		foreach ($piece as $index_piece2 => $valeur_piece2 ){
		    $total = $total + $_POST[$index_piece2] * $piece[$index_piece2];      
		}

		if ($total < $boisson[$_POST['canette']][$_POST['taille']]){
echo "<div class='annonce-non'>";
		    echo "Vous n'avez pas mis assez d'argent dans le monnayeur";
echo "</div>";		    
		}else{
		    $monnaie = $total - $boisson[$_POST['canette']][$_POST['taille']];

		    foreach ($stock_piece as $index_stock => $valeur_stock){
			if ($piece[$index_stock] <= $monnaie){
			    $fond_caisse = $fond_caisse + $stock_piece[$index_stock] * $piece[$index_stock] ;
			    }
		    }

		    if ($fond_caisse < $monnaie){
echo "<div class='annonce-non'>";			
			echo "Désolé, nous n'avons pas assez de monnaie dans le Drink o Matik, choisissez une autre canette";
echo "</div>";
		    }else{
echo "<div class='container'>";	
    echo "<div class='row'>";
	echo "<div class='col-12 text-center'>";
			echo "Voici votre canette de ".$_POST['canette']." de ".$_POST['taille']." taille.<br />";
	echo "</div>";
	echo "<div class='col-12 text-center mt-5'>";
			echo $image[$_POST['canette']];
	echo "</div>";
	echo "<blockquote class='col-12 quote-card blue-card text-center mt-5'>";
			echo "<p> ".$slogan[$_POST['canette']]." </p>";
	echo "</blockquote>";
	echo "<div class='col-12 text-center mt-5'>";
			echo "Cette canette vous  à coûté ".$boisson[$_POST['canette']][$_POST['taille']]." €.<br />";
	echo "</div>";
	echo "<div class='col-12 text-center mt-5'>";
			echo "Votre monnaie est de ".$monnaie." €";
	echo "</div>";
	echo "<div class='col-12 text-center mt-5'>";
	
////////////// RENDRE LA MONNAIE ////////////////////////////////////	
			foreach ($piece as $index_piece3 => $valeur_piece3){

			    while ($monnaie >= $valeur_piece3 && $stock_piece[$index_piece3] > 0 ){
echo "<pre>";
print_r ($monnaie);
echo "</pre>";
echo "<pre>";
print_r ($valeur_piece3);
echo "</pre>";
echo "<pre>";
print_r ($stock_piece[$index_piece3]);
echo "</pre>";

				echo "<img src='images/".$index_piece3.".png' alt='piece de ".$index_piece3."'/>";
				$monnaie = $monnaie - $valeur_piece3;
				$stock_piece[$index_piece3]--;
			    } 
			}
	echo "</div>";
		    }   		   
		}    
	    }
	}else{    
///////////////////   CREATION DU TABLEAU DU DISTRIBUTEUR ///////////////////////////////////
	    
echo "<div class='container'>";
    echo "<div class='row'>";
	echo "<table class='col-12 table table-inverse'>";
	    echo "<tr >";
		echo "<td class='font-bold-white text-center'>Drink O Matik</td>";
	    echo "</tr>";
	    echo "<tr>";
		echo "<td class='font-bold-red'>Boisson</td>";
		    foreach ($taille as $index_taille => $valeur_taille){
			echo "<td class='font-bold-red'>".$valeur_taille."</td>";
		    }
	    echo "</tr>";

	    foreach ($boisson as $index_boisson => $value_boisson){
		echo "<tr><td class='font-bold-red'>".$index_boisson."</td>";

		foreach ($value_boisson as $index_prix => $value_prix){
		    echo "<td>".$value_prix."€</td>";
		}
		
		echo "</tr>";
	    }
	    
	echo "</table>";

///////////////  CREATION DU FORMULAIRE DE SELECTION DE CANETTES  //////////////
		
	echo "<form action='index.php' method='post'>";
	    echo "<div  class='col-12 offset-4 mt-5'>";
		echo "<select name='canette' class='btn btn-success'>";
		
		    foreach ($boisson as $index_boisson => $value_boisson){
			echo "<option value='".$index_boisson."'>".$index_boisson."</option>";
		    }
		    
		echo "</select>";
		echo "<select name='taille' class='btn btn-success offset-1'>";
		
		    foreach ($taille as $index_taille => $valeur_taille){
			echo "<option value='".$valeur_taille."'>".$valeur_taille."</option>";
		    }
		    
		echo "</select>";
	    echo "</div>";    
	
//////////////////////// CREATION DU MONNAYEUR ////////////////////////////////
		
	    echo "<div class='row justify-content-between mt-5'>";
		
		foreach ($piece as $index_piece => $valeur_piece){
		    echo "<div class='col-1'>";	    
		    echo "<img src='images/".$index_piece.".png' alt='piece de".$index_piece."'/><br />";
		    echo "<input class='btn1 btn-danger' type='number' name='".$index_piece."'/><br />";
	    echo "</div>";
		}	
		
	    echo "</div>";
	    echo "<div class='col-12 mt-5'>";
		echo "<input class='btn btn-primary btn-lg offset-5' type='submit' value='Commander' class='col-12'/>";
	    echo "</div>";
	echo "</form>";	
    }
    echo "</div>";
echo "</div>";

ViPHP
ViPHP | 1980 Messages

20 mars 2017, 00:07

Es-tu sûr que tout est calculé correctement ? Les valeurs envoyées par $_POST sont au format "string" et je n'ai pas vu d’assignation de float ou integer.

Par exemple :
foreach ($piece as $index_piece2 => $valeur_piece2 ){
        $total += floatval($_POST[$index_piece2]) * floatval($valeur_piece2);      
    }
It is nice to be important but it is more important to be nice
http://www.aureuswebfactory.fr

Petit nouveau ! | 3 Messages

20 mars 2017, 19:02

Bonjour Aureusms,
je viens de vérifier $ total est celui-ci est bon.
En ce qui concerne les float et integer, je ne les ai pas encore vu donc je ne peux m'en servir. Je n'ai que 5 semaines de php derrière moi.
J'ai changé la version de php. En 5.5, la soustraction " $monnaie = $monnaie - $valeur_piece3; "avait un comportement bizarre.
Du genre 0.5 - 0.2 = 0.29999999999
Maintenant on ne le voit plus dans le print_r mais le problème reste le même et ceux doit être pour cela que le while saute, enfin je suppose.
J'ai tenté ta solution, mêmele problème reste le même.

Stef

Avatar de l’utilisateur
Modérateur PHPfrance
Modérateur PHPfrance | 8755 Messages

21 mars 2017, 11:58

salut,

ce n'est pas parce que tu n'as pas vu un truc que tu ne peux l'utiliser. La vie de dev c'est beaucoup de recherche et d'apprentissage (tout le temps) :mrgreen:

php 5.5 ? faudrait p'tet voir pour être a jour :)

D'abord le "esthétique"
a priori tu ne travail pas avec avec un niveau d'erreur suffisant. Il est important (pour ne pas obligatoire) de développer avec le paramètre error_reportin = E_ALL et bien sur display_error = on
avec ceci tu verrais une erreur indiquant que $total n'existe pas dans ce code
<?php
 foreach ($piece as $index_piece2 => $valeur_piece2 ){
        $total = $total + $_POST[$index_piece2] * $piece[$index_piece2];      
    }
ce n'est pas grand chose mais permet d'éviter des problèmes.
d'ailleurs tu as aussi une erreur parce que tu fait des calculs sur des chaines de caractères ;) => A non-numeric value encountered in (ligne 71 dans mon cas)
pour éviter cela utilise la fonction [url=http://php.net/intval]intval[/php]
=> intval($_POST[$index_piece2])

de manière générale pense à initialiser les variables. ($total = 0; par exemple)

Avec tes paramètres
- fanta moyen
- 1x 2€
- 1 x 1€
on obtient
Cette canette vous à coûté 2.5 €.
Votre monnaie est de 0.5 €
Donc cette partie fonctionne bien

Pour la gestion du rendu de monnaie effectivement c'est pas simple.
Ton affichage ne permet pas de comprendre ce que tu fais vu que tu affiche tout et sans information (on ne sais a quoi cela correspond 0.2 une image de pièces de 20cents tu donnes 20% d'une pièce ?)
il faut que tu indiques le nombre pièce pas la valeur.
$piece['2euro']=2;
  $piece['1euro']=1;
  $piece['50cents']=0.5;
  $piece['20cents']=0.2;
  $piece['10cents']=0.1;
  $piece['5cents']=0.05;
  $piece['2cents']=0.02;
  $piece['1cents']=0.01;


  $stock_piece['2euro']=4;
  $stock_piece['1euro']=2;
  $stock_piece['50cents']=0;
  $stock_piece['20cents']=1;
  $stock_piece['10cents']=1;
  $stock_piece['5cents']=5;
  $stock_piece['2cents']=5;
  $stock_piece['1cents']=5;
tu peux utiliser un tableau 2D
$piece['2euros']['valeur'] = 5
$piece['2euros']['stock'] = 1

avec tes données tu dois avoir en résultat
- 20c x 1
- 10c x1
- 5c x 4

total 20 +10 + 5x4 (20) = 50 centimes

le coté technique

avec un peu de débug on se rend compte qu'a un moment (pour la dernière pièce de 5c) on se retrouve avec ($monnaie >= $value) == false avec un stock de pièce == 2
pourquoi ?
parce que 0.05 >= 0.05 retourne true O_o

d'ailleurs la doc indique
Ainsi, ne faites jamais confiance aux derniers chiffres d'un nombre décimal, mais aussi, ne comparez pas l'égalité de 2 nombres décimaux directement
LE problème c'est que
<?php
$v = 0.05;

if($v >= $v){
  echo 'you win';
}else {
  echo 'loose';
}
=> affiche you win

mais pas dans ce cas alors que php nous indique bien le type et la valeur

Code : Tout sélectionner

float 0.05 float 0.05
mais le truc en fait c'est que les valeurs sont vraiment différente :)
non je ne suis pas dingue, la [url=http://php.net/number_format]number_format[/php] permet de formater un nombre en indiquant le nombre de décimale que l'on veux.
et bien figure toi qu'a partir de la 17ème décimale on à

Code : Tout sélectionner

monnaie : 0.04999999999999996 valeur : 0.05000000000000000
et avec 20 on voi que même ta valeur figée n'est pas parfaite

Code : Tout sélectionner

0.04999999999999996114 0.05000000000000000278
bon tu va me dire que t'en a rien a foutre d'avoir autant de décimale. Oui mais c'est la représentation interne d'un nombre a virgule qui fait cela (ça n'existe pas les virgule en informatique ;) ).

maintenant les solutions (ou il y en a :) )
- utiliser la fonction [url=http://php.net/manual/fr/function.bccomp.php]bccomp[/php]
- utiliser des entiers et compter qu'en centime 2€ => 200, 5c => 5 et la plus de problème de conversion vu que c'est toi qui garde coté serveur les valeurs ;)

je te conseil la seconde solution.
Pour l'affichage je préfères gérer un tableau de résultat qui va permettre d'afficher simplement le résultat.
A moins que le but ce soit d'avoir une ribambelle d'image pour chaque pièce ?
dans mon cas
$result = [];
        foreach ($piece as $i => $value){
          while ($monnaie >= $value && $stock_piece[$i] > 0 ){
            // si l'index existe pas dans le tableau
            if(empty($result[$i])){
              $result[$i] = 1;
            }else {
              $result[$i]++;
            }
            $monnaie -= $value;
            $stock_piece[$i]--;
          }
        }
        // affichage du résultat
        foreach ($result as $key => $value) {
          echo $value , '<img src="images/',$i,'.png" alt="pièce de ',$key,'" /><br />';
        }
@+
Il en faut peu pour être heureux ......

Petit nouveau ! | 3 Messages

21 mars 2017, 19:08

Salut Moogli,
merci pour toutes ces explications.
Cela fais parti de l'exercice, seulement avec des notions déjà vu et effectivement il faut afficher une ribambelle de pièces.
Je m'en vais de ce pas transformer mes valeurs en centimes et consulter tes liens.
Merci d'avoir pris le temps de me répondre.

Stef

Avatar de l’utilisateur
Modérateur PHPfrance
Modérateur PHPfrance | 8755 Messages

22 mars 2017, 09:57

de rien, t'es juste tombé sur un classique un peux tordu qui existe dans tous les langages :-)

bon courage

ps : si tu considère le sujet comme résolus, peut tu cliquer sur le bouton à gauche du titre ? ;) merci

@+
Il en faut peu pour être heureux ......