You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

logic.go 5.0 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. package core
  2. import (
  3. "errors"
  4. "sync"
  5. "sync/atomic"
  6. main "API"
  7. pb "API/proto"
  8. thuai6 "API/thuai6"
  9. )
  10. type Logic struct {
  11. communication *Communication
  12. playerType thuai6.PlayerType
  13. playerID int64
  14. studentType thuai6.StudentType
  15. trickerType thuai6.TrickerType
  16. timer thuai6.IGameTimer
  17. mtxAI sync.Mutex
  18. mtxState sync.Mutex
  19. mtxBuffer sync.Mutex
  20. cvBuffer *sync.Cond
  21. cvAI *sync.Cond
  22. state [2]thuai6.State
  23. currentState *thuai6.State
  24. bufferState *thuai6.State
  25. counterState int32
  26. counterBuffer int32
  27. gameState thuai6.GameState
  28. aiStart bool
  29. bufferUpdated bool
  30. aiLoop int32
  31. freshed int32
  32. }
  33. func NewLogic(playerType thuai6.PlayerType, id int64, tricker thuai6.TrickerType, student thuai6.StudentType) *Logic {
  34. logic := &Logic{
  35. communication: nil,
  36. playerType: playerType,
  37. playerID: id,
  38. studentType: student,
  39. trickerType: tricker,
  40. timer: nil,
  41. mtxAI: sync.Mutex{},
  42. mtxState: sync.Mutex{},
  43. mtxBuffer: sync.Mutex{},
  44. cvBuffer: nil,
  45. cvAI: nil,
  46. state: [2]thuai6.State{},
  47. counterState: 0,
  48. counterBuffer: 0,
  49. gameState: thuai6.NullGameState,
  50. aiStart: false,
  51. bufferUpdated: true,
  52. aiLoop: 1,
  53. freshed: 0,
  54. }
  55. logic.currentState = &logic.state[0]
  56. logic.bufferState = &logic.state[1]
  57. logic.cvBuffer = sync.NewCond(&logic.mtxBuffer)
  58. logic.cvAI = sync.NewCond(&logic.mtxAI)
  59. return logic
  60. }
  61. func (logic *Logic) GetStudentSelfInfo() *thuai6.Student {
  62. logic.mtxState.Lock()
  63. defer logic.mtxState.Unlock()
  64. return logic.currentState.StudentSelf
  65. }
  66. func (logic *Logic) GetTrickerSelfInfo() *thuai6.Tricker {
  67. logic.mtxState.Lock()
  68. defer logic.mtxState.Unlock()
  69. return logic.currentState.TrickerSelf
  70. }
  71. func (logic *Logic) Move(time int64, angle float64) bool {
  72. return logic.communication.Move(time, angle, logic.playerID)
  73. }
  74. func (logic *Logic) TryConnection() bool {
  75. return logic.communication.TryConnection(logic.playerID)
  76. }
  77. func (logic *Logic) Wait() {
  78. atomic.StoreInt32(&logic.freshed, 0)
  79. logic.mtxBuffer.Lock()
  80. defer logic.mtxBuffer.Unlock()
  81. for atomic.LoadInt32(&logic.freshed) == 0 {
  82. logic.cvBuffer.Wait()
  83. }
  84. }
  85. func (logic *Logic) Update() {
  86. if main.Asynchronous == false {
  87. logic.mtxBuffer.Lock()
  88. defer logic.mtxBuffer.Unlock()
  89. for logic.bufferUpdated == false {
  90. logic.cvBuffer.Wait()
  91. }
  92. // Go 的 defer 是函数推出时执行而非 block 退出时执行,故包装一层 func
  93. func() {
  94. logic.mtxState.Lock()
  95. defer logic.mtxState.Unlock()
  96. var tmpState = logic.currentState
  97. logic.currentState = logic.bufferState
  98. logic.bufferState = tmpState
  99. logic.counterState = logic.counterBuffer
  100. }()
  101. logic.bufferUpdated = false
  102. }
  103. }
  104. func (logic *Logic) ProcessMessage() <-chan int {
  105. endChan := make(chan int, 1)
  106. go func() {
  107. logic.communication.AddPlayer(logic.playerID, logic.playerType, logic.studentType, logic.trickerType)
  108. for logic.gameState != thuai6.GameEnd {
  109. clientMsg := logic.communication.GetMessageToClient()
  110. logic.gameState = thuai6.GameStateToTHUAI6[clientMsg.GameState]
  111. switch logic.gameState {
  112. case thuai6.GameStart:
  113. playerGUIDs := make([]int64, 0)
  114. for _, obj := range clientMsg.ObjMessage {
  115. switch obj.MessageOfObj.(type) {
  116. case *(pb.MessageOfObj_StudentMessage):
  117. playerGUIDs = append(playerGUIDs, obj.GetStudentMessage().GetGuid())
  118. }
  119. }
  120. for _, obj := range clientMsg.ObjMessage {
  121. switch obj.MessageOfObj.(type) {
  122. case *(pb.MessageOfObj_TrickerMessage):
  123. playerGUIDs = append(playerGUIDs, obj.GetTrickerMessage().GetGuid())
  124. }
  125. }
  126. logic.currentState.Guids = playerGUIDs
  127. logic.bufferState.Guids = playerGUIDs
  128. // TODO: LoadBuffer
  129. break
  130. case thuai6.GameEnd:
  131. }
  132. }
  133. // TODO: ProcessMessage
  134. endChan <- 0
  135. }()
  136. return endChan
  137. }
  138. func (logic *Logic) Main(createAI thuai6.CreateAIFunc, ip string, port string) error {
  139. comm, err := NewCommunication(ip, port)
  140. if err != nil {
  141. return err
  142. }
  143. logic.communication = comm
  144. if logic.playerType == thuai6.StudentPlayer {
  145. logic.timer = NewStudentAPI(logic)
  146. } else if logic.playerType == thuai6.TrickerPlayer {
  147. logic.timer = NewTrickerAPI(logic)
  148. } else {
  149. return errors.New("Invalid player type")
  150. }
  151. aiThread := func() {
  152. // Go 的 defer 是函数推出时执行而非 block 退出时执行,故包装一层 func
  153. func() {
  154. logic.mtxAI.Lock()
  155. defer logic.mtxAI.Unlock()
  156. for logic.aiStart == false {
  157. logic.cvAI.Wait()
  158. }
  159. }()
  160. ai := createAI(logic.playerID)
  161. for atomic.LoadInt32(&logic.aiLoop) != 0 {
  162. if main.Asynchronous {
  163. logic.Wait()
  164. } else {
  165. logic.Update()
  166. }
  167. logic.timer.StartTimer()
  168. logic.timer.Play(ai)
  169. logic.timer.EndTimer()
  170. }
  171. }
  172. if logic.TryConnection() == false {
  173. atomic.StoreInt32(&logic.aiLoop, 0)
  174. return errors.New("Connection failed.")
  175. }
  176. aiEnd := make(chan int, 1)
  177. go func() {
  178. aiThread()
  179. aiEnd <- 1
  180. }()
  181. <-logic.ProcessMessage()
  182. <-aiEnd
  183. return nil
  184. }