Skip to content

Commit

Permalink
Used methods to manipulate the data and improved the algorithm.
Browse files Browse the repository at this point in the history
  • Loading branch information
taflaj committed Apr 17, 2019
1 parent 7d0126b commit bbabbf0
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 57 deletions.
1 change: 1 addition & 0 deletions board.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# sample board
# 1 solution, 0:0:2.312 > 0:0:0.836 > 0:0:0.819 > 0:0:0.227
4 3 # 3 rows, containing 4 elements each
1 2 3 4 6 # first row
5 6 7 8 13
Expand Down
3 changes: 2 additions & 1 deletion complex.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# 115 solutions
# high complexity
# 115 solutions, 0:18:47.647 > 0:2:44.168 > 0:1:10.585 > 0:1:9.382
8 8
2 2 3 4 3 4 4 3 17
4 2 3 4 3 3 4 4 16
Expand Down
12 changes: 12 additions & 0 deletions high.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# high complexity
# 435 solutions, 0:4:0.955 > 0:1:19.424 > 0:0:52.183 > 0:0:51.410
8 8
4 2 3 2 4 3 4 4 18
3 4 3 3 3 2 4 2 16
3 4 2 4 4 4 3 4 21
3 3 3 4 3 3 2 2 17
4 3 4 4 3 2 3 4 24
3 4 3 4 2 4 3 4 21
4 4 2 4 3 2 4 4 19
3 3 3 4 4 3 2 4 19
20 20 17 21 14 21 18 24
12 changes: 12 additions & 0 deletions medium.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# medium complexity
# 3 solutions, 0:1:50.036 > 0:0:25.832 > 0:0:18.215 > 0:0:15.834
8 8
3 4 2 4 3 3 4 4 18
2 2 3 2 3 2 2 3 14
2 2 4 2 2 4 3 4 17
3 3 4 3 2 4 3 4 19
3 2 2 4 4 4 2 4 22
2 2 3 3 3 3 3 2 19
3 3 2 3 4 4 3 2 14
2 3 2 2 4 3 2 4 16
14 16 20 21 20 19 12 17
157 changes: 101 additions & 56 deletions rullo.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,72 @@ import (
"strings"
)

// Row represents a row within a board.
type Row []int

// Sum sums all elements of a row.
func (row Row) Sum() int {
sum := 0
for _, v := range row {
sum += v
}
return sum
}

// Board contains a series of rows forming a board.
type Board []Row

// Duplicate creates an exact copy of the board on a separate space.
func (board Board) Duplicate() Board {
rows := len(board)
dup := Board(make(Board, rows))
for i := 0; i < rows; i++ {
dup[i] = Row(make([]int, len(board[i])))
copy(dup[i], board[i])
}
return dup
}

// Sum sums a given column of a board.
func (board Board) Sum(col int) int {
sum := 0
for _, r := range board {
sum += r[col]
}
return sum
}

// Array contains an array of rows with valid solutions.
type Array []Row

// Append adds a new plausible solution to a given row.
func (a *Array) Append(solution Row) {
*a = append(*a, solution)
}

// Plausibles contains all rows with valid solutions.
type Plausibles []Array

// Assemble returns a board with a plausible solution.
func (p Plausibles) Assemble(c chan Board, board *Board, rowNo int) {
if rowNo >= len(p) { // board is assembled
c <- *board
*board = (*board).Duplicate() // to avoid data contamination
} else {
for _, row := range p[rowNo] { // choose each plausible solution on this row
(*board)[rowNo] = row
p.Assemble(c, board, rowNo+1) // proceed with the following row
}
}
}

// Iterate is a goroutine that returns all combinations of plausible solutions.
func (p Plausibles) Iterate(c chan Board) {
board := make(Board, len(p))
p.Assemble(c, &board, 0)
close(c)
}

// Converts a string to its numeric value.
func convert(line int, value string) int {
n, err := strconv.Atoi(value)
Expand Down Expand Up @@ -77,7 +143,7 @@ func load(c chan []int, s *bufio.Scanner) {
}

// Creates a new board with data from the input file.
func newBoard(file string) ([][]int, []int, []int) {
func newBoard(file string) (Board, []int, []int) {
f, err := os.Open(file)
if err != nil {
panic(fmt.Sprintf("Error opening file %v", file))
Expand All @@ -87,9 +153,9 @@ func newBoard(file string) ([][]int, []int, []int) {
go load(data, bufio.NewScanner(f))
row := <-data // first row contains board dimensions
rows := row[1]
board := make([][]int, rows)
for i := 0; i < rows; i++ {
board[i] = <-data
board := Board(make(Board, rows))
for i := 0; i < rows; i++ { // load rows
board[i] = Row(<-data)
}
horz := <-data // horizontal sums
vert := <-data // vertical sums
Expand All @@ -99,67 +165,46 @@ func newBoard(file string) ([][]int, []int, []int) {
return board, horz, vert
}

// Creates an exact copy of the board.
func duplicate(board [][]int) [][]int {
rows := len(board)
dup := make([][]int, rows)
for i := 0; i < rows; i++ {
dup[i] = make([]int, len(board[i]))
copy(dup[i], board[i])
}
return dup
}

// Sums all elements of a row.
func sum(row []int) int {
sum := 0
for _, v := range row {
sum += v
}
return sum
}

// Sums a given column of a board.
func vsum(board [][]int, col int) int {
sum := 0
for _, r := range board {
sum += r[col]
}
return sum
}

var solutions int

// Explores all possible solutions using brute force.
func explore(board [][]int, solution [][]int, r int, cols int, horz []int, vert []int) {
if r >= len(board) { // we may have a solution
solved := true
for i := 0; i < cols; i++ {
if vsum(solution, i) != vert[i] {
solved = false // this column failed validation
break
}
}
if solved {
solutions++
fmt.Printf("%3v: %v\n", solutions, solution)
}
} else {
for i := 0; i < 1<<uint(cols); i++ { // exercise all cells
func explore(board Board, horz []int, vert []int) {
rows := len(board)
cols := len(board[0])
plausibles := make(Plausibles, rows)
// find all plausible solutions for each row
for r := 0; r < rows; r++ {
plausibles[r] = Array{}
for i := 0; i < 1<<uint(cols); i++ { // exercise all combinations
k := i
row := make([]int, cols)
row := make(Row, cols)
for j := 0; j < cols; j++ {
if k%2 != 0 {
if k%2 == 0 {
row[j] = board[r][j]
}
k >>= 1
}
if sum(row) == horz[r] { // we have a plausibe solution
solution[r] = row
explore(board, solution, r+1, cols, horz, vert) // try the next row
if row.Sum() == horz[r] { // we have a plausible solution
plausibles[r].Append(row)
}
}
}
// match all plausible solutions with one another.
n := 0
solutions := make(chan Board, 100)
go plausibles.Iterate(solutions)
for solution := range solutions {
// see if the newly assembled board is an actual solution
solved := true
for col := range solution[0] {
if solution.Sum(col) != vert[col] {
solved = false // this column failed validation
break
}
}
if solved {
n++
fmt.Printf("%3v: %v\n", n, solution)
}
}
}

func main() {
Expand All @@ -176,6 +221,6 @@ func main() {
} else {
board, horz, vert := newBoard(os.Args[1])
fmt.Printf("board = %v\n horz = %v\n vert = %v\n", board, horz, vert)
explore(board, duplicate(board), 0, len(board[0]), horz, vert)
explore(board, horz, vert)
}
}

0 comments on commit bbabbf0

Please sign in to comment.