Lukeetah commited on
Commit
37001fe
·
verified ·
1 Parent(s): 97de684

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +720 -474
app.py CHANGED
@@ -1,479 +1,438 @@
1
- # main_game.py - CRISIS Y CORAJE: EL JUEGO ARGENTINO DEFINITIVO
2
  import gradio as gr
3
  import time
4
  import math
5
  import random
 
6
  from PIL import Image, ImageDraw
7
- from typing import Dict, List, Tuple
 
8
 
9
- class ArgentinaGameEngine:
 
10
  def __init__(self):
11
- # Core del juego
12
- self.width, self.height = 900, 600
13
- self.player = ArgentineCharacter()
14
- self.world = ArgentineWorld()
15
-
16
- # Sistema de supervivencia argentino
17
- self.resources = {
18
- 'pesos': 1000,
19
- 'dolares': 50,
20
- 'comida': 80,
21
- 'esperanza': 100,
22
- 'solidaridad': 90,
23
- 'trabajo': 70
24
- }
25
-
26
- # Mecánicas únicas argentinas
27
- self.inflation_rate = 1.0
28
- self.social_network = []
29
- self.cultural_events = []
30
- self.crisis_level = 1
31
-
32
- # Estados del juego dinámicos
33
- self.day = 1
34
- self.season = "verano"
35
- self.current_crisis = "corralito_2001"
36
- self.neighborhood_mood = "esperanzado"
37
-
38
- self.initialize_argentina()
39
 
40
- def initialize_argentina(self):
41
- """Inicializa el mundo argentino auténtico"""
42
- self.create_neighborhoods()
43
- self.spawn_cultural_events()
44
- self.setup_crisis_timeline()
45
-
46
- class ArgentineCharacter:
47
- def __init__(self):
48
- self.name = "Carlos"
49
- self.profession = random.choice(["albañil", "docente", "comerciante", "empleado_publico"])
50
- self.position = [450, 300] # Centro de CABA
51
- self.family = {
52
- 'spouse': True,
53
- 'children': random.randint(1, 3),
54
- 'elderly_parents': random.choice([True, False])
55
- }
56
-
57
- # Skills argentinos únicos
58
- self.skills = {
59
- 'rebusque': 70,
60
- 'mate_sharing': 90,
61
- 'asado_expertise': 80,
62
- 'crisis_survival': 60,
63
- 'soccer_knowledge': 95,
64
- 'political_debate': 75
65
- }
66
-
67
- self.current_strategy = "supervivencia_diaria"
68
- self.stress_level = 30
69
- self.community_reputation = 50
70
-
71
- class CrisisManager:
72
- """Sistema que simula las crisis argentinas reales"""
73
- def __init__(self):
74
- self.crisis_timeline = {
75
- 2001: {
76
- 'name': 'Corralito',
77
- 'effects': {'peso_devaluation': 300, 'unemployment': 25, 'social_unrest': 80},
78
- 'opportunities': ['trueque', 'economia_popular', 'solidaridad_vecinal']
79
  },
80
- 2008: {
81
- 'name': 'Crisis Mundial',
82
- 'effects': {'export_drop': 40, 'inflation': 25},
83
- 'opportunities': ['mercado_interno', 'cooperativas']
84
  },
85
- 2018: {
86
- 'name': 'Crisis Cambiaria',
87
- 'effects': {'peso_devaluation': 100, 'inflation': 50},
88
- 'opportunities': ['dolarizacion_popular', 'emprendedurismo']
89
  },
90
- 2020: {
91
- 'name': 'Pandemia',
92
- 'effects': {'lockdown': 90, 'unemployment': 15, 'solidarity_boost': 120},
93
- 'opportunities': ['delivery', 'remote_work', 'community_support']
94
  }
95
  }
96
 
97
- def apply_crisis_effects(self, game_state, current_year):
98
- """Aplica efectos realistas de las crisis"""
99
- if current_year in self.crisis_timeline:
100
- crisis = self.crisis_timeline[current_year]
101
- return self.modify_game_state(game_state, crisis)
102
- return game_state
 
 
 
 
 
 
103
 
104
- class NeighborhoodSystem:
105
- """Sistema de barrios argentinos dinámicos"""
106
- def __init__(self):
107
- self.neighborhoods = {
108
- 'villa_31': {
109
- 'solidarity': 95, 'resources': 30, 'creativity': 90,
110
- 'challenges': ['infraestructura', 'estigma_social'],
111
- 'strengths': ['union_vecinal', 'cultura_popular']
112
- },
113
- 'palermo': {
114
- 'solidarity': 60, 'resources': 85, 'creativity': 75,
115
- 'challenges': ['gentrificacion', 'burbuja_social'],
116
- 'strengths': ['startups', 'vida_nocturna']
117
- },
118
- 'san_telmo': {
119
- 'solidarity': 80, 'resources': 70, 'creativity': 95,
120
- 'challenges': ['turismo_masivo'],
121
- 'strengths': ['tango', 'arte', 'historia']
122
- },
123
- 'mataderos': {
124
- 'solidarity': 90, 'resources': 50, 'creativity': 85,
125
- 'challenges': ['infraestructura'],
126
- 'strengths': ['folklore', 'tradicion_gaucha']
127
- }
128
- }
129
 
130
- class GameRenderer:
131
- def __init__(self):
132
- self.current_view = "neighborhood"
133
- self.animation_frame = 0
134
-
135
- def render_argentina_frame(self, game_state) -> Image.Image:
136
- """Renderiza Argentina de manera épica y auténtica"""
137
- img = Image.new('RGB', (900, 600), (20, 30, 60))
138
- draw = ImageDraw.Draw(img)
139
-
140
- # Fondo: Skyline de Buenos Aires
141
- self.draw_buenos_aires_skyline(draw, game_state)
142
-
143
- # Primer plano: Vecindario actual
144
- self.draw_neighborhood(draw, game_state)
145
-
146
- # Personajes: Vecinos interactuando
147
- self.draw_community_life(draw, game_state)
148
-
149
- # UI: Información de supervivencia
150
- self.draw_survival_ui(draw, game_state)
151
-
152
- # Efectos especiales: Crisis o celebraciones
153
- self.draw_dynamic_effects(draw, game_state)
154
-
155
- return img
156
-
157
- def draw_buenos_aires_skyline(self, draw, game_state):
158
- """Dibuja el skyline icónico de Buenos Aires"""
159
- # Río de la Plata
160
- draw.rectangle([0, 400, 900, 600], fill=(30, 60, 120))
161
-
162
- # Puerto Madero
163
- for i in range(5):
164
- building_height = 250 + random.randint(-50, 50)
165
- draw.rectangle([700 + i*30, 600-building_height, 720 + i*30, 600],
166
- fill=(40, 40, 60), outline=(80, 80, 100))
167
-
168
- # Microcentro
169
- for i in range(8):
170
- building_height = 200 + random.randint(-100, 100)
171
- draw.rectangle([200 + i*40, 600-building_height, 230 + i*40, 600],
172
- fill=(60, 60, 80), outline=(100, 100, 120))
173
-
174
- # Obelisco (si estamos en el centro)
175
- if game_state.get('location') == 'microcentro':
176
- draw.polygon([(450, 150), (445, 400), (455, 400)],
177
- fill=(200, 200, 200), outline=(255, 255, 255))
178
-
179
- def draw_neighborhood(self, draw, game_state):
180
- """Dibuja el barrio actual con detalles auténticos"""
181
- neighborhood = game_state.get('current_neighborhood', 'villa_31')
182
-
183
- if neighborhood == 'villa_31':
184
- self.draw_villa_scene(draw, game_state)
185
- elif neighborhood == 'palermo':
186
- self.draw_palermo_scene(draw, game_state)
187
- elif neighborhood == 'san_telmo':
188
- self.draw_san_telmo_scene(draw, game_state)
189
-
190
- def draw_villa_scene(self, draw, game_state):
191
- """Villa 31: Casas coloridas, solidaridad, creatividad"""
192
- # Casas de chapa coloridas
193
- colors = [(255, 100, 100), (100, 255, 100), (100, 100, 255), (255, 255, 100)]
194
- for i in range(6):
195
- x = 50 + i * 120
196
- y = 350 + random.randint(-30, 30)
197
- color = random.choice(colors)
198
 
199
- # Casa principal
200
- draw.rectangle([x, y, x+80, y+80], fill=color, outline=(0, 0, 0), width=2)
 
 
 
 
 
 
 
201
 
202
- # Techo de chapa
203
- draw.polygon([(x-5, y), (x+40, y-20), (x+85, y)],
204
- fill=(150, 150, 150), outline=(100, 100, 100))
205
 
206
- # Antena parabólica
207
- draw.ellipse([x+60, y-30, x+75, y-15], outline=(200, 200, 200), width=2)
208
-
209
- # Cancha de fútbol improvisada
210
- draw.rectangle([300, 450, 600, 550], fill=(100, 150, 50), outline=(255, 255, 255), width=3)
211
-
212
- # Arcos de fútbol
213
- draw.rectangle([300, 480, 310, 520], outline=(255, 255, 255), width=3)
214
- draw.rectangle([590, 480, 600, 520], outline=(255, 255, 255), width=3)
215
-
216
- def draw_community_life(self, draw, game_state):
217
- """Dibuja la vida comunitaria argentina"""
218
- # Ronda de mate
219
- mate_circle_x, mate_circle_y = 200, 500
220
- for i in range(5):
221
- angle = i * (math.pi * 2 / 5)
222
- x = mate_circle_x + 40 * math.cos(angle)
223
- y = mate_circle_y + 40 * math.sin(angle)
224
 
225
- # Persona
226
- draw.ellipse([x-8, y-15, x+8, y+10], fill=(150, 120, 90), outline=(100, 80, 60))
 
227
 
228
- # Mate (persona central)
229
- if i == 0:
230
- draw.ellipse([x-3, y-5, x+3, y+2], fill=(100, 50, 0), outline=(150, 100, 50))
231
-
232
- # Parrilla/asado
233
- if game_state.get('day_time') == 'tarde':
234
- asado_x, asado_y = 700, 500
235
- draw.rectangle([asado_x, asado_y, asado_x+60, asado_y+30],
236
- fill=(50, 50, 50), outline=(100, 100, 100))
237
 
238
- # Humo del asado
239
- for i in range(5):
240
- smoke_y = asado_y - 20 - i*15
241
- smoke_x = asado_x + 30 + random.randint(-10, 10)
242
- draw.ellipse([smoke_x-5, smoke_y-5, smoke_x+5, smoke_y+5],
243
- fill=(200, 200, 200, 100))
244
-
245
- # Chicos jugando
246
- for i in range(3):
247
- child_x = 400 + i*50 + random.randint(-20, 20)
248
- child_y = 470 + random.randint(-10, 10)
249
- draw.ellipse([child_x-5, child_y-10, child_x+5, child_y+5],
250
- fill=(180, 140, 100), outline=(120, 100, 80))
251
-
252
- # Pelota de fútbol
253
- ball_x = 450 + 20 * math.sin(time.time() * 2)
254
- draw.ellipse([ball_x-8, 485, ball_x+8, 501],
255
- fill=(255, 255, 255), outline=(0, 0, 0), width=2)
256
 
257
- def draw_survival_ui(self, draw, game_state):
258
- """UI de supervivencia argentina"""
259
- # Panel principal
260
- draw.rectangle([10, 10, 300, 150], fill=(0, 0, 0, 180), outline=(150, 150, 150))
261
-
262
- # Recursos
263
- resources = game_state.get('resources', {})
264
- y_offset = 25
265
-
266
- for resource, value in resources.items():
267
- color = self.get_resource_color(resource, value)
 
 
 
 
 
 
 
 
 
 
268
 
269
- # Barra de recurso
270
- draw.rectangle([20, y_offset, 200, y_offset+15], fill=(50, 50, 50))
271
- bar_width = int((value / 100) * 180)
272
- draw.rectangle([20, y_offset, 20 + bar_width, y_offset+15], fill=color)
 
 
 
 
 
273
 
274
- # Texto del recurso
275
- resource_names = {
276
- 'pesos': '💰 Pesos', 'dolares': '💵 Dólares', 'comida': '🍖 Comida',
277
- 'esperanza': '💪 Esperanza', 'solidaridad': '🤝 Solidaridad', 'trabajo': '🔨 Trabajo'
278
- }
279
- # draw.text([210, y_offset], f"{resource_names.get(resource, resource)}: {value}", fill=(255, 255, 255))
280
 
281
- y_offset += 20
282
-
283
- # Indicador de crisis
284
- crisis_intensity = game_state.get('crisis_level', 1)
285
- crisis_color = (255, 255 - crisis_intensity * 50, 255 - crisis_intensity * 50)
286
- draw.rectangle([320, 10, 500, 40], fill=crisis_color, outline=(255, 255, 255))
287
-
288
- # Día y situación
289
- day = game_state.get('day', 1)
290
- draw.rectangle([320, 50, 500, 80], fill=(20, 20, 20), outline=(100, 100, 100))
291
 
292
- def get_resource_color(self, resource, value):
293
- """Colores dinámicos según el estado del recurso"""
294
- if value > 70:
295
- return (100, 255, 100) # Verde
296
- elif value > 30:
297
- return (255, 255, 100) # Amarillo
298
- else:
299
- return (255, 100, 100) # Rojo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
 
301
- class CrisisYCorajeGame:
 
302
  def __init__(self):
 
303
  self.engine = ArgentinaGameEngine()
304
  self.renderer = GameRenderer()
305
- self.crisis_manager = CrisisManager()
306
- self.neighborhood_system = NeighborhoodSystem()
307
 
308
- # Estado del juego
309
  self.game_state = {
310
  'resources': self.engine.resources.copy(),
311
  'day': 1,
312
  'current_neighborhood': 'villa_31',
313
  'crisis_level': 1,
314
- 'location': 'villa_31',
315
- 'day_time': 'mañana'
 
 
316
  }
317
 
318
- # Eventos dinámicos
319
- self.active_events = []
320
- self.decisions_made = []
 
321
 
322
- def process_action(self, action):
323
- """Procesa las acciones del jugador con consecuencias reales"""
 
 
 
 
 
324
  if action == "trabajar":
325
- return self.work_day()
 
 
 
 
 
 
 
 
 
 
326
  elif action == "ayudar_vecinos":
327
- return self.help_neighbors()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  elif action == "buscar_rebusque":
329
- return self.find_rebusque()
330
- elif action == "organizar_comunitario":
331
- return self.organize_community()
332
- elif action == "ahorrar_dolares":
333
- return self.save_dollars()
 
 
 
 
 
 
 
 
 
 
334
  elif action == "hacer_asado":
335
- return self.make_asado()
336
-
337
- return self.advance_day()
338
-
339
- def work_day(self):
340
- """Simula un día de trabajo con variables argentinas"""
341
- profession = self.engine.player.profession
342
- base_income = {
343
- 'albañil': random.randint(2000, 4000),
344
- 'docente': random.randint(1500, 2500),
345
- 'comerciante': random.randint(1000, 8000),
346
- 'empleado_publico': random.randint(1800, 2200)
347
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
 
349
- income = base_income.get(profession, 2000)
 
 
350
 
351
- # Efectos de la inflación
352
- real_income = income / self.engine.inflation_rate
353
 
354
- self.game_state['resources']['pesos'] += real_income
355
- self.game_state['resources']['trabajo'] = min(100, self.game_state['resources']['trabajo'] + 10)
 
356
 
357
- # Stress por la crisis
358
- if self.game_state['crisis_level'] > 3:
359
- self.engine.player.stress_level += 5
360
- self.game_state['resources']['esperanza'] -= 5
361
 
362
- return self.advance_day(), f"Trabajaste como {profession}. Ganaste ${real_income:.0f} pesos (inflación: {self.engine.inflation_rate:.1f}x)"
363
 
364
- def help_neighbors(self):
365
- """Ayudar a los vecinos - mecánica clave argentina"""
366
- solidarity_gain = random.randint(10, 20)
367
- self.game_state['resources']['solidaridad'] += solidarity_gain
368
- self.game_state['resources']['esperanza'] += 5
369
-
370
- # Costo en recursos pero ganancia en red social
371
- self.game_state['resources']['comida'] -= 10
372
- self.game_state['resources']['pesos'] -= 200
373
-
374
- # Chance de reciprocidad
375
- if random.random() < 0.3:
376
- favor_returned = random.choice([
377
- "Te devolvieron un favor con trabajo",
378
- "Te invitaron a un asado",
379
- "Te prestaron herramientas",
380
- "Te cuidaron a los chicos"
381
- ])
382
- self.game_state['resources']['trabajo'] += 15
383
- return self.advance_day(), f"Ayudaste a tus vecinos. {favor_returned}."
384
-
385
- return self.advance_day(), f"Ayudaste a tus vecinos. Ganaste {solidarity_gain} puntos de solidaridad."
386
 
387
- def find_rebusque(self):
388
- """Rebusque - supervivencia argentina pura"""
389
- rebusque_skill = self.engine.player.skills['rebusque']
390
- success_chance = rebusque_skill / 100
391
-
392
- if random.random() < success_chance:
393
- rebusque_options = [
394
- "Vendiste empanadas caseras",
395
- "Arreglaste celulares",
396
- "Hiciste changas de albañilería",
397
- "Vendiste en la feria",
398
- "Diste clases particulares"
399
- ]
400
-
401
- chosen_rebusque = random.choice(rebusque_options)
402
- income = random.randint(500, 2000)
403
- self.game_state['resources']['pesos'] += income
404
- self.engine.player.skills['rebusque'] += 2
405
-
406
- return self.advance_day(), f"{chosen_rebusque}. Ganaste ${income} pesos!"
407
- else:
408
- self.game_state['resources']['esperanza'] -= 10
409
- return self.advance_day(), "El rebusque no funcionó hoy. Seguí intentando."
410
-
411
- def make_asado(self):
412
- """Hacer asado - tradición argentina que mejora la moral"""
413
- if self.game_state['resources']['pesos'] >= 1500:
414
- self.game_state['resources']['pesos'] -= 1500
415
- self.game_state['resources']['solidaridad'] += 25
416
- self.game_state['resources']['esperanza'] += 20
417
-
418
- # Bonus de comunidad
419
- self.engine.player.community_reputation += 10
420
-
421
- return self.advance_day(), "Hiciste un asado bárbaro. Todo el barrio vino, mejoró la moral general!"
422
- else:
423
- return self.advance_day(), "No tenés suficiente plata para el asado. Seguí juntando."
424
-
425
- def advance_day(self):
426
- """Avanza el día con eventos dinámicos"""
427
  self.game_state['day'] += 1
428
 
429
- # Inflación diaria
430
- self.engine.inflation_rate += random.uniform(0.01, 0.05)
 
431
 
432
- # Consumo diario
433
- daily_costs = {
434
- 'comida': random.randint(5, 15),
435
- 'pesos': random.randint(100, 500)
436
- }
437
 
438
- for resource, cost in daily_costs.items():
439
- self.game_state['resources'][resource] -= cost
 
 
 
440
  self.game_state['resources'][resource] = max(0, self.game_state['resources'][resource])
441
 
442
- # Eventos random
443
  if random.random() < 0.2:
444
- self.trigger_random_event()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
445
 
446
- # Cambio de estación
447
- if self.game_state['day'] % 90 == 0:
448
- self.change_season()
 
 
449
 
450
- return self.renderer.render_argentina_frame(self.game_state)
 
 
 
 
451
 
452
- def trigger_random_event(self):
453
- """Eventos aleatorios argentinos"""
454
- events = [
455
- "Piquete en 9 de Julio - no pudiste trabajar",
456
- "Encontraste $500 en el subte",
457
- "El almacenero te fió hasta fin de mes",
458
- "Ganaste en la quiniela",
459
- "Se rompió el colectivo - llegaste tarde",
460
- "Apareció laburo extra en el barrio"
461
  ]
462
 
463
- event = random.choice(events)
464
- self.active_events.append(event)
465
-
466
- # Aplicar efectos del evento
467
- if "Piquete" in event:
468
- self.game_state['resources']['trabajo'] -= 20
469
- elif "Encontraste $500" in event:
470
- self.game_state['resources']['pesos'] += 500
471
- elif "quiniela" in event:
472
- self.game_state['resources']['pesos'] += random.randint(1000, 5000)
473
- self.game_state['resources']['esperanza'] += 30
 
 
 
 
 
 
 
 
474
 
475
- def get_game_status(self):
476
- """Estado completo del juego"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
477
  return {
478
  "📅 Día": self.game_state['day'],
479
  "🏠 Barrio": self.game_state['current_neighborhood'].replace('_', ' ').title(),
@@ -482,29 +441,303 @@ class CrisisYCorajeGame:
482
  "🍖 Comida": f"{self.game_state['resources']['comida']:.0f}%",
483
  "💪 Esperanza": f"{self.game_state['resources']['esperanza']:.0f}%",
484
  "🤝 Solidaridad": f"{self.game_state['resources']['solidaridad']:.0f}%",
485
- "📈 Inflación": f"{self.engine.inflation_rate:.2f}x",
486
- "🎯 Crisis": f"Nivel {self.game_state['crisis_level']}/5"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
 
489
- def create_revolutionary_interface():
490
- game = CrisisYCorajeGame()
 
491
 
492
  with gr.Blocks(
493
- title="🇦🇷 CRISIS Y CORAJE - El Juego Argentino Definitivo",
494
- theme=gr.themes.Soft()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
495
  ) as interface:
496
 
497
  gr.HTML("""
498
- <div style="background: linear-gradient(135deg, #74b9ff, #0984e3, #fdcb6e);
499
- padding: 25px; text-align: center; border-radius: 15px; margin: 15px;">
500
- <h1 style="color: white; font-size: 3em; text-shadow: 2px 2px 4px rgba(0,0,0,0.7); margin: 0;">
501
  🇦🇷 CRISIS Y CORAJE
502
  </h1>
503
- <h2 style="color: #ffffff; font-size: 1.3em; margin: 10px 0;">
504
- Supervivencia, Solidaridad y Cultura en la Argentina Real
505
  </h2>
506
- <p style="color: #f1f2f6; font-size: 1.1em; margin: 5px 0;">
507
- Navegá las crisis económicas mientras preservás lo que nos hace argentinos
508
  </p>
509
  </div>
510
  """)
@@ -512,81 +745,94 @@ def create_revolutionary_interface():
512
  with gr.Row():
513
  with gr.Column(scale=2):
514
  game_display = gr.Image(
515
- label="🌆 Tu Barrio en Argentina",
516
  width=900,
517
  height=600
518
  )
519
 
520
- gr.Markdown("### 🎮 ACCIONES ARGENTINAS")
521
  with gr.Row():
522
- work_btn = gr.Button("💼 TRABAJAR", variant="primary", size="lg")
523
- help_btn = gr.Button("🤝 AYUDAR VECINOS", variant="secondary", size="lg")
524
- rebusque_btn = gr.Button("💡 REBUSQUE", variant="stop", size="lg")
525
 
526
  with gr.Row():
527
- organize_btn = gr.Button("📢 ORGANIZAR", variant="secondary", size="lg")
528
- save_btn = gr.Button("💵 AHORRAR", variant="primary", size="lg")
529
- asado_btn = gr.Button("🔥 HACER ASADO", variant="stop", size="lg")
530
 
531
  with gr.Column(scale=1):
532
  gr.Markdown("### 📊 ESTADO DE SUPERVIVENCIA")
533
  status_display = gr.JSON(
534
- label="🎯 Tu Situación",
535
- value=game.get_game_status()
536
  )
537
 
538
- gr.Markdown("### 📰 ÚLTIMAS NOTICIAS")
539
  news_display = gr.Textbox(
540
- value="Bienvenido a tu barrio. La crisis está, pero la solidaridad también. ¿Cómo vas a sobrevivir hoy?",
541
- label="📺 Canal de Noticias",
542
  lines=4,
543
  interactive=False
544
  )
545
 
546
- gr.Markdown("### 🎯 TUTORIAL RÁPIDO")
547
- gr.HTML("""
548
- <div style="background: #2d3436; color: white; padding: 15px; border-radius: 10px;">
549
- <p><strong>🎮 Cómo Jugar:</strong></p>
550
- <ul style="margin: 10px 0; padding-left: 20px;">
551
- <li>💼 <strong>Trabajá</strong> para ganar pesos</li>
552
- <li>🤝 <strong>Ayudá</strong> para aumentar solidaridad</li>
553
- <li>💡 <strong>Rebuscátelas</strong> en crisis</li>
554
- <li>🔥 <strong>Hacé asados</strong> para la moral</li>
555
- <li>💵 <strong>Ahorrá dólares</strong> contra inflación</li>
 
556
  </ul>
557
- <p><em>¡Sobreviví con creatividad argentina!</em></p>
558
  </div>
559
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
 
561
- # Conectar acciones
562
- def handle_action(action_name):
563
- frame, message = game.process_action(action_name)
564
- status = game.get_game_status()
565
- return frame, status, message
566
-
567
- work_btn.click(fn=lambda: handle_action("trabajar"),
568
- outputs=[game_display, status_display, news_display])
569
- help_btn.click(fn=lambda: handle_action("ayudar_vecinos"),
570
- outputs=[game_display, status_display, news_display])
571
- rebusque_btn.click(fn=lambda: handle_action("buscar_rebusque"),
572
- outputs=[game_display, status_display, news_display])
573
- organize_btn.click(fn=lambda: handle_action("organizar_comunitario"),
574
- outputs=[game_display, status_display, news_display])
575
- save_btn.click(fn=lambda: handle_action("ahorrar_dolares"),
576
- outputs=[game_display, status_display, news_display])
577
- asado_btn.click(fn=lambda: handle_action("hacer_asado"),
578
- outputs=[game_display, status_display, news_display])
579
-
580
- # Inicialización
581
  interface.load(
582
- fn=lambda: (game.renderer.render_argentina_frame(game.game_state),
583
- game.get_game_status(),
584
- "¡Arrancó el juego! Tomate tu tiempo para pensar cada decisión."),
 
 
585
  outputs=[game_display, status_display, news_display]
586
  )
587
 
588
  return interface
589
 
590
  if __name__ == "__main__":
591
- interface = create_revolutionary_interface()
592
- interface.launch(share=True, show_error=True)
 
1
+ # app.py - CRISIS Y CORAJE CON IA NARRATIVA
2
  import gradio as gr
3
  import time
4
  import math
5
  import random
6
+ import os
7
  from PIL import Image, ImageDraw
8
+ from groq import Groq
9
+ import json
10
 
11
+ class AIDialogueSystem:
12
+ """Sistema de diálogos con IA usando Groq"""
13
  def __init__(self):
14
+ try:
15
+ self.client = Groq(api_key=os.getenv("GROQ_API_KEY"))
16
+ self.context_memory = []
17
+ self.character_personalities = self._load_character_personalities()
18
+ self.ai_enabled = True
19
+ except Exception as e:
20
+ print(f"Groq no disponible: {e}")
21
+ self.ai_enabled = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
+ def _load_character_personalities(self):
24
+ return {
25
+ 'narrator': {
26
+ 'role': 'Narrador porteño con experiencia en crisis argentinas',
27
+ 'style': 'Realista, empático, usa lunfardo y jerga argentina',
28
+ 'knowledge': 'Historia argentina reciente, crisis económicas, cultura popular'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  },
30
+ 'dona_rosa': {
31
+ 'role': 'Vecina mayor, sabia del barrio',
32
+ 'style': 'Maternal, directa, llena de consejos prácticos',
33
+ 'knowledge': 'Supervivencia en crisis, redes vecinales, cocina criolla'
34
  },
35
+ 'el_checo': {
36
+ 'role': 'Parrillero del barrio, organizador social',
37
+ 'style': 'Carismático, solidario, siempre con una anécdota',
38
+ 'knowledge': 'Asados, organización comunitaria, fútbol'
39
  },
40
+ 'comerciante': {
41
+ 'role': 'Dueño del almacén, conoce la economía barrial',
42
+ 'style': 'Pragmático, conoce precios y mercado, observador',
43
+ 'knowledge': 'Economía local, precios, crédito informal'
44
  }
45
  }
46
 
47
+ def generate_contextual_dialogue(self, character, situation, player_action, game_state):
48
+ """Genera diálogo contextual usando IA"""
49
+ if not self.ai_enabled:
50
+ return self._fallback_dialogue(character, situation)
51
+
52
+ try:
53
+ personality = self.character_personalities.get(character, self.character_personalities['narrator'])
54
+
55
+ prompt = f"""
56
+ Sos {personality['role']} en un juego sobre supervivencia en Argentina durante crisis económicas.
57
+ Estilo: {personality['style']}
58
+ Conocimiento: {personality['knowledge']}
59
 
60
+ CONTEXTO DEL JUEGO:
61
+ - Día: {game_state.get('day', 1)}
62
+ - Barrio: {game_state.get('current_neighborhood', 'villa_31')}
63
+ - Recursos del jugador: {json.dumps(game_state.get('resources', {}), indent=2)}
64
+ - Inflación actual: {game_state.get('inflation_rate', 1.0):.2f}x
65
+ - Último evento: {game_state.get('last_event', 'Inicio del juego')}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
+ SITUACIÓN ACTUAL: {situation}
68
+ ACCIÓN DEL JUGADOR: {player_action}
69
+
70
+ Recordá que estás en Argentina, usá expresiones auténticas. empático pero realista sobre las crisis.
71
+ Mencioná detalles específicos argentinos cuando sea relevante.
72
+ Máximo 2-3 oraciones, directo y conversacional.
73
+
74
+ Respuesta como {personality['role']}:
75
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
 
77
+ response = self.client.chat.completions.create(
78
+ messages=[
79
+ {"role": "system", "content": "Sos un personaje argentino en un juego de supervivencia ambientado en Argentina. Usá lenguaje auténtico porteno y mantené el tono realista pero esperanzador."},
80
+ {"role": "user", "content": prompt}
81
+ ],
82
+ model="llama-3.1-8b-instant",
83
+ temperature=0.8,
84
+ max_tokens=150
85
+ )
86
 
87
+ dialogue = response.choices[0].message.content.strip()
 
 
88
 
89
+ # Guardar en memoria para contexto futuro
90
+ self.context_memory.append({
91
+ 'character': character,
92
+ 'situation': situation,
93
+ 'dialogue': dialogue,
94
+ 'game_day': game_state.get('day', 1)
95
+ })
 
 
 
 
 
 
 
 
 
 
 
96
 
97
+ # Mantener solo los últimos 10 diálogos
98
+ if len(self.context_memory) > 10:
99
+ self.context_memory.pop(0)
100
 
101
+ return dialogue
 
 
 
 
 
 
 
 
102
 
103
+ except Exception as e:
104
+ print(f"Error en IA: {e}")
105
+ return self._fallback_dialogue(character, situation)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
+ def generate_neighborhood_news(self, game_state):
108
+ """Genera noticias dinámicas del barrio usando IA"""
109
+ if not self.ai_enabled:
110
+ return "El barrio sigue adelante con solidaridad y creatividad."
111
+
112
+ try:
113
+ prompt = f"""
114
+ Sos un periodista local que cubre noticias del barrio en Argentina.
115
+ Generá una noticia breve (1-2 líneas) basada en:
116
+
117
+ Estado actual:
118
+ - Día {game_state.get('day', 1)}
119
+ - Barrio: {game_state.get('current_neighborhood', 'villa_31')}
120
+ - Nivel de crisis: {game_state.get('crisis_level', 1)}/5
121
+ - Solidaridad comunitaria: {game_state.get('resources', {}).get('solidaridad', 50)}%
122
+
123
+ Hacé que sea realista pero no deprimente. Enfocate en la resistencia y creatividad argentina.
124
+ Incluí detalles específicos del barrio si es relevante.
125
+
126
+ Noticia breve:
127
+ """
128
 
129
+ response = self.client.chat.completions.create(
130
+ messages=[
131
+ {"role": "system", "content": "Sos un periodista barrial argentino que ve el lado humano de las crisis."},
132
+ {"role": "user", "content": prompt}
133
+ ],
134
+ model="llama-3.1-8b-instant",
135
+ temperature=0.7,
136
+ max_tokens=100
137
+ )
138
 
139
+ return response.choices[0].message.content.strip()
 
 
 
 
 
140
 
141
+ except Exception as e:
142
+ return "Los vecinos siguen organizándose para enfrentar juntos los desafíos."
 
 
 
 
 
 
 
 
143
 
144
+ def generate_crisis_commentary(self, crisis_level, resources):
145
+ """Genera comentario sobre la situación económica"""
146
+ if not self.ai_enabled:
147
+ return "La situación económica sigue desafiante pero manejable."
148
+
149
+ try:
150
+ prompt = f"""
151
+ Sos un analista económico argentino con sensibilidad social.
152
+ Comentá brevemente la situación basada en:
153
+ - Nivel de crisis: {crisis_level}/5
154
+ - Recursos familiares: pesos {resources.get('pesos', 0)}, dólares {resources.get('dolares', 0)}
155
+ - Nivel de esperanza: {resources.get('esperanza', 50)}%
156
+
157
+ Sé realista pero no catastrófico. Mencioná estrategias argentinas típicas.
158
+ Máximo 2 líneas.
159
+
160
+ Análisis:
161
+ """
162
+ response = self.client.chat.completions.create(
163
+ messages=[
164
+ {"role": "system", "content": "Sos un economista argentino que entiende las estrategias populares de supervivencia."},
165
+ {"role": "user", "content": prompt}
166
+ ],
167
+ model="llama-3.1-8b-instant",
168
+ temperature=0.6,
169
+ max_tokens=80
170
+ )
171
+
172
+ return response.choices[0].message.content.strip()
173
+
174
+ except Exception as e:
175
+ return "El rebusque y la solidaridad siguen siendo clave en estos momentos."
176
+
177
+ def _fallback_dialogue(self, character, situation):
178
+ """Diálogos de respaldo si la IA no está disponible"""
179
+ fallbacks = {
180
+ 'narrator': [
181
+ "La vida en Argentina nunca es fácil, pero siempre hay una manera de salir adelante.",
182
+ "En el barrio todos se conocen, y eso marca la diferencia en tiempos difíciles.",
183
+ "El rebusque argentino nunca falla, che."
184
+ ],
185
+ 'dona_rosa': [
186
+ "Mirá, pibe, en mis años he visto de todo. Esto también se supera.",
187
+ "¿Viste? Siempre es mejor cuando nos ayudamos entre vecinos.",
188
+ "Con un buen guiso y buena onda, todo se arregla."
189
+ ],
190
+ 'el_checo': [
191
+ "¿Vamos haciendo un asadito para levantar el ánimo?",
192
+ "En la cancha y en la vida, lo que importa es el equipo.",
193
+ "Acá en el barrio nunca falta una mano amiga."
194
+ ]
195
+ }
196
+
197
+ character_lines = fallbacks.get(character, fallbacks['narrator'])
198
+ return random.choice(character_lines)
199
 
200
+ class EnhancedArgentinaGame:
201
+ """Versión mejorada del juego con IA narrativa"""
202
  def __init__(self):
203
+ # Sistema base
204
  self.engine = ArgentinaGameEngine()
205
  self.renderer = GameRenderer()
206
+ self.ai_dialogue = AIDialogueSystem()
 
207
 
208
+ # Estado expandido del juego
209
  self.game_state = {
210
  'resources': self.engine.resources.copy(),
211
  'day': 1,
212
  'current_neighborhood': 'villa_31',
213
  'crisis_level': 1,
214
+ 'inflation_rate': 1.0,
215
+ 'last_event': 'Inicio del juego',
216
+ 'current_character': None,
217
+ 'story_progress': 0
218
  }
219
 
220
+ # Sistema de eventos narrativos
221
+ self.story_events = []
222
+ self.character_interactions = 0
223
+ self.neighborhood_reputation = 50
224
 
225
+ def process_enhanced_action(self, action):
226
+ """Procesa acciones con narrativa IA mejorada"""
227
+ # Acción base
228
+ old_resources = self.game_state['resources'].copy()
229
+ message = ""
230
+ character_dialogue = ""
231
+
232
  if action == "trabajar":
233
+ income = self._calculate_work_income()
234
+ self.game_state['resources']['pesos'] += income
235
+ self.game_state['resources']['trabajo'] = min(100, self.game_state['resources']['trabajo'] + 10)
236
+
237
+ # Generar diálogo contextual
238
+ situation = f"El jugador fue a trabajar y ganó ${income} pesos en un día de crisis nivel {self.game_state['crisis_level']}"
239
+ character_dialogue = self.ai_dialogue.generate_contextual_dialogue(
240
+ 'narrator', situation, 'trabajar', self.game_state
241
+ )
242
+ message = f"Trabajaste y ganaste ${income} pesos."
243
+
244
  elif action == "ayudar_vecinos":
245
+ solidarity_gain = random.randint(15, 25)
246
+ self.game_state['resources']['solidaridad'] += solidarity_gain
247
+ self.game_state['resources']['esperanza'] += 10
248
+ self.game_state['resources']['pesos'] -= 200
249
+ self.character_interactions += 1
250
+
251
+ # Elegir personaje aleatorio para interactuar
252
+ characters = ['dona_rosa', 'el_checo', 'comerciante']
253
+ chosen_character = random.choice(characters)
254
+ self.game_state['current_character'] = chosen_character
255
+
256
+ situation = f"El jugador ayudó a los vecinos, gastando $200 pero ganando {solidarity_gain} puntos de solidaridad"
257
+ character_dialogue = self.ai_dialogue.generate_contextual_dialogue(
258
+ chosen_character, situation, 'ayudar_vecinos', self.game_state
259
+ )
260
+ message = f"Ayudaste a tus vecinos. +{solidarity_gain} solidaridad"
261
+
262
  elif action == "buscar_rebusque":
263
+ rebusque_success = random.random() < 0.7
264
+ if rebusque_success:
265
+ income = random.randint(800, 2000)
266
+ self.game_state['resources']['pesos'] += income
267
+ situation = f"El rebusque del jugador fue exitoso, ganando ${income} pesos"
268
+ message = f"¡El rebusque funcionó! Ganaste ${income}"
269
+ else:
270
+ self.game_state['resources']['esperanza'] -= 8
271
+ situation = f"El rebusque del jugador no funcionó, perdiendo esperanza"
272
+ message = "El rebusque no salió bien hoy"
273
+
274
+ character_dialogue = self.ai_dialogue.generate_contextual_dialogue(
275
+ 'narrator', situation, 'buscar_rebusque', self.game_state
276
+ )
277
+
278
  elif action == "hacer_asado":
279
+ asado_cost = 1500
280
+ if self.game_state['resources']['pesos'] >= asado_cost:
281
+ self.game_state['resources']['pesos'] -= asado_cost
282
+ self.game_state['resources']['solidaridad'] += 25
283
+ self.game_state['resources']['esperanza'] += 20
284
+ self.neighborhood_reputation += 15
285
+
286
+ situation = f"El jugador organizó un asado que costó ${asado_cost}, mejorando la moral del barrio"
287
+ character_dialogue = self.ai_dialogue.generate_contextual_dialogue(
288
+ 'el_checo', situation, 'hacer_asado', self.game_state
289
+ )
290
+ message = f"¡Asado bárbaro! Toda la cuadra vino."
291
+ else:
292
+ situation = "El jugador quiso hacer asado pero no tenía suficiente plata"
293
+ character_dialogue = self.ai_dialogue.generate_contextual_dialogue(
294
+ 'dona_rosa', situation, 'hacer_asado', self.game_state
295
+ )
296
+ message = "No tenés suficiente plata para el asado, pibe."
297
+
298
+ elif action == "ahorrar_dolares":
299
+ peso_cost = 1000
300
+ if self.game_state['resources']['pesos'] >= peso_cost:
301
+ self.game_state['resources']['pesos'] -= peso_cost
302
+ self.game_state['resources']['dolares'] += 1
303
+
304
+ situation = f"El jugador compró US$1 por ${peso_cost} pesos como protección contra inflación"
305
+ character_dialogue = self.ai_dialogue.generate_contextual_dialogue(
306
+ 'comerciante', situation, 'ahorrar_dolares', self.game_state
307
+ )
308
+ message = "Compraste US$1. Protección contra inflación."
309
+ else:
310
+ message = "No tenés suficientes pesos para comprar dólares."
311
+ character_dialogue = "Los dólares están carísimos, pero hay que cuidarse de la inflación."
312
 
313
+ # Sistema de eventos especiales basados en progreso
314
+ if self.game_state['day'] % 7 == 0:
315
+ self._trigger_weekly_event()
316
 
317
+ # Avanzar día con narrativa mejorada
318
+ self._advance_enhanced_day()
319
 
320
+ # Generar frame y status
321
+ frame = self.renderer.render_argentina_frame(self.game_state)
322
+ status = self.get_enhanced_status()
323
 
324
+ # Combinar mensaje de acción con diálogo de personaje
325
+ full_message = f"{message}\n\n💬 {character_dialogue}" if character_dialogue else message
 
 
326
 
327
+ return frame, status, full_message
328
 
329
+ def _calculate_work_income(self):
330
+ """Calcula ingresos de trabajo según crisis y profesión"""
331
+ base_income = random.randint(1500, 3500)
332
+ crisis_modifier = max(0.5, 1.5 - (self.game_state['crisis_level'] * 0.2))
333
+ return int(base_income * crisis_modifier)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
+ def _advance_enhanced_day(self):
336
+ """Avanza el día con eventos narrativos"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
  self.game_state['day'] += 1
338
 
339
+ # Inflación dinámica
340
+ inflation_increase = random.uniform(0.01, 0.04) * self.game_state['crisis_level']
341
+ self.game_state['inflation_rate'] += inflation_increase
342
 
343
+ # Gastos diarios ajustados por inflación
344
+ daily_food_cost = random.randint(5, 12) * self.game_state['inflation_rate']
345
+ daily_living_cost = random.randint(200, 500) * self.game_state['inflation_rate']
 
 
346
 
347
+ self.game_state['resources']['comida'] -= daily_food_cost
348
+ self.game_state['resources']['pesos'] -= daily_living_cost
349
+
350
+ # Mantener recursos en rango válido
351
+ for resource in self.game_state['resources']:
352
  self.game_state['resources'][resource] = max(0, self.game_state['resources'][resource])
353
 
354
+ # Eventos aleatorios con narrativa IA
355
  if random.random() < 0.2:
356
+ self._trigger_ai_event()
357
+
358
+ # Actualizar nivel de crisis basado en condiciones
359
+ self._update_crisis_level()
360
+
361
+ def _trigger_ai_event(self):
362
+ """Eventos aleatorios con narrativa generada por IA"""
363
+ base_events = [
364
+ ("Se cortó la luz", "solidaridad", 15, "Los vecinos se organizaron para afrontar el corte"),
365
+ ("Llegó mercadería al almacén", "comida", 25, "Doña Rosa te guardó algunos productos"),
366
+ ("Paro de transporte", "trabajo", -20, "No pudiste llegar al trabajo por el paro"),
367
+ ("Feria en la plaza", "pesos", 600, "Vendiste algunas cosas en la feria del barrio"),
368
+ ("Reunión vecinal", "solidaridad", 20, "Se organizó una asamblea para mejorar el barrio")
369
+ ]
370
+
371
+ event_name, resource, change, context = random.choice(base_events)
372
+ self.game_state['resources'][resource] += change
373
+ self.game_state['last_event'] = event_name
374
 
375
+ # Generar comentario IA sobre el evento
376
+ situation = f"Ocurrió el evento: {event_name}. {context}. Cambió {resource} en {change} puntos."
377
+ ai_comment = self.ai_dialogue.generate_contextual_dialogue(
378
+ 'narrator', situation, 'evento_aleatorio', self.game_state
379
+ )
380
 
381
+ self.story_events.append({
382
+ 'day': self.game_state['day'],
383
+ 'event': event_name,
384
+ 'comment': ai_comment
385
+ })
386
 
387
+ def _trigger_weekly_event(self):
388
+ """Eventos semanales especiales con narrativa extendida"""
389
+ weekly_events = [
390
+ "Asamblea vecinal extraordinaria",
391
+ "Llegada de ayuda municipal",
392
+ "Feria gastronómica del barrio",
393
+ "Torneo de fútbol inter-barrios",
394
+ "Jornada de trabajo comunitario"
 
395
  ]
396
 
397
+ event = random.choice(weekly_events)
398
+ self.game_state['last_event'] = f"Evento Semanal: {event}"
399
+
400
+ # Efectos especiales de eventos semanales
401
+ if "Asamblea" in event:
402
+ self.game_state['resources']['solidaridad'] += 30
403
+ self.game_state['resources']['esperanza'] += 15
404
+ elif "ayuda municipal" in event:
405
+ self.game_state['resources']['comida'] += 40
406
+ self.game_state['resources']['pesos'] += 1000
407
+ elif "Feria gastronómica" in event:
408
+ self.game_state['resources']['pesos'] += random.randint(800, 2000)
409
+ self.game_state['resources']['solidaridad'] += 20
410
+ elif "Torneo" in event:
411
+ self.game_state['resources']['esperanza'] += 25
412
+ self.neighborhood_reputation += 10
413
+ elif "trabajo comunitario" in event:
414
+ self.game_state['resources']['solidaridad'] += 35
415
+ self.game_state['resources']['trabajo'] += 20
416
 
417
+ def _update_crisis_level(self):
418
+ """Actualiza nivel de crisis basado en condiciones"""
419
+ # Crisis basada en recursos e inflación
420
+ avg_resources = sum(self.game_state['resources'].values()) / len(self.game_state['resources'])
421
+ inflation_factor = min(5, self.game_state['inflation_rate'])
422
+
423
+ if avg_resources < 30 or inflation_factor > 3:
424
+ self.game_state['crisis_level'] = min(5, self.game_state['crisis_level'] + 1)
425
+ elif avg_resources > 70 and inflation_factor < 2:
426
+ self.game_state['crisis_level'] = max(1, self.game_state['crisis_level'] - 1)
427
+
428
+ def get_enhanced_status(self):
429
+ """Estado del juego con información narrativa"""
430
+ # Generar análisis económico IA
431
+ economic_analysis = self.ai_dialogue.generate_crisis_commentary(
432
+ self.game_state['crisis_level'],
433
+ self.game_state['resources']
434
+ )
435
+
436
  return {
437
  "📅 Día": self.game_state['day'],
438
  "🏠 Barrio": self.game_state['current_neighborhood'].replace('_', ' ').title(),
 
441
  "🍖 Comida": f"{self.game_state['resources']['comida']:.0f}%",
442
  "💪 Esperanza": f"{self.game_state['resources']['esperanza']:.0f}%",
443
  "🤝 Solidaridad": f"{self.game_state['resources']['solidaridad']:.0f}%",
444
+ "📈 Inflación": f"{self.game_state['inflation_rate']:.2f}x",
445
+ "🏆 Reputación": f"{self.neighborhood_reputation}/100",
446
+ "📊 Análisis IA": economic_analysis
447
+ }
448
+
449
+ def get_neighborhood_news(self):
450
+ """Genera noticias del barrio con IA"""
451
+ return self.ai_dialogue.generate_neighborhood_news(self.game_state)
452
+
453
+ # Continúo con las otras clases necesarias...
454
+ class ArgentinaGameEngine:
455
+ """Motor base del juego"""
456
+ def __init__(self):
457
+ self.resources = {
458
+ 'pesos': 1200,
459
+ 'dolares': 30,
460
+ 'comida': 75,
461
+ 'esperanza': 85,
462
+ 'solidaridad': 80,
463
+ 'trabajo': 65
464
+ }
465
+
466
+ class GameRenderer:
467
+ """Renderizador mejorado"""
468
+ def __init__(self):
469
+ self.animation_frame = 0
470
+
471
+ def render_argentina_frame(self, game_state) -> Image.Image:
472
+ """Renderiza con detalles mejorados"""
473
+ img = Image.new('RGB', (900, 600), (15, 25, 50))
474
+ draw = ImageDraw.Draw(img)
475
+
476
+ # Skyline dinámico según hora del día
477
+ self._draw_dynamic_skyline(draw, game_state)
478
+
479
+ # Barrio con actividad según solidaridad
480
+ self._draw_active_neighborhood(draw, game_state)
481
+
482
+ # Personaje con animaciones
483
+ self._draw_animated_character(draw, game_state)
484
+
485
+ # UI mejorada con gradientes
486
+ self._draw_enhanced_ui(draw, game_state)
487
+
488
+ return img
489
+
490
+ def _draw_dynamic_skyline(self, draw, game_state):
491
+ """Skyline que cambia según el estado del juego"""
492
+ # Color del cielo según esperanza
493
+ hope_level = game_state.get('resources', {}).get('esperanza', 50)
494
+ sky_blue = min(255, int(60 + hope_level * 1.6))
495
+
496
+ # Gradiente de cielo
497
+ for y in range(200):
498
+ color_intensity = int(sky_blue * (1 - y/400))
499
+ draw.rectangle([0, y, 900, y+1], fill=(15, 25, color_intensity))
500
+
501
+ # Edificios con luces según recursos
502
+ prosperity = sum(game_state.get('resources', {}).values()) / 500
503
+ buildings = [
504
+ (100, 120, 140, 400), (160, 100, 200, 400), (220, 140, 260, 400),
505
+ (700, 80, 750, 350), (770, 110, 820, 350)
506
+ ]
507
+
508
+ for building in buildings:
509
+ draw.rectangle(building, fill=(30, 30, 50), outline=(60, 60, 80))
510
+
511
+ # Ventanas encendidas según prosperidad
512
+ for window_y in range(building[1] + 20, building[3], 25):
513
+ for window_x in range(building[0] + 8, building[2], 18):
514
+ if random.random() < prosperity:
515
+ draw.rectangle([window_x, window_y, window_x+10, window_y+10],
516
+ fill=(255, 255, 180))
517
+
518
+ def _draw_active_neighborhood(self, draw, game_state):
519
+ """Barrio con actividad dinámica"""
520
+ solidarity = game_state.get('resources', {}).get('solidaridad', 50)
521
+
522
+ # Base del neighborhood
523
+ draw.rectangle([0, 400, 900, 600], fill=(40, 60, 30))
524
+
525
+ # Casas con colores según solidaridad
526
+ house_colors = [(200, 100, 100), (100, 200, 100), (100, 100, 200), (200, 200, 100)]
527
+ brightness_multiplier = 0.6 + (solidarity / 200)
528
+
529
+ for i in range(6):
530
+ x = 60 + i * 130
531
+ y = 350 + random.randint(-15, 15)
532
+ base_color = random.choice(house_colors)
533
+ bright_color = tuple(int(c * brightness_multiplier) for c in base_color)
534
+
535
+ # Casa principal
536
+ draw.rectangle([x, y, x+70, y+70], fill=bright_color, outline=(0, 0, 0), width=2)
537
+
538
+ # Techo
539
+ draw.polygon([(x-5, y), (x+35, y-12), (x+75, y)], fill=(120, 120, 120))
540
+
541
+ # Detalles según solidaridad
542
+ if solidarity > 70:
543
+ # Jardincito al frente
544
+ draw.rectangle([x-10, y+70, x+80, y+80], fill=(80, 120, 40))
545
+ # Flores
546
+ for flower_x in range(x, x+70, 15):
547
+ draw.ellipse([flower_x-2, y+72, flower_x+2, y+76], fill=(255, 100, 150))
548
+
549
+ # Actividad comunitaria según solidaridad
550
+ if solidarity > 60:
551
+ self._draw_mate_circle(draw, 180, 520)
552
+ if solidarity > 80:
553
+ self._draw_community_garden(draw, 600, 480)
554
+
555
+ def _draw_mate_circle(self, draw, center_x, center_y):
556
+ """Dibuja ronda de mate"""
557
+ for i in range(5):
558
+ angle = i * (math.pi * 2 / 5)
559
+ person_x = center_x + 35 * math.cos(angle)
560
+ person_y = center_y + 35 * math.sin(angle)
561
+
562
+ # Persona
563
+ draw.ellipse([person_x-6, person_y-12, person_x+6, person_y+6],
564
+ fill=(140, 110, 80), outline=(100, 80, 60))
565
+
566
+ # Mate en el centro
567
+ if i == 0:
568
+ draw.ellipse([center_x-4, center_y-4, center_x+4, center_y+4], fill=(80, 40, 0))
569
+
570
+ def _draw_community_garden(self, draw, x, y):
571
+ """Jardín comunitario"""
572
+ # Base del jardín
573
+ draw.rectangle([x, y, x+80, y+60], fill=(60, 100, 40))
574
+
575
+ # Plantas
576
+ for plant_x in range(x+10, x+70, 20):
577
+ for plant_y in range(y+10, y+50, 15):
578
+ draw.ellipse([plant_x-3, plant_y-3, plant_x+3, plant_y+3], fill=(100, 180, 60))
579
+
580
+ def _draw_animated_character(self, draw, game_state):
581
+ """Personaje con animaciones"""
582
+ x, y = 420, 450
583
+
584
+ # Animación de respiración
585
+ breath_offset = math.sin(time.time() * 2) * 2
586
+
587
+ # Sombra
588
+ draw.ellipse([x-10, y+15, x+10, y+18], fill=(0, 0, 0, 120))
589
+
590
+ # Cuerpo con animación
591
+ body_y = y + breath_offset
592
+ draw.ellipse([x-12, body_y-18, x+12, body_y+12], fill=(130, 100, 70), outline=(90, 70, 50), width=2)
593
+
594
+ # Remera argentina
595
+ draw.rectangle([x-10, body_y-15, x+10, body_y+5], fill=(100, 150, 255), outline=(255, 255, 255))
596
+
597
+ # Cabeza
598
+ head_y = body_y - 25 + breath_offset * 0.5
599
+ draw.ellipse([x-8, head_y-15, x+8, head_y+5], fill=(160, 130, 90), outline=(120, 100, 70))
600
+
601
+ # Expresión según esperanza
602
+ hope = game_state.get('resources', {}).get('esperanza', 50)
603
+ if hope > 70:
604
+ # Sonrisa
605
+ draw.arc([x-4, head_y-5, x+4, head_y+2], 0, 180, fill=(0, 0, 0), width=2)
606
+ elif hope < 30:
607
+ # Preocupación
608
+ draw.arc([x-4, head_y+2, x+4, head_y-5], 0, 180, fill=(0, 0, 0), width=2)
609
+
610
+ # Ojos
611
+ draw.ellipse([x-5, head_y-8, x-2, head_y-5], fill=(255, 255, 255))
612
+ draw.ellipse([x+2, head_y-8, x+5, head_y-5], fill=(255, 255, 255))
613
+ draw.ellipse([x-4, head_y-7, x-3, head_y-6], fill=(0, 0, 0))
614
+ draw.ellipse([x+3, head_y-7, x+4, head_y-6], fill=(0, 0, 0))
615
+
616
+ # Mate en la mano con brillo
617
+ mate_x = x + 10
618
+ mate_glow = int(150 + 50 * math.sin(time.time() * 3))
619
+ draw.ellipse([mate_x-3, body_y-8, mate_x+3, body_y-2],
620
+ fill=(100, 50, 0), outline=(mate_glow, mate_glow//2, 0), width=2)
621
+
622
+ def _draw_enhanced_ui(self, draw, game_state):
623
+ """UI mejorada con efectos visuales"""
624
+ resources = game_state.get('resources', {})
625
+
626
+ # Panel principal con gradiente
627
+ for i in range(170):
628
+ alpha = int(180 * (1 - i/170))
629
+ draw.rectangle([10, 10+i, 350, 11+i], fill=(0, 0, 0, alpha))
630
+
631
+ draw.rectangle([10, 10, 350, 180], outline=(100, 150, 200), width=2)
632
+
633
+ # Título
634
+ crisis_level = game_state.get('crisis_level', 1)
635
+ crisis_colors = [(100, 255, 100), (150, 255, 100), (255, 255, 100), (255, 150, 100), (255, 100, 100)]
636
+ title_color = crisis_colors[min(4, crisis_level-1)]
637
+
638
+ # Recursos con barras animadas
639
+ y_pos = 35
640
+ for resource, value in resources.items():
641
+ # Barra de fondo con gradiente
642
+ draw.rectangle([25, y_pos, 220, y_pos+12], fill=(30, 30, 30))
643
+
644
+ # Barra de valor con animación
645
+ bar_width = int((max(0, min(value, 100)) / 100) * 195)
646
+ bar_color = self._get_animated_resource_color(resource, value)
647
+
648
+ if bar_width > 0:
649
+ # Efecto de brillo en la barra
650
+ for i in range(bar_width):
651
+ brightness = int(255 * (0.7 + 0.3 * math.sin(time.time() * 2 + i/10)))
652
+ color_with_glow = tuple(min(255, c + brightness//4) for c in bar_color)
653
+ draw.rectangle([25+i, y_pos, 26+i, y_pos+12], fill=color_with_glow)
654
+
655
+ # Iconos de recursos
656
+ resource_icons = {
657
+ 'pesos': '💰', 'dolares': '💵', 'comida': '🍖',
658
+ 'esperanza': '💪', 'solidaridad': '🤝', 'trabajo': '🔨'
659
+ }
660
+
661
+ # Valor numérico
662
+ y_pos += 18
663
+
664
+ # Indicador de inflación animado
665
+ inflation = game_state.get('inflation_rate', 1.0)
666
+ inflation_intensity = min(255, int(100 + inflation * 30))
667
+ inflation_color = (255, 255-inflation_intensity//2, 255-inflation_intensity)
668
+
669
+ # Pulso según inflación
670
+ pulse = math.sin(time.time() * (1 + inflation)) * 10
671
+ draw.rectangle([230, 35, 340, 60], fill=inflation_color, outline=(255, 255, 255), width=2)
672
+
673
+ # Crisis meter con efectos
674
+ crisis_width = int((crisis_level / 5) * 100)
675
+ crisis_color = crisis_colors[min(4, crisis_level-1)]
676
+ draw.rectangle([230, 70, 340, 85], fill=(50, 50, 50))
677
+ draw.rectangle([230, 70, 230 + crisis_width, 85], fill=crisis_color)
678
+
679
+ def _get_animated_resource_color(self, resource, value):
680
+ """Color animado según el recurso y valor"""
681
+ base_colors = {
682
+ 'pesos': (255, 215, 0), # Dorado
683
+ 'dolares': (100, 255, 100), # Verde dólar
684
+ 'comida': (255, 140, 0), # Naranja
685
+ 'esperanza': (100, 149, 237), # Azul esperanza
686
+ 'solidaridad': (255, 105, 180), # Rosa solidario
687
+ 'trabajo': (139, 69, 19) # Marrón trabajo
688
  }
689
+
690
+ base_color = base_colors.get(resource, (255, 255, 255))
691
+
692
+ # Intensidad según valor
693
+ if value > 70:
694
+ multiplier = 1.0
695
+ elif value > 30:
696
+ multiplier = 0.8
697
+ else:
698
+ multiplier = 0.6
699
+
700
+ # Efecto pulsante en valores críticos
701
+ if value < 20:
702
+ pulse_effect = 0.8 + 0.4 * math.sin(time.time() * 4)
703
+ multiplier *= pulse_effect
704
+
705
+ return tuple(int(c * multiplier) for c in base_color)
706
 
707
+ def create_ai_enhanced_interface():
708
+ """Interfaz mejorada con IA"""
709
+ game = EnhancedArgentinaGame()
710
 
711
  with gr.Blocks(
712
+ title="🇦🇷 CRISIS Y CORAJE - Con IA Narrativa",
713
+ theme=gr.themes.Soft(),
714
+ css="""
715
+ .enhanced-header {
716
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
717
+ border-radius: 15px;
718
+ padding: 25px;
719
+ color: white;
720
+ text-align: center;
721
+ margin: 15px 0;
722
+ }
723
+ .action-button {
724
+ font-size: 1.1em;
725
+ padding: 12px;
726
+ margin: 5px;
727
+ }
728
+ """
729
  ) as interface:
730
 
731
  gr.HTML("""
732
+ <div class="enhanced-header">
733
+ <h1 style="font-size: 2.8em; margin: 0; text-shadow: 2px 2px 4px rgba(0,0,0,0.7);">
 
734
  🇦🇷 CRISIS Y CORAJE
735
  </h1>
736
+ <h2 style="font-size: 1.4em; margin: 10px 0; opacity: 0.9;">
737
+ Con Inteligencia Artificial Narrativa
738
  </h2>
739
+ <p style="font-size: 1.1em; margin: 5px 0; opacity: 0.8;">
740
+ Supervivencia, Solidaridad y Cultura Argentina Powered by Groq AI
741
  </p>
742
  </div>
743
  """)
 
745
  with gr.Row():
746
  with gr.Column(scale=2):
747
  game_display = gr.Image(
748
+ label="🌆 Tu Barrio Argentino",
749
  width=900,
750
  height=600
751
  )
752
 
753
+ gr.Markdown("### 🎮 ACCIONES DE SUPERVIVENCIA")
754
  with gr.Row():
755
+ work_btn = gr.Button("💼 TRABAJAR", variant="primary", elem_classes="action-button")
756
+ help_btn = gr.Button("🤝 AYUDAR VECINOS", variant="secondary", elem_classes="action-button")
757
+ rebusque_btn = gr.Button("💡 REBUSQUE", variant="stop", elem_classes="action-button")
758
 
759
  with gr.Row():
760
+ save_btn = gr.Button("💵 COMPRAR DÓLARES", variant="primary", elem_classes="action-button")
761
+ asado_btn = gr.Button("🔥 HACER ASADO", variant="stop", elem_classes="action-button")
 
762
 
763
  with gr.Column(scale=1):
764
  gr.Markdown("### 📊 ESTADO DE SUPERVIVENCIA")
765
  status_display = gr.JSON(
766
+ label="📈 Recursos y Análisis IA",
767
+ value=game.get_enhanced_status()
768
  )
769
 
770
+ gr.Markdown("### 🗞️ NOTICIAS DEL BARRIO")
771
  news_display = gr.Textbox(
772
+ value="🎮 ¡Bienvenido a Crisis y Coraje con IA! Los diálogos son generados dinámicamente por inteligencia artificial para crear una experiencia narrativa única.",
773
+ label="📺 Canal Barrial + IA",
774
  lines=4,
775
  interactive=False
776
  )
777
 
778
+ gr.Markdown("### 🤖 SISTEMA DE IA")
779
+ ai_status = gr.HTML(f"""
780
+ <div style="background: #2d3436; color: white; padding: 15px; border-radius: 10px; margin: 10px 0;">
781
+ <p><strong>🧠 IA Narrativa:</strong> {'🟢 Activa' if game.ai_dialogue.ai_enabled else '🔴 Inactiva'}</p>
782
+ <p><strong>🎭 Personajes:</strong> Doña Rosa, El Checo, Comerciante</p>
783
+ <p><strong>🎯 Características:</strong></p>
784
+ <ul style="margin: 5px 0; padding-left: 20px; font-size: 0.9em;">
785
+ <li>Diálogos contextuales dinámicos</li>
786
+ <li>Análisis económico inteligente</li>
787
+ <li>Noticias del barrio generadas</li>
788
+ <li>Narrativa adaptativa al progreso</li>
789
  </ul>
 
790
  </div>
791
  """)
792
+
793
+ # Botón para generar noticias frescas
794
+ news_btn = gr.Button("📰 GENERAR NOTICIAS IA", variant="secondary")
795
+
796
+ # Conectar acciones principales
797
+ work_btn.click(
798
+ fn=lambda: game.process_enhanced_action("trabajar"),
799
+ outputs=[game_display, status_display, news_display]
800
+ )
801
+ help_btn.click(
802
+ fn=lambda: game.process_enhanced_action("ayudar_vecinos"),
803
+ outputs=[game_display, status_display, news_display]
804
+ )
805
+ rebusque_btn.click(
806
+ fn=lambda: game.process_enhanced_action("buscar_rebusque"),
807
+ outputs=[game_display, status_display, news_display]
808
+ )
809
+ save_btn.click(
810
+ fn=lambda: game.process_enhanced_action("ahorrar_dolares"),
811
+ outputs=[game_display, status_display, news_display]
812
+ )
813
+ asado_btn.click(
814
+ fn=lambda: game.process_enhanced_action("hacer_asado"),
815
+ outputs=[game_display, status_display, news_display]
816
+ )
817
+
818
+ # Botón de noticias IA
819
+ news_btn.click(
820
+ fn=lambda: game.get_neighborhood_news(),
821
+ outputs=news_display
822
+ )
823
 
824
+ # Estado inicial
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
825
  interface.load(
826
+ fn=lambda: (
827
+ game.renderer.render_argentina_frame(game.game_state),
828
+ game.get_enhanced_status(),
829
+ "🎮 ¡Crisis y Coraje con IA activado! Cada acción generará diálogos únicos y contextuales. Los personajes reaccionarán de manera inteligente a tus decisiones."
830
+ ),
831
  outputs=[game_display, status_display, news_display]
832
  )
833
 
834
  return interface
835
 
836
  if __name__ == "__main__":
837
+ interface = create_ai_enhanced_interface()
838
+ interface.launch(share=True, show_error=True, show_api=False)