Logo AND Algorithmique Numérique Distribuée

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