Don't recurse to size 2; only average corner of particular side you're on

The former makes things so much faster. omg.
This commit is contained in:
Eryn Wells 2018-11-26 08:36:53 -08:00
parent 240499ced8
commit 1a32b8e085
2 changed files with 92 additions and 82 deletions

View file

@ -85,7 +85,7 @@ public class DiamondSquareGenerator: TerrainGenerator {
} }
var subdivisions: [Box] { var subdivisions: [Box] {
guard size.w > 2 && size.h > 2 else { guard size.w > 3 && size.h > 3 else {
return [] return []
} }
let halfSize = size.half let halfSize = size.half
@ -159,16 +159,21 @@ public class DiamondSquareGenerator: TerrainGenerator {
heightMap[convert(pointToIndex: midpoint)] = midpointValue heightMap[convert(pointToIndex: midpoint)] = midpointValue
// 2. Square step. For each of the side midpoints of this box, compute its value. // 2. Square step. For each of the side midpoints of this box, compute its value.
for pt in box.sideMidpoints {
let corners = diamondCorners(forPoint: pt, diamondSize: box.size) func updateHeight(for p: Point, a: Point, b: Point) {
let cornerValues = corners.map { (pt: Point) -> Float in let aValue = heightMap[convert(pointToIndex: a)]
let idx = self.convert(pointToIndex: pt) let bValue = heightMap[convert(pointToIndex: b)]
return heightMap[idx] let avg = 0.5 * (aValue + bValue)
} let rand = Float.random(in: spread)
let ptValue = Float.random(in: spread) + self.average(ofPoints: cornerValues) let value = avg + rand
heightMap[convert(pointToIndex: pt)] = ptValue heightMap[convert(pointToIndex: p)] = value
} }
updateHeight(for: box.north, a: box.northeast, b: box.northwest)
updateHeight(for: box.west, a: box.northwest, b: box.southwest)
updateHeight(for: box.south, a: box.southwest, b: box.southeast)
updateHeight(for: box.east, a: box.southeast, b: box.northeast)
if box.size != boxSize { if box.size != boxSize {
// Reduce the spread as we recurse down to smaller squares. // Reduce the spread as we recurse down to smaller squares.
spread = -(spread.lowerBound * 0.5)...(spread.upperBound * 0.5) spread = -(spread.lowerBound * 0.5)...(spread.upperBound * 0.5)
@ -182,25 +187,30 @@ public class DiamondSquareGenerator: TerrainGenerator {
} }
/// Find our diamond's corners, wrapping around the grid if needed. /// Find our diamond's corners, wrapping around the grid if needed.
func diamondCorners(forPoint pt: Point, diamondSize: Size) -> [Point] { // func diamondCorners(forPoint pt: Point, diamondSize: Size) -> [Point] {
let halfSize = diamondSize.half // let halfSize = diamondSize.half
var corners = [Point(x: pt.x, y: pt.y - halfSize.h), //
Point(x: pt.x - halfSize.w, y: pt.y), // func ptIsValid(pt: Point) -> Bool {
Point(x: pt.x, y: pt.y + halfSize.h), // return pt.x >= origin.x && pt.x < size.w && pt.y >= origin.y && pt.y < size.h
Point(x: pt.x + halfSize.w, y: pt.y)] // }
for i in 0..<corners.count { //
if corners[i].x < 0 { // var corners = [Point(x: pt.x, y: pt.y - halfSize.h),
corners[i].x += grid.size.w - 1 // Point(x: pt.x - halfSize.w, y: pt.y),
} else if corners[i].x >= grid.size.w { // Point(x: pt.x, y: pt.y + halfSize.h),
corners[i].x -= grid.size.w - 1 // Point(x: pt.x + halfSize.w, y: pt.y)].filter(ptIsValid)
} else if corners[i].y < 0 { // for i in 0..<corners.count {
corners[i].y += grid.size.h - 1 // if corners[i].x < 0 {
} else if corners[i].y >= grid.size.h { // corners[i].x += grid.size.w - 1
corners[i].y -= grid.size.h - 1 // } else if corners[i].x >= grid.size.w {
} // corners[i].x -= grid.size.w - 1
} // } else if corners[i].y < 0 {
return corners // corners[i].y += grid.size.h - 1
} // } else if corners[i].y >= grid.size.h {
// corners[i].y -= grid.size.h - 1
// }
// }
// return corners
// }
func average(ofPoints pts: [Float]) -> Float { func average(ofPoints pts: [Float]) -> Float {
let scale: Float = 1.0 / Float(pts.count) let scale: Float = 1.0 / Float(pts.count)

View file

@ -38,41 +38,41 @@ class DiamondSquareAlgorithmTests: XCTestCase {
// MARK: Diamond Corners // MARK: Diamond Corners
func testDiamondCornersNorth() { // func testDiamondCornersNorth() {
let corners = alg.diamondCorners(forPoint: Point(x: 2, y: 0), diamondSize: grid.size) // let corners = alg.diamondCorners(forPoint: Point(x: 2, y: 0), diamondSize: grid.size)
XCTAssertEqual(corners.count, 4) // XCTAssertEqual(corners.count, 4)
XCTAssertEqual(corners[0], Point(x: 2, y: 2)) // XCTAssertEqual(corners[0], Point(x: 2, y: 2))
XCTAssertEqual(corners[1], Point(x: 0, y: 0)) // XCTAssertEqual(corners[1], Point(x: 0, y: 0))
XCTAssertEqual(corners[2], Point(x: 2, y: 2)) // XCTAssertEqual(corners[2], Point(x: 2, y: 2))
XCTAssertEqual(corners[3], Point(x: 4, y: 0)) // XCTAssertEqual(corners[3], Point(x: 4, y: 0))
} // }
//
func testDiamondCornersWest() { // func testDiamondCornersWest() {
let corners = alg.diamondCorners(forPoint: Point(x: 0, y: 2), diamondSize: grid.size) // let corners = alg.diamondCorners(forPoint: Point(x: 0, y: 2), diamondSize: grid.size)
XCTAssertEqual(corners.count, 4) // XCTAssertEqual(corners.count, 4)
XCTAssertEqual(corners[0], Point(x: 0, y: 0)) // XCTAssertEqual(corners[0], Point(x: 0, y: 0))
XCTAssertEqual(corners[1], Point(x: 2, y: 2)) // XCTAssertEqual(corners[1], Point(x: 2, y: 2))
XCTAssertEqual(corners[2], Point(x: 0, y: 4)) // XCTAssertEqual(corners[2], Point(x: 0, y: 4))
XCTAssertEqual(corners[3], Point(x: 2, y: 2)) // XCTAssertEqual(corners[3], Point(x: 2, y: 2))
} // }
//
func testDiamondCornersSouth() { // func testDiamondCornersSouth() {
let corners = alg.diamondCorners(forPoint: Point(x: 2, y: 4), diamondSize: grid.size) // let corners = alg.diamondCorners(forPoint: Point(x: 2, y: 4), diamondSize: grid.size)
XCTAssertEqual(corners.count, 4) // XCTAssertEqual(corners.count, 4)
XCTAssertEqual(corners[0], Point(x: 2, y: 2)) // XCTAssertEqual(corners[0], Point(x: 2, y: 2))
XCTAssertEqual(corners[1], Point(x: 0, y: 4)) // XCTAssertEqual(corners[1], Point(x: 0, y: 4))
XCTAssertEqual(corners[2], Point(x: 2, y: 2)) // XCTAssertEqual(corners[2], Point(x: 2, y: 2))
XCTAssertEqual(corners[3], Point(x: 4, y: 4)) // XCTAssertEqual(corners[3], Point(x: 4, y: 4))
} // }
//
func testDiamondCornersEast() { // func testDiamondCornersEast() {
let corners = alg.diamondCorners(forPoint: Point(x: 4, y: 2), diamondSize: grid.size) // let corners = alg.diamondCorners(forPoint: Point(x: 4, y: 2), diamondSize: grid.size)
XCTAssertEqual(corners.count, 4) // XCTAssertEqual(corners.count, 4)
XCTAssertEqual(corners[0], Point(x: 4, y: 0)) // XCTAssertEqual(corners[0], Point(x: 4, y: 0))
XCTAssertEqual(corners[1], Point(x: 2, y: 2)) // XCTAssertEqual(corners[1], Point(x: 2, y: 2))
XCTAssertEqual(corners[2], Point(x: 4, y: 4)) // XCTAssertEqual(corners[2], Point(x: 4, y: 4))
XCTAssertEqual(corners[3], Point(x: 2, y: 2)) // XCTAssertEqual(corners[3], Point(x: 2, y: 2))
} // }
} }
class DiamondSquareBoxTests: XCTestCase { class DiamondSquareBoxTests: XCTestCase {
@ -102,25 +102,25 @@ class DiamondSquareBoxTests: XCTestCase {
Box(origin: Point(x: 0, y: 2), size: Size(w: 3, h: 3)), Box(origin: Point(x: 0, y: 2), size: Size(w: 3, h: 3)),
Box(origin: Point(x: 2, y: 2), size: Size(w: 3, h: 3)), Box(origin: Point(x: 2, y: 2), size: Size(w: 3, h: 3)),
Box(origin: Point(x: 0, y: 0), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 0, y: 0), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 1, y: 0), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 1, y: 0), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 0, y: 1), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 0, y: 1), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 1, y: 1), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 1, y: 1), size: Size(w: 2, h: 2)),
//
Box(origin: Point(x: 2, y: 0), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 2, y: 0), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 3, y: 0), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 3, y: 0), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 2, y: 1), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 2, y: 1), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 3, y: 1), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 3, y: 1), size: Size(w: 2, h: 2)),
//
Box(origin: Point(x: 0, y: 2), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 0, y: 2), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 1, y: 2), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 1, y: 2), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 0, y: 3), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 0, y: 3), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 1, y: 3), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 1, y: 3), size: Size(w: 2, h: 2)),
//
Box(origin: Point(x: 2, y: 2), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 2, y: 2), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 3, y: 2), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 3, y: 2), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 2, y: 3), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 2, y: 3), size: Size(w: 2, h: 2)),
Box(origin: Point(x: 3, y: 3), size: Size(w: 2, h: 2)), // Box(origin: Point(x: 3, y: 3), size: Size(w: 2, h: 2)),
].reversed() ].reversed()
let prog = Progress(totalUnitCount: 1) let prog = Progress(totalUnitCount: 1)