snakesimulator.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. package snakesimulator
  2. import (
  3. fmt "fmt"
  4. math "math"
  5. "math/rand"
  6. "net"
  7. "time"
  8. "gonum.org/v1/gonum/mat"
  9. genetic "../genetic"
  10. grpc "google.golang.org/grpc"
  11. )
  12. type SnakeSimulator struct {
  13. field *Field
  14. snake *Snake
  15. stats *Stats
  16. fieldUpdateQueue chan bool
  17. snakeUpdateQueue chan bool
  18. statsUpdateQueue chan bool
  19. }
  20. func NewSnakeSimulator() (s *SnakeSimulator) {
  21. s = &SnakeSimulator{
  22. field: &Field{
  23. Food: &Point{},
  24. Width: 40,
  25. Height: 40,
  26. },
  27. snake: &Snake{
  28. Points: []*Point{
  29. &Point{X: 20, Y: 20},
  30. &Point{X: 21, Y: 20},
  31. &Point{X: 22, Y: 20},
  32. },
  33. },
  34. stats: &Stats{},
  35. fieldUpdateQueue: make(chan bool, 2),
  36. snakeUpdateQueue: make(chan bool, 2),
  37. statsUpdateQueue: make(chan bool, 2),
  38. }
  39. return
  40. }
  41. func (s *SnakeSimulator) Verify(population *genetic.Population) (results []*genetic.IndividalResult) {
  42. s.stats.Generation++
  43. s.statsUpdateQueue <- true
  44. results = make([]*genetic.IndividalResult, len(population.Networks))
  45. for index, inidividual := range population.Networks {
  46. s.stats.Individual = uint32(index)
  47. s.statsUpdateQueue <- true
  48. s.field.GenerateNextFood()
  49. rand.Seed(time.Now().UnixNano())
  50. switch rand.Uint32() % 4 {
  51. case 1:
  52. s.snake = &Snake{
  53. Points: []*Point{
  54. &Point{X: 20, Y: 20},
  55. &Point{X: 21, Y: 20},
  56. &Point{X: 22, Y: 20},
  57. },
  58. }
  59. case 2:
  60. s.snake = &Snake{
  61. Points: []*Point{
  62. &Point{X: 22, Y: 20},
  63. &Point{X: 21, Y: 20},
  64. &Point{X: 20, Y: 20},
  65. },
  66. }
  67. case 3:
  68. s.snake = &Snake{
  69. Points: []*Point{
  70. &Point{X: 20, Y: 20},
  71. &Point{X: 20, Y: 21},
  72. &Point{X: 20, Y: 22},
  73. },
  74. }
  75. default:
  76. s.snake = &Snake{
  77. Points: []*Point{
  78. &Point{X: 20, Y: 22},
  79. &Point{X: 20, Y: 21},
  80. &Point{X: 20, Y: 20},
  81. },
  82. }
  83. }
  84. i := 0
  85. for i < 300 {
  86. s.stats.Move = uint32(i)
  87. s.statsUpdateQueue <- true
  88. i++
  89. s.snakeUpdateQueue <- true
  90. direction, _ := inidividual.Predict(mat.NewDense(inidividual.Sizes[0], 1, s.GetHeadState()))
  91. newHead := s.snake.NewHead(Direction(direction + 1))
  92. if newHead.X == s.field.Food.X && newHead.Y == s.field.Food.Y {
  93. s.snake.Feed(newHead)
  94. s.field.GenerateNextFood()
  95. s.fieldUpdateQueue <- true
  96. } else if newHead.X >= s.field.Width || newHead.Y >= s.field.Height {
  97. fmt.Printf("Game over\n")
  98. // time.Sleep(1000 * time.Millisecond)
  99. break
  100. } else if selfCollisionIndex := s.snake.SelfCollision(newHead); selfCollisionIndex > 0 {
  101. if selfCollisionIndex == 1 {
  102. fmt.Printf("Step backward, skip\n")
  103. continue
  104. }
  105. fmt.Printf("Game over self collision\n")
  106. break
  107. } else {
  108. s.snake.Move(newHead)
  109. }
  110. time.Sleep(10 * time.Millisecond)
  111. }
  112. results[index] = &genetic.IndividalResult{
  113. Result: float64(len(s.snake.Points)) * float64(i),
  114. Index: index,
  115. }
  116. }
  117. return
  118. }
  119. func (s *SnakeSimulator) GetHeadState() []float64 {
  120. headX := int32(s.snake.Points[0].X)
  121. headY := int32(s.snake.Points[0].Y)
  122. foodX := int32(s.field.Food.X)
  123. foodY := int32(s.field.Food.Y)
  124. width := int32(s.field.Width)
  125. height := int32(s.field.Height)
  126. diag := float64(width) * math.Sqrt2
  127. lWall := headX
  128. rWall := width - headX
  129. tWall := headY
  130. bWall := height - headY
  131. lFood := int32(0)
  132. rFood := int32(0)
  133. tFood := int32(0)
  134. bFood := int32(0)
  135. tlFood := float64(0)
  136. trFood := float64(0)
  137. blFood := float64(0)
  138. brFood := float64(0)
  139. tlWall := float64(0)
  140. trWall := float64(0)
  141. blWall := float64(0)
  142. brWall := float64(0)
  143. if foodX == headX {
  144. if foodY > headY {
  145. bFood = foodY - headY
  146. } else {
  147. tFood = headY - foodY
  148. }
  149. }
  150. if foodY == headY {
  151. if foodX > headX {
  152. rFood = foodX - headX
  153. } else {
  154. lFood = headX - foodX
  155. }
  156. }
  157. if lWall > tWall {
  158. tlWall = float64(tWall) * math.Sqrt2
  159. } else {
  160. tlWall = float64(lWall) * math.Sqrt2
  161. }
  162. if rWall > tWall {
  163. trWall = float64(tWall) * math.Sqrt2
  164. } else {
  165. trWall = float64(rWall) * math.Sqrt2
  166. }
  167. if lWall > bWall {
  168. blWall = float64(bWall) * math.Sqrt2
  169. } else {
  170. blWall = float64(lWall) * math.Sqrt2
  171. }
  172. if rWall > bWall {
  173. blWall = float64(bWall) * math.Sqrt2
  174. } else {
  175. brWall = float64(rWall) * math.Sqrt2
  176. }
  177. foodDiagXDiff := math.Abs(float64(foodX - headX))
  178. foodDiagYDiff := math.Abs(float64(foodY - headY))
  179. if foodDiagXDiff == foodDiagYDiff {
  180. if math.Signbit(float64(foodX - headX)) {
  181. if math.Signbit(float64(foodY - headY)) {
  182. trFood = foodDiagXDiff * math.Sqrt2
  183. } else {
  184. brFood = foodDiagXDiff * math.Sqrt2
  185. }
  186. } else {
  187. if math.Signbit(float64(foodY - headY)) {
  188. tlFood = foodDiagXDiff * math.Sqrt2
  189. } else {
  190. blFood = foodDiagXDiff * math.Sqrt2
  191. }
  192. }
  193. }
  194. return []float64{
  195. float64(lWall) / float64(width),
  196. float64(lFood) / float64(lWall),
  197. float64(rWall) / float64(width),
  198. float64(rFood) / float64(rWall),
  199. float64(tWall) / float64(height),
  200. float64(tFood) / float64(tWall),
  201. float64(bWall) / float64(height),
  202. float64(bFood) / float64(bWall),
  203. float64(tlWall) / diag,
  204. float64(tlFood) / diag,
  205. float64(trFood) / diag,
  206. float64(trWall) / diag,
  207. float64(blFood) / diag,
  208. float64(blWall) / diag,
  209. float64(brFood) / diag,
  210. float64(brWall) / diag,
  211. }
  212. }
  213. func (s *SnakeSimulator) StartServer() {
  214. go func() {
  215. grpcServer := grpc.NewServer()
  216. RegisterSnakeSimulatorServer(grpcServer, s)
  217. lis, err := net.Listen("tcp", "localhost:65002")
  218. if err != nil {
  219. fmt.Printf("Failed to listen: %v\n", err)
  220. }
  221. fmt.Printf("Listen SnakeSimulator localhost:65002\n")
  222. if err := grpcServer.Serve(lis); err != nil {
  223. fmt.Printf("Failed to serve: %v\n", err)
  224. }
  225. }()
  226. }
  227. func (s *SnakeSimulator) Run() {
  228. s.field.GenerateNextFood()
  229. for true {
  230. direction := rand.Int31()%4 + 1
  231. newHead := s.snake.NewHead(Direction(direction))
  232. if newHead.X == s.field.Food.X && newHead.Y == s.field.Food.Y {
  233. s.snake.Feed(newHead)
  234. s.field.GenerateNextFood()
  235. s.fieldUpdateQueue <- true
  236. } else if newHead.X >= s.field.Width || newHead.Y >= s.field.Height {
  237. fmt.Printf("Game over\n")
  238. break
  239. } else if selfCollisionIndex := s.snake.SelfCollision(newHead); selfCollisionIndex > 0 {
  240. if selfCollisionIndex == 1 {
  241. fmt.Printf("Step backward, skip\n")
  242. continue
  243. }
  244. fmt.Printf("Game over self collision\n")
  245. break
  246. } else {
  247. s.snake.Move(newHead)
  248. }
  249. s.snakeUpdateQueue <- true
  250. time.Sleep(50 * time.Millisecond)
  251. }
  252. }
  253. func (s *SnakeSimulator) Field(_ *None, srv SnakeSimulator_FieldServer) error {
  254. ctx := srv.Context()
  255. for {
  256. select {
  257. case <-ctx.Done():
  258. return ctx.Err()
  259. default:
  260. }
  261. srv.Send(s.field)
  262. <-s.fieldUpdateQueue
  263. }
  264. }
  265. func (s *SnakeSimulator) Snake(_ *None, srv SnakeSimulator_SnakeServer) error {
  266. ctx := srv.Context()
  267. for {
  268. select {
  269. case <-ctx.Done():
  270. return ctx.Err()
  271. default:
  272. }
  273. srv.Send(s.snake)
  274. <-s.snakeUpdateQueue
  275. }
  276. }
  277. func (s *SnakeSimulator) Stats(_ *None, srv SnakeSimulator_StatsServer) error {
  278. ctx := srv.Context()
  279. for {
  280. select {
  281. case <-ctx.Done():
  282. return ctx.Err()
  283. default:
  284. }
  285. srv.Send(s.stats)
  286. <-s.statsUpdateQueue
  287. }
  288. }