Update textris draft
This commit is contained in:
parent
48abd89324
commit
09b22d132e
|
@ -1,13 +1,16 @@
|
|||
---
|
||||
title: "Textris - Creating a terminal-based Tetris clone in Go - Part 1: Pieces and playfield"
|
||||
title: "Textris - Part 1: Pieces and playfield - Creating a terminal-based Tetris clone"
|
||||
#date: 2019-11-26T01:42:18-07:00
|
||||
categories: [tutorial]
|
||||
draft: true
|
||||
---
|
||||
|
||||
This is the first in a series of tutorials on creating a [terminal-based](https://en.wikipedia.org/wiki/Text-based_user_interface) [Tetris](https://en.wikipedia.org/wiki/Tetris) clone with [Go](https://golang.org).
|
||||
|
||||
Game pieces (minos) are generated and added to a playfield (matrix).
|
||||
|
||||
## Disclaimer
|
||||
|
||||
Tetris is a registered trademark of the Tetris Holding, LLC.
|
||||
|
||||
Rocket Nine Labs is in no way affiliated with Tetris Holding, LLC.
|
||||
|
@ -17,13 +20,16 @@ Rocket Nine Labs is in no way affiliated with Tetris Holding, LLC.
|
|||
* [Minos](#minos)
|
||||
* [Data model](#data-model)
|
||||
* [Generation](#generation)
|
||||
* [Comparing and sorting](#comparing-and-sorting)
|
||||
* [Generating new minos](#generating-new-minos)
|
||||
* [Matrix](#matrix)
|
||||
* [Data model](#data-model)
|
||||
|
||||
# Minos
|
||||
|
||||
Game pieces are called "Minos" because they are [polyominos](https://en.wikipedia.org/wiki/Polyomino).
|
||||
Game pieces are called "minos" because they are [polyominos](https://en.wikipedia.org/wiki/Polyomino).
|
||||
This tutorial focuses on the seven one-sided [terominos](https://en.wikipedia.org/wiki/Tetromino), where each piece has four blocks.
|
||||
|
||||
The number of blocks a mino has is also known as its rank.
|
||||
|
||||
| I | O | T | J | L | S | Z |
|
||||
|
@ -33,7 +39,7 @@ The number of blocks a mino has is also known as its rank.
|
|||
## Data model
|
||||
|
||||
Tetris is played on an [X-Y grid](https://en.wikipedia.org/wiki/Cartesian_coordinate_system).
|
||||
We will store Minos as slices of points:
|
||||
We will store Minos as slices of points.
|
||||
|
||||
```go
|
||||
type Point struct {
|
||||
|
@ -45,15 +51,6 @@ func (p Point) Rotate180() Point { return Point{-p.X, -p.Y} }
|
|||
func (p Point) Rotate270() Point { return Point{-p.Y, p.X} }
|
||||
func (p Point) Reflect() Point { return Point{-p.X, p.Y} }
|
||||
|
||||
// Neighborhood returns the Von Neumann neighborhood of a point
|
||||
func (p Point) Neighborhood() Mino {
|
||||
return Mino{
|
||||
{p.X - 1, p.Y},
|
||||
{p.X, p.Y - 1},
|
||||
{p.X + 1, p.Y},
|
||||
{p.X, p.Y + 1}}
|
||||
}
|
||||
|
||||
type Mino []Point
|
||||
|
||||
var minoT = Mino{{0, 0}, {1, 0}, {2, 0}, {1, 1}}
|
||||
|
@ -66,7 +63,7 @@ This allows us to play with any size of mino.
|
|||
|
||||
### Comparing and sorting
|
||||
|
||||
To compare minos more easily, we will use their string representation.
|
||||
To compare minos efficiently while generating, we will compare their string representation.
|
||||
We will define a String method which sorts the coordinates before printing.
|
||||
This allows us to compare duplicate minos just by checking their string values.
|
||||
|
||||
|
@ -236,7 +233,19 @@ func (m Mino) Canonical() Mino {
|
|||
|
||||
### Generating new minos
|
||||
|
||||
WIP
|
||||
Neighborhood returns the [Von Neumann neighborhood](https://en.wikipedia.org/wiki/Von_Neumann_neighborhood) of a point.
|
||||
|
||||
```go
|
||||
func (p Point) Neighborhood() []Point {
|
||||
return []Point{
|
||||
{p.X - 1, p.Y},
|
||||
{p.X, p.Y - 1},
|
||||
{p.X + 1, p.Y},
|
||||
{p.X, p.Y + 1}}
|
||||
}
|
||||
```
|
||||
|
||||
NewPoints calculates the neighborhood of each point of a mino and returns only new points.
|
||||
|
||||
```go
|
||||
func (m Mino) HasPoint(p Point) bool {
|
||||
|
@ -249,22 +258,26 @@ func (m Mino) HasPoint(p Point) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (m Mino) newPoints() Mino {
|
||||
var newMino Mino
|
||||
func (m Mino) NewPoints() []Point {
|
||||
var newPoints []Point
|
||||
|
||||
for _, p := range m {
|
||||
for _, np := range p.Neighborhood() {
|
||||
if !m.HasPoint(np) {
|
||||
newMino = append(newMino, np)
|
||||
newPoints = append(newPoints, np)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newMino
|
||||
return newPoints
|
||||
}
|
||||
```
|
||||
|
||||
func (m Mino) newMinos() []Mino {
|
||||
points := m.newPoints()
|
||||
NewMinos returns a new mino for every new neighborhood point of a supplied mino.
|
||||
|
||||
```go
|
||||
func (m Mino) NewMinos() []Mino {
|
||||
points := m.NewPoints()
|
||||
|
||||
minos := make([]Mino, len(points))
|
||||
for i, p := range points {
|
||||
|
@ -275,13 +288,56 @@ func (m Mino) newMinos() []Mino {
|
|||
}
|
||||
```
|
||||
|
||||
Generate procedurally generates minos of a supplied rank.
|
||||
|
||||
```go
|
||||
func Generate(rank int) ([]Mino, error) {
|
||||
switch {
|
||||
case rank < 0:
|
||||
return nil, errors.New("invalid rank")
|
||||
case rank == 0:
|
||||
return []Mino{}, nil
|
||||
case rank == 1:
|
||||
return []Mino{monomino()}, nil
|
||||
default:
|
||||
r, err := Generate(rank - 1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
minos []Mino
|
||||
s string
|
||||
found = make(map[string]bool)
|
||||
)
|
||||
for _, mino := range r {
|
||||
for _, newMino := range mino.NewMinos() {
|
||||
s = newMino.Canonical().String()
|
||||
if found[s] {
|
||||
continue
|
||||
}
|
||||
|
||||
minos = append(minos, newMino.Canonical())
|
||||
found[s] = true
|
||||
}
|
||||
}
|
||||
|
||||
return minos, nil
|
||||
}
|
||||
}
|
||||
|
||||
func monomino() Mino {
|
||||
return Mino{{0, 0}}
|
||||
}
|
||||
```
|
||||
|
||||
# Matrix
|
||||
|
||||
The matrix is typically 10 blocks wide and 20 blocks high.
|
||||
|
||||
## Data model
|
||||
|
||||
A block represents the contents of a single X-Y coordinate on the matrix.
|
||||
A block is an integer representing the contents of a single X-Y coordinate on the matrix.
|
||||
|
||||
```go
|
||||
type Block int
|
||||
|
@ -301,6 +357,9 @@ const (
|
|||
The matrix will be stored as a slice of blocks.
|
||||
The zero-value of Block is a blank space.
|
||||
|
||||
The matrix has a width, height and buffer height.
|
||||
The buffer is additional space above the visible playfield.
|
||||
|
||||
```go
|
||||
type Matrix struct {
|
||||
W int // Width
|
||||
|
|
Loading…
Reference in New Issue