<commit_before>package runner

import (
	"fmt"
	"path"
	"io/ioutil"
	"common"
	"time"
)

// Defines a puzzle.
type Puzzle struct {
	Name      string
	Filename  string
	Solver    func(string) (string, string)
	SolutionA string
	SolutionB string
}

// Run all the AOC 2016 puzzles
func Run(dataDir string, puzzles []Puzzle) {

	// Go through all puzzles and run them.
	for _, puzzle := range puzzles {
		start := time.Now()
		solutionA, solutionB, err := solve(dataDir, &puzzle)
		elapsed := time.Now().Sub(start)
		if err != nil {
			fmt.Printf("Error running puzzle solver: %s\n", err)
		} else {
			fmt.Printf(compareResults(solutionA, solutionB, &puzzle, elapsed))
		}
	}
}

// Solves a given puzzle with the given data directory.
func solve(dataDir string, puzzle *Puzzle) (string, string, error) {
	filename := path.Join(dataDir, puzzle.Filename)
	if !common.IsRegularFile(filename) {
		return "", "", fmt.Errorf("not a readable file '%s'", filename)
	}

	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", "", fmt.Errorf("cannot read file '%s'", filename)
	}
	solutionA, solutionB := puzzle.Solver(string(data))
	return solutionA, solutionB, nil
}

// Creates a result string for puzzles results
func compareResults(solutionA string, solutionB string, puzzle *Puzzle, elapsed time.Duration) string {
	result := fmt.Sprintf("[%s] - %v\n", puzzle.Name, elapsed)
	result += fmt.Sprintf("  --> Solution A: %s\n", compareSolution(solutionA, puzzle.SolutionA))
	result += fmt.Sprintf("  --> Solution B: %s\n\n", compareSolution(solutionB, puzzle.SolutionB))
	return result
}

// Creates a result string for a single solution.
func compareSolution(actual string, expected string) string {
	if actual == expected {<commit_msg>Exclude file reading from timing.<commit_after>package runner

import (
	"fmt"
	"path"
	"io/ioutil"
	"common"
	"time"
)

// Defines a puzzle.
type Puzzle struct {
	Name      string
	Filename  string
	Solver    func(string) (string, string)
	SolutionA string
	SolutionB string
}

// Run all the AOC 2016 puzzles
func Run(dataDir string, puzzles []Puzzle) {

	// Go through all puzzles and run them.
	for _, puzzle := range puzzles {
		solutionA, solutionB, elapsed, err := solve(dataDir, &puzzle)
		if err != nil {
			fmt.Printf("Error running puzzle solver: %s\n", err)
		} else {
			fmt.Printf(compareResults(solutionA, solutionB, &puzzle, elapsed))
		}
	}
}

// Solves a given puzzle with the given data directory.
func solve(dataDir string, puzzle *Puzzle) (string, string, time.Duration, error) {
	filename := path.Join(dataDir, puzzle.Filename)
	if !common.IsRegularFile(filename) {
		return "", "", 0, fmt.Errorf("not a readable file '%s'", filename)
	}

	data, err := ioutil.ReadFile(filename)
	if err != nil {
		return "", "", 0, fmt.Errorf("cannot read file '%s'", filename)
	}
	start := time.Now()
	solutionA, solutionB := puzzle.Solver(string(data))
	elapsed := time.Now().Sub(start)
	return solutionA, solutionB, elapsed, nil
}

// Creates a result string for puzzles results
func compareResults(solutionA string, solutionB string, puzzle *Puzzle, elapsed time.Duration) string {
	result := fmt.Sprintf("[%s] - %v\n", puzzle.Name, elapsed)
	result += fmt.Sprintf("  --> Solution A: %s\n", compareSolution(solutionA, puzzle.SolutionA))
	result += fmt.Sprintf("  --> Solution B: %s\n\n", compareSolution(solutionB, puzzle.SolutionB))
	return result
}

// Creates a result string for a single solution.
func compareSolution(actual string, expected string) string {
	if actual == expected {
{'fraction_non_alphanumeric': 0.13647923142130544, 'fraction_numerical': 0.0028256569652444193, 'mean_word_length': 4.205882352941177, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3064541', 'n_tokens_mistral': 1216, 'n_tokens_neox': 1125, 'n_words': 357}