Desentrañando el juez de CMS: Parte 1

En el sub-mundo de la programación competitiva, lo más habitual es que las soluciones de l@s participantes a los problemas de un concurso se envíen a un juez en línea para que éste determine si la solución es correcta o no. Estos jueces también son muy usados para practicar resolviendo problemas de competencias anteriores, y es una de las herramientas principales empleadas en el entrenamiento de l@s aficionad@s.

Un tipo particular de concursos de programación es la Olimpíada de Informática, dónde el formato de las competencias tiene varias diferencias con otras clases de concursos (como la ICPC, Codeforces, etc). El principal sistema usado para gestionar estas Olimpíadas es el Contest Management System (CMS, no confundir con Content Management System), diseñado para soportar el formato de Olimpíada. Con el objetivo de desarrollar un juez local que el/la usuari@ pueda usar para entrenar sin depender de un servidor, he estado estudiando el código fuente de la última versión estable de CMS. En este artículo mostraré un vistazo general al funcionamiento de la función de evaluación del mismo, y en las otras partes profundizaré en otros aspectos relevantes para el desarrollo de un juez local.

Para que puedas entender el contenido del artículo, espero que sepas programación en Python (incluyendo creación y uso de módulos, programación orientada a objetos en un nivel intermedio) y conceptos básicos de sistemas de bases de datos.

Generalidades: ¿Cómo rayos funciona CMS?

Lo primero a tener en cuenta es que CMS no es únicamente un juez, es un sistema muy complejo para gestionar Olimpíadas de Informática. Entre otras funcionalidades, permite gestionar cuentas, pedir y dar aclaraciones sobre los enunciados de los problemas, generar una tabla de puntuación, ejecutar pruebas personalizadas, configurar concursos y meta datos de los problemas, mandar archivos para imprimir. Por eso es que CMS está organizado de forma modular, de modo que los módulos (en el código fuente y en la documentación oficial le llaman servicios) puedan ejecutarse en distintos servidores y de de forma distribuida.

A pesar de que CMS tenga un diseño modular, para el desarrollo de un juez local evitaré el uso de los servicios que se encuentran en el directorio cms/service y todo lo que tenga que ver con gestión de servidores, incluyendo cms/io y cms/server.

Toda la información relacionada a una competencia se guarda en una base de datos PostgreSQL, un sistema de gestión de base de datos relacional con características de un sistema orientado a objetos. Todos los servicios de CMS dependen de esta base de datos, lo que tiene sentido pues así no es necesario que cada módulo maneje sus propios datos de manera separada.

Respecto de los lenguajes de programación y tecnologías empleadas, el backend de CMS está principalmente escrito en Python y hace uso de SQLAlchemy, un conjunto de herramientas para manejar bases de datos y asociar clases a las relaciones de la base de datos (dichas clases están definidas en el código de CMS). SQLAlchemy también crea objetos en Python para trabajar con los tipos de datos de PostgreSQL.

Los archivos que importan

Los principales archivos que se usan para juzgar una solución enviada al sistema están en la carpeta cms/grading. A continuación una breve descripción del contenido de la carpeta:

-init.py: Instrucciones que se ejecutan al importar grading como módulo (de Python, no los servicios de CMS). Establece qué clases y funciones se pueden usar para el usuario del módulo.

-language.py: Contiene dos clases base para el manejo de los lenguajes soportados por CMS, que definen propiedades y métodos abstractos que las clases específicas para cada lenguaje implementan.

-languages: Directorio con los archivos para cada lenguaje soportado, dónde están las clases que implementan las propiedades y métodos abstractos definidos en language.py

-languagemanager.py: Algunas funcionalidades para trabajar con las clases de los lenguajes de programación presentes en languages.

-scoring.py: Varias funciones para computar el puntaje obtenido por un(a) participante en un problema, con distintos métodos que han sido usados en la IOI.

-scoretypes: Directorio con clases para distintas formas de asignar una puntuación a una solución. En la documentación oficial (en inglés) se detalla cómo es que funcionan.

-steps: Los archivos de este directorio contienen las clases y funciones que efectúan las distintas fases de evaluación de una solución: la compilación, la evaluación (ejecución frente a casos de prueba, una evaluación corresponde a un caso distinto), comparación con la salida “correcta” (es con la que cuenta el juez, pero no necesariamente es correcta, pues el autor (o autora) de la solución oficial también puede cometer errores), generación de mensajes para el/la participante.

-Job.py: Un Job es una unidad básica de trabajo realizada por un Worker, que es el servicio que se dedica a procesar los envíos. Para prescindir de los servicios voy a remover las funciones que dependan de algún servicio. La clase Job tiene métodos para crear trabajos de compilación y evaluación a partir de un envío.

-tasktypes: Directorio con los distintos tipos de problemas. En la documentación oficial (en inglés) se detallan sus características distintivas. Aquí se definen los métodos para compilar y evaluar una solución a partir de un trabajo (Job) de compilación y evaluación, respectivamente.

-Sandbox.py: Pequeña máquina virtual dónde se ejecutan las soluciones en un entorno aislado del sistema operativo para evitar que la solución haga uso de una función prohibida (por ejemplo, conectarse a internet o manipular ficheros).

Conclusiones

Muchas de las clases dentro de la carpeta tienen funcionalidades para trabajar con los servicios de CMS. Para un juez local, lo más sencillo sería recortar dichas funciones para facilitar el desarrollo. Afortunadamente no son demasiadas y al parecer es razonable hacer recortes y conservar el funcionamiento básico de las clases y funciones. También voy a estudiar conceptos de bases de datos, además del uso de SQLAlchemy y PostgreSQL, porque el código de cms/grading si hace uso de la base de datos, y es necesaria para muchas funciones importantes, como la creación de trabajos y la compilación y evaluación de soluciones.

En un próximo post resumiré el modelo de datos y qué partes son las más importantes para juzgar una solución.