snakesimulator.go 7.4 KB

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