Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
17459db
feat: add Conway's Game of Life realm
recule556688 Sep 22, 2025
50a7784
chore: remove README from root of namespace
recule556688 Sep 23, 2025
74a3608
feat: add tests for coordinate parsing and column conversion
recule556688 Sep 23, 2025
66e02b4
feat: add unit tests for grid, game engine, pattern manager, and rend…
recule556688 Sep 23, 2025
056025a
feat: add unit tests for grid operations, generation, and clearing fu…
recule556688 Sep 23, 2025
d4d9144
feat: add tests for pattern manager initialization and loading functi…
recule556688 Sep 23, 2025
7a6daf1
feat: add unit tests for renderer functionality including grid render…
recule556688 Sep 23, 2025
e5d11c5
refactor: reorganize game initialization and improve function documen…
recule556688 Sep 23, 2025
de72618
refactor: improve test function documentation for clarity and consist…
recule556688 Sep 23, 2025
114ebf4
refactor: enhance documentation for grid functions to improve clarity
recule556688 Sep 23, 2025
6fe83d5
refactor: improve documentation for GameEngine methods for clarity an…
recule556688 Sep 23, 2025
6892df9
refactor: enhance documentation for Pattern and PatternManager method…
recule556688 Sep 23, 2025
fcf1871
refactor: enhance documentation for Renderer methods for clarity and …
recule556688 Sep 23, 2025
b309ddc
feat: add GitHub Actions workflow for testing Conway package
recule556688 Sep 23, 2025
3e234c7
feat: add GitHub Actions workflow for testing Conway package
recule556688 Sep 23, 2025
0015c5b
fix: ensure Gno binary path is added to GITHUB_PATH during installation
recule556688 Sep 23, 2025
19f0fe7
style: remove unnecessary whitespace in code files for cleaner format…
recule556688 Sep 23, 2025
b51aa78
del: Removing the CI/CD
recule556688 Sep 24, 2025
7047593
feat: optimize grid handling by introducing a temporary grid for in-p…
recule556688 Sep 26, 2025
5aa4a77
feat: add optimized neighbor counting method to improve performance i…
recule556688 Sep 26, 2025
3c22c82
fix: update field name from 'cells' to 'Cells' for consistency and op…
recule556688 Sep 26, 2025
e7b1fa5
fix: update help text for 'Step' command to reflect optimized gas usa…
recule556688 Sep 26, 2025
6cb023e
fix: update command examples in RenderHelp to use correct package pat…
recule556688 Sep 26, 2025
106e4e2
fix: update README to replace 'NewGame' command with 'Clear' and adju…
recule556688 Sep 26, 2025
4af6120
Merge branch 'main' into main
leohhhn Oct 2, 2025
ac19313
fix: Fixing the coding style
recule556688 Oct 7, 2025
6b4a4bd
Merge branch 'main' into main
leohhhn Oct 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 188 additions & 0 deletions packages/r/karma1337/conway/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Conway's Game of Life

A fully-featured implementation of Conway's Game of Life as a Gno realm (smart contract). This implementation includes multiple coordinate systems, pre-defined patterns, and an intuitive web interface.

## Features

- **Dual Coordinate Systems**: Support for both numeric (x,y) and letter-based (e.g., "F5") coordinates
- **Pre-defined Patterns**: Includes classic patterns like blinker, block, and glider
- **Web Rendering**: Beautiful grid display with column labels and proper formatting
- **Interactive Help**: Built-in documentation and command examples
- **Gas-Optimized**: Efficient state management for blockchain deployment

## Package Path

When deployed to gnoverse, this package will be available at:
```
gno.land/r/karma1337/conway
```

## Usage

### Clearing the Grid

```bash
gnokey maketx call -pkgpath "gno.land/r/karma1337/conway" -func "Clear" -gas-fee 1000000ugnot -gas-wanted 5000000 -send "" --broadcast [your-key]
```

### Setting Individual Cells

**Using numeric coordinates (x, y):**
```bash
gnokey maketx call -pkgpath "gno.land/r/karma1337/conway" -func "SetCell" -args "5" -args "5" -args "true" -gas-fee 1000000ugnot -gas-wanted 5000000 -send "" --broadcast [your-key]
```

**Using letter coordinates (e.g., F5):**
```bash
gnokey maketx call -pkgpath "gno.land/r/karma1337/conway" -func "SetCellAt" -args "F5" -args "true" -gas-fee 1000000ugnot -gas-wanted 5000000 -send "" --broadcast [your-key]
```

### Loading Patterns

**Available patterns:** `blinker`, `block`, `glider`

**Using numeric coordinates:**
```bash
gnokey maketx call -pkgpath "gno.land/r/karma1337/conway" -func "LoadPattern" -args "blinker" -args "5" -args "5" -gas-fee 1000000ugnot -gas-wanted 5000000 -send "" --broadcast [your-key]
```

**Using letter coordinates:**
```bash
gnokey maketx call -pkgpath "gno.land/r/karma1337/conway" -func "LoadPatternAt" -args "glider" -args "C3" -gas-fee 1000000ugnot -gas-wanted 5000000 -send "" --broadcast [your-key]
```

### Advancing the Game

```bash
gnokey maketx call -pkgpath "gno.land/r/karma1337/conway" -func "Step" -gas-fee 2000000ugnot -gas-wanted 20000000 -send "" --broadcast [your-key]
```

**Note:** The Step function requires significant gas due to calculating the next generation for all cells.

### Viewing the Game State

Visit the web interface at:
```
https://gno.land/r/karma1337/conway
```

Or query programmatically:
```bash
gnokey query vm/qrender -data "gno.land/r/karma1337/conway"
```

## API Reference

### Game Management Functions

- `Step()` - Advance the game by one generation
- `Clear()` - Reset the grid to empty state

### Cell Manipulation Functions

#### Numeric Coordinates
- `SetCell(x, y, alive)` - Set cell state using numeric coordinates
- `GetCell(x, y)` - Get cell state using numeric coordinates
- `LoadPattern(pattern, x, y)` - Load pattern at numeric coordinates

#### Letter Coordinates
- `SetCellAt(coordinate, alive)` - Set cell state using letter coordinates (e.g., "F5")
- `GetCellAt(coordinate)` - Get cell state using letter coordinates
- `LoadPatternAt(pattern, coordinate)` - Load pattern at letter coordinates

### Information Functions

- `GetGeneration()` - Get current generation number
- `GetAvailablePatterns()` - List all available patterns
- `Render()` - Get formatted grid display (called automatically by web interface)

## Coordinate Systems

### Numeric Coordinates
- x: 0-19 (columns, left to right)
- y: 0-19 (rows, top to bottom)
- Example: `(10, 10)` is near the center

### Letter Coordinates
- Columns: A-T (left to right, 20 columns)
- Rows: 0-19 (top to bottom, 20 rows)
- Example: `"K10"` is near the center
- Case insensitive: `"k10"` and `"K10"` are equivalent

## Available Patterns

### Blinker (Oscillator)
A simple 3-cell pattern that oscillates between horizontal and vertical:
```
.#. ...
.#. -> ###
.#. ...
```

### Block (Still Life)
A stable 2x2 pattern that never changes:
```
##
##
```

### Glider (Spaceship)
A 5-cell pattern that moves diagonally across the grid:
```
.#.
..#
###
```

## Game Rules

Conway's Game of Life follows these simple rules:

1. **Underpopulation**: Live cells with fewer than 2 neighbors die
2. **Survival**: Live cells with 2-3 neighbors survive
3. **Overpopulation**: Live cells with more than 3 neighbors die
4. **Reproduction**: Dead cells with exactly 3 neighbors become alive

## Grid Display

The web interface displays the grid with:
- Capital letters (A-T) for column headers (20 columns)
- Numbers (0-19) for row headers (20 rows)
- `●` for alive cells
- `.` for dead cells
- Proper spacing for readability

Example display:
```
A B C D E F G H I J K L M N O P Q R S T
0 . . . . . . . . . . . . . . . . . . . .
1 . . . . . . . . . . . . . . . . . . . .
2 . . ● . . . . . . . . . . . . . . . . .
3 . . . ● . . . . . . . . . . . . . . . .
4 . ● ● ● . . . . . . . . . . . . . . . .
5 . . . . . . . . . . . . . . . . . . . .
...
```

## Development

This package consists of several modules:

- **conway.gno**: Main API and coordinate handling
- **grid.gno**: Core game logic and grid management
- **patterns.gno**: Pattern definitions and loading
- **renderer.gno**: Web display and help text
- **game.gno**: Game state management

## Contributing

This package is part of the Gnoverse community repository. To contribute:

1. Fork the [gnoverse/community](https://github.com/gnoverse/community) repository
2. Make your changes in `packages/r/karma1337/conway/`
3. Test your changes locally
4. Submit a pull request

## License

This implementation is part of the Gno ecosystem and follows the same licensing terms.
151 changes: 151 additions & 0 deletions packages/r/karma1337/conway/conway.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package conway

import (
"strconv"
"strings"
)

var (
// currentGrid holds the current state of the Conway's Game of Life grid
currentGrid = NewGrid()
// tempGrid is a reusable grid to avoid memory allocation on each step
tempGrid = NewGrid()
// gameEngine handles the game logic and evolution rules
gameEngine = NewGameEngine()
// patternManager manages predefined patterns that can be loaded into the grid
patternManager = NewPatternManager()
// renderer handles the display and formatting of the game state
renderer = NewRenderer()
)

// SetCell sets a cell at coordinates (x, y) to alive (true) or dead (false).
func SetCell(_ realm, x, y int, alive bool) {
currentGrid.SetCell(x, y, alive)
}

// GetCell returns the state of the cell at coordinates (x, y).
func GetCell(_ realm, x, y int) bool {
return currentGrid.GetCell(x, y)
}

// Step advances the game by one generation according to Conway's rules.
func Step(_ realm) {
gameEngine.StepInPlace(currentGrid, tempGrid)
// Swap the grids to avoid copying
currentGrid, tempGrid = tempGrid, currentGrid
}

// GetGeneration returns the current generation number.
func GetGeneration(_ realm) int {
return currentGrid.GetGeneration()
}

// Clear resets the grid to all dead cells.
func Clear(_ realm) {
currentGrid.Clear()
}

// LoadPattern loads a predefined pattern into the grid at the specified position.
// Returns true if the pattern was successfully loaded, false otherwise.
func LoadPattern(_ realm, pattern string, startX, startY int) bool {
return patternManager.LoadPattern(currentGrid, pattern, startX, startY)
}

// GetAvailablePatterns returns a list of available pattern names.
func GetAvailablePatterns(_ realm) []string {
return patternManager.GetAvailablePatterns()
}

// SetCellAt sets a cell using letter-number coordinates (e.g., "F5").
// Returns true if the coordinate was valid and the cell was set, false otherwise.
func SetCellAt(_ realm, coordinate string, alive bool) bool {
col, row, valid := parseCoordinate(coordinate)
if !valid {
return false
}
currentGrid.SetCell(col, row, alive)
return true
}

// GetCellAt returns the state of a cell using letter-number coordinates (e.g., "F5").
// Returns the cell state and a boolean indicating if the coordinate was valid.
func GetCellAt(_ realm, coordinate string) (bool, bool) {
col, row, valid := parseCoordinate(coordinate)
if !valid {
return false, false
}
return currentGrid.GetCell(col, row), true
}

// LoadPatternAt loads a pattern using letter-number coordinates (e.g., "F5").
// Returns true if the coordinate was valid and the pattern was loaded, false otherwise.
func LoadPatternAt(_ realm, pattern string, coordinate string) bool {
col, row, valid := parseCoordinate(coordinate)
if !valid {
return false
}
return patternManager.LoadPattern(currentGrid, pattern, col, row)
}

// Render displays the current state of the game as a formatted string.
func Render(path string) string {
var output strings.Builder

output.WriteString("# Conway's Game of Life\n\n")
output.WriteString("Generation: " + strconv.Itoa(currentGrid.GetGeneration()) + "\n\n")

output.WriteString(renderer.RenderHelp(patternManager))
output.WriteString(renderer.RenderGrid(currentGrid))

return output.String()
}

// letterToColumn converts a letter to column number (A=0, B=1, etc.).
// Returns -1 if the letter is invalid or out of range.
func letterToColumn(letter string) int {
if len(letter) == 0 {
return -1
}
// Convert to uppercase and get first character
upper := strings.ToUpper(letter)
col := int(upper[0] - 'A')
if col < 0 || col >= GRID_WIDTH {
return -1
}
return col
}

// columnToLetter converts a column number to letter (0=A, 1=B, etc.).
// Returns an empty string if the column is out of range.
func columnToLetter(col int) string {
if col < 0 || col >= GRID_WIDTH {
return ""
}
return string(rune('A' + col))
}

// parseCoordinate parses coordinates like "F5" into column and row numbers.
// Returns the column, row, and a boolean indicating if the coordinate was valid.
func parseCoordinate(coordinate string) (int, int, bool) {
if len(coordinate) < 2 {
return -1, -1, false
}

// Extract letter part and number part
letter := coordinate[:1]
numberStr := coordinate[1:]

// Convert letter to column
col := letterToColumn(letter)
if col == -1 {
return -1, -1, false
}

// Convert number string to row
row, err := strconv.Atoi(numberStr)
if err != nil || row < 0 || row >= GRID_HEIGHT {
return -1, -1, false
}

return col, row, true
}
Loading