Skip to content

Commit 18f6eaf

Browse files
mouredev#42 - javascript
1 parent c29f4fc commit 18f6eaf

File tree

1 file changed

+311
-0
lines changed

1 file changed

+311
-0
lines changed

Roadmap/duendeintemporal.js

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
//42 - TORNEO DRAGON BALL
2+
/*
3+
* EJERCICIO:
4+
* ¡El último videojuego de Dragon Ball ya está aquí!
5+
* Se llama Dragon Ball: Sparking! ZERO.
6+
*
7+
* Simula un Torneo de Artes Marciales, al más puro estilo
8+
* de la saga, donde participarán diferentes luchadores, y el
9+
* sistema decidirá quién es el ganador.
10+
*
11+
* Luchadores:
12+
* - Nombre.
13+
* - Tres atributos: velocidad, ataque y defensa
14+
* (con valores entre 0 a 100 que tú decidirás).
15+
* - Comienza cada batalla con 100 de salud.
16+
* Batalla:
17+
* - En cada batalla se enfrentan 2 luchadores.
18+
* - El luchador con más velocidad comienza atacando.
19+
* - El daño se calcula restando el daño de ataque del
20+
* atacante menos la defensa del oponente.
21+
* - El oponente siempre tiene un 20% de posibilidad de
22+
* esquivar el ataque.
23+
* - Si la defensa es mayor que el ataque, recibe un 10%
24+
* del daño de ataque.
25+
* - Después de cada turno y ataque, el oponente pierde salud.
26+
* - La batalla finaliza cuando un luchador pierde toda su salud.
27+
* Torneo:
28+
* - Un torneo sólo es válido con un número de luchadores
29+
* potencia de 2.
30+
* - El torneo debe crear parejas al azar en cada ronda.
31+
* - Los luchadores se enfrentan en rondas eliminatorias.
32+
* - El ganador avanza a la siguiente ronda hasta que sólo
33+
* quede uno.
34+
* - Debes mostrar por consola todo lo que sucede en el torneo,
35+
* así como el ganador.
36+
*/
37+
38+
//We use https://sigmawire.net/image-to-url-converter service to include image in our javascript code
39+
40+
class Fighter {
41+
constructor(id, name, speed, attack, defense) {
42+
this.id = id;
43+
this.name = name;
44+
this.speed = speed;
45+
this.attack = attack;
46+
this.defense = defense;
47+
this.health = 100; // Each fighter starts with 100 health
48+
}
49+
50+
calculateDamage(opponent) {
51+
let damage = Math.max(this.attack - opponent.defense, 0); // No negative damage
52+
53+
// Check if the opponent dodges the attack
54+
if (Math.random() < 0.2) { // 20% chance to dodge
55+
return 0; // No damage dealt
56+
}
57+
58+
// If the opponent's defense is greater than the attack, reduce damage
59+
if (opponent.defense > this.attack) {
60+
damage *= 0.1; // 10% of the attack damage
61+
}
62+
63+
return Math.floor(damage); // Return the damage as an integer
64+
}
65+
}
66+
67+
68+
class Battle {
69+
constructor(fighter1, fighter2) {
70+
this.fighter1 = fighter1;
71+
this.fighter2 = fighter2;
72+
this.attacker = fighter1.speed >= fighter2.speed ? fighter1 : fighter2;
73+
this.defender = this.attacker === fighter1 ? fighter2 : fighter1;
74+
}
75+
winner(winFighter) {
76+
let fighter = winFighter;
77+
let element = document.querySelectorAll('.contrincant')[fighter.id - 1];
78+
79+
if (element.classList.contains('loser')) {
80+
element.classList.remove('loser');
81+
}
82+
83+
element.classList.add('winner');
84+
}
85+
86+
87+
loser(losFighter) {
88+
let fighter = losFighter;
89+
let element = document.querySelectorAll('.contrincant')[fighter.id - 1];
90+
91+
if (element.classList.contains('winner')) {
92+
element.classList.remove('winner');
93+
}
94+
95+
element.classList.add('loser');
96+
}
97+
98+
async start() {
99+
while (this.fighter1.health > 0 && this.fighter2.health > 0) {
100+
const damage = this.attacker.calculateDamage(this.defender);
101+
102+
// Ensure a minimum level of damage
103+
const minDamage = 10;
104+
const actualDamage = Math.max(minDamage, damage);
105+
106+
this.defender.health -= actualDamage;
107+
108+
// Log the attack and damage
109+
if (actualDamage === minDamage) {
110+
logMessage(`${this.attacker.name}'s attack was partially blocked by ${this.defender.name}, dealing ${actualDamage} damage.`);
111+
} else {
112+
logMessage(`${this.attacker.name} attacks ${this.defender.name} for ${actualDamage} damage.`);
113+
}
114+
logMessage(`${this.defender.name} has ${this.defender.health} health left.`);
115+
116+
// Swap roles for the next turn
117+
[this.attacker, this.defender] = [this.defender, this.attacker];
118+
119+
// Introduce a delay between attacks
120+
await new Promise(resolve => setTimeout(resolve, 500));
121+
}
122+
123+
const winner = this.fighter1.health > 0 ? this.fighter1 : this.fighter2;
124+
logMessage(`${winner.name} wins the battle!`);
125+
const winningFighter = this.fighter1.health > 0 ? this.fighter1 : this.fighter2;
126+
const losingFighter = winningFighter === this.fighter1 ? this.fighter2 : this.fighter1;
127+
128+
// Add Winner and Loser class to fighter containers respectibily
129+
this.winner(winningFighter);
130+
this.loser(losingFighter);
131+
132+
return winner;
133+
}
134+
}
135+
136+
class Tournament {
137+
constructor(fighters) {
138+
if (!this.isPowerOfTwo(fighters.length)) {
139+
throw new Error("Number of fighters must be a power of 2.");
140+
}
141+
this.fighters = fighters;
142+
}
143+
144+
isPowerOfTwo(n) {
145+
return (n & (n - 1)) === 0 && n > 0; // Check if n is a power of two
146+
}
147+
148+
async start() {
149+
logMessage("Starting the tournament...");
150+
let round = 1;
151+
152+
while (this.fighters.length > 1) {
153+
logMessage(`\n--- Round ${round} ---`);
154+
155+
const winners = [];
156+
for (let i = 0; i < this.fighters.length; i += 2) {
157+
const battle = new Battle(this.fighters[i], this.fighters[i + 1]);
158+
const winner = await battle.start();
159+
winners.push(winner);
160+
}
161+
162+
logMessage("\nWinners of Round " + round + ":");
163+
winners.forEach(fighter => {
164+
logMessage("- " + fighter.name);
165+
});
166+
167+
this.fighters = winners; // Update fighters for the next round
168+
round++;
169+
}
170+
171+
logMessage(`\nThe champion of the tournament is ${this.fighters[0].name}!`);
172+
}
173+
}
174+
175+
176+
const fighters = [
177+
new Fighter(1, 'Goku', 95, 80, 50),
178+
new Fighter(2, 'Vegeta', 90, 85, 45),
179+
new Fighter(3, 'Gohan', 85, 75, 55),
180+
new Fighter(4, 'Piccolo', 80, 70, 60),
181+
new Fighter(5, 'Frieza', 88, 90, 40),
182+
new Fighter(6, 'Cell', 85, 80, 50),
183+
new Fighter(7, 'Majin Buu', 70, 60, 70),
184+
new Fighter(8, 'Trunks', 75, 65, 65)
185+
];
186+
187+
// DOM Manipulation
188+
const styles = `
189+
body {
190+
background: #000;
191+
display: flex;
192+
justify-content: center;
193+
align-items: center;
194+
transition: background .5s ease;
195+
margin: 0;
196+
padding: 0;
197+
}
198+
199+
.winner{
200+
display: flex;
201+
justify-content: center;
202+
align-items: center;
203+
opacity: 1;
204+
transform: scale(1.1);
205+
font-weight: 600;
206+
}
207+
.winner::before{
208+
content: 'WINNER';
209+
color: rgba(0,255,0,0.4);
210+
}
211+
212+
.loser{
213+
display: flex;
214+
justify-content: center;
215+
align-items: center;
216+
opacity: 0.5;
217+
font-weight: 600;
218+
}
219+
220+
.loser::after{
221+
content: 'LOSER';
222+
color: rgba(255,0,0,0.7);
223+
}
224+
225+
.contrincants_wrapper {
226+
margin-top: 20px;
227+
display: flex;
228+
justify-content: center;
229+
align-items: center;
230+
flex-flow: row wrap;
231+
width: 95vw;
232+
gap: 10px;
233+
}
234+
235+
.contrincant {
236+
width: 200px;
237+
height: 200px;
238+
border: 1px solid #fff outset;
239+
object-fit: cover;
240+
object-position: center center;
241+
flex: 0 0 70px;
242+
background-size: cover;
243+
background-position: center;
244+
}
245+
246+
.log_container {
247+
background: rgba(0, 0, 0, 0.7);
248+
padding: 10px;
249+
border-radius: 5px;
250+
max-height: 200px;
251+
overflow-y: auto;
252+
z-index: 1;
253+
border: 1px solid #fff;
254+
color: #fff;
255+
margin-top: 20px;
256+
width: 100%;
257+
text-align: center;
258+
}
259+
`;
260+
261+
// Create a <style> element and append the styles
262+
let styleSheet = document.createElement("style");
263+
styleSheet.type = "text/css";
264+
styleSheet.innerText = styles;
265+
document.head.appendChild(styleSheet);
266+
267+
// Create the combatants' wrapper
268+
let div_wrapper = document.createElement('div');
269+
div_wrapper.classList.add('contrincants_wrapper');
270+
271+
// Create a DocumentFragment to batch updates
272+
let fragment = document.createDocumentFragment();
273+
274+
// Create and append combatants to the fragment
275+
for (let i = 0; i < fighters.length; i++) {
276+
let div = document.createElement('div');
277+
div.classList.add('contrincant');
278+
div.style.backgroundImage = `url(https://i.imgur.com/${['vDUO50X', 'fDitnqa', 'XHhWd32', 'yea6HcH', 'BTaQ8g4', 'LACYE3s', 'QIUnWuQ', 'SHXxvjC'][i]}.jpeg)`;
279+
fragment.appendChild(div);
280+
}
281+
282+
// Append the fragment to the wrapper
283+
div_wrapper.appendChild(fragment);
284+
285+
// Create the log container
286+
let logContainer = document.createElement('div');
287+
logContainer.classList.add('log_container');
288+
div_wrapper.appendChild(logContainer);
289+
290+
// Append the wrapper to the body
291+
document.body.appendChild(div_wrapper);
292+
293+
// Function to log messages to the log container
294+
function logMessage(message) {
295+
const logEntry = document.createElement('div');
296+
logEntry.textContent = message;
297+
logContainer.appendChild(logEntry);
298+
logContainer.scrollTop = logContainer.scrollHeight; // Auto-scroll to the bottom
299+
}
300+
301+
// Override console.log to also log to the log container
302+
console.log = (function(originalLog) {
303+
return function(...args) {
304+
originalLog.apply(console, args); // Call the original console.log
305+
logMessage(args.join(' ')); // Log to the log container
306+
};
307+
})(console.log);
308+
309+
// Start the tournament
310+
const tournament = new Tournament(fighters);
311+
tournament.start();

0 commit comments

Comments
 (0)