snakesimulator.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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)) * float64(s.stats.Move),
  137. Index: index,
  138. }
  139. }
  140. return
  141. }
  142. func (s *SnakeSimulator) GetHeadState() []float64 {
  143. headX := int32(s.snake.Points[0].X)
  144. headY := int32(s.snake.Points[0].Y)
  145. foodX := int32(s.field.Food.X)
  146. foodY := int32(s.field.Food.Y)
  147. width := int32(s.field.Width)
  148. height := int32(s.field.Height)
  149. diag := float64(width) * math.Sqrt2
  150. lWall := headX
  151. rWall := width - headX
  152. tWall := headY
  153. bWall := height - headY
  154. lFood := int32(0)
  155. rFood := int32(0)
  156. tFood := int32(0)
  157. bFood := int32(0)
  158. tlFood := float64(0)
  159. trFood := float64(0)
  160. blFood := float64(0)
  161. brFood := float64(0)
  162. tlWall := float64(0)
  163. trWall := float64(0)
  164. blWall := float64(0)
  165. brWall := float64(0)
  166. if foodX == headX {
  167. if foodY > headY {
  168. bFood = foodY - headY
  169. } else {
  170. tFood = headY - foodY
  171. }
  172. }
  173. if foodY == headY {
  174. if foodX > headX {
  175. rFood = foodX - headX
  176. } else {
  177. lFood = headX - foodX
  178. }
  179. }
  180. if lWall > tWall {
  181. tlWall = float64(tWall) * math.Sqrt2
  182. } else {
  183. tlWall = float64(lWall) * math.Sqrt2
  184. }
  185. if rWall > tWall {
  186. trWall = float64(tWall) * math.Sqrt2
  187. } else {
  188. trWall = float64(rWall) * math.Sqrt2
  189. }
  190. if lWall > bWall {
  191. blWall = float64(bWall) * math.Sqrt2
  192. } else {
  193. blWall = float64(lWall) * math.Sqrt2
  194. }
  195. if rWall > bWall {
  196. blWall = float64(bWall) * math.Sqrt2
  197. } else {
  198. brWall = float64(rWall) * math.Sqrt2
  199. }
  200. foodDiagXDiff := math.Abs(float64(foodX - headX))
  201. foodDiagYDiff := math.Abs(float64(foodY - headY))
  202. if foodDiagXDiff == foodDiagYDiff {
  203. if math.Signbit(float64(foodX - headX)) {
  204. if math.Signbit(float64(foodY - headY)) {
  205. trFood = foodDiagXDiff * math.Sqrt2
  206. } else {
  207. brFood = foodDiagXDiff * math.Sqrt2
  208. }
  209. } else {
  210. if math.Signbit(float64(foodY - headY)) {
  211. tlFood = foodDiagXDiff * math.Sqrt2
  212. } else {
  213. blFood = foodDiagXDiff * math.Sqrt2
  214. }
  215. }
  216. }
  217. return []float64{
  218. float64(lWall) / float64(width),
  219. float64(lFood) / float64(lWall),
  220. float64(rWall) / float64(width),
  221. float64(rFood) / float64(rWall),
  222. float64(tWall) / float64(height),
  223. float64(tFood) / float64(tWall),
  224. float64(bWall) / float64(height),
  225. float64(bFood) / float64(bWall),
  226. float64(tlWall) / diag,
  227. float64(tlFood) / diag,
  228. float64(trFood) / diag,
  229. float64(trWall) / diag,
  230. float64(blFood) / diag,
  231. float64(blWall) / diag,
  232. float64(brFood) / diag,
  233. float64(brWall) / diag,
  234. }
  235. }
  236. func (s *SnakeSimulator) StartServer() {
  237. go func() {
  238. grpcServer := grpc.NewServer()
  239. RegisterSnakeSimulatorServer(grpcServer, s)
  240. lis, err := net.Listen("tcp", "localhost:65002")
  241. if err != nil {
  242. fmt.Printf("Failed to listen: %v\n", err)
  243. }
  244. fmt.Printf("Listen SnakeSimulator localhost:65002\n")
  245. if err := grpcServer.Serve(lis); err != nil {
  246. fmt.Printf("Failed to serve: %v\n", err)
  247. }
  248. }()
  249. }
  250. func (s *SnakeSimulator) Run() {
  251. s.field.GenerateNextFood()
  252. for true {
  253. direction := rand.Int31()%4 + 1
  254. newHead := s.snake.NewHead(Direction(direction))
  255. if newHead.X == s.field.Food.X && newHead.Y == s.field.Food.Y {
  256. s.snake.Feed(newHead)
  257. s.field.GenerateNextFood()
  258. s.fieldUpdateQueue <- true
  259. } else if newHead.X > s.field.Width || newHead.Y > s.field.Height {
  260. fmt.Printf("Game over\n")
  261. break
  262. } else if selfCollisionIndex := s.snake.SelfCollision(newHead); selfCollisionIndex > 0 {
  263. if selfCollisionIndex == 1 {
  264. fmt.Printf("Step backward, skip\n")
  265. continue
  266. }
  267. fmt.Printf("Game over self collision\n")
  268. break
  269. } else {
  270. s.snake.Move(newHead)
  271. }
  272. s.snakeUpdateQueue <- true
  273. time.Sleep(50 * time.Millisecond)
  274. }
  275. }
  276. func (s *SnakeSimulator) Field(_ *None, srv SnakeSimulator_FieldServer) error {
  277. ctx := srv.Context()
  278. for {
  279. select {
  280. case <-ctx.Done():
  281. return ctx.Err()
  282. default:
  283. }
  284. srv.Send(s.field)
  285. <-s.fieldUpdateQueue
  286. }
  287. }
  288. func (s *SnakeSimulator) Snake(_ *None, srv SnakeSimulator_SnakeServer) error {
  289. ctx := srv.Context()
  290. for {
  291. select {
  292. case <-ctx.Done():
  293. return ctx.Err()
  294. default:
  295. }
  296. srv.Send(s.snake)
  297. <-s.snakeUpdateQueue
  298. }
  299. }
  300. func (s *SnakeSimulator) Stats(_ *None, srv SnakeSimulator_StatsServer) error {
  301. ctx := srv.Context()
  302. for {
  303. select {
  304. case <-ctx.Done():
  305. return ctx.Err()
  306. default:
  307. }
  308. srv.Send(s.stats)
  309. <-s.statsUpdateQueue
  310. }
  311. }
  312. func (s *SnakeSimulator) SetSpeed(ctx context.Context, speed *Speed) (*None, error) {
  313. s.speedQueue <- speed.Speed
  314. return &None{}, nil
  315. }