Skip to content

Commit

Permalink
refactor: cleanup pkg/tetris/ (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
Broderick-Westrope authored Dec 21, 2024
1 parent b031d24 commit bd944b2
Show file tree
Hide file tree
Showing 10 changed files with 782 additions and 760 deletions.
14 changes: 12 additions & 2 deletions cmd/tetrigo/subcommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,18 @@ func launchStarter(globals *GlobalVars, starterMode tui.Mode, switchIn tui.Switc
return fmt.Errorf("creating starter model: %w", err)
}

if _, err = tea.NewProgram(model, tea.WithAltScreen()).Run(); err != nil {
return fmt.Errorf("running tea program: %w", err)
exitModel, err := tea.NewProgram(model, tea.WithAltScreen()).Run()
if err != nil {
return fmt.Errorf("failed to run program: %w", err)
}

typedExitModel, ok := exitModel.(*starter.Model)
if !ok {
return fmt.Errorf("failed to assert exit model type: %w", err)
}

if err = typedExitModel.ExitError; err != nil {
return fmt.Errorf("starter model exited with an error: %w", err)
}

return nil
Expand Down
6 changes: 3 additions & 3 deletions internal/tui/views/single.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,9 +444,9 @@ func (m *SingleModel) bagView() string {

func (m *SingleModel) renderTetrimino(t *tetris.Tetrimino, background byte) string {
var output string
for row := range t.Minos {
for col := range t.Minos[row] {
if t.Minos[row][col] {
for row := range t.Cells {
for col := range t.Cells[row] {
if t.Cells[row][col] {
output += m.renderCell(t.Value)
} else {
output += m.renderCell(background)
Expand Down
12 changes: 7 additions & 5 deletions pkg/tetris/matrix.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
// Matrix represents the board of cells on which the game is played.
type Matrix [][]byte

// DefaultMatrix creates a new Matrix with a height of 40 and a width of 10.
func DefaultMatrix() Matrix {
m, err := NewMatrix(40, 10)
if err != nil {
Expand All @@ -17,6 +18,7 @@ func DefaultMatrix() Matrix {
}

// NewMatrix creates a new Matrix with the given height and width.
// It returns an error if the height is less than 20 to allow for a buffer zone of 20 lines.
func NewMatrix(height, width int) (Matrix, error) {
if height <= 20 {
return nil, errors.New("matrix height must be greater than 20 to allow for a buffer zone of 20 lines")
Expand Down Expand Up @@ -76,13 +78,13 @@ func (m *Matrix) RemoveTetrimino(tet *Tetrimino) error {
return cell == tet.Value
}

return m.modifyCell(tet.Minos, tet.Pos, 0, isExpectedValue)
return m.modifyCell(tet.Cells, tet.Position, 0, isExpectedValue)
}

// AddTetrimino adds the given Tetrimino to the Matrix.
// It returns an error if the Tetrimino is out of bounds or if the Tetrimino overlaps with an occupied mino.
func (m *Matrix) AddTetrimino(tet *Tetrimino) error {
return m.modifyCell(tet.Minos, tet.Pos, tet.Value, isCellEmpty)
return m.modifyCell(tet.Cells, tet.Position, tet.Value, isCellEmpty)
}

func (m *Matrix) modifyCell(minos [][]bool, pos Coordinate, newValue byte, isExpectedValue func(byte) bool) error {
Expand Down Expand Up @@ -122,9 +124,9 @@ func (m *Matrix) modifyCell(minos [][]bool, pos Coordinate, newValue byte, isExp
// It returns an Action to be used for calculating the score.
func (m *Matrix) RemoveCompletedLines(tet *Tetrimino) Action {
lines := 0
for row := range tet.Minos {
if m.isLineComplete(tet.Pos.Y + row) {
m.removeLine(tet.Pos.Y + row)
for row := range tet.Cells {
if m.isLineComplete(tet.Position.Y + row) {
m.removeLine(tet.Position.Y + row)
lines++
}
}
Expand Down
52 changes: 26 additions & 26 deletions pkg/tetris/matrix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ func TestMatrix_RemoveCompletedLines(t *testing.T) {
for name, tc := range tt {
t.Run(name, func(t *testing.T) {
tet := &Tetrimino{
Pos: Coordinate{0, tc.posY},
Minos: tc.cells,
Position: Coordinate{0, tc.posY},
Cells: tc.cells,
}

act := tc.matrix.RemoveCompletedLines(tet)
Expand Down Expand Up @@ -319,9 +319,9 @@ func TestMatrix_AddTetrimino(t *testing.T) {
{0, 0, 0},
},
tet: &Tetrimino{
Value: 'X',
Pos: Coordinate{1, 0},
Minos: [][]bool{
Value: 'X',
Position: Coordinate{1, 0},
Cells: [][]bool{
{false, true},
{true, true},
},
Expand All @@ -334,9 +334,9 @@ func TestMatrix_AddTetrimino(t *testing.T) {
"failure; row out of bounds": {
matrix: Matrix{{0}},
tet: &Tetrimino{
Value: 'X',
Pos: Coordinate{0, 1},
Minos: [][]bool{
Value: 'X',
Position: Coordinate{0, 1},
Cells: [][]bool{
{true},
{true},
},
Expand All @@ -346,9 +346,9 @@ func TestMatrix_AddTetrimino(t *testing.T) {
"failure; col out of bounds": {
matrix: Matrix{{0}},
tet: &Tetrimino{
Value: 'X',
Pos: Coordinate{1, 0},
Minos: [][]bool{
Value: 'X',
Position: Coordinate{1, 0},
Cells: [][]bool{
{true, true},
},
},
Expand All @@ -357,9 +357,9 @@ func TestMatrix_AddTetrimino(t *testing.T) {
"failure; mino not expected value": {
matrix: Matrix{{'#'}},
tet: &Tetrimino{
Value: 'X',
Pos: Coordinate{0, 0},
Minos: [][]bool{
Value: 'X',
Position: Coordinate{0, 0},
Cells: [][]bool{
{true},
},
},
Expand Down Expand Up @@ -395,9 +395,9 @@ func TestMatrix_RemoveTetrimino(t *testing.T) {
{0, 'X', 'X'},
},
tet: &Tetrimino{
Value: 'X',
Pos: Coordinate{1, 0},
Minos: [][]bool{
Value: 'X',
Position: Coordinate{1, 0},
Cells: [][]bool{
{false, true},
{true, true},
},
Expand All @@ -410,9 +410,9 @@ func TestMatrix_RemoveTetrimino(t *testing.T) {
"failure; row out of bounds": {
matrix: Matrix{{0}},
tet: &Tetrimino{
Value: 'X',
Pos: Coordinate{0, 1},
Minos: [][]bool{
Value: 'X',
Position: Coordinate{0, 1},
Cells: [][]bool{
{true},
{true},
},
Expand All @@ -422,9 +422,9 @@ func TestMatrix_RemoveTetrimino(t *testing.T) {
"failure; col out of bounds": {
matrix: Matrix{{0}},
tet: &Tetrimino{
Value: 'X',
Pos: Coordinate{1, 0},
Minos: [][]bool{
Value: 'X',
Position: Coordinate{1, 0},
Cells: [][]bool{
{true, true},
},
},
Expand All @@ -433,9 +433,9 @@ func TestMatrix_RemoveTetrimino(t *testing.T) {
"failure; mino not expected value": {
matrix: Matrix{{'#'}},
tet: &Tetrimino{
Value: 'X',
Pos: Coordinate{0, 0},
Minos: [][]bool{
Value: 'X',
Position: Coordinate{0, 0},
Cells: [][]bool{
{true},
},
},
Expand Down
16 changes: 8 additions & 8 deletions pkg/tetris/modes/single/single.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (g *Game) Hold() (bool, error) {
return false, err
}
g.holdQueue = t.DeepCopy()
g.holdQueue.Pos.Y += g.matrix.GetSkyline()
g.holdQueue.Position.Y += g.matrix.GetSkyline()

g.canHold = false
return false, nil
Expand All @@ -145,7 +145,7 @@ func (g *Game) TickLower() (bool, error) {
}

if g.fall.IsSoftDrop {
linesCleared := g.tetInPlay.Pos.Y - g.softDropStartRow
linesCleared := g.tetInPlay.Position.Y - g.softDropStartRow
if linesCleared > 0 {
g.scoring.AddSoftDrop(linesCleared)
}
Expand All @@ -161,7 +161,7 @@ func (g *Game) TickLower() (bool, error) {
}

func (g *Game) HardDrop() (bool, error) {
startRow := g.tetInPlay.Pos.Y
startRow := g.tetInPlay.Position.Y

for {
lockedDown, err := g.lowerTetInPlay()
Expand All @@ -176,7 +176,7 @@ func (g *Game) HardDrop() (bool, error) {
return true, nil
}

linesCleared := g.tetInPlay.Pos.Y - startRow
linesCleared := g.tetInPlay.Position.Y - startRow
g.scoring.AddHardDrop(linesCleared)

g.tetInPlay = g.nextQueue.Next()
Expand All @@ -194,10 +194,10 @@ func (g *Game) HardDrop() (bool, error) {
func (g *Game) ToggleSoftDrop() time.Duration {
g.fall.ToggleSoftDrop()
if g.fall.IsSoftDrop {
g.softDropStartRow = g.tetInPlay.Pos.Y
g.softDropStartRow = g.tetInPlay.Position.Y
return g.fall.SoftDropInterval
}
linesCleared := g.tetInPlay.Pos.Y - g.softDropStartRow
linesCleared := g.tetInPlay.Position.Y - g.softDropStartRow
if linesCleared > 0 {
g.scoring.AddSoftDrop(linesCleared)
}
Expand Down Expand Up @@ -252,7 +252,7 @@ func (g *Game) lowerTetInPlay() (bool, error) {
// It does not modify Game.tetInPlay. If true is returned the game is over.
func (g *Game) setupNewTetInPlay() bool {
// Block Out
if g.tetInPlay.IsOverlapping(g.matrix) {
if !g.tetInPlay.IsValid(g.matrix, false) {
g.gameOver = true
return true
}
Expand All @@ -268,7 +268,7 @@ func (g *Game) setupNewTetInPlay() bool {
g.canHold = true

if g.fall.IsSoftDrop {
g.softDropStartRow = g.tetInPlay.Pos.Y
g.softDropStartRow = g.tetInPlay.Position.Y
}

g.updateGhost()
Expand Down
16 changes: 9 additions & 7 deletions pkg/tetris/next_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ import (
// NextQueue is a collection of up to 14 Tetriminos that are drawn from randomly.
// The queue is refilled when it has less than 7 Tetriminos.
type NextQueue struct {
elements []Tetrimino
startLine int
elements []Tetrimino
skyline int
}

// NewNextQueue creates a new NextQueue of Tetriminos.
func NewNextQueue(startLine int) *NextQueue {
func NewNextQueue(skyline int) *NextQueue {
nq := NextQueue{
elements: make([]Tetrimino, 0, 14),
startLine: startLine,
elements: make([]Tetrimino, 0, 14),
skyline: skyline,
}
nq.fill()
nq.fill()
return &nq
}

// GetElements returns the Tetriminos in the queue.
func (nq *NextQueue) GetElements() []Tetrimino {
return nq.elements
}
Expand All @@ -36,10 +36,12 @@ func (nq *NextQueue) Next() *Tetrimino {
nq.fill()
}

tet.Pos.Y += nq.startLine
tet.Position.Y += nq.skyline
return &tet
}

// fill adds Tetriminos to the queue until it has 7 or more.
// This is done by getting all valid Tetriminos, shuffling them, and adding them to the queue.
func (nq *NextQueue) fill() {
if len(nq.elements) > 7 {
return
Expand Down
28 changes: 12 additions & 16 deletions pkg/tetris/next_queue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestNewNextQueue(t *testing.T) {
Expand All @@ -22,18 +23,13 @@ func TestNewNextQueue(t *testing.T) {
t.Run(name, func(t *testing.T) {
b := NewNextQueue(tc.matrixHeight)

if len(b.elements) != 14 {
t.Errorf("Length: want 14, got %d", len(b.elements))
}
assert.GreaterOrEqual(t, len(b.elements), 7, "Length: want at least 7, got %d", len(b.elements))

for _, e := range b.elements {
for _, tet := range GetValidTetriminos() {
if tet.Value != e.Value {
continue
}
tet, err := GetTetrimino(e.Value)
require.NoError(t, err)

assert.Equal(t, tet.Pos.X, e.Pos.X)
}
assert.Equal(t, tet.Position.X, e.Position.X)
}
})
}
Expand Down Expand Up @@ -64,24 +60,24 @@ func TestNextQueue_Next(t *testing.T) {
for name, tc := range tt {
t.Run(name, func(t *testing.T) {
nq := NextQueue{
elements: tc.elements,
startLine: 40,
elements: tc.elements,
skyline: 40,
}
expected := tc.elements[0].DeepCopy()
expected.Pos.Y += nq.startLine
expected.Position.Y += nq.skyline

var expectedElements []Tetrimino
for _, e := range tc.elements[1:] {
temp := e.DeepCopy()
temp.Pos.Y += nq.startLine
temp.Position.Y += nq.skyline
expectedElements = append(expectedElements, *temp)
}

result := nq.Next()
assert.EqualValues(t, *expected, *result)

for i := range nq.elements {
nq.elements[i].Pos.Y += nq.startLine
nq.elements[i].Position.Y += nq.skyline
}

v := nq.elements[:len(expectedElements)]
Expand Down Expand Up @@ -132,8 +128,8 @@ func TestNextQueue_Fill(t *testing.T) {
for name, tc := range tt {
t.Run(name, func(t *testing.T) {
nq := NextQueue{
elements: tc.elements,
startLine: 40,
elements: tc.elements,
skyline: 40,
}

for range tc.timesToFill {
Expand Down
Loading

0 comments on commit bd944b2

Please sign in to comment.