Files

383 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md
Guía de trabajo para agentes de IA (y humanos) que colaboran en este repositorio.
---
## 1. Qué es este proyecto
Este repositorio es un **libro de ejercicios de programación en lenguaje C**.
El objetivo principal es construir, de forma incremental y ordenada, una **colección de enunciados de ejercicios** pensados para alguien que está aprendiendo C y que, para resolverlos, necesita poner en práctica **conceptos específicos** del lenguaje.
Cada enunciado:
- Presenta un **problema de la vida real** como contexto.
- Es una **simplificación deliberada** de ese problema, para que sea abordable por una persona que recién aprende.
- Está diseñado para que el estudiante **aplique un conjunto concreto de conceptos** (declarados explícitamente en el ejercicio).
- **Nunca incluye la solución en código.** El libro provee el problema, no la respuesta.
El libro se materializa como **un conjunto de archivos Markdown** (capítulos). El repositorio no contiene código C de solución; contiene enunciados.
---
## 2. Reglas no negociables
Estas reglas tienen prioridad sobre cualquier otra instrucción. Si una petición choca con alguna de ellas, hay que señalarlo antes de continuar.
1. **NUNCA generar el código de solución.** No se escribe, insinúa ni deja entrever la implementación completa del enunciado. Se permiten, como máximo, fragmentos ilustrativos de *entrada/salida esperada* (texto por consola), no de lógica del programa.
2. **Los enunciados siempre en español.** El texto dirigido al estudiante (título, contexto, consigna, ejemplos, aclaraciones) va en español, con ortografía y redacción cuidadas.
3. **Contexto real, complejidad simplificada.** Todo enunciado parte de una situación del mundo real, pero recortada a lo esencial para que sea resoluble con los conceptos objetivo. Nunca convertir el ejercicio en un proyecto de ingeniería.
4. **Conceptos explícitos.** Cada ejercicio declara qué conceptos de C debe ejercitar. La consigna tiene que poder resolverse **usando esos conceptos** y no otros innecesarios.
5. **Claridad absoluta.** Un enunciado ambiguo es un enunciado roto. Debe quedar claro qué entra, qué sale y qué se espera. Se recomienda incluir un ejemplo.
6. **Identificadores pueden sugerirse en inglés.** Los nombres de variables, funciones y tipos sugeridos van **en inglés** (idioma de facto del código). No es obligatorio imponerlos, pero sí la convención del repositorio.
---
## 3. Anatomía de un ejercicio
Todo ejercicio sigue esta plantilla. Los campos marcados como *opcionales* pueden omitirse cuando aportan poco.
````markdown
### Ejercicio N.M — [Título corto en español]
**Conceptos** · `concepto-1`, `concepto-2`, `concepto-3`
**Contexto** · Situación real en 1–3 oraciones (qué problema del mundo real motiva el ejercicio).
Aclarar de forma explícita que es una simplificación.
**Consigna** · Qué hay que lograr. Enumerable si tiene varios pasos. Sin ambigüedad.
**Entrada** · Qué recibe el programa (formato, tipo y rango esperado).
**Salida** · Qué debe producir, con el formato esperado.
**Ejemplo** *(opcional)* ·
```
Entrada: ...
Salida: ...
```
**Identificadores sugeridos** *(opcional)* · `average`, `studentList`, `MAX_ITEMS`
(En inglés. Se ofrecen como guía, no como obligación.)
**Restricciones / pistas** *(opcional)* · Qué construcciones usar,
qué evitar, casos borde a considerar. NUNCA la lógica de la solución.
**Criterios de aceptación** · Lista verificable de qué debe cumplir una solución correcta.
````
### Regla de oro del ejemplo
El bloque de **Ejemplo** ilustra **entrada y salida** (o un caso de uso textual). Jamás muestra
cómo se calcula internamente. Está permitido describir con palabras el resultado;
está prohibido mostrar el algoritmo.
---
## 4. Estructura del libro (archivos)
El libro vive bajo un directorio raíz de contenido. Se propone:
```
c-programming/
├─ AGENTS.md # este archivo (reglas del proyecto)
├─ README.md # presentación del libro e índice general
├─ book/ # FUENTE: capítulos en Markdown
│ ├─ 00-introduccion.md
│ ├─ 01-conceptos-basicos.md
│ ├─ 02-variables-y-tipos.md
│ ├─ 03-operadores-y-expresiones.md
│ ├─ 04-estructuras-de-control.md
│ ├─ 05-funciones.md
│ ├─ 06-arreglos-y-cadenas.md
│ ├─ 07-punteros.md
│ ├─ 08-structs-y-uniones.md
│ ├─ 09-memoria-dinamica.md
│ ├─ 10-archivos.md
│ ├─ 11-estructuras-de-datos.md
│ └─ 12-arenas.md
├─ dist/ # SALIDA: un PDF por cada capítulo trabajado
│ └─ 12-arenas.pdf
├─ assets/
│ └─ pdf/
│ └─ print.css # hoja de estilo canónica de los PDF
└─ .opencode/
└─ skills/
└─ book-pdf/SKILL.md # procedimiento para generar los PDF
```
- **Un archivo por tema/concepto principal.**
- El `README.md` mantiene el **índice** y el enlace a cada capítulo.
- Nombres de archivo en **kebab-case** y con prefijo numérico para conservar el orden.
- El prefijo numérico del archivo se usa también para numerar los ejercicios (`### Ejercicio 04.2`).
---
## 5. Progresión de conceptos
Los ejercicios deben seguir una dificultad creciente. Orden de referencia de los conceptos:
1. Estructura de un programa, `main`, `#include`, compilación.
2. Variables, tipos primitivos, constantes.
3. Operadores aritméticos, lógicos y relacionales, precedencia.
4. Condicionales: `if`, `else`, `switch`.
5. Bucles: `for`, `while`, `do-while`.
6. Funciones: parámetros, retorno, alcance, prototipos.
7. Arreglos y cadenas de caracteres.
8. Punteros y aritmética de punteros.
9. `struct`, `typedef`, `union`, `enum`.
10. Memoria dinámica: `malloc`, `free`, manejo de errores.
11. Archivos: lectura y escritura con `stdio.h`.
12. Estructuras de datos simples (listas, pilas, colas) y algoritmos básicos de ordenamiento/búsqueda.
Un ejercicio puede combinar conceptos de niveles anteriores, pero **no debe exigir conceptos de niveles posteriores** sin declararlos como objetivo.
---
## 6. Convenciones de redacción
- **Tono**: docente, claro y motivador. Tratar al lector de "vos" o de forma neutra, de manera consistente dentro de un capítulo.
- **Idioma del texto**: español. Términos técnicos del lenguaje pueden quedar en inglés cuando sea lo natural (`array`, `pointer`, `struct`), pero preferir el término en español con el inglés entre paréntesis la primera vez.
- **Identificadores sugeridos**: en inglés, `lowercase_snake_case` o `camelCase` según se elija por capítulo, pero **consistente** dentro del mismo.
- **Números de ejercicio**: `N.M`, donde `N` es el número del capítulo y `M` el del ejercicio.
- **Extensión**: enunciados concisos. Si un ejercicio crece demasiado, dividirlo.
- **Un problema real por ejercicio**, con su simplificación aclarada.
---
## 7. Estilo didáctico al explicar conceptos ("para tontos")
Los capítulos no solo enuncian ejercicios: también **explican** los conceptos que el lector necesita.
Esa explicación sigue un estilo llano, concreto y progresivo —el mismo que se usó en
`book/14-entrada-salida-estandar.md`—, pensado para que el lector **entienda de verdad** y no solo
lea. Estas reglas aplican a **todo capítulo** que explique conceptos.
**Analogía cotidiana primero.** Todo concepto arranca con una comparación del mundo real que el lector
ya domina; recién después aparece el término técnico. Ejemplos del capítulo 14: las tres tuberías
(`stdin`/`stdout`/`stderr`) son "una fábrica"; `getchar` es "sacar caramelos de a uno"; el búfer es
"el villano de la película". La analogía se sostiene durante toda la explicación; no se abandona a la
primera frase.
**Títulos con gancho, no etiquetas.** En vez de "Introducción a `getchar`", el título promete algo
concreto: "`getchar`: el caramelito de a uno". Lo mismo vale para las subsecciones.
**Explicar el POR QUÉ, no solo el qué.** Cada regla llega con su motivo. No alcanza con decir "guardá
en `int`, no en `char`": hay que explicar por qué (tiene que representar los 256 bytes posibles **y**
un valor extra, `EOF`).
**Voz cercana y frases cortas.** Se trata al lector de "vos" (ver sección 6). Párrafos breves, en
presente, sin rodeos. Se permite —y se espera— marcar la idea clave con **negrita** y con MAYÚSCULAS
ocasionales.
**Cómo estructurar un capítulo largo:**
- Dividirlo en **partes** con un **índice** al inicio. La tabla lleva, por cada parte, "la idea en una
frase".
- Después de cada concepto, un **bloque de práctica** con uno o más ejercicios cortos, antes de
avanzar al siguiente concepto.
- Cerrar con un apartado tipo "lo que te llevás": las ideas clave en pocos bullets, y el puente al
capítulo siguiente.
**Recursos que se repiten:**
- **Apodos para las trampas** clásicas: "la trampa N.º 1", "el bug más famoso del principiante", "el
villano de la película".
- **Blockquotes** (`>`) para notas, advertencias y "momentos ajá": "Momento ajá", "Ojo con esto",
"Para guardar", "Truco de laboratorio". En el PDF todas se dibujan con fondo de color (sección 10).
- **Tablas comparativas** para contrastar opciones o señales parecidas (p. ej. `EOF` vs `'\0'` vs
`'\n'`).
- **Diagramas ASCII** para mostrar lo visual: flujos conectados, los dos búferes en serie.
- **Código ilustrativo comentado en lenguaje llano**: cada línea que introduce algo nuevo lleva un
comentario claro y **de varias líneas** que dice exactamente qué hace. Los bloques declaran su
lenguaje en el fence para que `highlight.js` los resalte (sección 10).
- **Escenario de prueba** en cada ejercicio: un bloque `text` con la entrada y la salida esperada,
para que el lector pueda **comprobar** su solución.
**El límite que NO se cruza.** Este estilo permite **código ilustrativo para explicar un concepto**
(una llamada a una función, un esqueleto mínimo, un patrón genérico), pero **nunca** la solución de un
ejercicio. Las reglas no negociables (sección 2) siguen mandando: se entrega el **problema**; la
lógica que resuelve la consigna la escribe el lector. El código de ejemplo sirve para **entender** una
herramienta, jamás para resolver un enunciado del libro.
---
## 8. Lo que está prohibido
- Escribir la solución, total o parcial, del enunciado (incluida la lógica en pseudocódigo).
- Convertir el ejercicio en un proyecto grande, con build system, múltiples archivos o dependencias externas.
- Usar bibliotecas que no sean la librería estándar de C, salvo que sea el tema explícito del capítulo.
- Dejar conceptos de la consigna sin declarar o usar-`sin-avisar` conceptos fuera del objetivo.
- Enunciados ambiguos, incompletos o sin criterios de aceptación.
- Mezclar idiomas dentro de un mismo enunciado (salvo la excepción de identificadores sugeridos).
---
## 9. Flujo para agregar contenido
Checklist al crear o editar un ejercicio:
1. Elegir el capítulo (archivo) y el número de ejercicio.
2. Declarar los **conceptos** objetivo.
3. Redactar el **contexto real** y aclarar la simplificación.
4. Escribir la **consigna**, entrada y salida de forma inequívoca.
5. Agregar un **ejemplo** de entrada/salida si aporta claridad.
6. Sugerir **identificadores en inglés**.
7. Añadir **criterios de aceptación** verificables.
8. Revisar que **no haya código de solución**.
9. Verificar idioma (español), ortografía y consistencia de estilo.
10. Actualizar el índice del `README.md` si se agregó un capítulo.
> Recordatorio permanente: se entrega el **problema**, nunca la **respuesta**.
---
## 10. Generación de PDF (`dist/`)
Cada capítulo trabajado se publica como **PDF** en `dist/`, con el **mismo nombre** que su
Markdown: `book/12-arenas.md` → `dist/12-arenas.pdf`.
- Los PDF se generan con el MCP **`md-to-pdf`** (herramienta `md-to-pdf_markdown_to_pdf`).
**No** instalar pandoc/LaTeX ni armar un pipeline propio: ya existe.
- El diseño es **único y compartido**: vive en `assets/pdf/print.css`. No se estiliza capítulo
por capítulo.
- El procedimiento completo y los **parámetros fijos** de generación están en la skill del
proyecto: `.opencode/skills/book-pdf/SKILL.md`. Hay que **seguirla siempre** para que todos los
PDF tengan el mismo diseño.
Reglas de diseño (resumen):
- **Fuente de código:** monoespaciada, distinta de la fuente del cuerpo (serif). Todo bloque de
código declara su lenguaje en el fence (```` ```c ````, ```` ```bash ````, ```` ```text ````);
así `highlight.js` aplica **resaltado de sintaxis**. Un bloque sin lenguaje no se resalta
(las trazas de consola van como ```` ```text ````).
- **Notas / advertencias:** se escriben como **blockquote** (`>`). En el PDF **todas** se dibujan
igual, con un **fondo de color** que resalta del blanco de la hoja.
- **Títulos sin huérfanos:** un título (`h1`–`h4`) **nunca** puede quedar solo al pie de página:
siempre tiene que llevar **al menos tres líneas de contenido** debajo, en la misma hoja. Si no
caben, se fuerza un **salto de página** antes del título. `print.css` ya lo aplica
(`break-after: avoid` en los títulos y en el primer párrafo que los sigue, más `orphans`/`widows: 3`);
no romper esas reglas.
- `printBackground` debe estar **activo** (si no, no se pintan los fondos de código y notas).
- Encabezado, pie de página y **numeración de páginas** fijos.
> Si se modifica `assets/pdf/print.css`, hay que **regenerar todos** los capítulos para que ningún
> PDF quede con un diseño distinto.
---
## Protocolo de escritura de archivos extensos
Cuando el agente (humano o IA) necesita escribir un archivo Markdown de contenido grande
(≥ 600 líneas, como los capítulos del libro), **no usar una única llamada a `write` con todo el contenido**.
Los herramientas de escritura pasan el contenido dentro de un string JSON y los caracteres especiales
(tres backticks ```, `$`, `{`, `}`, `\`, comillas) pueden romper el parseo.
### Enfoque correcto (confirmado en producción)
1. **Escribir con `write` solo los primeros ~500-600 líneas**, hasta la primera sección completa
(hasta un `---` o final de una parte). El archivo se crea correctamente porque el contenido
es manejable para el parser JSON.
2. **Usar `edit` para ir agregando las secciones restantes**. Cada llamada a `edit` reemplaza
una cadena corta (`oldString`) por otra más larga (`newString`). La cadena a buscar es siempre
muy breve (ej: el último texto del archivo actual) y la cadena de reemplazo incluye la nueva sección.
```
oldString: "- [ ] Termina limpiamente al escribir \"exit\"." ← solo la última línea existente
newString: "- [ ] Termina limpiamente al escribir \"exit\".\n\n---\n# PARTE 5 — ..." ← misma + nueva sección
```
3. **Verificar el conteo de líneas** con un bash/PowerShell simple después de cada edit grande,
para confirmar que la sección se incorporó correctamente:
```
Get-Content book\22-file-descriptors.md | Measure-Object -Line
```
### Por qué fallaba el enfoque anterior
Un archivo de capítulo tiene ~1200-1500 líneas con:
- Bloques de código C con backticks triples (```` ```c ````) que el parser JSON confunde
- Strings con comillas escapadas (`\"`) que colisionan con las del string JSON
- Caracteres especiales como `$` en ejemplos de shell o `\n` en strings C
Con chunks de ≤ 600 líneas, el contenido cabe en un string JSON sin romper el parseo.
### Regla práctica
> **Nunca escribir más de 600 líneas de una sola vez con `write`.** Si el contenido total es mayor,
> usar `write` para la primera parte y `edit` sucesivo para el resto.
---
## 11. Corrección de caracteres malformados (mojibake)
Los capítulos en español pueden acumular **codificación doble**: bytes UTF-8 almacenados como si
fuera Latin-1/CP1252, lo que genera mojibake visible como `ú`, `Práctica` o caracteres
`\xef\xbf\xbd` (replacement char) en vez de "práctica". Esto pasa cuando el parser JSON del tool
de escritura corrompe los bytes multibyte.
### Cómo detectar
```python
import os
path = r"C:\Users\horacio\Desarrollo\c-programming\book\TU-CAPITULO.md"
with open(path, "rb") as f:
raw = f.read()
# Si hay bytes no ASCII pero el archivo se decodifica como UTF-8 bien formado,
# puede haber entidades HTML o caracteres dobles codificados.
try:
text = raw.decode("utf-8")
except UnicodeDecodeError:
print("NO es UTF-8 — hay corrupción de encoding")
# Buscar replacement char U+FFFD (EF BF BD)
if b"\xef\xbf\xbd" in raw:
print("Encontrado replacement char — el archivo tiene mojibake")
# Buscar entidades HTML sueltas (ú, é, ñ)
for ent in [b"ú", b"é", b"ñ", b"á", b"ó", b"ú"]:
if ent in raw:
print(f"Entidad HTML detectada: {ent}")
```
### Cómo corregir (reconstruir UTF-8 limpio)
Si el archivo está corrupto, **borrar y reconstruir** desde un script Python que escriba en
UTF-8 nativo. El pattern probado en producción es:
1. **Borrar el archivo corrupto.** No intentes repararlo con `edit` — si ya tiene entidades HTML
mezcladas con bytes dobles, la reparación parcial deja residuos.
2. **Escribir con un script Python que use `encoding='utf-8'`.** El script construye el contenido
como strings de Python (que son Unicode internos) y lo escribe como bytes UTF-8 limpios.
No uses `write` del agente para contenido > 600 líneas.
```python
# rebuild_chapter.py
chapter_file = r"C:\Users\horacio\Desarrollo\c-programming\book\25-drm-kms.md"
with open(chapter_file, "w", encoding="utf-8") as f:
f.write("# Capítulo 25 — DRM/KMS\n") # texto en Unicode → se escribe como UTF-8 limpio
```
3. **Si el contenido es largo**, dividí en chunks de ~250-300 líneas y uso `open(..., 'a')` para
append cada chunk al archivo ya creado.
4. **Verificar** que no queden caracteres corruptos:
```python
raw = open(path, "rb").read()
text = raw.decode("utf-8", errors="replace")
assert "\ufffd" not in text # sin replacement chars
for ent in [b"ú", b"é", b"ñ"]:
assert ent not in raw # sin entidades HTML sueltas
```
### Regla de prevención
> **Nunca pasar texto con acentos/ñ directamente en un string JSON `write`.** Si el contenido del
> capítulo tiene caracteres UTF-8 multibyte, escribirlo como un bloque grande en `write` puede
> corromper la codificación. La forma segura es: script Python que construya el Unicode interno y
> lo escriba con `encoding="utf-8"`.