Skip to content

Commit 80f7aa1

Browse files
Añadir ejercicios resueltos de POO
1 parent 58580f0 commit 80f7aa1

31 files changed

+920
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Configuraciones y constantes globales
2+
COLOR_FONDO = (0, 0, 0)
3+
COLORES = [
4+
(255, 0, 0),
5+
(0, 255, 0),
6+
(0, 0, 255),
7+
(255, 255, 0),
8+
(255, 0, 255),
9+
(0, 255, 255),
10+
(255, 128, 0),
11+
(128, 0, 255),
12+
(0, 128, 255),
13+
(128, 255, 0),
14+
]
15+
ANCHO = 800
16+
ALTO = 600
17+
FPS = 60
18+
G = 0.1
19+
MAX_PARTICULAS_NODO = 4
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import pygame
2+
from pygame.locals import *
3+
4+
5+
class EventHandler:
6+
@staticmethod
7+
def procesar_eventos(particula_manager):
8+
eventos = {
9+
"salir": False,
10+
"reiniciar": False,
11+
"particula_seleccionada": None,
12+
"mostrar_distancias": True,
13+
}
14+
15+
for evento in pygame.event.get():
16+
if evento.type == QUIT:
17+
eventos["salir"] = True
18+
elif evento.type == MOUSEBUTTONDOWN:
19+
x, y = pygame.mouse.get_pos()
20+
for i in range(particula_manager.num_particulas):
21+
dx = x - particula_manager.posiciones[i, 0]
22+
dy = y - particula_manager.posiciones[i, 1]
23+
if dx**2 + dy**2 <= particula_manager.radios[i] ** 2:
24+
eventos["particula_seleccionada"] = i
25+
break
26+
else:
27+
eventos["particula_seleccionada"] = None
28+
elif evento.type == KEYDOWN:
29+
if evento.key == K_SPACE:
30+
eventos["mostrar_distancias"] = not eventos["mostrar_distancias"]
31+
elif evento.key == K_r:
32+
eventos["reiniciar"] = True
33+
elif evento.key == K_ESCAPE:
34+
eventos["particula_seleccionada"] = None
35+
return eventos
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import numpy as np
2+
from quadtree_node import QuadtreeNode
3+
from constants import G, MAX_PARTICULAS_NODO, ANCHO, ALTO
4+
5+
6+
# Clase que gestiona la física y el comportamiento de las partículas en la simulación
7+
class ParticulaManager:
8+
# Constructor: inicializa el sistema con un número específico de partículas
9+
def __init__(self, num_particulas):
10+
self.num_particulas = num_particulas
11+
self.min_distancia = float("inf")
12+
self.par_mas_cercano = (
13+
None,
14+
None,
15+
) # Almacena los índices de las partículas más cercanas
16+
self.inicializar_particulas()
17+
18+
# Método para crear y configurar las partículas iniciales
19+
def inicializar_particulas(self):
20+
# Genera posiciones aleatorias dentro de los límites de la pantalla
21+
self.posiciones = np.random.rand(self.num_particulas, 2)
22+
self.posiciones[:, 0] *= ANCHO
23+
self.posiciones[:, 1] *= ALTO
24+
# Genera velocidades aleatorias con componentes entre -2 y 2
25+
self.velocidades = (np.random.rand(self.num_particulas, 2) - 0.5) * 4
26+
# Genera masas aleatorias entre 5 y 15
27+
self.masas = np.random.rand(self.num_particulas) * 10 + 5
28+
# El radio de cada partícula es proporcional a su masa
29+
self.radios = self.masas / 2
30+
31+
# Método para construir el árbol cuaternario (quadtree) para optimización espacial
32+
def construir_quadtree(self):
33+
root = QuadtreeNode(0, 0, ANCHO, ALTO, max_particulas=MAX_PARTICULAS_NODO)
34+
for i in range(self.num_particulas):
35+
part = {"id": i, "pos": tuple(self.posiciones[i])}
36+
root.insertar(part)
37+
return root
38+
39+
# Método principal que actualiza la física del sistema
40+
def actualizar_fisica(self):
41+
n = self.num_particulas
42+
# Array para almacenar las aceleraciones de cada partícula
43+
aceleraciones = np.zeros((n, 2))
44+
self.min_distancia = float("inf")
45+
self.par_mas_cercano = (None, None)
46+
47+
# Cálculo de fuerzas gravitacionales entre todas las partículas
48+
for i in range(n):
49+
for j in range(i + 1, n):
50+
# Calcula la distancia entre partículas
51+
dx = self.posiciones[j, 0] - self.posiciones[i, 0]
52+
dy = self.posiciones[j, 1] - self.posiciones[i, 1]
53+
dist = np.sqrt(dx**2 + dy**2)
54+
55+
# Actualiza el par más cercano si corresponde
56+
if dist < self.min_distancia:
57+
self.min_distancia = dist
58+
self.par_mas_cercano = (i, j)
59+
60+
# Previene superposición excesiva estableciendo una distancia mínima
61+
dist = max(dist, 2 * max(self.radios[i], self.radios[j]))
62+
# Calcula la fuerza gravitacional
63+
fuerza = G * self.masas[i] * self.masas[j] / (dist**2)
64+
# Actualiza las aceleraciones según la ley de Newton
65+
aceleraciones[i] += fuerza * np.array([dx, dy]) / (dist * self.masas[i])
66+
aceleraciones[j] -= fuerza * np.array([dx, dy]) / (dist * self.masas[j])
67+
68+
# Actualiza velocidades y posiciones usando las aceleraciones calculadas
69+
self.velocidades += aceleraciones
70+
self.posiciones += self.velocidades
71+
72+
# Manejo de colisiones con los bordes de la pantalla
73+
for i in range(n):
74+
for dim in range(2):
75+
limite = ANCHO if dim == 0 else ALTO
76+
# Rebote en los bordes con pérdida de energía (factor 0.9)
77+
if (
78+
self.posiciones[i, dim] < self.radios[i]
79+
or self.posiciones[i, dim] > limite - self.radios[i]
80+
):
81+
self.velocidades[i, dim] *= -0.9
82+
# Asegura que las partículas permanezcan dentro de los límites
83+
self.posiciones[i] = np.clip(
84+
self.posiciones[i],
85+
self.radios[i],
86+
[ANCHO - self.radios[i], ALTO - self.radios[i]],
87+
)
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import numpy as np
2+
3+
4+
class QuadtreeNode:
5+
def __init__(self, x_min, y_min, x_max, y_max, profundidad=0, max_particulas=4):
6+
self.limite = (x_min, y_min, x_max, y_max)
7+
self.profundidad = profundidad
8+
self.max_particulas = max_particulas
9+
self.particulas = []
10+
self.hijos = []
11+
12+
def insertar(self, particula):
13+
if self.hijos:
14+
for hijo in self.hijos:
15+
if hijo.contiene(particula):
16+
hijo.insertar(particula)
17+
return
18+
else:
19+
self.particulas.append(particula)
20+
if len(self.particulas) > self.max_particulas:
21+
self.subdividir()
22+
for p in self.particulas:
23+
for hijo in self.hijos:
24+
if hijo.contiene(p):
25+
hijo.insertar(p)
26+
break
27+
self.particulas = []
28+
29+
def contiene(self, particula):
30+
x, y = particula["pos"]
31+
x_min, y_min, x_max, y_max = self.limite
32+
return x_min <= x < x_max and y_min <= y < y_max
33+
34+
def subdividir(self):
35+
x_min, y_min, x_max, y_max = self.limite
36+
mx = (x_min + x_max) / 2
37+
my = (y_min + y_max) / 2
38+
self.hijos = [
39+
QuadtreeNode(
40+
x_min, y_min, mx, my, self.profundidad + 1, self.max_particulas
41+
),
42+
QuadtreeNode(
43+
mx, y_min, x_max, my, self.profundidad + 1, self.max_particulas
44+
),
45+
QuadtreeNode(
46+
x_min, my, mx, y_max, self.profundidad + 1, self.max_particulas
47+
),
48+
QuadtreeNode(
49+
mx, my, x_max, y_max, self.profundidad + 1, self.max_particulas
50+
),
51+
]
52+
53+
def buscar_vecinos(self, particula, distancia_minima=float("inf")):
54+
x, y = particula["pos"]
55+
vecino = None
56+
if self.hijos:
57+
for hijo in self.hijos:
58+
if hijo.contiene(particula):
59+
vecino, distancia_minima = hijo.buscar_vecinos(
60+
particula, distancia_minima
61+
)
62+
else:
63+
distancia_al_cuadrante = hijo.distancia_a_cuadrante(x, y)
64+
if distancia_al_cuadrante < distancia_minima:
65+
v, d = hijo.buscar_vecinos(particula, distancia_minima)
66+
if d < distancia_minima:
67+
vecino, distancia_minima = v, d
68+
else:
69+
for p in self.particulas:
70+
if p["id"] != particula["id"]:
71+
dx = p["pos"][0] - x
72+
dy = p["pos"][1] - y
73+
dist = (dx**2 + dy**2) ** 0.5
74+
if dist < distancia_minima:
75+
vecino, distancia_minima = p, dist
76+
return vecino, distancia_minima
77+
78+
def distancia_a_cuadrante(self, x, y):
79+
x_min, y_min, x_max, y_max = self.limite
80+
dx = max(x_min - x, 0, x - x_max)
81+
dy = max(y_min - y, 0, y - y_max)
82+
return (dx**2 + dy**2) ** 0.5

0 commit comments

Comments
 (0)