-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathSolution.java
211 lines (193 loc) · 6.75 KB
/
Solution.java
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
/**
* classe permettant la resolution du compte est bon
*
* @author emmanuel adam
*/
class Solution
{
/** solution à trouver */
int but;
/** nombres a utiliser */
Integer[] nombres;
/** noeuds libres (valeurs pouvant être utilisée pour le calcul) */
List<Integer> valeursLibres;
/** operateurs à utiliser pour le calcul */
List<OperateurFunc> operateurs = Arrays.asList(OperateurFunc.values());
/** hasard */
Random hasard;
/** enchainement des etapes sous forme de chaien de caracteres */
StringBuilder etapes;
// constantes pour optimiser la création de la chaine des étapes
static final String space = " ";
static final String equal = " = ";
static final String coma = " ; ";
/** constructeur */
Solution() {
valeursLibres = new ArrayList<>();
etapes = new StringBuilder();
hasard = new Random();
}
/**
* constructeur
*
* @param nombres
* nombres à utiliser pour le calcul
* @param but
* nombre à atteindre
*/
Solution(Integer[] nombres, int but) {
this();
this.but = but;
this.nombres = Arrays.copyOf(nombres, nombres.length);
valeursLibres = new ArrayList<>(Arrays.asList(nombres));
}
/**
* reinitialise les variables globales
* replace les 6 nombres de base dans la pile valeursLibres<br>
* efface la liste des étapes
*/
void reinit()
{
valeursLibres.clear();
for (int nb : nombres)
valeursLibres.add(nb);
etapes.delete(0, etapes.length());
}
/**
* fonction de calcul d'une solution par méthode aléatoire<br>
* modifie l'objet etapes en indiquant les etapes de calcul suivies
*
* @return la meilleure solution trouvée
*/
public int calcule()
{
int dernierCalcul = 0;
int bestSolution = 0;
int bestEcart = Integer.MAX_VALUE;
OperateurFunc operateur = null;
int nbValLibres = valeursLibres.size();
// tant que le dernier resultat est différent du but et qu'il reste au moins 2
// nombres à choisir
while ((dernierCalcul != but) && (nbValLibres > 1))
{
// prendre 2 nombres au hasard
int indice = hasard.nextInt(nbValLibres);
int nb1 = valeursLibres.remove(indice);
indice = hasard.nextInt(nbValLibres - 1);
int nb2 = valeursLibres.remove(indice);
// tirer un opérateur applicable
operateur = choixOperateurApplicable(nb1, nb2);
// appliquer l'operateur et ajouter le resultat à la pile des valeurs libres
dernierCalcul = operateur.calcul.apply(nb1, nb2);
valeursLibres.add(dernierCalcul);
// on ajoute aux étapes la chaine " nb1 (+,-,* ou /) nb2 = dernierCalcul;"
etapes.append(space).append(nb1).append(space).append(operateur).append(space);
etapes.append(nb2).append(equal).append(dernierCalcul).append(coma);
// si valeur intéressante, la mémoriser
int ecart = Math.abs(dernierCalcul - but);
if (ecart < bestEcart)
{
bestEcart = ecart;
bestSolution = dernierCalcul;
}
nbValLibres--;
}
return bestSolution;
}
/**
* choix au hasard d'un operateur applicable sur nb1 et nb2
*
* @param nb1
* premier argument de l'operation
* @param nb2
* second argument de l'operation
* @return operateur dans (+, -, *, /)
*/
OperateurFunc choixOperateurApplicable(int nb1, int nb2)
{
int i = hasard.nextInt(4);
boolean ok = false;
do
{
i = (i + 1) % 4;
ok = operateurs.get(i).test.apply(nb1, nb2);
} while (!ok);
return operateurs.get(i);
}
/**
* fonction statique qui lance la recherche d'une solution
* jusqu'a ce que la solution exacte soit trouvee
* ou que le nombre de tests max a été atteint
*
* @param nombres
* nombres à utiliser pour le calcul
* @param but
* solution à trouver
* @param nbCalculsMax
* nb max de tests de solution autorisé
* @return l'enchainement des etapes menant à la solution ou à la valeur la
* plus proche trouvée, séparées par des ';' le dernier élément de la
* chaine est la valeur trouvée
*/
public static String testDesSols(Integer[] nombres, int but, int nbCalculsMax)
{
int nbCalculs = 0;
Solution sol = new Solution(nombres, but);
int solutionTrouvee = 0;
String bestSol = null;
int meilleurEcart = Integer.MAX_VALUE;
while (solutionTrouvee != but && nbCalculs < nbCalculsMax && !Thread.currentThread().isInterrupted())
{
solutionTrouvee = sol.calcule();
int ecart = Math.abs(solutionTrouvee - but);
if (ecart < meilleurEcart)
{
meilleurEcart = ecart;
sol.etapes.append(solutionTrouvee);
bestSol = sol.etapes.toString();
}
nbCalculs++;
sol.reinit();
Thread.yield();
}
if (Thread.currentThread().isInterrupted()) bestSol = null;
return bestSol;
}
/** fonction principale, lance la resolution */
public static void main(String[] args)
{
int but = 495;
Integer[] tab = new Integer[] { 75, 8, 4, 8, 1, 7 };
System.out.print("trouver " + but + ", avec : ");
for (int v : tab)
System.out.print(v + " ; ");
System.out.println();
System.out.println("tente de trouver 5 solutions : ");
System.out.println("---------------------------------");
long debut = System.currentTimeMillis();
ThreadGroup groupe = new ThreadGroup("calcul");
for (int i = 0; i < 5; i++)
{
new Thread(groupe, () -> {
String strSol = testDesSols(tab, but, 5000);
if (strSol != null)
{
int pos = strSol.lastIndexOf(";");
String res = strSol.substring(pos + 1);
System.out.println("resultat = " + res + " : " + strSol.substring(0, pos - 1));
System.out.println("---------------------------------");
}
}).start();
}
while (groupe.activeCount() == 5)
Thread.yield();
groupe.interrupt();
long fin = System.currentTimeMillis();
double duree = (fin - debut) / 1000d;
System.out.println("duree pour la 1ere solution = " + duree + " ms");
}
}