Last active
February 17, 2024 00:56
-
-
Save benigumocom/24bfb3c6295ada5c1a86fbd8408f27f8 to your computer and use it in GitHub Desktop.
【SwiftUI】Conway's Game of Life 👉 https://android.benigumo.com/20240215/conways-game-of-life/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
// inspiered by | |
// lifegame/swift/lifegame.swift at master · tex2e/lifegame | |
// https://github.com/tex2e/lifegame/blob/master/swift/lifegame.swift | |
@Observable final class LifeGame { | |
var field: [[Int]] = [] | |
var generation = 0 | |
private var height: Int = 0 | |
private var width: Int = 0 | |
private var task: Task<Void, Never>? | |
func create(_ width: Int, _ height: Int) { | |
self.width = width | |
self.height = height | |
self.field = Array(repeating: Array(repeating: 0, count: width), count: height) | |
for y in 0 ..< height { | |
for x in 0 ..< width { | |
self.field[y][x] = self.random(max: 2) | |
} | |
} | |
} | |
private func random(max maxNumber: Int) -> Int { | |
return Int(arc4random_uniform(UInt32(maxNumber))) | |
} | |
func start() { | |
task = Task { @MainActor in | |
do { | |
while true { | |
self.field = evolve() | |
generation += 1 | |
//usleep(100000) | |
try await Task.sleep(for: .seconds(0.1)) | |
} | |
} catch { | |
if Task.isCancelled { | |
print("cancelled.") | |
} | |
} | |
} | |
} | |
func stop() { | |
task?.cancel() | |
} | |
func reset() { | |
stop() | |
field = [] | |
generation = 0 | |
create(width, height) | |
} | |
private func evolve() -> Array<Array<Int>> { | |
var newField = Array(repeating: Array(repeating: 0, count: width), count: height) | |
for y in 0 ..< height { | |
for x in 0 ..< width { | |
switch countAliveNeighbours(y: y, x: x) { | |
case 2: | |
newField[y][x] = field[y][x] | |
case 3: | |
newField[y][x] = 1 | |
default: | |
newField[y][x] = 0 | |
} | |
} | |
} | |
return newField | |
} | |
private func countAliveNeighbours(y: Int, x: Int) -> Int { | |
var count = 0 | |
for yi in -1 ... 1 { | |
for xi in -1 ... 1 { | |
if yi == 0 && xi == 0 { continue } | |
if field[mod(y + yi, divBy: height)][mod(x + xi, divBy: width)] == 1 { | |
count += 1 | |
} | |
} | |
} | |
return count | |
} | |
private func mod(_ a: Int, divBy b: Int) -> Int { | |
return (a + b) % b | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import SwiftUI | |
struct LifeGameView: View { | |
private var lifeGame = LifeGame() | |
@State private var on = false | |
private let num = 20 | |
var body: some View { | |
VStack(spacing: 0) { | |
GeometryReader { geo in | |
let (cols, rows) = nums(geo) | |
Grid(horizontalSpacing: 1, verticalSpacing: 1) { | |
ForEach(lifeGame.field.indices, id: \.self) { y in | |
GridRow { | |
ForEach(lifeGame.field.first!.indices, id: \.self) { x in | |
lifeGame.field[y][x] == 1 ? Color.alive : Color.dead | |
} | |
} | |
} | |
} | |
.onAppear { | |
lifeGame.create(cols, rows) | |
} | |
} | |
.onTapGesture(count: 2) { | |
lifeGame.reset() | |
} | |
.onTapGesture(count: 1) { | |
on.toggle() | |
if on { | |
lifeGame.start() | |
} else { | |
lifeGame.stop() | |
} | |
} | |
Text("generation \(lifeGame.generation)").font(.headline) | |
.padding() | |
} | |
} | |
func nums(_ geo: GeometryProxy) -> (Int, Int) { | |
let (w, h) = (geo.size.width, geo.size.height) | |
let size = min(w, h) / Double(num) | |
return (Int(w / size), Int(h / size)) | |
} | |
} | |
extension Color { | |
static let alive = Color(red: 15 / 256, green: 75 / 256, blue: 89 / 256) | |
static let dead = Color(red: 217 / 256, green: 231 / 256, blue: 226 / 256) | |
} | |
#Preview { | |
LifeGameView() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment