Repository: vaskoz/dailycodingproblem-go (go)

Issue:
Day 64
Good morning! Here's your coding interview problem for today.

This problem was asked by Google.

A knight's tour is a sequence of moves by a knight on a chessboard such that all squares are visited once.

Given N, write a function to return the number of knight's tours on an N by N chessboard.

Pull request:
Day64
Resolves #138.

Patch:
diff --git a/README.md b/README.md
index f7d7a15..2ce9bd2 100644
--- a/README.md
+++ b/README.md
@@ -74,6 +74,7 @@ problems from
 * [Day 61](https://github.com/vaskoz/dailycodingproblem-go/issues/132)
 * [Day 62](https://github.com/vaskoz/dailycodingproblem-go/issues/134)
 * [Day 63](https://github.com/vaskoz/dailycodingproblem-go/issues/136)
+* [Day 64](https://github.com/vaskoz/dailycodingproblem-go/issues/138)
 * [Day 65](https://github.com/vaskoz/dailycodingproblem-go/issues/139)
 * [Day 66](https://github.com/vaskoz/dailycodingproblem-go/issues/141)
 * [Day 67](https://github.com/vaskoz/dailycodingproblem-go/issues/143)
diff --git a/day64/problem.go b/day64/problem.go
new file mode 100644
index 0000000..d8e133f
--- /dev/null
+++ b/day64/problem.go
@@ -0,0 +1,49 @@
+package day64
+
+// KnightsTourCountBacktracking returns the number of tours
+// on a NxN chessboard. The only argument is N.
+// Operates in exponential time. O(8^(N^2)).
+func KnightsTourCountBacktracking(N int) int {
+	var count int
+	for i := 0; i < N; i++ {
+		for j := 0; j < N; j++ {
+			board := make([][]bool, N)
+			for x := range board {
+				board[x] = make([]bool, N)
+			}
+			board[i][j] = true
+			count += knightsTourCounter(N, board, [][]int{{i, j}})
+		}
+	}
+	return count
+}
+
+func knightsTourCounter(N int, board [][]bool, tour [][]int) int {
+	if len(tour) == N*N {
+		return 1
+	}
+	var count int
+	last := tour[len(tour)-1]
+	r, c := last[0], last[1]
+	for _, move := range validMoves(board, r, c, N) {
+		board[move[0]][move[1]] = true
+		count += knightsTourCounter(N, board, append(tour, move))
+		board[move[0]][move[1]] = false
+	}
+	return count
+}
+
+func validMoves(board [][]bool, r, c, N int) [][]int {
+	moves := make([][]int, 0, 8)
+	deltas := [][]int{{2, 1}, {1, 2}, {1, -2}, {-2, 1}, {-1, 2}, {2, -1}, {-1, -2}, {-2, -1}}
+	for _, delta := range deltas {
+		if isValidMove(board, N, r+delta[0], c+delta[1]) {
+			moves = append(moves, []int{r + delta[0], c + delta[1]})
+		}
+	}
+	return moves
+}
+
+func isValidMove(board [][]bool, n, r, c int) bool {
+	return 0 <= r && r < n && 0 <= c && c < n && !board[r][c]
+}


Test patch:
diff --git a/day64/problem_test.go b/day64/problem_test.go
new file mode 100644
index 0000000..c2008af
--- /dev/null
+++ b/day64/problem_test.go
@@ -0,0 +1,28 @@
+package day64
+
+import "testing"
+
+var testcases = []struct {
+	N, Tours int
+}{
+	{1, 1},
+	{2, 0},
+	{3, 0},
+	{4, 0},
+	// {5, 1728}, // uncommenting takes 94.08s user 1.04s system 104% cpu 1:31.42 total
+}
+
+func TestKnightsTourCountBacktracking(t *testing.T) {
+	t.Parallel()
+	for _, tc := range testcases {
+		if result := KnightsTourCountBacktracking(tc.N); result != tc.Tours {
+			t.Errorf("For N=%d expected %d got %d", tc.N, tc.Tours, result)
+		}
+	}
+}
+
+func BenchmarkKnightsTourCountBacktracking(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		KnightsTourCountBacktracking(3)
+	}
+}