Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
.
[graphlib.git] / chateaux / chateaux.cpp
1 #include <QApplication>
2 #include <DrawingWindow.h>
3 #include <cmath>
4 #include <iostream>
5 #include <ctime>
6 #include <cstdlib>
7 #include <sstream>
8
9 /* Note : les coordonnées réelles vont de -100 à +100 en abscisse, et
10  *  de -10 à +140 en ordonnée
11  */
12
13 const float PI = 4.0 * atan(1.0);
14
15 const float rXMin = -100.0;
16 const float rXMax = 100.0;
17 const float rYMin = -10.0;
18 const float rYMax = 140.0;
19
20 const float hauteurMin = 10;
21 const float hauteurMax = 130;
22 const float largeurMin = 40;
23 const float largeurMax = 150;
24
25 const float largeurChateau = 8.5;
26 const float hauteurChateau = 7;
27
28 const float positionChateau1 = -85.0;
29 const float positionChateau2 = 85.0;
30
31 const float g = 9.81;
32 const float k = 0.005;
33 const float dt = 0.05;
34
35 int nbJoueurs = 2;
36 int score1 = 0;
37 int score2 = 0;
38
39 float largeurMont;
40 float hauteurMont;
41 float wnd;
42
43 /* Retourne un nombre pseudo-aléatoire compris entre 0 et le paramètre
44  * 'max' (exclus)
45  */
46 float frand(float min, float max)
47 {
48     static bool first = true;
49     if (first) {
50         srand(time(NULL));
51         first = false;
52     }
53     return min + (max - min)* (rand() / (RAND_MAX + 1.0));
54 }
55
56 float deg2rad(float deg)
57 {
58     return deg * PI / 180.0;
59 }
60
61 // conversion coordonnées réelles -> coordonnées fenêtre
62 int rtowX(const DrawingWindow& w, float rx)
63 {
64     return (int )roundf(w.width * (rx - rXMin) / (rXMax - rXMin + 1.0));
65 }
66
67 int rtowY(const DrawingWindow& w, float ry)
68 {
69     return (int )roundf(w.height * (rYMax - ry) / (rYMax - rYMin + 1.0));
70 }
71
72 // conversion coordonnées réelles -> coordonnées fenêtre
73 float wtorX(const DrawingWindow& w, int wx)
74 {
75     return (rXMax - rXMin + 1.0) * wx / w.width + rXMin;
76 }
77
78 float wtorY(const DrawingWindow& w, int wy)
79 {
80     return -(rYMax - rYMin + 1.0) * wy / w.height - rYMax;
81 }
82
83 float hauteurMontagne(float largeur, float hauteur, float x)
84 {
85     float rx = 2.0 * x / largeur;
86     return hauteur * (1.0 - rx * rx);
87 }
88
89 void dessineTerrain(DrawingWindow& w, float largeur, float hauteur)
90 {
91     int y0 = rtowY(w, 0) + 1;
92     int xmin = rtowX(w, -largeur / 2.0) - 1;
93     int xmax = rtowX(w, largeur / 2.0) + 1;
94     w.setColor("forestgreen");
95     for (int x = xmin; x <= xmax; x++) {
96         float rx = wtorX(w, x);
97         float ry = hauteurMontagne(largeur, hauteur, rx);
98         int y = rtowY(w, ry);
99         if (y <= y0)
100             w.drawLine(x, y0, x, y);
101     }
102     w.setColor("maroon");
103     w.fillRect(0, y0 + 1, w.width - 1, w.height - 1);
104 }
105
106 void dessineChateau(DrawingWindow& w, float position)
107 {
108     w.setColor("black");
109     w.setColor("darkslategray");
110     int y1 = rtowY(w, 0);
111     int h0 = rtowY(w, 3);
112     int h1 = rtowY(w, 4);
113     for (int i = 0; i < 7; i++) {
114         int h = i % 2 ? h0 : h1;
115         int x1 = rtowX(w, position + i - 3.5);
116         int x2 = rtowX(w, position + i - 2.5) - 1;
117         w.fillRect(x1, y1, x2, h);
118     }
119     w.setColor("dimgray");
120     h0 = rtowY(w, 6);
121     h1 = rtowY(w, 7);
122     for (int i = 0; i < 5; i++) {
123         int h = i % 2 ? h0 : h1;
124         int x1 = rtowX(w, position + i - 8.5);
125         int x2 = rtowX(w, position + i - 7.5) - 1;
126         w.fillRect(x1, y1, x2, h);
127         x1 = rtowX(w, position + i + 3.5);
128         x2 = rtowX(w, position + i + 4.5) - 1;
129         w.fillRect(x1, y1, x2, h);
130     }
131 }
132
133 void dessineVent(DrawingWindow &w, float vitesse)
134 {
135     int lg = rtowX(w, vitesse) - rtowX(w, 0);
136     int dir = lg > 0 ? 1 : -1;
137     int y = 20;
138     w.setColor("black");
139     if (lg == 0) {
140         w.drawCircle(w.width / 2, y, 4);
141     } else {
142         int x1 = (w.width - lg) / 2;
143         int x2 = (w.width + lg) / 2;
144         w.drawLine(x1 - dir, y - 1, x2 - dir, y - 1);
145         w.drawLine(x1, y, x2, y);
146         w.drawLine(x1 - dir, y + 1, x2 - dir, y + 1);
147         for (int i = 0; i < 3; i++) {
148             w.drawLine(x2 - i * dir, y, x2 - (6 + i) * dir, y - 4);
149             w.drawLine(x2 - i * dir, y, x2 - (6 + i) * dir, y + 4);
150         }
151     }
152 }
153
154 void dessineExplosion(DrawingWindow& w, float rx, float ry)
155 {
156     const int maxray = rtowX(w, 2.5) - rtowX(w, 0);
157     // 1/2 rouge -> rouge -> jaune
158     const int x = rtowX(w, rx);
159     const int y = rtowY(w, ry);
160     int i;
161     for (i = 0; i <= maxray / 3; i++) {
162         w.setColor(0.5 + 3.0 * i / (2.0 * maxray), 0.0, 0.0);
163         w.drawCircle(x, y, i);
164         w.msleep(20);
165     }
166     for (/* i */; i < maxray; i++) {
167         w.setColor(1.0, 1.5 * i / maxray - 0.5, 0.0);
168         w.drawCircle(x, y, i);
169         w.msleep(20);
170     }
171     w.setColor("skyblue");
172     for (i = 0; i < maxray; i++) {
173         w.drawCircle(x, y, i);
174         w.msleep(10);
175     }
176     w.fillCircle(x, y, maxray - 1);
177 }
178
179 void dessineFlammes(DrawingWindow& w, float x0, float y0)
180 {
181     for (int i = 0; i < 70; i++) {
182         float dt = 0.05;
183         float vx = frand(-2.5, 2.5);
184         float vy = frand(5, 17);
185         float x = x0;
186         float y = y0;
187         float red = frand(0.5, 1);
188         float green = frand(0, red);
189         float blue = 0;
190         w.setColor(red, green, blue);
191         while (y >= 0.0) {
192             w.drawPoint(rtowX(w, x), rtowY(w, y));
193             x += vx * dt;
194             y += vy * dt;
195             vy -= 9.81 * dt;
196         }
197         w.msleep(30);
198     }
199 }
200
201 void initialise(DrawingWindow& w)
202 {
203     largeurMont = frand(largeurMin, largeurMax);
204     hauteurMont = frand(hauteurMin, hauteurMax);
205     wnd = frand(-30, 30);
206     w.setBgColor("skyblue");
207     w.clearGraph();
208     dessineTerrain(w, largeurMont, hauteurMont);
209     dessineVent(w, wnd);
210     dessineChateau(w, positionChateau1);
211     dessineChateau(w, positionChateau2);
212     w.setColor("wheat");
213     w.drawText(rtowX(w, positionChateau1), rtowY(w, 0) + 8, "Joueur 1",
214                Qt::AlignHCenter);
215     w.drawText(rtowX(w, positionChateau2), rtowY(w, 0) + 8, "Joueur 2",
216                Qt::AlignHCenter);
217     std::stringstream s;
218     s << score1 << " / " << score2;
219     w.drawText(rtowX(w, 0), rtowY(w, 0) + 8, s.str().c_str(),
220                Qt::AlignHCenter);
221 }
222
223 /* Retour : numéro du perdant, 0 sinon
224    x et y contiennent les coordonnées de la collision
225 */
226 int tir(DrawingWindow& w,
227         float x0, float y0, float v0, float alpha, float& x, float &y)
228 {
229     float vx = v0 * cos(alpha);
230     float vy = v0 * sin(alpha);
231     x = x0;
232     y = y0;
233     int collision = 0;
234     do {
235         int wx = rtowX(w, x);
236         int wy = rtowY(w, y);
237         w.setColor("black");
238         w.fillCircle(wx, wy, 2);
239
240         float vxr = vx - wnd;
241         float kvr = -k * sqrt(vxr * vxr + vy * vy);
242         float ax = kvr * vxr;
243         float ay = kvr * vy - g;
244         x += vx * dt;
245         y += vy * dt;
246         vx += ax * dt;
247         vy += ay * dt;
248
249         w.msleep(10);
250         w.setColor("skyblue");
251         w.fillCircle(wx, wy, 2);
252 //         w.setColor("black");
253 //         w.drawPoint(wx, wy);
254
255         if (y <= 0) {
256             collision = 3;
257         } else if (y < hauteurChateau) {
258             if (positionChateau1 - largeurChateau <= x
259                 && positionChateau1 + largeurChateau >= x)
260                 collision = 1;
261             else if (positionChateau2 - largeurChateau <= x
262                        && positionChateau2 + largeurChateau >= x)
263                 collision = 2;
264         }
265         if (!collision) {
266             float h = hauteurMontagne(largeurMont, hauteurMont, x);
267             if (h > 0 && y < h)
268                 collision = 3;
269         }
270     } while (!collision);
271     return collision == 3 ? 0 : collision;
272 }
273
274 int jeu1(DrawingWindow& w)
275 {
276     initialise(w);
277     int joueur = 2;
278     float x, y;
279     int perdant;
280     do {
281         joueur = 3 - joueur;
282
283         std::cout << "-=| Joueur " << joueur << " |=-";
284
285         float alpha;
286         float v0;
287         if (joueur <= nbJoueurs) {
288             std::cout << "\nangle ? ";
289             std::cin >> alpha;
290             std::cout << "vitesse initiale ? ";
291             std::cin >> v0;
292         } else {
293             alpha = frand(10, 90);
294             v0 = frand(10, 100);
295             std::cout << " [ " << (int )alpha << "° ; " << (int )v0 << " ]\n";
296         }
297
298         alpha = deg2rad(alpha);
299         float x0;
300         if (joueur == 1) {
301             x0 = positionChateau1 + 0.8 * largeurChateau;
302         } else {
303             x0 = positionChateau2 - 0.8 * largeurChateau;
304             alpha = PI - alpha;
305         }
306         float y0 = hauteurChateau + 1;
307         perdant = tir(w, x0, y0, v0, alpha, x, y);
308         dessineExplosion(w, x, y);
309         dessineVent(w, wnd);
310     } while (!perdant);
311     dessineFlammes(w, x, y);
312     std::stringstream msg;
313     msg << "Joueur " << perdant;
314     if (perdant == joueur)
315         msg << " s'est suicidé !";
316     else
317         msg << " a perdu !";
318     w.setColor("darkred");
319     w.setBgColor("white");
320     w.drawTextBg(w.width / 2, w.height / 3, msg.str().c_str(),
321                  Qt::AlignCenter);
322     std::cout << msg.str() << "\n";
323     return perdant;
324 }
325
326 void jeu(DrawingWindow& w)
327 {
328     bool rejouer = true;
329     do {
330         int perdant = jeu1(w);
331         if (perdant == 1)
332             score2++;
333         else if (perdant == 2)
334             score1++;
335         std::cout << "### SCORE : " << score1 << " / " << score2 << " ###\n";
336         if (nbJoueurs == 0)
337             w.sleep(2);
338         else {
339             char r;
340             do {
341                 std::cout << "Recommencer (o/n) ? ";
342                 std::cin >> r;
343             } while (std::cin.good() && r != 'o' && r != 'n');
344             rejouer = r == 'o';
345         }
346     } while (rejouer);
347     w.closeGraph();
348 }
349
350 int main(int argc, char *argv[])
351 {
352     QApplication application(argc, argv);
353
354     if (argc > 1)
355         nbJoueurs = atoi(argv[1]);
356
357     DrawingWindow window(jeu, 640, 480);
358     window.show();
359     return application.exec();
360 }