Skip to content

Commit e6c58bb

Browse files
committed
internal/puzzle: Add Solver interface and Run solutions func
1 parent 905ec77 commit e6c58bb

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

internal/puzzle/solver.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package puzzle
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"io/ioutil"
7+
"log"
8+
"sort"
9+
"sync"
10+
11+
"github.com/pkg/errors"
12+
)
13+
14+
// Solver represents solutions for puzzles methods.
15+
type Solver interface {
16+
Part1(input io.Reader) (string, error)
17+
Part2(input io.Reader) (string, error)
18+
Name() string
19+
}
20+
21+
var (
22+
solversMu sync.RWMutex
23+
solvers = make(map[string]Solver)
24+
)
25+
26+
// Register makes a puzzle solver available by the provided name.
27+
// If Register is called twice with the same name or if solver is nil,
28+
// it panics.
29+
func Register(name string, solver Solver) {
30+
solversMu.Lock()
31+
defer solversMu.Unlock()
32+
if solver == nil {
33+
panic("puzzle: Register solver is nil")
34+
}
35+
if _, dup := solvers[name]; dup {
36+
panic("puzzle: Register called twice for solver " + name)
37+
}
38+
solvers[name] = solver
39+
}
40+
41+
func unregisterAllSolvers() {
42+
solversMu.Lock()
43+
defer solversMu.Unlock()
44+
// For tests.
45+
solvers = make(map[string]Solver)
46+
}
47+
48+
// Solvers returns a sorted list of the names of the registered puzzle solvers.
49+
func Solvers() []string {
50+
solversMu.RLock()
51+
defer solversMu.RUnlock()
52+
var list []string
53+
for name := range solvers {
54+
list = append(list, name)
55+
}
56+
sort.Strings(list)
57+
return list
58+
}
59+
60+
// GetSolver returns registered solver by passed puzzle name.
61+
func GetSolver(name string) (Solver, error) {
62+
if name == "" {
63+
return nil, errors.New("empty puzzle name")
64+
}
65+
66+
solversMu.Lock()
67+
defer solversMu.Unlock()
68+
69+
s, exist := solvers[name]
70+
71+
if !exist {
72+
return nil, errors.Errorf("unknown puzzle name [%s]", name)
73+
}
74+
75+
return s, nil
76+
}
77+
78+
// Run uses solver of puzzle and path to input.
79+
func Run(solver Solver, filepath string) error {
80+
var (
81+
input []byte
82+
res string
83+
err error
84+
)
85+
86+
input, err = ioutil.ReadFile(filepath)
87+
if err != nil {
88+
return errors.Wrap(err, "failed to open file")
89+
}
90+
91+
log.Printf("run puzzle solver [%s]\n", solver.Name())
92+
93+
res, err = solver.Part1(bytes.NewBuffer(input))
94+
if err != nil {
95+
return errors.Wrapf(err, "failed to run Part1 for puzzle [%s]", solver.Name())
96+
}
97+
98+
log.Printf("Part1 answer: %s \n", res)
99+
100+
res, err = solver.Part2(bytes.NewBuffer(input))
101+
if err != nil {
102+
return errors.Wrapf(err, "failed to run Part2 for puzzle [%s]", solver.Name())
103+
}
104+
105+
log.Printf("Part2 answer: %s \n", res)
106+
107+
return nil
108+
}

0 commit comments

Comments
 (0)