LE COMPTE EST BON

cppdupdup34 Messages postés 212 Date d'inscription dimanche 29 juin 2003 Statut Membre Dernière intervention 13 mai 2006 - 29 avril 2004 à 16:42
Kypper_667 Messages postés 15 Date d'inscription samedi 22 mai 2004 Statut Membre Dernière intervention 10 octobre 2008 - 28 févr. 2008 à 14:09
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/22392-le-compte-est-bon

Kypper_667 Messages postés 15 Date d'inscription samedi 22 mai 2004 Statut Membre Dernière intervention 10 octobre 2008
28 févr. 2008 à 14:09
Très bon travail. Ca m'a toujours étonné les programmes comme ça ;) Ca vaut bien un 10/10 :D
patemino Messages postés 80 Date d'inscription lundi 28 juillet 2003 Statut Membre Dernière intervention 22 mars 2007
19 mai 2007 à 12:59
Bonjour VonCarstein,
Ta solution algorithmique n'oblige-t-elle pas le programme à "consommer" toutes les opérations ?
Ta condition sur nombre gène l'arrêt de l'algo si le compte se trouve être bon avant 5 opérations, si je ne m'abuse. Et aussi, l'affichage des opérations se fait à l'envers ;) l'utilisation du backtracking nécessite d'inverser le résultat pour être dans le bon sens.
StanOfSky Messages postés 43 Date d'inscription mardi 30 mars 2004 Statut Membre Dernière intervention 7 octobre 2006
23 mai 2004 à 00:56
heu en quoi est ce que la nouvelle version est c++???
a part le fait que tu utilises iostream c du c simple et bete
le c++ implique : classes, héritages, etc... sinon c tout simplement du c...
en plus tu utilises string.h qui est en c alors que string est effectivement une classe c++

quelques remarques sur ce fameux c++
tout d'abord using namespace std; n'est pas recommandé, il vau mieux ecrire std:: devant chaque fonction, c chiant mais ca évite des problemes entre librairies
ensuite, essai de séparaer tout ce qui est calcul de l'affichage sinon ton code n'est pas du tout portable ou réutilisable pour etre incorporé dans un environnement graphique
de meme il fau séprarer entrée/sorties des calculs

de plus une fonction telle que
int absolue(int x)
{
return x>0?x:-x;
}
est boulet... c pas du tout optimisé
tu aurai pu ecrire soit:
inline int absolue(int x)
{
return x>0?x:-x;
}
ou alors fai une macro:
#define abs(x) ((x<0)?(-x):(x))

sinon une vieille source prolog qui cherche les résultat des chiff&lettres aussi. ce programme est capable de trouver toutes les solutions possible et les affiche. normalement ca va assez vite pour trouver ttes les solutions
j'ai essayé de l'optimiser pour qu'il ne donne pas trop de fois la meme solutions genre
5*9=45 équivalent à 5*3=15 etc...
45*3=135 15*9=135

/* fonction de tri */

divise([],[],[]).
divise([X],[X],[]).
divise([X,Y|L],[X|R1],[Y|R2]) :- divise(L,R1,R2).

fusion([],L,L).
fusion(L,[],L).
fusion([X|L1],[Y|L2],[X|M]) :-
X =< Y,
fusion(L1,[Y|L2],M).
fusion([X|L1],[Y|L2],[Y|M]) :-
X > Y,
fusion([X|L1],L2,M).

tri_fusion([],[]).
tri_fusion([X],[X]).
tri_fusion([X,Y|L],Lt) :-
divise([X,Y|L],L1,L2),
tri_fusion(L1,L1t),
tri_fusion(L2,L2t),
fusion(L1t,L2t,Lt).

/* supprime l'élt E de la liste */

enleve(_,[],[]).
enleve(E,[E|L],L).
enleve(E,[X|L],[X|R]) :- X \== E, enleve(E,L,R).

/* fonction de permutation de listes */

permut([],[]).
permut(L,[M|R]) :-
member(M,L),
enleve(M,L,LmM),
permut(LmM,R).

/* supprime tous les élts avant E compris*/

reste(E,[E|L],L) :- !.
reste(E,[_|L],R) :- reste(E,L,R).

/* supprime les elts présents plusieurs fois */

elimine(E,L,L) :- not(member(E,L)),!.
elimine(E,L,R) :- enleve(E,L,LmE), elimine(E,LmE,R).

elimine_all([],[]).
elimine_all([X|L],[X|R]) :- elimine(X,L,Rt), elimine_all(Rt,R).

/* transforme une liste de liste en une liste d'éléments */

uneliste([],[]).
uneliste([X|L],S) :- uneliste(L,R), append(X,R,S).

/* affichage d'une liste */

aff([],[]).
aff([X|L],[A,[46]|Ecrire]) :- name(X,A), aff(L,Ecrire).

/* Affichage du résultat */

affiche([],_) :- nl.
affiche([[X,Op,Y,=,R]|L],Liste) :-
name(X,A),
name(Op,B),
name(Y,C),
name(R,D),
uneliste([A,B,C,[61],D],ListeTexte),
name(Texte,ListeTexte),
print(Texte),
affiche(L,Liste).

/*
définition de chaque opération avec A > B
+ : Addition A!=0 ou B!=0
* : multiplication A!=1 ou B!=1
- : soustraction A>B donc que des valeurs positives
/ : division avec diviseur non nul et reste de la division nul
*/

operations([A,B],+,R) :- R is A+B.

operations([A,B],*,R) :-
A =\= 1,
B =\= 1,
R is A*B.

operations([A,B],-,R) :-
A =\= B,
R is A-B,
R =\= B.

operations([A,B],/,R) :-
B =\= 1,
B =\= 0,
A mod B =:= 0,
R is A / B,
R =\= B.

/*
opérations sur listes

prend les éléments 2 par 2, effectue l'opération, supprime les
2 éléments de la liste et rajoute le résultat au début.

*/

ope(Ec,[X,Op,Y,=,R],[R|Ls2]) :-
member(A,Ec), /* prend 1 élts */
reste(A,Ec,Lt), /* enleve l'élts */
member(B,Lt), /* prend 1 autre élts */
X is max(A,B), /* X le plus gd des 2 élts */
Y is min(A,B), /* Y le plus pt des 2 élts */
operations([X,Y],Op,R), /* execute une opération */
enleve(X,Ec,Ls1), /* supprime gd élt */
enleve(Y,Ls1,Ls2). /* supprime pt élt */

/* algo de recherche de tout les résultats possible */

rechpf_op([X|_],[],[X]).
rechpf_op(Ec,[Op|Lop],Save) :-
ope(Ec,Op,Es),
rechpf_op(Es,Lop,Save).

resoudre(S) :- etatinitial(Ei), etatfinal(Ej), rechpf_op(Ei,S,Ej).
resoudre(S,Ej) :- etatinitial(Ei), rechpf_op(Ei,S,Ej).
resoudre(S,Ei,Ej) :- rechpf_op(Ei,S,[Ej]).

valeur(V) :- etatinitial(Ei), rechpf_op(Ei,_,V).

all_valeur :-
print('Recherche'), nl,
/*findall(V,valeur(V),R),
print('Elimine'), nl,
elimine_all(R,Rt),
print('Tri'), nl,
tri_fusion(Rt,L),*/
setof(V,valeur(V),L),
print('Valeurs possibles : '),
uneliste(L,ListeTexte),
print(ListeTexte).

aff_solution(_,[]).
aff_solution(Liste,[X|L]) :-
aff(Liste,Ecrire),
uneliste(Ecrire,ListeTexte),
name(Texte,ListeTexte),
print(Texte),
print('->'),
affiche(X,Liste), nl,
aff_solution(Liste,L).

solution :- setof(S,resoudre(S),L), nl, etatinitial(Liste), aff_solution(Liste,L).
solution(Ef) :- setof(S,resoudre(S,[Ef]),L), nl, etatinitial(Liste), aff_solution(Liste,L).
solution(Liste,Ef) :- setof(S,resoudre(S,Liste,[Ef]),L), nl, aff_solution(Liste,L).

/* Etatinitiaux et finaux */

etatinitial([1,7,9,75,20,5]).
etatfinal([298]).
VonCarstein Messages postés 2 Date d'inscription mardi 31 décembre 2002 Statut Membre Dernière intervention 7 mai 2004
7 mai 2004 à 08:44
Hey pas mal :] meme si je continue à preferer le C...
Exact pour la condition manquante, par contre pour trouver la solution avec tous les nombres exclusivement c'est fait expres.
En fait c'est un exo que le prof de prog nous a filé. C'est vachement bien, tu le mets ici et on te le corrige :]
satanfifi Messages postés 1 Date d'inscription mercredi 5 mai 2004 Statut Membre Dernière intervention 6 mai 2004
6 mai 2004 à 21:36
Je sais pas si cela interesse quelqu'un, mais j'ai re-ecris le code precedent en c++ de facon plus claire (pour moi) et j'ai apporte deux (toute petites) ameliorations :

* si une solution est trouvee sans utiliser toutes les valeurs, l'afficher
* et une correction (un oubli sans doute) pour l'operation de division dans la fonction compte.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include


using namespace std;

// Fonction abs

int absolue(int x)
{
return x>0?x:-x;
}


// Fonction recursive qui va calculer toutes les combinaisons d'operandes et d'operateurs
//
// Remarque : on utilise les proprietes suivantes pour accelerer le calcul :
// a + b = b + a
// a * b = b * a
// le resultat de la soustraction doit etre positif
// le resultat de la division doit donner un entier non nul

bool compte(int *tab, int nombre, int total, int *compteur)
{
int i, j, k, t[6];
(*compteur)++;

// On va faire le test sur toutes les valeurs
for (i = 0; i < nombre-1 ; ++i)
{
// i+1 = on evite de recommencer les combinaisons deja testees
for (j = i+1; j < nombre; ++j)
{
for (k = 1; k <= 4; ++k)
{
// Copie sur la pile locale les valeurs que l'on utilise
memcpy(t, tab, sizeof(int)*6);

switch (k)
{

case 1:
t[i] += t[j];
if(t[i] == total)
{
cout << " Le compte est bon! En " << (*compteur) << " operations" << endl << endl;
cout << "\t" << tab[i] << "\t+\t" << tab[j] << "\t=\t" << t[i] << endl << endl;
return true;
}
if(nombre > 0)
t[j] = t[nombre-1];
if(compte(t, nombre-1, total, compteur))
{
cout << "\t" << tab[i] << "\t+\t" << tab[j] << "\t=\t" << t[i] << endl << endl;
return true;
}
break;

case 2:
t[i] *= t[j];
if(t[i] == total)
{
cout << endl << " Le compte est bon! En " << (*compteur) << " operations" << endl;
cout << "\t" << tab[i] << "\t*\t" << tab[j] << "\t=\t" << t[i] << endl << endl;
return true;
}
if(nombre > 0)
t[j] = t[nombre-1];
if(compte(t, nombre-1, total, compteur))
{
cout << "\t" << tab[i] << "\t*\t" << tab[j] << "\t=\t" << t[i] << endl << endl;
return true;
}
break;

case 3:
if( t[i] > t[j] && t[i] != 0 && t[j] != 0 && (t[i]%t[j]) == 0 )
{
t[i] = t[i]/t[j];
}
else
{
if( t[j] > t[i] && t[i] != 0 && t[j] != 0 && (t[j]%t[i]) == 0 )
{
t[i] = t[j]/t[i];
}
else
break; // La division ne respecte pas les conditions precedentes
// Cela ne sert a rien de continuer le calcul sur cette voie
}

if(t[i] == total)
{
cout << endl << " Le compte est bon! En " << (*compteur) << " operations" << endl;
if(tab[i] > tab[j])
cout << "\t" << tab[i] << "\t/\t" << tab[j] << "\t=\t" << t[i] << endl << endl;
else
cout << "\t" << tab[j] << "\t/\t" << tab[i] << "\t=\t" << t[i] << endl << endl;
return true;
}
if(nombre > 0)
t[j] = t[nombre-1];
if(compte(t, nombre-1, total, compteur))
{
if(tab[i] > tab[j])
cout << "\t" << tab[i] << "\t/\t" << tab[j] << "\t=\t" << t[i] << endl << endl;
else
cout << "\t" << tab[j] << "\t/\t" << tab[i] << "\t=\t" << t[i] << endl << endl;
return true;
}
break;

case 4:
t[i] = absolue(t[j]-t[i]);
if(t[i] == total)
{
cout << endl << " Le compte est bon! En " << (*compteur) << " operations" << endl;
if(tab[i] > tab[j])
cout << "\t" << tab[i] << "\t-\t" << tab[j] << "\t=\t" << t[i] << endl << endl;
else
cout << "\t" << tab[j] << "\t-\t" << tab[i] << "\t=\t" << t[i] << endl << endl;
return true;
}
if(nombre > 0)
t[j] = t[nombre-1];
if(compte(t, nombre-1, total, compteur))
{
if(tab[i] > tab[j])
cout << "\t" << tab[i] << "\t-\t" << tab[j] << "\t=\t" << t[i] << endl << endl;
else
cout << "\t" << tab[j] << "\t-\t" << tab[i] << "\t=\t" << t[i] << endl << endl;
return true;
}
break;
}
}
}
}
return false;
}




int main(void)
{
int depart[13] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 25, 50, 100};
int nombre[6];
int i, tranz, total, choix, compteur, plus_proche;

// initialisation de la fonction rand()
srand(time(NULL));

for(i = 0; i < 7 ; ++i)
{
nombre[i] = 0;
}

while(true)
{
cout << "Choisissez le mode appropriZ :" << endl << "\t[1] mode personnalisZ" << endl << "\t[2] mode automatique" << endl << "\t[autre] sortir" << endl;
cin >> choix;

compteur = 0;

switch(choix)
{

case 2:
total = (rand()%900) + 100;
i = 0;
while(i < 7)
{
// Choisis de facon aleatoire les chiffres parmi la liste definie dans depart
tranz = depart[rand() % 13];
nombre[i]= tranz;
i++;
}
break;

case 1:
// Permet la saisie des nombres
cout << "Inscrivez les 6 nombres sous le format a b c d e f g" << endl;
cin >> nombre[0] >> nombre[1] >> nombre[2] >> nombre[3] >> nombre[4] >> nombre[5];

cout << "Entrer le nombre a chercher :" << endl;
cin >> total;
break;

default:
return 0;
}

// Quelques affichages avant le calcul
cout << "Le nombre a atteindre est: "<< total << endl << "Avec les nombres : ";
for (i = 0; i < 6; ++i)
{
cout << nombre[i] << " ";
}
cout << endl << "Et les operateurs: + * / -" << endl;

// Lance le calcul et eventuellement cherche la solution la plus proche s'il n'y a pas de solution au probleme
plus_proche = 0;
while( compte(nombre, 6, total + plus_proche, &compteur) == 0 )
{
if(plus_proche < 0)
{
plus_proche = -plus_proche;
}
else
{
plus_proche = -plus_proche-1;
}
cout << "Le compte exact est impossible, chercher la solution la + proche : " << total + plus_proche << endl;
}
}

return 0;
}
StanOfSky Messages postés 43 Date d'inscription mardi 30 mars 2004 Statut Membre Dernière intervention 7 octobre 2006
30 avril 2004 à 16:48
oulala attention à ta syntaxe!!!

&*compteur aieaieaie tres mauvais
l'adresse de la valeur pointé, c le pointeur :) donc suffit d'écrire : compteur

sinon a part ca c vrai que ce n'est pas forcement simple de comprendre ce que tu fais sans commentaire (surtt en lisant vie fait ton code)

bon compte c ta fonction récursive de calcul
int compte(int *tab, int nombre, int total,long *compteur)

tab c ta liste de nombre
nombre c l'index dans le tableau du nombre actuel
total c le total à trouver
compteur c le nombre d'opérations

et compte renvoi le resultat du calcul

pour ceux qui veulent faire de l'IA ou ce genre d'algo en 10 lignes de code je conseille PROLOG ;)
MoDDiB Messages postés 546 Date d'inscription mardi 26 novembre 2002 Statut Membre Dernière intervention 4 mai 2007 1
29 avril 2004 à 20:15
C'est pour ca que ca s'appelle algo de resolution :p
cppdupdup34 Messages postés 212 Date d'inscription dimanche 29 juin 2003 Statut Membre Dernière intervention 13 mai 2006
29 avril 2004 à 20:00
le programme ne permet pas de jouer ?
chez moi je coisis le mode je tape entrer et pour le mode normal ca me donne tout de suite la sol et pour le mode personnaliser pareil apres que je lui ai donné les 7 chiffres
c'est bizarre
MoDDiB Messages postés 546 Date d'inscription mardi 26 novembre 2002 Statut Membre Dernière intervention 4 mai 2007 1
29 avril 2004 à 18:30
Un prog comme ca ca se commetne a mort ^^ parce que la !Sinon c'est une bonen idée :)
VonCarstein Messages postés 2 Date d'inscription mardi 31 décembre 2002 Statut Membre Dernière intervention 7 mai 2004
29 avril 2004 à 17:01
Voila voila.....
cppdupdup34 Messages postés 212 Date d'inscription dimanche 29 juin 2003 Statut Membre Dernière intervention 13 mai 2006
29 avril 2004 à 16:42
un ptit zip avec l'exe steplé ;-)
je suis pas chez moi et j'ai pas de compilo :-/