danielmaxx avatar danielmaxx committed f16da9a

First commit!

Comments (0)

Files changed (22)

+==============================================
+Framework for creating new programming contest
+==============================================
+
+:Autor:
+	"Daniel Ampuero" <danielmaxx@gmail.com>
+
+:Versión: 1.0 13/07/2012
+
+The next documents explains the directory scheme used on this framework.
+Please read it before you start.
+
+
+problems
+--------
+  Everything related with the problems should be placed here. Every problem
+  should have its own directory. The directory name will be the problem 
+  "code" name. By instance, if a there is a problem called "George Quest",
+  the directory could be named "quest". Inside each directory, there will
+  be the following files and directories (taking as example the problem quest):
+
+  ::
+
+    -- quest
+      | quest-someperson1.cpp
+      | quest-somperson2.java
+      | quest-someperson3.py
+      | generator-quest.py
+      | sample.in
+      | sample.out
+      | validator-quest.py
+      | -- statement
+          | quest.tex
+          | -- images
+              | quest.png
+
+
+  Obviously, not all problems directory should have solutions from every problem
+  setter, but it is suggested that every solution had its author name as a suffix.
+
+  In order to save time on this mechanic task, there is an script called "mkproblem.sh"
+  who will create this directory structure for you. It will be explained later.
+
+judge_tools
+-----------
+  You should dowload judge_tools from https://bitbucket.org/danielmaxx/judge-tools.git
+  and install it on your system with:
+  
+  ::  
+
+    $ cd judge_tools
+    $ sudo python3 setup.py install
+  
+  NOTE: You need Python 3 installed first.
+
+statement
+---------
+  This directory should be updated with "update-statement.sh" script. You should
+  not modify anything else than "problems.tex" file, where you must include each
+  one of the problems files.
+  
+  Whenever you want to generate a pdf copy of the statement, simply run "generate.sh".
+
+template
+--------
+  This directory contains a empty problem template. If you type:
+  
+  ::
+
+    $ ./mkproblem <problem-name>
+  
+  an empty problem will be copied in the problems directory. After that, you must
+  change the names inside "problems/<problem-name>".
+
+judge_tools-configuration.py
+-------------
+  This is the configuration file for judge_tools. In order to run it, you must:
+
+  ::
+
+    $ ./ceidec2012.py
+
+mkproblem.sh
+------------
+  See "template"
+
+update-statement
+----------------
+  See "statement"
+
+

ceidec2012.py

-#!/usr/bin/python3
-# -*- coding: utf-8 -*-
-import judge_tools.test_driver as jtest
-
-languages = {
-  "C":  jtest.Language(
-    name = "C",
-    extension = "c",
-    source_name = "{directory}-{solution}.{extension}",
-    executable_name = "{directory}-{solution}.exe",
-    compile_script = [["gcc", "-O2", "-o", "{executable}", "{source}"]],
-    execute_script = [["./{executable}"]]),
-
-  "C++":  jtest.Language(
-    name = "C++",
-    extension = "cpp",
-    source_name = "{directory}-{solution}.{extension}",
-    executable_name = "{directory}-{solution}.exe",
-    compile_script = [["g++", "-O2", "-o", "{executable}", "{source}"]],
-    execute_script = [["./{executable}"]]),
-
-  "Java":  jtest.Language(
-    name = "Java",
-    extension = "java",
-    source_name = "{directory}-{solution}.{extension}",
-    executable_name = "Main.class",
-    compile_script = [["javac", "-g:none", "{source}"]],
-    execute_script = [["java", "-server", "-Xss8m", "-Xmx512m", "Main", "{input}", "{output}"]]),
-
-  "python2":  jtest.Language(
-    name = "python2",
-    extension = "py2",
-    source_name = "{directory}-{solution}.{extension}",
-    execute_script = [["python2",  "{source}"]]),
-
-  "python3":  jtest.Language(
-    name = "python3",
-    extension = "py3",
-    source_name = "{directory}-{solution}.{extension}",
-    execute_script = [["python3",  "{source}"]]),
-}
-
-problems = {
-  "prison": jtest.Problem(
-    name = "prison",
-    directory = "prison",
-    generator = [["./generator-prison.py", "{problem}.in"]],
-    validator = [["./validator-prison.py", "{problem}.in"]],
-    valid_solution = jtest.Solution(
-      name = "prison",
-      language = languages["C++"],
-      redirect_stdin = True,
-      redirect_stdout = True),
-    test_solutions = (jtest.Solution(
-        name = "prison-zyx",
-        language = languages["C++"],
-        redirect_stdin = True,
-        redirect_stdout = True),
-    )),
-
-  "juice": jtest.Problem(
-    # Todo lo que diga {problem} se sustituye por esto.
-    name = "juice",
-
-    # No hace falta problems/, se incluye por defecto.
-    directory = "juice",
-
-    # Este generará un archivo llamado bed-div2.in en data/.
-    generator = [["./generator-juice.py", "{problem}.in"]],
-
-    # Si no hay validador sólo emite un warning. Pero se vería como esto.
-    validator = [["./validator-juice.py", "{problem}.in"]],
-
-    valid_solution = jtest.Solution(
-      name = "juice-emiliot",
-      language = languages["C++"],
-      redirect_stdin = True,
-      redirect_stdout = True),
-    test_solutions = (
-      # Aquí pones más objetos jtest.Solution, se construyen de igual manera
-      # que el anterior. Mientras no tengas el tester te muestra un warning.
-      jtest.Solution(
-        name = "juice-danielmaxx",
-        language = languages["C++"],
-        redirect_stdin = True,
-        redirect_stdout = True),
-      jtest.Solution(
-        name = "juice-zyx",
-        language = languages["C++"],
-        redirect_stdin = True,
-        redirect_stdout = True),
-    )),
-
-  "bankruptcy": jtest.Problem(
-    name = "bankruptcy",
-    directory = "bankruptcy",
-    generator = [["./generator-bankruptcy.py", "{problem}.in"]],
-    validator = [["./validator-bankruptcy.py", "{problem}.in"]],
-    valid_solution = jtest.Solution(
-      name = "bankruptcy-emiliot",
-      language = languages["C++"],
-      redirect_stdin = True,
-      redirect_stdout = True),
-    test_solutions = (
-      jtest.Solution(
-        name = "bankruptcy-danielmaxx",
-        language = languages["C++"],
-        redirect_stdin = True,
-        redirect_stdout = True),
-      jtest.Solution(
-        name = "bankruptcy-zyx",
-        language = languages["C++"],
-        redirect_stdin = True,
-        redirect_stdout = True),        
-    )),
-    
-  "sherlock": jtest.Problem(
-    name = "sherlock",
-    directory = "sherlock",
-    generator = [["./generator-sherlock.py", "{problem}.in"]],
-    validator = [["./validator-sherlock.py", "{problem}.in"]],
-    valid_solution = jtest.Solution(
-      name = "sherlock-emiliot",
-      language = languages["C++"],
-      redirect_stdin = True,
-      redirect_stdout = True),
-    test_solutions = (
-      jtest.Solution(
-        name = "sherlock-danielmaxx",
-        language = languages["C++"],
-        redirect_stdin = True,
-        redirect_stdout = True),
-    )),
-
-}
-jtest.test_problems(problems)

judge_tools-configuration.py

+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+import judge_tools.test_driver as jtest
+
+languages = {
+  "C":  jtest.Language(
+    name = "C",
+    extension = "c",
+    source_name = "{directory}-{solution}.{extension}",
+    executable_name = "{directory}-{solution}.exe",
+    compile_script = [["gcc", "-O2", "-o", "{executable}", "{source}"]],
+    execute_script = [["./{executable}"]]),
+
+  "C++":  jtest.Language(
+    name = "C++",
+    extension = "cpp",
+    source_name = "{directory}-{solution}.{extension}",
+    executable_name = "{directory}-{solution}.exe",
+    compile_script = [["g++", "-O2", "-o", "{executable}", "{source}"]],
+    execute_script = [["./{executable}"]]),
+
+  "Java":  jtest.Language(
+    name = "Java",
+    extension = "java",
+    source_name = "{directory}-{solution}.{extension}",
+    executable_name = "Main.class",
+    compile_script = [["javac", "-g:none", "{source}"]],
+    execute_script = [["java", "-server", "-Xss8m", "-Xmx512m", "Main", "{input}", "{output}"]]),
+
+  "python2":  jtest.Language(
+    name = "python2",
+    extension = "py2",
+    source_name = "{directory}-{solution}.{extension}",
+    execute_script = [["python2",  "{source}"]]),
+
+  "python3":  jtest.Language(
+    name = "python3",
+    extension = "py3",
+    source_name = "{directory}-{solution}.{extension}",
+    execute_script = [["python3",  "{source}"]]),
+}
+
+problems = {
+  "<problem-name>": jtest.Problem(
+    name = "<problem-name>",
+    directory = "<problem-directory>",
+    generator = [["./generator-<problem-name>.py", "{problem}.in"]], #{problem} will be replaced with <problem-name>
+    validator = [["./validator-<problem-name>.py", "{problem}.in"]],
+    valid_solution = jtest.Solution(
+      name = "<problem-name>-<author-name>",
+      language = languages["C++"],
+      redirect_stdin = True,
+      redirect_stdout = True),
+    test_solutions = (jtest.Solution(
+        name = "<problem-name>-<author-name>",
+        language = languages["Java"],
+        redirect_stdin = True,
+        redirect_stdout = True),
+    )),
+}
+jtest.test_problems(problems)

judge_tools/judge_tools/__init__.py

-# -*- coding: utf-8 -*-

judge_tools/judge_tools/case_count_generator.py

-# -*- coding: utf-8 -*-
-
-# Class used to store a file generator to append to the output file.
-class _TestCaseFile:
-  # Initialize the generator with the name of the file to append.
-  def __init__(self,*, input_file):
-    self.input_file = input_file
-
-  # Return the number of test cases inside the file.
-  def case_count(self):
-    try:
-      # Open the file and use the first line as test case count.
-      input = open(self.input_file, "rt")
-      return int(input.readline())
-    finally:
-      input.close()
-
-  # Run the generator and write all test cases to the specified output file.
-  def run(self, output):
-    try:
-      # Append all lines except the first one to the output file.
-      input = open(self.input_file, "rt")
-      for line in input.readlines()[1:]:
-        output.write(line)
-    finally:
-      input.close()
-
-# Class used to store a function to generate test cases.
-class _TestCaseFunction:
-  # Initialize the generator with the specified function and count.
-  def __init__(self, *, function, count):
-    self.function = function
-    self.count = count
-
-  # Return the number of test cases to generate.
-  def case_count(self):
-    return self.count
-
-  # Run the generator and write all test cases to the specified output file.
-  def run(self, output):
-    # Call the generator function as many times at it was specified, using the
-    # specified output file and giving the index to each call.
-    for index in range(self.count):
-      self.function(index, output)
-
-# List of generators to run when the generate_cases function is called.
-_generators = []
-
-# Add a file to the list of case files to append.
-def add_file(*, file):
-  _generators.append(_TestCaseFile(input_file = file))
-
-# Add a function generator to the list of generators.
-def add_function(*, f, n):
-  _generators.append(_TestCaseFunction(function = f, count = n))
-
-# Generate all cases and write them to the specified output file.
-def generate_cases(*, output):
-  # Write the case count at the begining of the file, the run all generators
-  # to the specified output file.
-  count = sum(generator.case_count() for generator in _generators)
-  output.write("{count}\n".format(count = count))
-  for generator in _generators: generator.run(output)
-

judge_tools/judge_tools/file_case_generator.py

-# -*- coding: utf-8 -*-
-import os
-import shutil
-
-# List of generators to run when the generate_cases function is called,
-# and counter used to number the input files.
-_generators = []
-_case_counter = 1
-
-# Class used to store a file generator to append to the output file.
-class _TestCaseFile:
-  # Initialize the generator with the name of the file to append.
-  def __init__(self, *, input_file):
-    self.input_file = input_file
-
-  def _copy_file(self, stem, dir, file_path):
-    # Generate the filename for the input file and increase the counter.
-    # Then, copy the file to the output directory.
-    global _case_counter
-    number, _case_counter = _case_counter, _case_counter + 1
-    output_filename = "{stem}.in.{n}".format(stem = stem, n = number)
-    output_path = os.path.normpath(os.path.join(dir, output_filename))
-    shutil.copyfile(file_path, output_path)
-
-  # Run the generator and write all test cases to the specified output file.
-  def run(self, stem, dir):
-    # Check if the filename points to a file or a directory.
-    if os.path.isfile(self.input_file):
-      # If a file was specified, copy it to the output directory.
-      self._copy_file(stem, dir, self.input_file)
-    elif os.path.isdir(self.input_file):
-      # If a directory was specified, copy each file into it to the output directory.
-      for dirpath, dirnames, filenames in os.walk(self.input_file):
-        for filename in filenames:
-          # Generate the complete path to the file and copy it.
-          file_path = os.path.normpath(os.path.join(dirpath, filename))
-          self._copy_file(stem, dir, file_path)
-
-# Class used to store a function to generate test cases.
-class _TestCaseFunction:
-  # Initialize the generator with the specified function and count.
-  def __init__(self, *, function, count):
-    self.function = function
-    self.count = count
-
-  # Run the generator and write all test cases to the specified output file.
-  def run(self, stem, dir):
-    # Call the generator function as many times at it was specified, with a
-    # different output file each time and giving the index to each call.
-    for index in range(self.count):
-      # Generate the filename for the input file and increase the counter.
-      global _case_counter
-      number, _case_counter = _case_counter, _case_counter + 1
-      output_filename = "{stem}.in.{n}".format(stem = stem, n = number)
-      output_path = os.path.normpath(os.path.join(dir, output_filename))
-
-      # Open the output file and make the function write in it.
-      output = open(output_path, "wt")
-      self.function(index, output)
-      output.close()
-
-# Add a file to the list of case files to append.
-def add_file(*, file):
-  _generators.append(_TestCaseFile(input_file = file))
-
-# Add a function generator to the list of generators.
-def add_function(*, f, n = 1):
-  _generators.append(_TestCaseFunction(function = f, count = n))
-
-# Generate all cases and write them to the specified output file.
-def generate_cases(*, stem, dir):
-  # Cleanse the specified directory and recreate it empty.
-  if os.path.exists(dir):
-    shutil.rmtree(dir)
-  os.makedirs(dir)
-
-  # Write the case count at the begining of the file, the run all generators
-  # to the specified output file.
-  global _case_counter
-  _case_counter = 1
-  for generator in _generators: generator.run(stem, dir)

judge_tools/judge_tools/input_validator.py

-# -*- coding: utf-8 -*-
-
-import re
-import sys
-
-# Class used for validate some input file.
-class _FormatValidator:
-  # Open the specified file and reset line counter.
-  def __init__(self, filename):
-    self.line_number = 0
-    self.file = open(filename, "rt")
-
-  # Close the opened file on destruction.
-  def __del__(self):
-    self.file.close()
-
-  # Read a line from the file and validate that it follows some regular expression.
-  def readline(self, regexp, *, desc = None):
-    # Read a line and increase line counter.
-    line = self.file.readline()
-    self.line_number += 1
-
-    # Format an error message and validate the regexp, the return the line read.
-    error_msg = "Line {line} does not match regexp '{regexp}'.".format(line = repr(line), regexp = regexp) if not desc \
-      else "Line {line} does not match regexp '{regexp}' for: {desc}.".format(line = repr(line), regexp = regexp, desc = desc)
-    self.check(re.match(regexp, line), error_msg)
-    return line
-
-  # Check some condition, if the condition does not hold,
-  # print an error message and exit.
-  def check(self, valid_flag, error_msg):
-    if not valid_flag:
-      print("Error at line #{line}: {error}.".format(line = self.line_number, error = error_msg), file = sys.stderr)
-      sys.exit(1)
-
-# Interface function used to create a format validator.
-def create_validator(filename):
-  return _FormatValidator(filename)

judge_tools/judge_tools/random_utils.py

-# -*- coding: utf-8 -*-
-import heapq
-
-# Import basic functions from the random module.
-from random import choice, random, sample, seed, shuffle, uniform
-import random
-
-# Common characters groups used to generate subsets.
-DIGITS = "".join(chr(c) for c in range(ord('0'), ord('9') + 1))
-UPPERCASE = "".join(chr(c) for c in range(ord('A'), ord('Z') + 1))
-LOWERCASE = "".join(chr(c) for c in range(ord('a'), ord('z') + 1))
-
-# Return a random integer between min_value and max_value, inclusive.
-def randrange(min_value, max_value):
-  return random.randrange(min_value, max_value + 1)
-
-# Return a subset with k elements from the specified population,
-# where order does not matter.
-def unordered_subset(population, k):
-  return sorted(random.sample(population, k))
-
-# Return a subset with k elements from the specified population,
-# where order does matter.
-def ordered_subset(population, k):
-  return random.sample(population, k)
-
-# Return a multiset with k elements from the specified population,
-# where order does matter.
-def ordered_multiset(population, k):
-  return [random.choice(population) for _ in range(k)]
-
-# Return a random tree with n nodes, using parent link representation.
-# The tree generation is done using Prufer's sequence.
-def generate_tree(n):
-  # The Prufer's sequence is invalid for tree with only one node,
-  # in this case return the only possible tree.
-  if n == 1: return []
-
-  # Generate a random Prufer's sequence for a tree with n nodes.
-  prufer = [randrange(0, n - 1) for _ in range(n - 2)]
-  degree = [prufer.count(i) + 1 for i in range(n)]
-
-  # Initialize a sorted queue to hold nodes with degree one, and list
-  # with edges for the constructed tree.
-  edges = []
-  fringe = [i for i, x in enumerate(degree) if x == 1]
-  heapq.heapify(fringe)
-
-  # Process all elements in the Prufer's sequence.
-  for x in prufer:
-    # Get the next unmatched leaf and push the new edge.
-    node = heapq.heappop(fringe)
-    edges.append((x, node))
-
-    # Update nodes degrees and push into the fringe those that
-    # became leafs (i.e.: have degree 1).
-    degree[x] -= 1
-    degree[node] -= 1
-    if degree[x] == 1:
-      heapq.heappush(fringe, x)
-
-  # Get the pair or remaining nodes, add the last edge and return.
-  a = heapq.heappop(fringe)
-  b = heapq.heappop(fringe)
-  edges.append((a, b))
-  return edges

judge_tools/judge_tools/sentinel_generator.py

-# -*- coding: utf-8 -*-
-
-# Class used to store a file generator to append to the output file.
-class _TestCaseFile:
-  # Initialize the generator with the name of the file to append.
-  def __init__(self,*, input_file):
-    self.input_file = input_file
-
-  # Run the generator and write all test cases to the specified output file.
-  def run(self, output, sentinel):
-    try:
-      # Append all lines to the output file, except the last one if
-      # there is a sentinel.
-      input = open(self.input_file, "rt")
-      lines = input.readlines()
-      if sentinel: lines.pop()
-      for line in lines: output.write(line)
-    finally:
-      input.close()
-
-# Class used to store a function to generate test cases.
-class _TestCaseFunction:
-  # Initialize the generator with the specified function and count.
-  def __init__(self, *, function, count):
-    self.function = function
-    self.count = count
-
-  # Return the number of test cases to generate.
-  def case_count(self):
-    return self.count
-
-  # Run the generator and write all test cases to the specified output file.
-  def run(self, output, _):
-    # Call the generator function as many times at it was specified, using the
-    # specified output file and giving the index to each call.
-    for index in range(self.count):
-      self.function(index, output)
-
-# List of generators to run when the generate_cases function is called.
-_generators = []
-
-# Add a file to the list of case files to append.
-def add_file(*, file):
-  _generators.append(_TestCaseFile(input_file = file))
-
-# Add a function generator to the list of generators.
-def add_function(*, f, n):
-  _generators.append(_TestCaseFunction(function = f, count = n))
-
-# Generate all cases and write them to the specified output file.
-def generate_cases(*, output, sentinel = None):
-  # Run all generators and the append the sentinel at the end.
-  # Use EOF if no sentinel was specified.
-  for generator in _generators:
-    generator.run(output, sentinel)
-  if sentinel: output.write(sentinel)
-

judge_tools/judge_tools/test_driver.py

-# -*- coding: utf-8 -*-
-import os
-import shutil
-import sys
-import subprocess
-import time
-
-# Execute a sequence of commands or a single command.
-def execute_script(script, *, stdin = None, stdout = None, **kwargs):
-  # Enclose a single line in a tuple, then call each instruction in it.
-  if isinstance(script, str): 
-    script = (script,)
-  for command in script:
-    # Show the command and execute it.
-    compiled_command = [token.format(**kwargs) for token in command]
-    print("    > {command}".format(command = ' '.join(compiled_command)))
-    subprocess.check_call(compiled_command, stdin = stdin, stdout = stdout)
-
-class Language:
-  # Construtor used to initialize a language.
-  def __init__(self, *, name, extension, source_name, executable_name = "",
-               compile_script = None, execute_script):
-    self.name = name
-    self.extension = extension
-    self.source_name = source_name
-    self.executable_name = executable_name
-    self.compile_script = compile_script
-    self.execute_script = execute_script
-
-class Solution:
-  # Constructor used to initialize a solution.
-  def __init__(self, *, name, language, redirect_stdin = False, redirect_stdout = False):
-    self.name = name
-    self.language = language
-    self.redirect_stdin = redirect_stdin
-    self.redirect_stdout = redirect_stdout
-
-  # Run this solution using the specified input and output files for the specified problem.
-  def compile_and_run(self, problem, input_name, output_name):
-    # Create the variables dictionary, including the formatted source name and executable name.
-    variables = {"problem": problem.name, "solution": self.name, "language": self.language.name,
-                 "extension": self.language.extension, "input": input_name, "output": output_name,}
-    print( variables )
-    source = variables["solution"] + "." + variables["extension"] #self.language.source_name.format(**variables)
-    variables.update([("source", source)])
-    executable = variables["solution"] #self.language.executable_name.format(**variables)
-    variables.update([("executable", executable)])
-
-    # Execute the compile command to compile this solution.
-    if self.language.compile_script is not None:
-      print("  Compiling solution '{solution}' in {language} for problem '{problem}'...".format(**variables))
-      execute_script(self.language.compile_script, **variables)
-
-    # Open the input and output files to redirect standard streams if necessary.
-    input = open(input_name, "rt") if self.redirect_stdin else None
-    output = open(output_name, "wt") if self.redirect_stdout else None
-
-    # Use the generated command to run the solution, then print the execution time.      
-    print("  Executing solution '{solution}' in {language} for problem '{problem}'...".format(
-      problem = problem.name, solution = self.name, language = self.language.name))
-    start_time = time.clock()
-    execute_script(self.language.execute_script, stdin = input, stdout = output, **variables)
-    exec_time = round(time.clock() - start_time, 2)
-    print("  Solution '{solution}' in {language} for problem '{problem}' ran in {time} seconds.".format(
-      time = exec_time, **variables))
-
-    # Remove the generated executable if there is one.
-    time.sleep(0.5)
-    if executable != "":
-      os.remove(executable)
-
-class Problem:
-  # Constructor used to initialize a problem.
-  def __init__(self, *, name, directory = "", generator = None, validator = None, valid_solution, test_solutions = ()):
-    self.name = name
-    self.generator = generator
-    self.validator = validator
-    self.valid_solution = valid_solution
-    self.test_solutions = test_solutions
-    self.directory = directory
-
-  # Generate the input file for the problem, using the generator
-  # command specified during initialization.
-  def generate_input(self):
-    # Check if there is a generator script, then execute it.
-    if self.generator is not None:
-      print("  Generating input file for problem '{problem}'...".format(problem = self.name))
-      execute_script(self.generator, problem = self.name)
-      print("  Input file for problem '{problem}' successfully generated.".format(problem = self.name))
-
-  # Validate the generated input file for the problem, using the
-  # validator command specified during initialization.
-  def validate_input(self):
-    # Check if there is a validator script, then execute it.
-    if self.validator is not None:
-      # Execute the constructed command to validate the input file.
-      print("  Validating input file for problem '{problem}'...".format(problem = self.name))
-      execute_script(self.validator, problem = self.name)
-      print("  Input file for problem '{problem}' successfully validated.".format(problem = self.name))
-    else:
-      print("  WARNING: No input validator found for problem '{problem}'".format(problem = self.name))
-
-  # Generate the correct output for the generated input file,
-  # running the valid solution specified during initialization.
-  def generate_output(self):
-    # Generate input and output file names and use them to compile
-    # and run the valid solution.
-    print("  Generating output file for problem '{problem}'...".format(problem = self.name))
-    input_name = "{problem}.in".format(problem = self.name)
-    output_name = "{problem}.out".format(problem = self.name)
-    self.valid_solution.compile_and_run(self, input_name, output_name)
-    print("  Output file for problem '{problem}' successfully generated.".format(problem = self.name))
-
-  # Validate other output using the valid output as reference.
-  def validate_output(self, solution, valid_output, other_output):
-    # Initialize error counter and read lines from the output files.
-    print("  Validating {other_output} output with correct results in {valid_output}...".format(
-      other_output = other_output, valid_output = valid_output))
-    error_count = 0
-    valid_lines = open(valid_output, "rt").readlines()
-    other_lines = open(other_output, "rt").readlines()
-
-    # Check each line in the files and look for errors.
-    for line_number, (valid_line, other_line) in enumerate(zip(valid_lines, other_lines), 1):
-      if valid_line != other_line:
-        if error_count == 0:
-          print("Diffrences found between '{valid}' and '{other}'.".format(
-            valid = valid_output, other = other_output), file = sys.stderr)
-        # Print the lines with the error and increase the counter.
-        print("{line}:< {text}".format(line = line_number, text = repr(valid_line)), file = sys.stderr)
-        print("{line}:> {text}".format(line = line_number, text = repr(other_line)), file = sys.stderr)
-        error_count += 1
-
-    # Check if there are extra lines or missing at the checked output.
-    if len(other_lines) > len(valid_lines):
-      print("{extra} extra line(s) found at {file}.".format(
-        extra = len(other_lines) - len(valid_lines), file = other_output), file = sys.stderr)
-    if len(other_lines) < len(valid_lines):
-      print("{missing} missing line(s) in {file}.".format(
-        missing = len(valid_lines) - len(other_lines), file = other_output), file = sys.stderr)
-
-    # Adjust error count by line differences and return it.
-    error_count += abs(len(other_lines) - len(valid_lines))
-    return error_count
-
-  def test_solution(self, solution):
-    # Generate input and output file names for the solution to test.
-    print("  Testing solution '{solution}' in {language} for problem '{problem}'...".format(
-      problem = self.name, solution = solution.name, language = solution.language.name))
-    input_name = "{problem}.in".format(problem = self.name)
-    valid_output_name = "{problem}.out".format(problem = self.name)
-    output_name = "{problem}-{solution}-{language}.out".format(
-      problem = self.name, solution = solution.name, language = solution.language.name)
-
-    # Compile and run solution using the input and output names, then
-    # check if the output is valid.
-    solution.compile_and_run(self, input_name, output_name)
-    error_count = self.validate_output(solution, valid_output_name, output_name)
-    if error_count == 0:
-      # Remove the output file and print success message.
-      os.remove(output_name)
-      print("  Solution '{solution}' in {language} for problem '{problem}' successfully tested.".format(
-        problem = self.name, solution = solution.name, language = solution.language.name))
-    else:
-      # Print error message and leave the output file for manual checking.
-      print("  Solution '{solution}' in {language} for problem '{problem}' had {errors} error(s).".format(
-        problem = self.name, solution = solution.name, language = solution.language.name, errors = error_count))
-
-  def test(self):
-    # Move the current directory to the problem directory.
-    print("Testing problem '{problem}'...".format(problem = self.name))
-    os.chdir("problems/{directory}".format(directory = self.directory))
-
-    # Generate the input, validate it and then run the valid
-    # solution to generate the output.
-    self.generate_input()
-    self.validate_input()
-    self.generate_output()
-
-    # Run all test solutions and validate them, and print a warning message
-    # if there are no test solutions.
-    for solution in self.test_solutions:
-      self.test_solution(solution)
-    if not self.test_solutions:
-      print("  WARNING: No test solutions found for problem '{problem}'".format(problem = self.name))
-
-    # Go back to the starting directory and move data files to the data directory.
-    os.chdir("../../")
-#    print( os.getcwd() )
-    shutil.copy("problems/{directory}/{problem}.in".format(directory = self.directory, problem = self.name), "data/")
-    shutil.copy("problems/{directory}/{problem}.out".format(directory = self.directory, problem = self.name), "data/")
-    print("Problem '{problem}' successfully tested.".format(problem = self.name))
-    print()
-
-def test_problems(problems):
-  # Get problems to test from command line, if there
-  # are no problems then test them all.
-  target_problems = [name for name in sys.argv[1:] if name in problems]
-  if not target_problems:
-    target_problems = sorted(problems.keys())
-
-  # Create the data directory and ignore any error (like directory already exists).
-  try: os.mkdir("data/")
-  except OSError: pass
-
-  # Test all problems in the array with targets.
-  for name in target_problems:
-    problems[name].test()

judge_tools/setup.py

-# -*- coding: utf-8 -*-
-
-from distutils.core import setup
-    
-'''
-IMPORTANTE: los campos que se describen a continuación deben ser rellenados en su totalidad.
-Aquellos campos que NO SE VAYAN A UTILIZAR, se deben BORRAR.
-'''
-
-setup(name='judge_tools',
-      version='1.0',
-      author='Jorge Bernadas',
-      author_email='jbernadas@gmail.com',
-      url='http://code.funvisis.gob.ve/funvisis/LoL',
-      download_url='http://code.funvisis.gob.ve/funvisis/',
-      description='A set of judge utilities',
-#      package_dir={'':'src'},
-      packages=['judge_tools'],
-      classifiers=['Development Status :: Alpha',
-                   'Intended Audience :: Developers',
-                   'Natural Language :: English',
-                   'Operating System :: OS Independent',
-                   'Programming Language :: Python :: 2.6+',
-                   'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
-                   'License :: OSI Approved :: GNU Affero General Public License v3',
-                   'Topic :: Internet',
-                   'Topic :: Scientific/Engineering :: GIS',
-                  ],
-     )
+Problems should be placed here. One directory for each one.

statement/ceidec2012.sty

-\usepackage[latin1]{inputenc}
-\usepackage[spanish]{babel}
-\usepackage{ifthen}
-
-\oddsidemargin  0.0in
-\evensidemargin 0.0in
-\textwidth      6.7in
-\headsep        0.5in
-\textheight     9.5in
-\topmargin     -0.5in
-\parindent      0.0in
-\addtolength{\parskip}{0.4\baselineskip}
-
-\pagestyle{myheadings}
-\markright{OVI 2012}
-\newcounter{pcounter}\setcounter{pcounter}{0}
-\newcounter{INPUT}
-\newcounter{OUTPUT}
-
-\newcommand{\inputstd}{\setcounter{INPUT}{0}}
-\newcommand{\inputfile}{\setcounter{INPUT}{1}}
-\newcommand{\outputstd}{\setcounter{OUTPUT}{0}}
-\newcommand{\outputfile}{\setcounter{OUTPUT}{1}}
-
-\newcommand{\inputnotice}[1]
-    {\vspace{2mm}\noindent
-	  \ifthenelse{\value{INPUT}=0}
-					 {\emph{La entrada debe ser le\'ida de la entrada est\'andar.}\par}
-					 {\emph{La entrada debe ser le\'ida del archivo {\sf #1.in}.}\par}
-    }
-
-\newcommand{\outputnotice}[1]
-    {\vspace{2mm}\noindent
-	  \ifthenelse{\value{OUTPUT}=0}
-                {\emph{La salida debe ser escrita en la salida est\'andar.}\par}
-                {\emph{La salida debe ser escrita al archivo {\sf #1.out}.}\par}
-    }
-
-\newcommand{\problemdir}{problemdir}
-
-\newcommand{\problem}[2]
-    {
-    \addtocounter{pcounter}{1}
-    \newpage
-    \begin{center}
-    \huge{\bf \sf Problema \Alph{pcounter}}\\
-    \LARGE{\sf #1}\\[2mm]
-    \normalsize {\em Nombre del archivo fuente:} {\tt #2.c}, {\tt #2.cpp} {\em o} {\tt #2.java}
-    \vspace{6pt}
-    \end{center}
-   \renewcommand{\problemdir}{#2}
-    }
-
-\newcommand{\sampleio}[1]{
-
-	\vspace{12pt}
-	\noindent
-	\begin{minipage}[c]{\textwidth}
-	\begin{center}
-	\begin{tabular}{|l|l|} \hline
-	\begin{minipage}[t]{0.475\textwidth}
-
-	\bf{Entrada de ejemplo}
-
-%	\verbatimtabinput{../#1.in}
-	\verbatimtabinput{\problemdir/#1.in}
-	\vskip 12pt
-
-	\end{minipage}
-	&
-	\begin{minipage}[t]{0.475\textwidth}
-
-	\bf{Salida para la entrada de ejemplo}
-
-%	\verbatimtabinput{../#1.out}
-	\verbatimtabinput{\problemdir/#1.out}
-	\vskip 12pt
-
-	\end{minipage}\\
-	\hline
-	\end{tabular}
-	\end{center}
-	\end{minipage}
-}
-
-\renewcommand{\subsection}{\@startsection{subsection}{2}{\z@}%
-                                     {-1.0ex\@plus -1ex \@minus -.2ex}%
-                                     {1.0ex \@plus .2ex}%
-                                   {\reset@font\large\bfseries}}
-
-
-

statement/contest.sty

+\usepackage[latin1]{inputenc}
+\usepackage{ifthen}
+
+\oddsidemargin  0.0in
+\evensidemargin 0.0in
+\textwidth      6.7in
+\headsep        0.5in
+\textheight     9.5in
+\topmargin     -0.5in
+\parindent      0.0in
+\addtolength{\parskip}{0.4\baselineskip}
+
+\pagestyle{myheadings}
+\markright{Maratón CEIDEC 2012 - Contest Session}
+\newcounter{pcounter}\setcounter{pcounter}{0}
+\newcounter{INPUT}
+\newcounter{OUTPUT}
+
+\newcommand{\inputstd}{\setcounter{INPUT}{0}}
+\newcommand{\inputfile}{\setcounter{INPUT}{1}}
+\newcommand{\outputstd}{\setcounter{OUTPUT}{0}}
+\newcommand{\outputfile}{\setcounter{OUTPUT}{1}}
+
+\newcommand{\inputnotice}[1]
+    {\vspace{2mm}\noindent
+	  \ifthenelse{\value{INPUT}=0}
+					 {\emph{The input must be read from standard input.}\par}
+					 {\emph{The input must be read from file {\sf #1.in}.}\par}
+    }
+
+\newcommand{\outputnotice}[1]
+    {\vspace{2mm}\noindent
+	  \ifthenelse{\value{OUTPUT}=0}
+                {\emph{The output must be written to standard output.}\par}
+                {\emph{The output must be written to file {\sf #1.out}.}\par}
+    }
+
+\newcommand{\problemdir}{problemdir}
+
+\newcommand{\problem}[2]
+    {
+    \addtocounter{pcounter}{1}
+    \newpage
+    \begin{center}
+    \huge{\bf \sf Problem \Alph{pcounter}}\\
+    \LARGE{\sf #1}\\[2mm]
+    \normalsize {\em Source file name:} {\tt #2.c}, {\tt #2.cpp}, {\tt #2.py} {\em or} {\tt #2.java}
+    \vspace{6pt}
+    \end{center}
+   \renewcommand{\problemdir}{#2}
+    }
+
+\newcommand{\sampleio}[1]{
+
+	\vspace{12pt}
+	\noindent
+	\begin{minipage}[c]{\textwidth}
+	\begin{center}
+	\begin{tabular}{|l|l|} \hline
+	\begin{minipage}[t]{0.475\textwidth}
+
+	\bf{Sample input}
+
+%	\verbatimtabinput{../#1.in}
+	\verbatimtabinput{\problemdir/#1.in}
+	\vskip 12pt
+
+	\end{minipage}
+	&
+	\begin{minipage}[t]{0.475\textwidth}
+
+	\bf{Output for the sample input}
+
+%	\verbatimtabinput{../#1.out}
+	\verbatimtabinput{\problemdir/#1.out}
+	\vskip 12pt
+
+	\end{minipage}\\
+	\hline
+	\end{tabular}
+	\end{center}
+	\end{minipage}
+}
+
+\renewcommand{\subsection}{\@startsection{subsection}{2}{\z@}%
+                                     {-1.0ex\@plus -1ex \@minus -.2ex}%
+                                     {1.0ex \@plus .2ex}%
+                                   {\reset@font\large\bfseries}}
+
+
+

statement/generar.sh

-#!/bin/bash
-
-latex --output-format=pdf problemas.tex
-rm -f problemas.aux problemas.log

statement/generate.sh

+#!/bin/bash
+
+latex --output-format=pdf problemas.tex
+rm -f problemas.aux problemas.log

statement/problems.tex

-% Template for a problem -- CEIMEC 2010
+% Template for a problem -- CEIDEC 2012
 
 \documentclass[12pt]{article}
 \usepackage{epsfig}
-\usepackage{ovni2012}
+\usepackage{contest}
 \usepackage{moreverb}
 
 % Choose one of the following styles for input files
 %\outputfile      % output to named file
 
 \begin{document}
-\input{<archivo>.tex}
+\input{<file>} % don't write file extension
 \end{document}

template/generator-problem.py

+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+import sys
+import judge_tools.case_count_generator as jgen
+import judge_tools.random_utils as jrand
+import random
+
+MIN_T, MAX_T = 1, 100
+#Any other constant value you need,
+#specially if it is a constraint
+
+def write_case(output, ...):
+  #Code for write ONE random case
+  output.write("")
+
+def random_case(output):
+  #Code for generate ONE random case 
+  write_case(output, ...)
+
+#for i in range(3, len(sys.argv)): jgen.add_file(file = sys.argv[i])
+jgen.add_function(f = lambda _, output: random_case(output = output), n = MAX_T)
+jgen.generate_cases(output = open(sys.argv[1], "wt"))

Empty file added.

Empty file added.

template/statement/problem-template.tex

+\problem{<Long problem name>}{<Code problem name>}
+
+\noindent
+<Problem description>\\
+
+\subsection*{Input}
+\noindent
+The first line contains an integer $T$, which specifies the number of test cases. Then, will follow the descriptions of $T$ test cases.\\
+
+\noident
+<Problem input description>\\
+
+\inputnotice{<Code problem name>}
+
+\subsection*{Output}
+\noindent
+For each input case you must print..\\
+
+\outputnotice{<Code problem name>}
+
+\sampleio{sample}\\
+
+\subsection*{Constraints}
+
+\begin{itemize}
+\item 1 $\leq$ $T$ $\leq$ 100
+\end{itemize}

template/validator-problem.py

+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+import judge_tools.input_validator as jval
+import sys
+
+MIN_T, MAX_T = 1, 50
+#Any other constant value you need,
+#specially if it is a constraint
+
+validator = jval.create_validator(sys.argv[1])
+T = int(validator.readline(r"^[1-9][0-9]*\n$", desc = "T line"))
+validator.check(MIN_T <= T <= MAX_T, "T={0} is invalid".format(T))
+for Ti in range(1, T + 1):
+  #Validation code for each case in the input
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.