Skip to content

Commit

Permalink
updating code to only write a simple parser and a simple output gener…
Browse files Browse the repository at this point in the history
…ator + better algorithms
  • Loading branch information
SuperFola committed Feb 26, 2021
1 parent 2f053bf commit f6e1913
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 70 deletions.
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# HashCode template

## To modify

- modify the problem parser (in `problem.py`) to your needs (from the INPUT and OUTPUT specifications)
- create `algo_name.py`, with algo_name the name of your algorithm
- run it with `main.py algo_name` to run on all files, or `main.py algo_name a b` to run on a and b problems

## Adding an algorithm

Create a file `algo_name.py` alongside `main.py`, base content looks like this:

```python
#!/usr/bin/env python3
# coding: utf-8

from hashcode import reporter


@reporter(__file__)
def run(filename: str, data: dict):
out = {}

# your code is here

return out
```

## Adding the INPUT and OUTPUT parsers

Your parsers should be written in `problem.py`.

### INPUT

The `parse_input` method will be given the header as a dict, defined by the `FIELDS` which is a mapping `field name => type` (you can choose whatever field name you want, but **the type has to be exactly what you want**).

The `parse_input` method is also given the rest of the lines of the file (without the first line) and should return what it parsed from those lines as a dict. **Do not include the header** it will be include by the caller.

### OUTPUT

The `generate_output` method will be given the original data parsed before for the problem, the dictionnary returned by the parser. It will also be given the solution your algorithm generated **as a dict**.

It should return a list of string, each one being an element of the problem.

**Then the parser will write at the top of the file the number of components you generated**. The first line of an output file for the google hashcode is **always** the number of solution, thus it should be carefully designed in your generate_output to return the right number of elements.
7 changes: 2 additions & 5 deletions algo_dummy.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
#!/usr/bin/env python3
# coding: utf-8

import hc_parser
from reporter import reporter
from hc_short import *
from hashcode import reporter, fbasename


@reporter(__file__)
def run(filename):
def run(filename: str, data: dict):
print(f"Running {fbasename(__file__)} on {filename}...")

out = {}
data = hc_parser.load(filename)

# dummy
for k, v in data.items():
Expand Down
5 changes: 5 additions & 0 deletions hashcode/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env python
# coding: utf-8

from . reporter import reporter
from .hc_short import *
62 changes: 62 additions & 0 deletions hashcode/hc_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
# coding: utf-8

from . import evalfile, pexist, gob, fbasenoext, fbasename, rm_eol
from . import rlines, prtnice, reporter, dcopy
from typing import List, Tuple


@reporter("hc_parser.reader")
def reader(fields: List[Tuple[str, type]], filename: str, callback) -> dict:
content = None or rlines(filename)
if content is None:
raise RuntimeError(
f"couldn't process {filename}: may be empty or can not read")

first_line = content[0].split(' ')
if len(first_line) > len(fields):
raise RuntimeError("You forgot to update the FIELDS definition in problem.py, parsed too many fields")
if len(first_line) < len(fields):
raise RuntimeError(f"You want too many fields ({len(fields)}) but the file has {len(first_line)} fields in its header")

data = {
fields[i][0]: fields[i][1](rm_eol(e)) for i,
e in enumerate(first_line)
}

cdata = callback(dcopy(data), content[1:])
data.update(cdata)

return data


@reporter("hc_parser.saver")
def saver(fields: List[Tuple[str, type]], filename: str, callback) -> None:
with open(f"parsed/{filename}", "w") as f:
f.write(prtnice(reader(fields, f"tests/{filename}", callback)))


def save_all(fields: List[Tuple[str, type]], callback) -> None:
print("Saving all...")
for f in gob(f"tests/*.txt"):
print(f"Exporting {f}...\r")
saver(fields, fbasename(f), callback)
print("\nDone!")


@reporter("hc_parser.generate_output")
def generate_output(data: dict, filename: str, algo_name: str, callback) -> None:
# if we need data from the problem source
og_file = load(filename)
out = callback(og_file, data)

content = str(len(data)) + '\n'
content += ''.join(map(str, (line for line in out)))

racine = fbasenoext(filename)
with open(f"output/{racine}-{algo_name}.txt", "w") as f:
f.write(content)


def load(filename: str) -> dict:
return evalfile(f"parsed/{filename}")
File renamed without changes.
File renamed without changes.
60 changes: 0 additions & 60 deletions hc_parser.py

This file was deleted.

13 changes: 8 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import sys
import glob

import hc_parser
from hc_short import G, L, pexist, gob
from hashcode import hc_parser, G, L, pexist, gob
from problem import FIELDS, parse_input, generate_output


try:
import numpy as np
Expand Down Expand Up @@ -54,7 +55,7 @@ def main(*args):
if len(gob("tests/*.txt")) != len(gob("parsed/*.txt")
) or "-f" in args or "--force" in args:
# run only if needed
hc_parser.save_all()
hc_parser.save_all(FIELDS, parse_input)
return 0

if len(args) == 0:
Expand All @@ -70,8 +71,10 @@ def main(*args):
func = eval(f"{algo_name}.run", G(), L())
for le in (args[1:] or "abcdef"):
try:
output = func(f"{le}.txt")
hc_parser.generate_output(output, f"{le}.txt")
fname = f"{le}.txt"
print(f"Running {algo_name} on {fname}...")
output = func(fname, hc_parser.load(fname))
hc_parser.generate_output(output, fname, algo_name, generate_output)
except Exception as e:
print(f"Error when running {algo_name}({le}): {e}")

Expand Down
25 changes: 25 additions & 0 deletions problem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
# coding: utf-8

from typing import List


# field name + its type, in the order they appear in the header
# of the input file
FIELDS = [
("Deadline", int),
("BonusPerCar", int),
("etc", int),
]


def parse_input(header: dict, content: List[str]) -> dict:
# TODO

return {}


def generate_output(og_data: dict, solution: dict) -> List[str]:
# TODO

return ["line0"]

0 comments on commit f6e1913

Please sign in to comment.