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