Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
Simulá partidas de Magic: The Gathering (Commander) online. Corré miles de partidas, probá tus decks y mirá cuánto gana cada uno.
Translation pending
GamesPython · JavaScriptGitHub @GaboariasOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
Motor de simulación de Magic: The Gathering, formato Commander, en Python puro (sin dependencias externas), con una interfaz web Next.js y una API serverless en Vercel. Sirve para medir con miles de partidas si un cambio a un mazo mejora su tasa de victoria. Cloud-first: desplegado en Vercel. El motor corre como funciones Python serverless bajo /api, y el frontend Next.js las consume.Read the full README ↗
Motor de simulación de Magic: The Gathering, formato Commander, en Python puro (sin dependencias externas), con una interfaz web Next.js y una API serverless en Vercel. Sirve para medir con miles de partidas si un cambio a un mazo mejora su tasa de victoria.
Cloud-first: desplegado en Vercel. El motor corre como funciones Python serverless bajo
/api, y el frontend Next.js las consume.
engine.py Motor de reglas. No conoce ninguna carta concreta.
policy.py IA (bots). Decide qué lanzar, activar, con qué atacar y cómo bloquear.
cards.py Biblioteca de cartas: constructores y efectos concretos.
cardsdb.py Parser Scryfall -> Card (mecánicas leídas del oracle text).
decks.py Listas de 99 + comandante (precons).
interactive.py Juego HUMANO (una persona + bots) para /play, con pausas de decisión.
run.py CLI y agregación estadística.
coverage.py Reporte de cuántas cartas tienen efecto real implementado.
tests/ Tests del motor (244: mana, combate, pila, copiar, reacciones,
costes alternativos, mecánicas complejas…).
api/ Funciones serverless de Vercel (Python). Entre otras:
simulate.py GET /api/simulate?matchup=lorehold,kang&n=200[&log=1&seed=0]
catalog.py GET /api/catalog (mazos + comandante + cobertura)
deck.py POST /api/deck (resolver decklist, brackets, precios)
cardsearch.py GET /api/cardsearch (corregir cartas no encontradas)
suggest.py POST /api/suggest (¿dónde sirve una carta? impacto 1-5 + razones;
acepta {card} o {cards:[...]} en bulk)
binderbuild.py POST /api/binderbuild (armá un mazo con el binder: asistente por
pasos -> comandante, tema/afinidad, sugerencias)
feedback.py POST /api/feedback (comentarios de usuarios -> Turso)
cloud.py, precons.py, samples.py, auth.py, supporter.py, …
app/ Frontend Next.js (App Router): simulador (/), /play, /watch,
editor de decks (/deck), reglas, y widget de feedback global.
docs/ ARCHITECTURE.md, API.md, MECHANICS.md (catálogo de mecánicas),
BACKLOG.md, ADDING_CARDS.md, DEPLOY.md, MULTIPLAYER_PLAN.md (futuro).
CLAUDE.md Reglas del proyecto para trabajar el motor.
Mecánicas destacadas: prioridad y pila (hechizos, habilidades activadas y disparadas pasan por la pila), reacciones a velocidad de instante, contrarrestar, copiar (clones completos, Fork/Twincast, Strionic, populate), planeswalkers, modales, X, y palabras clave de combate (vuelo, mortal, arrolla, amenaza, doble golpe, vínculo, infección…).
Costes alternativos / desde otra zona: flashback, jump-start, retrace, escape, unearth, embalm/eternalize, disturb, aftermath, foretell (exilio), madness, evoke, suspend, adventure y prepared (set FRA).
Mecánicas complejas modeladas: cascade, storm, replicate, buyback, kicker,
entwine, echo, cipher, level up, monstrosity, devour, exalted, extort, persist,
undying, soulbond, changeling; disparos "al lanzar / al ganar vida / cuando un
rival lanza"; efectos de reemplazo (dobladores de fichas/daño/contadores, "si
moriría, exíliala"); reducción de coste estática, tierra extra por turno,
ganar el control de todas las criaturas, "no se puede ganar vida / prevenir
daño / bloquear". Todo lo que requiere una decisión del jugador (elegir objetivo,
carta del cementerio/exilio, modo, X…) tiene su gesto de UI en /play. Ver
docs/MECHANICS.md.
Solo hace falta Python 3.11+ (nada que instalar):
python3 run.py # baseline: lorehold vs tricky vs kang, 200 partidas
python3 run.py lorehold kang # ese enfrentamiento, 200 partidas
python3 run.py lorehold kang -n 500 # 500 partidas
python3 run.py lorehold kang --log # una partida comentada turno a turno
python3 coverage.py # cobertura de cartas por mazo
python3 tests/test_engine.py # tests (o: python3 -m pytest tests/ -q)
Misma semilla ⇒ misma partida: run.one(keys, seed=i) es reproducible.
npm install
npm run dev # http://localhost:3000
En local, las funciones de /api/*.py requieren el runtime de Vercel
(vercel dev). Para probar solo el frontend contra datos reales, desplegá a
Vercel (abajo) o usá vercel dev con el CLI de Vercel instalado.
/api/*.py con el
runtime de Python (config en vercel.json).main publica producción; las ramas generan previews.vercel.json fija includeFiles: "*.py" para que las funciones serverless
empaqueten el motor (los .py de la raíz) junto al handler.
En /deck cada usuario tiene un perfil local (guardado en el navegador,
sin cuentas ni backend): un nombre y una lista de decks guardados
(app/localDecks.ts, localStorage). Puede guardar el deck que armó/editó,
recargarlo cuando quiera y simularlo. Los decks viven solo en ese dispositivo
(no sincronizan entre navegadores/personas); es la opción simple pedida. Para
cuentas reales cross-device haría falta auth + DB (p. ej. Supabase), no incluido.
En /deck el binder es la colección personal del usuario (localDecks.ts,
localStorage, con autosave a la nube/código por cambio). Funciones:
getCardCache/mergeCardCache): lo resuelto se guarda y
el binder no se re-analiza cada vez (sólo resuelve lo que falta)./api/suggest): por deck da impacto 1–5, si aporta
y las razones (fuera de color, qué hueco de rol cubre, qué tema refuerza)./api/binderbuild, asistente por pasos):
cuts), bracket
estimado y Game Changers en color para subir de bracket. Un botón
arma y guarda el deck (comandante + usables) y lo abre en el editor.
Las tierras básicas se tratan como un dado: no se listan como usables ni
como "fuera de color", y las sugerencias de tierras apuntan a las especiales
(fijado/rampeo).Los mazos propios viven como .md en presets/ (formato en
presets/FORMATO.md): una tabla por sección con
| n | Carta | Coste | P/T | Keywords | Tags | y una tabla de tierras con
| n | Carta | Produce | Tapeada |. mdparse.py los lee offline (sin
Scryfall) y decks.py los registra como mazos jugables — aparecen solos en el
simulador y como oponentes.
Reglas del importador (mdparse.py):
--- (lo de después son notas).## Comandante define el comandante; ? en una columna = error ruidoso
(no adivina); n = ? en básicas = rellena hasta 99.cardsdb) y el tipo coincide, usa la
versión con efecto; si no, la arma vainilla con los datos exactos de la
tabla. X en el coste se trata como 0.Para agregar un deck: dejá su .md en presets/ con ese formato.
El desplegable de precons (MTGJSON) es una comodidad y puede fallar según la
red del deploy. Alternativa siempre confiable: abrí el precon en Moxfield →
Export → copiá el texto (1 Nombre de Carta) → pegalo en /deck →
Resolver. Scryfall lo construye en Vercel. (La API de Moxfield no es pública
y bloquea automatización, por eso no se consume directo.)
La app permite cargar una lista de mazo, editar cartas y probar
variaciones midiendo la tasa de victoria (/deck en la web).
De dónde sale la info de cartas:
| Fuente | Qué aporta |
|---|---|
Scryfall /cards/collection | Datos reales de cada carta (coste, tipos, P/T, keywords, colores). Se llama en runtime desde la función serverless (Vercel), hasta 75 cartas por request. |
MTGJSON /api/v5/decks/ | Listas precon completas de Commander (para poblar un catálogo). |
| Moxfield / Archidekt | Export de texto del deck propio (1 Nombre de Carta). |
Cómo funciona la cobertura: las cartas con efecto programado (registro en
cardsdb.py) se simulan con sus habilidades; el resto se construye con stats
reales de Scryfall (vainilla pero con coste/P/T/tipos/keywords correctos), así
combate, maná y curva son fieles aunque el efecto especial no esté. No se
inventan datos (regla del proyecto): lo que no está registrado se resuelve por
Scryfall o queda marcado como no resuelto.
Piezas:
cardsdb.py — registro nombre→carta implementada + build_card_from_data
(dict tipo Scryfall → Card). Puro y testeable sin red.decklist.py — parser de listas (Moxfield/Archidekt/texto) y armado a 99.api/_scry.py — cliente Scryfall (stdlib, corre en Vercel).api/deck.py — POST /api/deck con action: "resolve" (tabla editable) y
action: "simulate" (winrate del deck editado vs un mazo registrado).app/deck/ — UI: pegar lista → tabla editable → probar variación.Nota: la resolución vía Scryfall requiere salida a internet. En Vercel funciona; en entornos de red restringida solo resuelven las cartas registradas y las tierras básicas.
Ver docs/ADDING_CARDS.md. Resumen: una entrada en
cards.py con sus ganchos y tags, y una línea en decks.py. Verificá con
python3 coverage.py y python3 run.py <a> <b> --log.
Ver CLAUDE.md y docs/ARCHITECTURE.md.
Las tres invariantes que ya causaron bugs y no se deben reintroducir:
engine.py no conoce cartas concretas. Si hace falta tocarlo para una
carta, lo que falta es un gancho genérico.produces devuelve OPCIONES, no producción simultánea. Una tierra dual
{R:1, W:1} vale UN maná.Game.SELF_SCOPED, o dispara para todos.