Compare commits

..

6 Commits

Author SHA1 Message Date
c45143dea5 Specify version
All checks were successful
Tests / build (push) Successful in 20s
2026-03-18 23:15:22 -07:00
d2d5243711 Test gitea
Some checks failed
Tests / build (push) Failing after 23s
2026-03-18 23:14:20 -07:00
5ddcbd461c Specify version
Some checks failed
Tests / build (push) Has been cancelled
2026-03-18 23:09:14 -07:00
2b8b721ec8 Add workflow
Some checks failed
Tests / build (push) Failing after 31s
2026-03-18 23:05:29 -07:00
0ec93d0a1d Tests 2026-03-18 23:01:19 -07:00
30812e9763 Colors... 2026-03-18 23:00:11 -07:00
7 changed files with 76 additions and 24 deletions

19
.github/workflows/tests.yml vendored Normal file
View File

@ -0,0 +1,19 @@
name: Tests
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-go@v3
with:
go-version: '1.25.x'
- name: Install dependencies
run: go get .
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...

View File

@ -8,7 +8,7 @@ import (
func TestCursor(t *testing.T) { func TestCursor(t *testing.T) {
Convey("Given a cursor", t, func() { Convey("Given a cursor", t, func() {
s := New(4, 4) s := New(4, 4, false)
So(*s.cursor, ShouldResemble, Point{0, 0}) So(*s.cursor, ShouldResemble, Point{0, 0})
Convey("When moving cell to cell", func() { Convey("When moving cell to cell", func() {

View File

@ -12,7 +12,7 @@ func TestHistory(t *testing.T) {
Convey("Given a game's history", t, func() { Convey("Given a game's history", t, func() {
Convey("You can maintain a history of all actions", func() { Convey("You can maintain a history of all actions", func() {
s := New(2, 2) s := New(2, 2, false)
s.Flag() s.Flag()
s.Mark() s.Mark()
s.Clear() s.Clear()

View File

@ -41,7 +41,7 @@ type State struct {
rowHeaders, colHeaders []header rowHeaders, colHeaders []header
} }
func New(sectionSize, cellsPerSection int) *State { func New(sectionSize, cellsPerSection int, reveal bool) *State {
s := &State{ s := &State{
sectionSize: sectionSize, sectionSize: sectionSize,
cellsPerSection: cellsPerSection, cellsPerSection: cellsPerSection,
@ -58,7 +58,33 @@ func New(sectionSize, cellsPerSection int) *State {
s.initSection(Point{x, y}) s.initSection(Point{x, y})
} }
} }
// TODO reveal 1 row per section, 1 col per sections/2 if reveal {
for i := 0; i < s.sectionSize; i++ {
reveal := i*s.cellsPerSection + rand.Intn(s.cellsPerSection)
s.history += fmt.Sprintf("ry(%d)", reveal)
for x := 0; x < s.size(); x++ {
p := Point{x, reveal}
if s.cells.state(p) {
s.mark(p)
} else {
s.flag(p)
}
}
if rand.Int()%2 == 0 {
reveal = i*s.cellsPerSection + rand.Intn(s.cellsPerSection)
s.history += fmt.Sprintf("rx(%d)", reveal)
for y := 0; y < s.size(); y++ {
p := Point{reveal, y}
if s.cells.state(p) {
s.mark(p)
} else {
s.flag(p)
}
}
}
}
}
s.initialized = true s.initialized = true
return s return s
} }

View File

@ -10,7 +10,7 @@ import (
func TestState(t *testing.T) { func TestState(t *testing.T) {
Convey("Given a game state", t, func() { Convey("Given a game state", t, func() {
s := New(2, 2) s := New(2, 2, false)
for x := 0; x < 4; x++ { for x := 0; x < 4; x++ {
for y := 0; y < 4; y++ { for y := 0; y < 4; y++ {
s.cells.kill(Point{x, y}) s.cells.kill(Point{x, y})

View File

@ -7,16 +7,18 @@ import (
) )
var ( var (
complete = []string{"██ ", "██ "}
flagged = []string{"╲╱ ", "╱╲ "}
marked = []string{"╭╮ ", "╰╯ "}
blank = []string{".- ", " "}
cursorStyle = lipgloss.NewStyle(). cursorStyle = lipgloss.NewStyle().
Background(lipgloss.Color("#005566")) Background(lipgloss.White)
gridStyle = lipgloss.NewStyle(). gridStyle = lipgloss.NewStyle().
Foreground(lipgloss.Black) Foreground(lipgloss.Black)
markedStyle = lipgloss.NewStyle()
complete = []string{"██ ", "██ "}
flagged = []string{"╲╱ ", "╱╲ "}
marked = []string{" ", " "}
blank = []string{" ", " "}
) )
func (c *cell) View() []string { func (c *cell) View() []string {
@ -32,7 +34,7 @@ func (c *cell) View() []string {
} }
func (f *field) View(p *Point, sectionSize, cellsPerSection int) string { func (f *field) View(p *Point, sectionSize, cellsPerSection int) string {
res := gridStyle.Render("┌") res := gridStyle.Render("┌")
for c := 0; c < cellsPerSection*sectionSize*3; c++ { for c := 0; c < cellsPerSection*sectionSize*3; c++ {
res += gridStyle.Render("─") res += gridStyle.Render("─")
if c == cellsPerSection*sectionSize*3-1 { if c == cellsPerSection*sectionSize*3-1 {
@ -40,43 +42,48 @@ func (f *field) View(p *Point, sectionSize, cellsPerSection int) string {
break break
} }
if c%(cellsPerSection*3) == cellsPerSection*3-1 { if c%(cellsPerSection*3) == cellsPerSection*3-1 {
res += gridStyle.Render("┬") res += gridStyle.Render("┬")
} }
} }
resA := gridStyle.Render("│") resA := gridStyle.Render("│ ")
resB := gridStyle.Render("│") resB := gridStyle.Render("│ ")
for i, c := range f.cells { for i, c := range f.cells {
cellRes := c.View() cellRes := c.View()
if i == f.i(*p) { if i == f.i(*p) {
resA += cursorStyle.Render(cellRes[0]) resA += cursorStyle.Render(cellRes[0])
resB += cursorStyle.Render(cellRes[1]) resB += cursorStyle.Render(cellRes[1])
} else if c.marked() {
markedStyle = lipgloss.NewStyle().
Background(lipgloss.Color(fmt.Sprintf("%d", i%214+16)))
resA += markedStyle.Render(cellRes[0])
resB += markedStyle.Render(cellRes[1])
} else { } else {
resA += cellRes[0] resA += cellRes[0]
resB += cellRes[1] resB += cellRes[1]
} }
if i%cellsPerSection == cellsPerSection-1 { if i%cellsPerSection == cellsPerSection-1 {
resA += gridStyle.Render("│") resA += gridStyle.Render("│ ")
resB += gridStyle.Render("│") resB += gridStyle.Render("│ ")
} }
if i%f.size == f.size-1 { if i%f.size == f.size-1 {
res += fmt.Sprintf("%s\n%s\n", resA, resB) res += fmt.Sprintf("%s\n%s\n", resA, resB)
resA = gridStyle.Render("│") resA = gridStyle.Render("│ ")
resB = gridStyle.Render("│") resB = gridStyle.Render("│ ")
} }
if i != 0 && i%(cellsPerSection*cellsPerSection*sectionSize) == 0 { if i != 0 && i%(cellsPerSection*cellsPerSection*sectionSize) == 0 {
res += gridStyle.Render("├") res += gridStyle.Render("├")
for section := 0; section < sectionSize; section++ { for section := 0; section < sectionSize; section++ {
for sectionCell := 0; sectionCell < cellsPerSection; sectionCell++ { for sectionCell := 0; sectionCell < cellsPerSection; sectionCell++ {
res += gridStyle.Render("───") res += gridStyle.Render("───")
} }
if section < sectionSize-1 { if section < sectionSize-1 {
res += gridStyle.Render("┼") res += gridStyle.Render("┼")
} }
} }
res += gridStyle.Render("┤") + "\n" res += gridStyle.Render("┤") + "\n"
} }
} }
res += gridStyle.Render("└") res += gridStyle.Render("└")
for c := 0; c < cellsPerSection*sectionSize*3; c++ { for c := 0; c < cellsPerSection*sectionSize*3; c++ {
res += gridStyle.Render("─") res += gridStyle.Render("─")
if c == cellsPerSection*sectionSize*3-1 { if c == cellsPerSection*sectionSize*3-1 {
@ -84,7 +91,7 @@ func (f *field) View(p *Point, sectionSize, cellsPerSection int) string {
break break
} }
if c%(cellsPerSection*3) == cellsPerSection*3-1 { if c%(cellsPerSection*3) == cellsPerSection*3-1 {
res += gridStyle.Render("┴") res += gridStyle.Render("┴")
} }
} }
return res return res

View File

@ -25,7 +25,7 @@ func NewModel(sectionSize, cellsPerSection int) model {
fieldSize: sectionSize * cellsPerSection, fieldSize: sectionSize * cellsPerSection,
sectionSize: sectionSize, sectionSize: sectionSize,
cellsPerSection: cellsPerSection, cellsPerSection: cellsPerSection,
state: state.New(sectionSize, cellsPerSection), state: state.New(sectionSize, cellsPerSection, true),
} }
return m return m