-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlangtons_ant.go
239 lines (195 loc) · 6.91 KB
/
langtons_ant.go
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
package main
import (
"fmt"
"time"
"math"
"math/rand"
"github.com/veandco/go-sdl2/sdl"
"github.com/veandco/go-sdl2/gfx"
"github.com/yakshaveinc/go-keycodes"
)
const winWidth, winHeight int = 1000, 1000
const gridDim int = 200 //size of grid
const stepTime = 0 //time between ant steps in ms
//Pattern: L: true, R: false
var pattern = []bool{true,false,false,false,false,false,true,true,false} //TODO: selectable?
//var pattern = []bool{true,false,false,false,false,false,true,true,false,true,false,false,false,false,false,true,true,false,true,false,false,false,false,false,true,true,false,true,false,false,false,false,false,true,true,false}
var colorList = []sdl.Color{}
var shuffleColors = true
type position struct {
x,y int
}
const (
NORTH = iota
EAST
SOUTH
WEST
OF
)
func printGrid(grid [][]int) {
for y := 0; y < gridDim; y++ {
fmt.Println(grid[y])
}
}
func drawAnt(renderer *sdl.Renderer, nx, ny, visRad int32, antpos position) {
bw := int32(winWidth)/(visRad*2)
bh := int32(winHeight)/(visRad*2)
startX := int32(nx/2) - visRad
startY := int32(ny/2) - visRad
cx := bw * (int32(antpos.x)-startX) + bw/2
cy := bh * (int32(antpos.y)-startY) + bh/2
//TODO: make ant ellipse-form based on direction?
ret := gfx.FilledEllipseColor(renderer, cx, cy, bw/2, bh/2, sdl.Color{100, 50, 0, 255})
if !ret {
fmt.Println("Error while drawing box")
}
}
func drawGrid(renderer *sdl.Renderer, grid [][]int, nx, ny, visRad int32) {
bw := int32(math.Round(float64(winWidth)/float64(visRad*2))) //TODO: still not 100% correct. math.Round didn't solve everything. There still is a black band with some gridDims. math.Round made it a bit better though.
bh := int32(math.Round(float64(winHeight)/float64(visRad*2)))
var ret bool
startX := int32(nx/2) - visRad
endX := int32(nx/2) + visRad
startY := int32(ny/2) - visRad
endY := int32(nx/2) + visRad
for y := startY; y < endY; y++ {
for x := startX; x < endX; x++ {
ret = gfx.BoxColor(renderer, (x-startX)*bw, (y-startY)*bh, ((x-startX)+1)*bw, ((y-startY)+1)*bh, colorList[grid[y][x]])
if !ret {
fmt.Println("Error while drawing box")
}
ret = gfx.RectangleColor(renderer, (x-startX)*bw, (y-startY)*bh, ((x-startX)+1)*bw, ((y-startY)+1)*bh, sdl.Color{0, 0, 0, 255})
if !ret {
fmt.Println("Error while drawing rect")
}
}
}
}
func moveAnt(grid [][]int, antpos *position, antdir *int) bool {
//move
switch *antdir {
case NORTH:
(*antpos).y-- //pixel coordinates origin is in top left corner
case EAST:
(*antpos).x++
case SOUTH:
(*antpos).y++
case WEST:
(*antpos).x--
default:
fmt.Println("Error moving ant: illegal direction")
}
if (*antpos).x < 0 || (*antpos).y < 0 || (*antpos).x > gridDim-1 || (*antpos).y > gridDim-1 {
return true //pause
}
//rotate based on the square we land on
if grid[(*antpos).y][(*antpos).x] >= len(pattern) {
fmt.Println("cell has invalid value! This should never happen!")
return true
}
if pattern[grid[(*antpos).y][(*antpos).x]] {
*antdir--;
} else {
*antdir++;
}
//Check for overflows
if *antdir >= OF{
*antdir = NORTH;
} else if *antdir <= -1 {
*antdir = WEST;
}
//Update cell
grid[(*antpos).y][(*antpos).x]++
if grid[(*antpos).y][(*antpos).x] >= len(pattern) {
grid[(*antpos).y][(*antpos).x] = 0
}
return false //don't pause
}
func main() {
err := sdl.Init(sdl.INIT_EVERYTHING)
if err != nil {
fmt.Println(err)
return
}
defer sdl.Quit()
window, err := sdl.CreateWindow("Testing SDL2", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, int32(winWidth), int32(winHeight), sdl.WINDOW_SHOWN)
if err != nil {
fmt.Println(err)
return
}
defer window.Destroy()
renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED)
if err != nil {
fmt.Println(err)
return
}
defer renderer.Destroy()
tex, err := renderer.CreateTexture(sdl.PIXELFORMAT_ABGR8888, sdl.TEXTUREACCESS_STREAMING, int32(winWidth), int32(winHeight))
if err != nil {
fmt.Println(err)
return
}
defer tex.Destroy()
//Create grid for the ant
grid := make([][]int, gridDim)
for i := 0; i < gridDim; i++ {
grid[i] = make([]int, gridDim)
}
//fill colorList based on patternlength //TODO: seperate function?
spacing := float64(360 / len(pattern))
var tmpCol = HSV{}
for i := 0; i<=len(pattern); i++ {
tmpCol = HSV{float64(i)*spacing, 0.5 ,0.5}
colorList = append(colorList, tmpCol.RGB())
}
if shuffleColors {
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(colorList), func(i, j int) {colorList[i], colorList[j]=colorList[j], colorList[i]})
}
antpos := position{gridDim/2, gridDim/2}
antdir := NORTH
fmt.Println("Starting position for ant: ", antpos, "in direction: ", antdir)
var frameStart time.Time
var elapsedTime float32
var running bool = true
var paused bool = false
var visRad int32 = 10 //inital visible grid
for running {
frameStart = time.Now()
if !paused {
paused = moveAnt(grid, &antpos, &antdir)
fmt.Println("Position: ", antpos, "direction: ", antdir)
drawGrid(renderer, grid, int32(gridDim), int32(gridDim), visRad);
drawAnt(renderer, int32(gridDim), int32(gridDim), visRad, antpos);
renderer.Present()
//calculate ant distance from center
dx := IntegerAbs(int(gridDim)/2 - antpos.x)
dy := IntegerAbs(int(gridDim)/2 - antpos.y)
if dx+2 > int(visRad) || dy+2 > int(visRad) { //Added +2 so it will zoom out sooner
visRad += 5;
}
//printGrid(grid)
}
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
switch t := event.(type) {
case *sdl.QuitEvent:
return
case *sdl.KeyboardEvent:
if(t.Type == sdl.KEYDOWN) {
fmt.Println("key pressed: ", t.Keysym.Scancode)
if uint16(t.Keysym.Scancode) == keycodes.KeyEscape{
fmt.Println("escape pressed, exiting...")
running = false
}
}
}
}
elapsedTime = float32(time.Since(frameStart).Seconds())
if elapsedTime < .005 {
sdl.Delay(5 - uint32(elapsedTime*1000))
elapsedTime = float32(time.Since(frameStart).Seconds())
}
fmt.Println("framerate: ", 1/elapsedTime)
sdl.Delay(stepTime)
}
}