samedi 8 mai 2010

Factoring the google codejam

This post will be about this year's (2010) google codejam.
May 8th was the online qualification round. Let's see how factor deals with the problems.

First of all, all google codejam problems so far have had the same structure:
give a file describing N instances of the problem, output the file giving the N solutions to these instances.
The input file starts with a line containing the value of N, and then the description of N problems.
The output file must contain exactly N lines, each line looking like this :
Case #X: SOLUTION
,
where X goes from 1 to N and SOLUTION is the solution to this instance of the problem.

Let's create a vocabulary that automates all this.

First, we load the vocabularies that we need.
USING: formatting io io.encodings.utf8 io.files math.parser
math.ranges sequences splitting kernel ;
IN: gcj.common
Then, declare a generic word that has to read the description of a problem and print it's solution:
 GENERIC: solve-case ( problem-class -- )
We often have to read integers from files, so here are two useful words for reading 1 or many integers from a line:
: read-int ( -- n )
readln 10 base> ;
: read-ints ( -- ints )
readln " " split [ string>number ] map ;
We then need to be able to read the first line containing the number of cases, and for each case print the Case #X: SOLUTION line.
: solve-cases ( problem-class -- )
read-int [1,b]
[ "Case #%d: " printf solve-case nl ] with each ;
We also need a function to generate a new filename to which we write the solution : the solution to X.in will be stored in X.out :
: out-file ( in-file -- out-file )
"." split but-last ".out" suffix concat ;
Now, all we have to do is open the input file for reading, the output file for writting, and solve each case !
: solve-file ( problem-class file -- )
dup out-file utf8 [ utf8 [ solve-cases ] with-file-reader ] with-file-writer ;

Then if one wants to use this generic solver for the gcj, all one has to do is create a new problem-class, and implement the solve-case method.
In another file :
SINGLETON: gcj.anamefortheproblem
M: gcj.anamefortheproblem solve-case
! implement your case here
;
and call the generic part like this :
gcj.anamefortheproblem "path/to/input/file" solve-file


Here's the complete source file:
! Copyright (C) 2010 Jon Harper.
! See http://factorcode.org/license.txt for BSD license.
USING: formatting io io.encodings.utf8 io.files math.parser
math.ranges sequences splitting kernel ;
IN: gcj.common
GENERIC: solve-case ( problem-class -- )

: read-int ( -- n )
readln 10 base> ;
: read-ints ( -- ints )
readln " " split [ string>number ] map ;
: solve-cases ( problem-class -- )
read-int [1,b]
[ "Case #%d: " printf solve-case nl ] with each ;
: out-file ( in-file -- out-file )
"." split but-last ".out" suffix concat ;
: solve-file ( problem-class file -- )
dup out-file utf8 [ utf8 [ solve-cases ] with-file-reader ] with-file-writer ;


Aucun commentaire:

Enregistrer un commentaire