-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtree.main.go
More file actions
149 lines (130 loc) · 3.18 KB
/
tree.main.go
File metadata and controls
149 lines (130 loc) · 3.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package main
import (
"math"
"math/rand"
"time"
"github.com/tfriedel6/canvas/sdlcanvas"
)
const (
width = 1000
height = 1000
numParticles = 600
particleSize = 3
)
type Particle struct {
x, y float64
vx, vy float64
col int
}
var particles []*Particle
var interactions []Interaction
type Interaction struct {
a, b int
g float64
}
// Rule sets the interaction between two groups
func rule(a, b int, g float64) {
interactions = append(interactions, Interaction{a: a, b: b, g: g})
}
func initParticles() {
particles = make([]*Particle, numParticles)
for i := 0; i < numParticles; i++ {
particles[i] = &Particle{
x: rand.Float64() * width,
y: rand.Float64() * height,
vx: 0,
vy: 0,
col: rand.Intn(3), // 0=green (yeast), 1=red, 2=yellow
}
}
}
func applyRules() {
for _, inter := range interactions {
for _, p1 := range particles {
if p1.col != inter.a {
continue
}
fx, fy := 0.0, 0.0
for _, p2 := range particles {
if p2.col != inter.b {
continue
}
dx := p1.x - p2.x
dy := p1.y - p2.y
dist := math.Sqrt(dx*dx + dy*dy)
if dist > 0 && dist < 80 { // interaction radius
f := inter.g / dist
fx += f * dx
fy += f * dy
}
}
p1.vx = (p1.vx + fx) * 0.5
p1.vy = (p1.vy + fy) * 0.5
}
}
for _, p := range particles {
p.x += p.vx
p.y += p.vy
if p.x < 0 {
p.x = 0
p.vx *= -1
}
if p.y < 0 {
p.y = 0
p.vy *= -1
}
if p.x > width {
p.x = width
p.vx *= -1
}
if p.y > height {
p.y = height
p.vy *= -1
}
}
}
func main() {
rand.Seed(time.Now().UnixNano())
win, cv, err := sdlcanvas.CreateWindow(width, height, "Yeast-like Simulation")
if err != nil {
panic(err)
}
initParticles()
// ---------- Interaction Rules ----------
// Yeast = green (0), Red competitor = 1, Yellow partial compatible = 2
// Self interactions
// Self interactions (same type flocking)
// Rule format: rule(a, b, g) — g > 0: attraction, g < 0: repulsion
rule(0, 0, -0.05) // green-green: mild attraction to maintain flock cohesion
rule(1, 1, 0.05) // red-red: mild attraction
rule(2, 2, -0.05) // yellow-yellow: mild attraction
// Self repulsion to avoid collisions (stronger when too close)
// We'll handle repulsion in applyRules via distance threshold (like 0-20px)
// Or we can define negative g for very close neighbors
// Cross interactions (different flocks influence each other slightly)
rule(0, 1, -0.02) // green slightly repelled by red (avoid collision)
rule(1, 0, -0.02) // red slightly repelled by green
rule(0, 2, -0.01) // green slightly repelled by yellow
rule(2, 0, -0.01) // yellow slightly repelled by green
rule(1, 2, -0.01) // red slightly repelled by yellow
rule(2, 1, -0.01) // yellow slightly repelled by red
// Main loop
win.MainLoop(func() {
// Background
cv.SetFillStyle("#000000") // black
cv.FillRect(0, 0, width, height)
applyRules()
// Draw particles
for _, p := range particles {
switch p.col {
case 0:
cv.SetFillStyle("#00FF00") // green (yeast)
case 1:
cv.SetFillStyle("#FF0000") // red
case 2:
cv.SetFillStyle("#FFFF00") // yellow
}
cv.FillRect(p.x, p.y, particleSize, particleSize)
}
})
}