Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 15 additions & 0 deletions lib/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -911,6 +911,21 @@ function makeHighResolutionCityRows() {
const garden = (x, y, w, h) => {
fill(x, y, w, h, ';')
border(x, y, w, h)
// Four open approaches keep the flowerbeds reachable instead of becoming
// another sealed compound (#5), the same idea civicSquare() applies to the
// plaza. Gates are two cells wide so the wide hero sprite reads cleanly
// while passing through, and they are carved in cobble to blend with the
// garden paths; the hedge stays continuous everywhere else.
const cxg = x + Math.floor(w / 2)
const cyg = y + Math.floor(h / 2)
set(cxg, y, ';')
set(cxg - 1, y, ';')
set(cxg, y + h - 1, ';')
set(cxg - 1, y + h - 1, ';')
set(x, cyg, ';')
set(x, cyg - 1, ';')
set(x + w - 1, cyg, ';')
set(x + w - 1, cyg - 1, ';')
for (let row = y + 3; row < y + h - 3; row += 5) {
for (let col = x + 4; col < x + w - 4; col += 7) set(col, row, (row + col) % 2 ? '*' : '"')
}
Expand Down
1 change: 1 addition & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const {
const render = require('../lib/render.js')

require('./sage.test.js')
require('./open-city-gardens.test.js')

function press(game, name) {
return game.onKey({ type: 'key', is: (...keys) => keys.includes(name) })
Expand Down
55 changes: 55 additions & 0 deletions test/open-city-gardens.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const { test } = require('brittle')
const M = require('../lib/map.js')

function walkableComponentFromSpawn(city) {
const seen = new Set()
const queue = [[city.spawn.x, city.spawn.y]]
while (queue.length) {
const [x, y] = queue.pop()
const key = x + ',' + y
if (seen.has(key)) continue
if (x < 0 || y < 0 || x >= city.width || y >= city.height) continue
if (M.isSolid(city, x, y)) continue
seen.add(key)
queue.push([x + 1, y], [x - 1, y], [x, y + 1], [x, y - 1])
}
return seen
}

test('both city gardens open into the main walkable component (#5)', (t) => {
const city = M.MAPS.city
const reached = walkableComponentFromSpawn(city)

// The exact compounds the issue measured as sealed: interiors of
// garden(5, 5, 65, 43) and garden(250, 5, 65, 43).
const gardens = [
{ x: 5, y: 5, w: 65, h: 43 },
{ x: 250, y: 5, w: 65, h: 43 }
]

for (const g of gardens) {
let reachedInside = 0
for (let y = g.y + 1; y < g.y + g.h - 1; y++) {
for (let x = g.x + 1; x < g.x + g.w - 1; x++) {
if (!M.isSolid(city, x, y) && reached.has(x + ',' + y)) reachedInside++
}
}
t.ok(
reachedInside > 1000,
`interior of garden at ${g.x},${g.y} joins the city (${reachedInside} cells reached)`
)
}
})

test('every garden side has a carved gate in the hedge (#5)', (t) => {
Comment on lines +30 to +44

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Quality: Connectivity test can't prove all four gates work

The first test only asserts that >1000 interior cells are reachable from spawn. Because a garden interior is one internally-connected region, this passes as soon as any single gate connects outward, so a gate that was mis-placed or opened onto a solid obstacle would go undetected — defeating the PR's stated goal of four open approaches. The second test checks gate cells are non-solid but never checks the cell just outside each gate is walkable. Consider asserting, per side, that both the gate cell and its immediate exterior neighbor are non-solid (e.g. for the north gate also check (cxg,y-1)), so each of the four approaches is independently verified.

Was this helpful? React with 👍 / 👎

const city = M.MAPS.city
for (const gx of [5, 250]) {
const cxg = gx + 32
const cyg = 5 + 21
t.is(M.isSolid(city, cxg, 5), false, 'north gate open')
t.is(M.isSolid(city, cxg - 1, 5), false)
t.is(M.isSolid(city, cxg, 47), false, 'south gate open')
t.is(M.isSolid(city, gx, cyg), false, 'west gate open')
t.is(M.isSolid(city, gx + 64, cyg), false, 'east gate open')
}
})