2026 semestre 2
En parejas o equipos de tres personas
Se les entrega un juego de Godot en C# que ya funciona, pero está mal organizado.
El taller no es hacer el juego. Es reorganizarlo aplicando correctamente los conceptos de POO, y extenderlo sin romper lo que ya anda.
Un vendedor de madera (Pawn) recorre el mapa. Hoy:
⬇ Descargar el diagrama (Draw.io) — es el mínimo. Lo que haga falta para limpiar el código va por encima.
Hoy Lancer.cs, Goblin.cs y Monk.cs tienen el mismo
bloque de código copiado tres veces: el campo _animator, el
_Ready() y un _Process() vacío.
NPC con lo comúnLancer, Goblin y Monk deben derivar de NPCEste es el corazón del taller. Hoy el vendedor pregunta por el tipo concreto:
// ANTES (Seller.cs)
if (_npc is Lancer lancer)
lancer.Buy(this);
// DESPUES
if (_npc is IBuyer buyer) buyer.Buy(this);
if (_npc is IThief thief) thief.Steal(this);
Crear IBuyer (Price, Buy) e IThief
(Steal), y que el Seller deje de conocer clases concretas.
El proyecto ya trae el sprite, la escena monk.tscn y un Monk.cs vacío.
Monk : NPC, IBuyerworld.tscn, porque todavía no está en el mapa
Prueba de fuego: si el refactor está bien hecho, el Seller no se toca para que esto
funcione.
Goblin : NPC, IThief con su método StealRegla concreta: si el vendedor no tiene madera, el Goblin no puede robar y no se descuenta nada.
Transaction con NPC y
TotalCounts como mínimo, y sus dos especializaciones:
Sale y Theft
Seller compone la lista: las crea, las posee y mueren con él
Una transacción por NPC: venderle dos veces al mismo Lancer
no crea dos instancias — incrementa el TotalCounts de la que ya
existe.
La tecla Z debe imprimir el historial de transacciones: qué NPC, qué tipo de transacción y cuánto acumula cada uno.
Ustedes deciden el formato y qué más guarda cada transacción. Justifíquenlo en la sustentación.
Debe seguir andando: moverse, animarse, el contador de madera, el contador de monedas, el indicador de "X para vender" y la venta al Lancer.
La regla debe salir del diseño, no de un condicional:
if (npc is Lancer) o cualquier chequeo de tipo concretoName, strings o tags para decidir si vende o le robanesComprador o esLadron_animator + _Ready() en cada NPCEsto se evalúa aparte:
_Process() no lleva lógica de negocio: orquesta y delega a métodos con
nombre[Export]El diagrama que entregan no es el que les di.
Espejo exacto. Si crearon una clase extra para limpiar algo, va al diagrama.
NPC y eliminación de la duplicaciónIBuyer / IThief y eliminación
del chequeo de tipo concretoMonk como segundo comprador con precio propioGoblin.Steal funcionandoSale / Theft) e historial
con ZEl taller no será evaluado si:
No hay excepciones.
En parejas o equipos de tres personas
Construir desde cero una aplicación de escritorio en .NET C# con Windows Forms que modele una tienda híbrida: vende productos físicos y productos digitales.
El tema lo eligen ustedes — videojuegos, películas, música, libros, lo que les apasione. El dominio es suyo; los requisitos no.
Porque los dos productos se comportan distinto, y ahí está el taller:
Si la venta tiene que preguntar de qué tipo es cada producto para cobrarlo, el diseño falló.
Constrúyanlos en ese orden. Cada uno se apoya en el anterior, y la venta es la que pone a prueba todo lo demás.
Lo primero es decidir qué datos guarda cada uno:
La regla: lo común sube a la clase base. Lo propio se queda abajo. Si un atributo no aplica a los dos, no va en la base.
Crear un producto físico no es lo mismo que crear uno digital, y el formulario lo tiene que mostrar.
Más el resto de operaciones CRUD
¿Qué pasa si eliminan un producto que ya fue vendido?
Guarden la respuesta. La necesitan en el CRUD 3.
El más simple de los tres. Aprovéchenlo para dejar el patrón limpio.
Otra decisión suya: ¿se puede eliminar un cliente que ya compró? Si dicen que no, expliquen por qué. Si dicen que sí, expliquen qué pasa con sus ventas.
Acá se junta todo. Una venta es:
El formulario: elegir cliente, ir agregando productos con cantidad, ver el total en vivo y guardar.
SaleDetail
La venta no guarda productos. Guarda SaleDetail,
y cada detalle copia lo que se vendió:
Porque si la venta apunta directo al producto, pasa esto:
Una venta es un registro histórico. Una vez registrada, nada de afuera la puede modificar. Eso es desacoplar.
Los tres CRUDs guardan en archivos .csv con
CsvHelper.
La prueba: cerrar la aplicación, volver a abrirla y que esté todo, tal como lo dejaron.
Un CSV es plano. Su modelo no lo es.
No hay una única respuesta correcta. Hay respuestas justificadas. La suya la explican en la sustentación.
.csv incluidosSaleDetail, reglas de stock y cálculo
del totalLa sustentación es individual y no tiene porcentaje. No suma: habilita.
El integrante que no sustente correctamente su entrega no tiene el taller evaluado — aunque el equipo haya entregado todo completo y funcionando.
No hay excepciones.
En parejas o equipos de tres personas
Construir una API REST con ASP.NET Core Web API en C# que exponga tres módulos:
Products, Receipt y
DetailReceipt.
En el Taller 2 la tienda tenía ventanas. Ahora no hay pantalla: cualquiera le habla por HTTP, y la API tiene que defenderse sola.
Constrúyanlos en ese orden. El detalle es el que pone a prueba todo lo demás.
Cada módulo se organiza en capas, y cada capa tiene un solo trabajo:
Las dependencias se inyectan por constructor y se registran en Program.cs.
GET /api/products — listarGET /api/products/{id} — consultar unoDatos mínimos: código, nombre, descripción, precio y stock.
El catálogo viene precargado en su archivo CSV. La API solo lo consulta; el stock cambia únicamente cuando se vende.
GET /api/receipts — listar facturasGET /api/receipts/{id} — la factura con sus detallesPOST /api/receipts — abrir una facturaPOST /api/receipts/{id}/details — agregar un producto a la
facturaPOST /api/receipts/{id}/close — cerrarlaUna factura tiene número, fecha, documento y nombre del cliente, un estado (abierta / cerrada) y un total que calcula la factura, no quien llama a la API.
Cada producto agregado a la factura se convierte en un DetailReceipt.
Igual que SaleDetail en el Taller 2, el detalle copia lo que se vendió:
No tiene endpoints propios: se crea desde la factura y se consulta con ella.
Y la pregunta de siempre: ¿qué pasa con una factura cerrada si mañana alguien cambia el precio del producto en el CSV? Respóndanlo con el diseño.
La API nunca expone las entidades. Entra un DTO, sale un DTO:
public record CreateDetailReceiptDto(int ProductId, int Quantity);
public record DetailReceiptDto(
int Id,
string Description,
decimal UnitPrice,
int Quantity,
decimal Subtotal);
Fíjense: para crear un detalle no se envía el precio ni el subtotal. Eso lo decide el servidor.
Sin base de datos. Todo se guarda en archivos .csv con
CsvHelper.
La prueba: detener la API, volver a levantarla y que esté todo, tal como lo dejaron.
.csv incluidosProducts: consultas del catálogoReceipt: agregar productos, cierre y cálculo
del totalDetailReceipt: copia del precio y reglas de
stockLa sustentación es individual y no tiene porcentaje. No suma: habilita.
El integrante que no sustente correctamente su entrega no tiene el proyecto evaluado — aunque el equipo haya entregado todo completo y funcionando.
No hay excepciones.