diff --git a/Readme.md b/Readme.md index 02bfc85..79a3816 100644 --- a/Readme.md +++ b/Readme.md @@ -12,7 +12,7 @@ Run the game of life directly with go -`go run main.go` +`go run .` ## Tests @@ -24,12 +24,12 @@ Execute all the test cases - [X] run it forever and update results in console - [ ] Review pending features from the origianl documentation -- [ ] refactor - - [ ] Modularize the code (Board Functionality != Game of Life Rules) +- [X] refactor + - [X] Modularize the code (Board Functionality != Game of Life Rules) - Is there a generic implementation to inject the Cell - How to restrict the types to be initialized just with specific functions - How to package the code? -- [ ] Board: connect edges so every cell will have 8 neighbors +- [X] Board: connect edges so every cell will have 8 neighbors - [ ] Refactor 2: - [ ] Memory Optimization? - Less memory consumption vs Inmutability diff --git a/board/board.go b/board/board.go index 1105417..22259f2 100644 --- a/board/board.go +++ b/board/board.go @@ -43,11 +43,21 @@ func NewRandomBoard(rows uint, columns uint, seed int64) Board { } func (board *Board) ToString() string { - strBuilder := strings.Builder{} - character := map[bool]string{ + return board.ToStringWith(map[bool]string{ true: "\u2588", false: "\u0020", - } + }) +} + +func (board *Board) ToNumbers() string { + return board.ToStringWith(map[bool]string{ + true: "1", + false: "0", + }) +} + +func (board *Board) ToStringWith(character map[bool]string) string { + strBuilder := strings.Builder{} for _, row := range *board { for _, cell := range row { strBuilder.WriteString(fmt.Sprintf("%s", character[cell])) @@ -66,26 +76,63 @@ func (board *Board) CountColumns() uint { return uint(len((*board)[0])) } -func (board *Board) LowerBound(index int) int { - if index == 0 { - return 0 +// TODO: Make borderless optional +func (board *Board) IterateNeighborsOfRow(row int) (val []bool, hasNext bool, idx int, it func() (val []bool, hasNext bool, idx int)) { + length := len(*board) + var currentIndex int + count := 1 + + if row == 0 { + currentIndex = int(board.CountRows()) - 1 + } else if row >= length { + currentIndex = length - 2 } else { - return index - 1 + currentIndex = row - 1 } -} + return (*board)[currentIndex], (count <= 3), currentIndex, func() (val []bool, hasNext bool, idx int) { + currentIndex++ + count++ -func (board *Board) RowsUpperBoundFor(index int) int { - return upperBound(index, len(*board)) -} + if currentIndex >= length { + currentIndex = 0 + } + + currentRow := (*board)[currentIndex] -func (board *Board) ColumnsUpperBoundFor(index int) int { - return upperBound(index, len((*board)[0])) + if len(currentRow) == 0 { + println("Here's an error") + } + + return (*board)[currentIndex], (count <= 3), currentIndex + + } } -func upperBound(index int, maxLength int) int { - if index >= maxLength-1 { - return index +func (board *Board) IterateNightborsOf(row []bool, column int) (cell bool, hasNext bool, idx int, it func() (cell bool, hasNext bool, idx int)) { + length := len(row) + var currentIndex int + count := 1 + + if column == 0 { + currentIndex = int(board.CountColumns()) - 1 + } else if column >= length { + currentIndex = length - 2 } else { - return index + 1 + currentIndex = column - 1 + } + + return row[currentIndex], (count <= 3), currentIndex, func() (cell bool, hasNext bool, idx int) { + currentIndex++ + count++ + + if currentIndex >= length { + currentIndex = 0 + } + + if length == 0 { + println("here's an error") + } + + return row[currentIndex], (count <= 3), currentIndex } } diff --git a/board/board_test.go b/board/board_test.go index 74c53da..ca418f3 100644 --- a/board/board_test.go +++ b/board/board_test.go @@ -76,48 +76,364 @@ func TestRandomInitializationBoard(t *testing.T) { } } -// func TestLowerBoundCentreCell(t *testing.T) { -// position := 3 -// expectedLowerBound := 2 +func TestIterateNeighborsOfRow(t *testing.T) { + boardExpected := Board{ + {false}, + {true}, + {false}, + } + + // first element, which is the prev neighgord + val, hasNext, idx, it := boardExpected.IterateNeighborsOfRow(1) + + if val[0] { + t.Error("Wrong `val`. Expected `false` in position 0") + } + + if idx != 0 { + t.Errorf("Wrong `idx=%d`. Expected position 0", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // second element, which is the row reviewed + val, hasNext, idx = it() + + if !val[0] { + t.Error("Wrong `val`. Expected `true` in position 1") + } + + if idx != 1 { + t.Errorf("Wrong `idx=%d`. Expected position 1", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // third element, which is the next row + val, hasNext, idx = it() + + if val[0] { + t.Error("Wrong `val`. Expected `false` in position 2") + } + + if idx != 2 { + t.Errorf("Wrong `idx=%d`. Expected position 2", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } +} + +func TestIterateNeighborsOfRowLowerBound(t *testing.T) { + boardExpected := Board{ + {false}, + {true}, + {false}, + } + + // first element, which is the prev neighgord + val, hasNext, idx, it := boardExpected.IterateNeighborsOfRow(0) + + if val[0] { + t.Error("Wrong `val`. Expected `false` in position 2") + } + + if idx != 2 { + t.Errorf("Wrong `idx=%d`. Expected position 2", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // second element, which is the row reviewed + val, hasNext, idx = it() + + if val[0] { + t.Error("Wrong `val`. Expected `true` in position 1") + } + + if idx != 0 { + t.Errorf("Wrong `idx=%d`. Expected position 0", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // third element, which is the next row + val, hasNext, idx = it() + + if !val[0] { + t.Error("Wrong `val`. Expected `false` in position 2") + } + + if idx != 1 { + t.Errorf("Wrong `idx=%d`. Expected position 1", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } +} + +func TestIterateNeighborsOfRowLowerBound100x100(t *testing.T) { + boardExpected := NewEmptyBoardOfSize(100, 100) + + row, hasNext, idx, it := boardExpected.IterateNeighborsOfRow(0) + + // first element, which is the prev neighgord + + if len(row) != 100 { + t.Error("Wrong `row` length. Expected 100") + } + + if idx != 99 { + t.Errorf("Wrong `idx=%d`. Expected position 99", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // second element, which is the row reviewed + row, hasNext, idx = it() + + if len(row) != 100 { + t.Error("Wrong `row` length. Expected 100") + } + + if idx != 0 { + t.Errorf("Wrong `idx=%d`. Expected position 0", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // third element, which is the next row + row, hasNext, idx = it() + + if len(row) != 100 { + t.Error("Wrong `row` length. Expected 100") + } + + if idx != 1 { + t.Errorf("Wrong `idx=%d`. Expected position 1", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } +} + +func TestIterateNeighborsOfRowUpperBound(t *testing.T) { + boardExpected := Board{ + {false}, + {true}, + {false}, + } + + // first element, which is the prev neighgord + val, hasNext, idx, it := boardExpected.IterateNeighborsOfRow(2) + + if !val[0] { + t.Error("Wrong `val`. Expected `false` in position 1") + } + + if idx != 1 { + t.Errorf("Wrong `idx=%d`. Expected position 1", idx) + } -// result := lowerBound(position) + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } -// if result != expectedLowerBound { -// t.Errorf("Lower bound mismatch result=%d | expected=%d", result, expectedLowerBound) -// } -// } + // second element, which is the row reviewed + val, hasNext, idx = it() -// func TestLowerBoundCornerCell(t *testing.T) { -// position := false -// expectedLowerBound := false + if val[0] { + t.Error("Wrong `val`. Expected `true` in position 2") + } -// result := lowerBound(position) + if idx != 2 { + t.Errorf("Wrong `idx=%d`. Expected position 2", idx) + } -// if result != expectedLowerBound { -// t.Errorf("Lower bound mismatch result=%d | expected=%d", result, expectedLowerBound) -// } -// } + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } -// func TestUpperBoundCentreCell(t *testing.T) { -// position := 3 -// length := 5 -// expectedLowerBound := 4 + // third element, which is the next row + val, hasNext, idx = it() -// result := upperBound(position, length) + if val[0] { + t.Error("Wrong `val`. Expected `false` in position 0") + } -// if result != expectedLowerBound { -// t.Errorf("Lower bound mismatch result=%d | expected=%d", result, expectedLowerBound) -// } -// } + if idx != 0 { + t.Errorf("Wrong `idx=%d`. Expected position 0", idx) + } -// func TestUpperBoundCornerCell(t *testing.T) { -// position := 4 -// length := 5 -// expectedLowerBound := 4 + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } +} + +func TestIterateNeighborsOfColumn(t *testing.T) { + boardExpected := Board{ + {false, true, false}, + } -// result := upperBound(position, length) + // first element, which is the prev neighgord + val, hasNext, idx, it := boardExpected.IterateNightborsOf(boardExpected[0], 1) -// if result != expectedLowerBound { -// t.Errorf("Lower bound mismatch result=%d | expected=%d", result, expectedLowerBound) -// } -// } + if val { + t.Error("Wrong `val`. Expected `false` in position 0") + } + + if idx != 0 { + t.Errorf("Wrong `idx=%d`. Expected position 0", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // second element, which is the row reviewed + val, hasNext, idx = it() + + if !val { + t.Error("Wrong `val`. Expected `true` in position 1") + } + + if idx != 1 { + t.Errorf("Wrong `idx=%d`. Expected position 1", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // third element, which is the next row + val, hasNext, idx = it() + + if val { + t.Error("Wrong `val`. Expected `false` in position 2") + } + + if idx != 2 { + t.Errorf("Wrong `idx=%d`. Expected position 2", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } +} + +func TestIterateNeighborsOfColumnsLowerBound(t *testing.T) { + boardExpected := Board{ + {false, true, false}, + } + + // first element, which is the prev neighgord + val, hasNext, idx, it := boardExpected.IterateNightborsOf(boardExpected[0], 0) + + if val { + t.Error("Wrong `val`. Expected `false` in position 2") + } + + if idx != 2 { + t.Errorf("Wrong `idx=%d`. Expected position 2", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // second element, which is the row reviewed + val, hasNext, idx = it() + + if val { + t.Error("Wrong `val`. Expected `true` in position 1") + } + + if idx != 0 { + t.Errorf("Wrong `idx=%d`. Expected position 0", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // third element, which is the next row + val, hasNext, idx = it() + + if !val { + t.Error("Wrong `val`. Expected `false` in position 2") + } + + if idx != 1 { + t.Errorf("Wrong `idx=%d`. Expected position 1", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } +} + +func TestIterateNeighborsOfColumnsUpperBound(t *testing.T) { + boardExpected := Board{ + {false, true, false}, + } + + // first element, which is the prev neighgord + val, hasNext, idx, it := boardExpected.IterateNightborsOf(boardExpected[0], 2) + + if !val { + t.Error("Wrong `val`. Expected `false` in position 1") + } + + if idx != 1 { + t.Errorf("Wrong `idx=%d`. Expected position 1", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // second element, which is the row reviewed + val, hasNext, idx = it() + + if val { + t.Error("Wrong `val`. Expected `true` in position 2") + } + + if idx != 2 { + t.Errorf("Wrong `idx=%d`. Expected position 2", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } + + // third element, which is the next row + val, hasNext, idx = it() + + if val { + t.Error("Wrong `val`. Expected `false` in position 0") + } + + if idx != 0 { + t.Errorf("Wrong `idx=%d`. Expected position 0", idx) + } + + if !hasNext { + t.Error("Iterator `it` calculated wrong `hasNext`") + } +}