The Qualification round for Google Code Jam 2009 is entering its closing hours, and having submitted my solutions for the three problems, I thought I would share just the framework I set up for solving the problems. This is something I originally began writing for last year’s Code Jam, but I have updated it for the altered format this year, as well as expanded the functionality.
The framework consitsts of a class that has a number of simple methods for accessing the input data as well as writing the output cases. The main convience is its abstraction of the text file I/O into simple methods that deal with arrays (and arrays of arrays) of primitive types. As a bonus, all the relevant output information, as well as the execution time, is printed to the standard out stream (console window).
using System;
using System.IO;
using System.Text;
public class CodeJamProblem : IDisposable
{
protected int caseNumber;
protected StreamReader textReader;
protected StreamWriter textWriter;
private bool disposed = false;
public CodeJamProblem(string inputFileName)
{
this.InputFileName = inputFileName;
this.OutputFileName = Path.ChangeExtension(this.InputFileName, ".out");
this.textReader = new StreamReader(this.InputFileName);
this.textWriter = new StreamWriter(this.OutputFileName);
this.caseNumber = 1;
this.StartTime = Environment.TickCount;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
this.ElapsedTime = Environment.TickCount - this.StartTime;
textReader.Dispose();
textWriter.Dispose();
Console.WriteLine("Elapsed time: {0:#,#0}ms", this.ElapsedTime);
Console.Beep();
Console.ReadKey(true);
}
}
disposed = true;
}
public int StartTime
{
get;
private set;
}
public int ElapsedTime
{
get;
private set;
}
public int CurrentCaseNumber
{
get { return this.caseNumber; }
}
public bool InputAvailable
{
get { return this.textReader.Peek() != -1; }
}
public string InputFileName
{
get;
private set;
}
public string OutputFileName
{
get;
private set;
}
public void OutputCase(params object[] values)
{
var parts = new string[values.Length];
for (int i = 0; i < parts.Length; i++)
parts[i] = values[i].ToString();
OutputCase(string.Join(" ", parts));
}
public void OutputCase()
{
OutputCase((string)null);
}
public void OutputCase(string value)
{
WriteLine("Case #{0:#0}: {1}", this.caseNumber, value);
this.caseNumber++;
}
public void WriteArrays<T>(T[][] entries)
{
for (int i = 0; i < entries.Length; i++)
WriteArray(entries[i]);
}
public void WriteArray<T>(T[] values)
{
var parts = new string[values.Length];
for (int i = 0; i < parts.Length; i++)
parts[i] = values[i].ToString();
WriteLine(string.Join(" ", parts));
}
public void WriteLines(string[] lines)
{
for (int i = 0; i < lines.Length; i++)
WriteLine(lines[i]);
}
public void WriteLine(string format, params object[] arg)
{
Console.WriteLine(format, arg);
this.textWriter.WriteLine(format, arg);
}
public void WriteLine(string line)
{
Console.WriteLine(line);
this.textWriter.WriteLine(line);
}
public int[][] ReadIntArrays(int count)
{
var entries = new int[count][];
for (int i = 0; i < entries.Length; i++)
entries[i] = ReadIntArray();
return entries;
}
public int[] ReadIntArray()
{
var parts = ReadParts();
var values = new int[parts.Length];
for (int i = 0; i < values.Length; i++)
values[i] = int.Parse(parts[i]);
return values;
}
public double[][] ReadDoubleArrays(int count)
{
var entries = new double[count][];
for (int i = 0; i < entries.Length; i++)
entries[i] = ReadDoubleArray();
return entries;
}
public double[] ReadDoubleArray()
{
var parts = ReadParts();
var values = new double[parts.Length];
for (int i = 0; i < values.Length; i++)
values[i] = double.Parse(parts[i]);
return values;
}
public string[] ReadParts()
{
return ReadLine().Split(' ');
}
public string[] ReadLines(int count)
{
var lines = new string[count];
for (int i = 0; i < lines.Length; i++)
lines[i] = ReadLine();
return lines;
}
public string ReadLine()
{
return this.textReader.ReadLine();
}
}
Hopefully this will assist someone other tham myself, though I suspect most contestants have set up something of the same sort. I will continue to make minor modifications over the duration of the contest, and will update this post to reflect them.
Regarding the Qualification round itself, the problems have proven to be fairly interesting. (Well, the first was rather trivial if one is honest.) Now, only to wait for the upcoming Round 1, and hope the problems don’t become too much more challenging!