Skip to content

Commit

Permalink
Merge 207700b into 694da09
Browse files Browse the repository at this point in the history
  • Loading branch information
vaskoz committed Jul 24, 2019
2 parents 694da09 + 207700b commit 3934abe
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,4 @@ problems from
* [Day 322](https://github.com/vaskoz/dailycodingproblem-go/issues/654)
* [Day 323](https://github.com/vaskoz/dailycodingproblem-go/issues/656)
* [Day 324](https://github.com/vaskoz/dailycodingproblem-go/issues/658)
* [Day 325](https://github.com/vaskoz/dailycodingproblem-go/issues/660)
63 changes: 63 additions & 0 deletions day325/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package day325

import (
"errors"
)

// Unit represents a unit of measure.
type Unit string

// Converter knows how to convert from/to different
// units of measure.
type Converter struct {
table map[Unit]map[Unit]float64
}

// ErrConversionImpossible returns the error given when a conversion
// isn't possible.
func ErrConversionImpossible() error {
return errConversionImpossible
}

var errConversionImpossible = errors.New("conversion is impossible between these units")

// Convert attempts to convert a value from one unit to another.
// Uses a DFS algorithm to find a path to that conversion.
func (c *Converter) Convert(val float64, from, to Unit) (float64, error) {
visited := make(map[Unit]struct{})
return c.convert(val, from, to, visited)
}

func (c *Converter) convert(val float64, from, to Unit, visited map[Unit]struct{}) (float64, error) {
if factor, found := c.table[from][to]; found {
return val * factor, nil
}
for nextTo, factor := range c.table[from] {
if _, seen := visited[nextTo]; seen {
continue
}
visited[nextTo] = struct{}{}
if result, err := c.convert(val*factor, nextTo, to, visited); err == nil {
return result, nil
}
delete(visited, nextTo)
}
return 0.0, ErrConversionImpossible()
}

// AddConversion adds a new conversion rule to the table in both directions.
func (c *Converter) AddConversion(factor float64, from, to Unit) {
if _, exists := c.table[from]; !exists {
c.table[from] = make(map[Unit]float64)
}
if _, exists := c.table[to]; !exists {
c.table[to] = make(map[Unit]float64)
}
c.table[from][to] = factor
c.table[to][from] = 1.0 / factor
}

// NewConverter returns a pointer to a new Converter.
func NewConverter() *Converter {
return &Converter{make(map[Unit]map[Unit]float64)}
}
81 changes: 81 additions & 0 deletions day325/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package day325

import (
"testing"
)

// nolint
var testcases = []struct {
val float64
from, to Unit
expected float64
err error
tolerance float64
}{
{
10.0,
"in", "cm",
25.4,
nil,
0.05,
},
{
10.0,
"in", "km",
0.000254,
nil,
0.0000005,
},
{
10.0,
"in", "km",
0.000254,
nil,
0.0000005,
},
{
10.0,
"in", "ml",
0.0,
ErrConversionImpossible(),
0.0,
},
}

func TestConverter(t *testing.T) {
t.Parallel()
c := NewConverter()
c.AddConversion(12.0, "ft", "in")
c.AddConversion(5280.0, "mi", "ft")
c.AddConversion(1.609, "mi", "km")
c.AddConversion(1000, "km", "m")
c.AddConversion(100, "m", "cm")
c.AddConversion(3.0, "yd", "ft")
c.AddConversion(22.0, "chain", "yd")
for _, tc := range testcases {
if result, err := c.Convert(tc.val, tc.from, tc.to); err != tc.err || abs(result-tc.expected) > tc.tolerance {
t.Errorf("Expected (%v,%v), got (%v,%v)", tc.expected, tc.err, result, err)
}
}
}

func BenchmarkConverter(b *testing.B) {
c := NewConverter()
c.AddConversion(12.0, "in", "ft")
c.AddConversion(5280.0, "ft", "mi")
c.AddConversion(1.609, "mi", "km")
c.AddConversion(0.001, "km", "m")
c.AddConversion(0.01, "m", "cm")
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
c.Convert(tc.val, tc.from, tc.to) // nolint
}
}
}

func abs(a float64) float64 {
if a < 0 {
return -a
}
return a
}

0 comments on commit 3934abe

Please sign in to comment.