-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #926 from vaskoz/day458
Day458
- Loading branch information
Showing
3 changed files
with
155 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package day458 | ||
|
||
import "strings" | ||
|
||
// Direction represents the eight cardinal and intercardinal directions. | ||
type Direction string | ||
|
||
const ( | ||
// N is North | ||
N Direction = "N" | ||
// NE is North-East | ||
NE Direction = "NE" | ||
// E is East | ||
E Direction = "E" | ||
// SE is South-East | ||
SE Direction = "SE" | ||
// S is South | ||
S Direction = "S" | ||
// SW is South-West | ||
SW Direction = "SW" | ||
// W is West | ||
W Direction = "W" | ||
// NW is North-West | ||
NW Direction = "NW" | ||
) | ||
|
||
// Position represents a point in Euclidean geometry. | ||
type Position struct { | ||
X, Y int | ||
} | ||
|
||
// directions defines the relative coordinates of each Direction. | ||
// nolint | ||
var directions = map[Direction]Position{ | ||
N: {0, -1}, | ||
NE: {1, -1}, | ||
E: {1, 0}, | ||
SE: {1, 1}, | ||
S: {0, 1}, | ||
SW: {-1, 1}, | ||
W: {-1, 0}, | ||
NW: {-1, -1}, | ||
} | ||
|
||
// IsValidRules answers if the rules are consistent. | ||
func IsValidRules(rules []string) bool { | ||
positions := make(map[string]Position) | ||
|
||
for _, rule := range rules { | ||
parts := strings.Split(rule, " ") | ||
to, dir, from := parts[0], Direction(parts[1]), parts[2] | ||
toPos, toFound := positions[to] | ||
fromPos, fromFound := positions[from] | ||
|
||
switch delta := directions[dir]; { | ||
case toFound && fromFound: | ||
if !checkValid(fromPos, toPos, dir) { | ||
return false | ||
} | ||
case toFound && !fromFound: | ||
positions[from] = Position{toPos.X - delta.X, toPos.Y - delta.Y} | ||
case !toFound && fromFound: | ||
positions[to] = Position{fromPos.X + delta.X, fromPos.Y + delta.Y} | ||
default: | ||
positions[from] = Position{0, 0} | ||
positions[to] = directions[dir] | ||
} | ||
} | ||
|
||
return true | ||
} | ||
|
||
func checkValid(from, to Position, dir Direction) bool { | ||
return isNorth(from, to, dir) || | ||
isNorthEast(from, to, dir) || | ||
isEast(from, to, dir) || | ||
isSouthEast(from, to, dir) || | ||
isSouth(from, to, dir) || | ||
isSouthWest(from, to, dir) || | ||
isWest(from, to, dir) || | ||
isNorthWest(from, to, dir) | ||
} | ||
|
||
func isNorth(from, to Position, dir Direction) bool { | ||
return dir == N && to.Y < from.Y | ||
} | ||
|
||
func isNorthEast(from, to Position, dir Direction) bool { | ||
return dir == NE && to.Y < from.Y && to.X > from.X | ||
} | ||
|
||
func isEast(from, to Position, dir Direction) bool { | ||
return dir == E && to.X > from.X | ||
} | ||
|
||
func isSouthEast(from, to Position, dir Direction) bool { | ||
return dir == SE && to.X > from.X && to.Y > from.Y | ||
} | ||
|
||
func isSouth(from, to Position, dir Direction) bool { | ||
return dir == S && to.Y > from.Y | ||
} | ||
|
||
func isSouthWest(from, to Position, dir Direction) bool { | ||
return dir == SW && to.X < from.X && to.Y > from.Y | ||
} | ||
|
||
func isWest(from, to Position, dir Direction) bool { | ||
return dir == W && to.X < from.X | ||
} | ||
|
||
func isNorthWest(from, to Position, dir Direction) bool { | ||
return dir == NW && to.Y < from.Y && to.X < from.X | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package day458 | ||
|
||
import "testing" | ||
|
||
// nolint | ||
var testcases = []struct { | ||
rules []string | ||
isValid bool | ||
}{ | ||
{[]string{"A N B", "B NE C", "C N A"}, false}, | ||
{[]string{"A NW B", "A N B"}, true}, | ||
{[]string{"A N B", "C N A", "A S C"}, true}, | ||
{[]string{"A NW B", "C NE A", "A S C"}, true}, | ||
{[]string{"A NW B", "C NE A", "A SE C"}, false}, | ||
{[]string{"A NW B", "C NE A", "A SW C"}, true}, | ||
{[]string{"A NW B", "C NE A", "A W C"}, true}, | ||
{[]string{"A NW B", "C NE A", "A E C"}, false}, | ||
{[]string{"A NW B", "C NE A", "B S C"}, true}, | ||
{[]string{"A NW B", "C NE A", "C E B"}, false}, | ||
{[]string{"A NW B", "C NE A", "B SE A"}, true}, | ||
{[]string{"A NW B", "C NE A", "A SE B"}, false}, | ||
} | ||
|
||
func TestIsValidRules(t *testing.T) { | ||
t.Parallel() | ||
|
||
for tcid, tc := range testcases { | ||
if result := IsValidRules(tc.rules); result != tc.isValid { | ||
t.Errorf("TC%d Expected %v got %v", tcid, tc.isValid, result) | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkIsValidRules(b *testing.B) { | ||
for i := 0; i < b.N; i++ { | ||
for _, tc := range testcases { | ||
IsValidRules(tc.rules) | ||
} | ||
} | ||
} |