diff --git a/config/Constants.go b/config/Constants.go index 2c45117..5dba1d0 100644 --- a/config/Constants.go +++ b/config/Constants.go @@ -27,6 +27,7 @@ const ( const ( GameMsgType int = iota TableOrderMsgType + GameResultMsgType RoomControl ChatMsgType ) diff --git a/container/ConnManager.go b/container/ConnManager.go index d0f41a9..3767bb4 100644 --- a/container/ConnManager.go +++ b/container/ConnManager.go @@ -15,17 +15,20 @@ type ConnManager struct { gameRecvCh chan message.GameMsgRecv gameSendCh chan message.GameMsgSend tableOrderCh chan int + gameResultCh chan message.GameResultMsg } func NewConnManager(playersCount int, gameRecvCh chan message.GameMsgRecv, gameSendCh chan message.GameMsgSend, - tableOrderCh chan int) *ConnManager { + tableOrderCh chan int, + gameResultCh chan message.GameResultMsg) *ConnManager { connManager := ConnManager{playersCount: playersCount, conns: make([]websocket.Conn, 0), gameRecvCh: gameRecvCh, gameSendCh: gameSendCh, tableOrderCh: tableOrderCh, + gameResultCh: gameResultCh, } go connManager.Broadcaster() return &connManager @@ -53,6 +56,11 @@ func (m *ConnManager) Broadcaster() { } m.conns[(first+i)%4].WriteJSON(msg) } + case msg := <-m.gameResultCh: + log.Println("broadcast game result") + for _, conn := range m.conns { + conn.WriteJSON(msg) + } } } } diff --git a/container/Room.go b/container/Room.go index ce1c238..bd3e2e3 100644 --- a/container/Room.go +++ b/container/Room.go @@ -14,6 +14,7 @@ type Room struct { gameRecvCh chan message.GameMsgRecv gameSendCh chan message.GameMsgSend tableOrderCh chan int + gameResultCh chan message.GameResultMsg password string playerCount int @@ -23,12 +24,14 @@ func NewRoom(rule rule.MahjongRule) *Room { gameRecvChannel := make(chan message.GameMsgRecv) gameSendChannel := make(chan message.GameMsgSend) tableOrderChannel := make(chan int) + gameResultChannel := make(chan message.GameResultMsg) return &Room{ gameRecvCh: gameRecvChannel, gameSendCh: gameSendChannel, tableOrderCh: tableOrderChannel, - connManager: NewConnManager(4, gameRecvChannel, gameSendChannel, tableOrderChannel), - mahjongManager: game.NewMahjongManager(gameRecvChannel, gameSendChannel, tableOrderChannel, rule), + gameResultCh: gameResultChannel, + connManager: NewConnManager(4, gameRecvChannel, gameSendChannel, tableOrderChannel, gameResultChannel), + mahjongManager: game.NewMahjongManager(gameRecvChannel, gameSendChannel, tableOrderChannel, gameResultChannel, rule), } } diff --git a/game/MahjongManager.go b/game/MahjongManager.go index ffb4438..7152178 100644 --- a/game/MahjongManager.go +++ b/game/MahjongManager.go @@ -17,6 +17,7 @@ type MahjongManager struct { gameRecvCh chan message.GameMsgRecv gameSendCh chan message.GameMsgSend tableOrderCh chan int + gameResultCh chan message.GameResultMsg lastTableOrder int currentTableOrder int @@ -30,6 +31,7 @@ type MahjongManager struct { func NewMahjongManager(gameRecvCh chan message.GameMsgRecv, gameSendCh chan message.GameMsgSend, tableOrderCh chan int, + gameResultCh chan message.GameResultMsg, r rule.MahjongRule) *MahjongManager { mahjong := MahjongManager{} mahjong.rules = r @@ -39,6 +41,7 @@ func NewMahjongManager(gameRecvCh chan message.GameMsgRecv, mahjong.gameRecvCh = gameRecvCh mahjong.gameSendCh = gameSendCh mahjong.tableOrderCh = tableOrderCh + mahjong.gameResultCh = gameResultCh return &mahjong } @@ -77,7 +80,6 @@ func (m *MahjongManager) gameLoop(gameRecvCh chan message.GameMsgRecv, gameSendC case config.Cancel: m.handleCancel(msg) } - // TODO:main logic here } } @@ -87,6 +89,10 @@ func (m *MahjongManager) handleStart(msg message.GameMsgRecv) { m.dealTile() //m.dealTileTest() newTile := m.wall.FrontDraw() + if newTile.IsEmpty() { + m.gameResultCh <- getTieResult() + return + } //TODO:判断第一张牌能否碰、杠、胡 availableActions := m.getAvailableActions(m.playerTile[msg.TableOrder].HandTiles, m.playerTile[msg.TableOrder].ShownTiles, newTile) m.playerTile[msg.TableOrder].HandTiles = append(m.playerTile[msg.TableOrder].HandTiles, newTile) @@ -234,6 +240,10 @@ func (m *MahjongManager) handleDiscard(msg message.GameMsgRecv, removeHand bool) m.lastTableOrder = msg.TableOrder m.currentTableOrder = (msg.TableOrder + 1) % 4 newTile := m.wall.FrontDraw() + if newTile.IsEmpty() { + m.gameResultCh <- getTieResult() + return + } availableActions := m.getAvailableActions(m.playerTile[m.currentTableOrder].HandTiles, m.playerTile[m.currentTableOrder].ShownTiles, newTile) m.playerTile[m.currentTableOrder].HandTiles = append(m.playerTile[m.currentTableOrder].HandTiles, newTile) model.SortTiles(m.playerTile[m.currentTableOrder].HandTiles) @@ -349,6 +359,10 @@ func (m *MahjongManager) handleExposedKong(msg message.GameMsgRecv) { m.playerTile[msg.TableOrder].ShownTiles = newShown //为玩家发牌 newTile := m.wall.BackDraw() + if newTile.IsEmpty() { + m.gameResultCh <- getTieResult() + return + } availableActions := m.getAvailableActions(m.playerTile[msg.TableOrder].HandTiles, m.playerTile[msg.TableOrder].ShownTiles, newTile) m.playerTile[msg.TableOrder].HandTiles = append(m.playerTile[msg.TableOrder].HandTiles, newTile) @@ -383,6 +397,10 @@ func (m *MahjongManager) handleConcealedKong(msg message.GameMsgRecv) { m.playerTile[msg.TableOrder].ShownTiles = newShown //为玩家发牌 newTile := m.wall.BackDraw() + if newTile.IsEmpty() { + m.gameResultCh <- getTieResult() + return + } availableActions := m.getAvailableActions(m.playerTile[msg.TableOrder].HandTiles, m.playerTile[msg.TableOrder].ShownTiles, newTile) m.playerTile[msg.TableOrder].HandTiles = append(m.playerTile[msg.TableOrder].HandTiles, newTile) model.SortTiles(m.playerTile[msg.TableOrder].HandTiles) @@ -427,6 +445,10 @@ func (m *MahjongManager) handleAddedKong(msg message.GameMsgRecv) { //发牌 newTile := m.wall.BackDraw() + if newTile.IsEmpty() { + m.gameResultCh <- getTieResult() + return + } availableActions := m.getAvailableActions(m.playerTile[msg.TableOrder].HandTiles, m.playerTile[msg.TableOrder].ShownTiles, newTile) m.playerTile[msg.TableOrder].HandTiles = append(m.playerTile[msg.TableOrder].HandTiles, newTile) model.SortTiles(m.playerTile[msg.TableOrder].HandTiles) @@ -447,7 +469,12 @@ func (m *MahjongManager) handleAddedKong(msg message.GameMsgRecv) { func (m *MahjongManager) handleWin(msg message.GameMsgRecv) { m.resetCancelList() - + msgSend := message.GameResultMsg{ + MsgType: config.GameResultMsgType, + Winner: msg.TableOrder, + FinalTile: msg.Tile, + } + m.gameResultCh <- msgSend } func (m *MahjongManager) handleCancel(msg message.GameMsgRecv) { @@ -476,6 +503,14 @@ func (m *MahjongManager) resetCancelList() { m.cancelList[3] = false } +func getTieResult() message.GameResultMsg { + return message.GameResultMsg{ + MsgType: config.GameResultMsgType, + Winner: -1, + FinalTile: model.Tile{}, + } +} + func (m *MahjongManager) dealTile() { for i := 0; i < 3; i++ { m.playerTile[0].HandTiles = append(m.playerTile[0].HandTiles, m.wall.FrontDraw()) diff --git a/message/RoomControlMessage.go b/message/RoomControlMessage.go index 92e09d8..e80552b 100644 --- a/message/RoomControlMessage.go +++ b/message/RoomControlMessage.go @@ -1,5 +1,7 @@ package message +import "github.com/c-my/MahjongServer/model" + type TableOrderMsg struct { MsgType int `json:"msg_type"` TableOrder int `json:"table_order"` @@ -10,6 +12,7 @@ type RoomInfoMsg struct { } type GameResultMsg struct { - MsgType int `json:"msg_type"` - Winner int `json:"winner"` + MsgType int `json:"msg_type"` + Winner int `json:"winner"` + FinalTile model.Tile `json:"final_tile"` } diff --git a/model/Tile.go b/model/Tile.go index 05ecdce..6fdaaae 100644 --- a/model/Tile.go +++ b/model/Tile.go @@ -227,3 +227,7 @@ func (t *Tile) GetRightTile() *Tile { } return nil } + +func (t *Tile) IsEmpty() bool { + return t.Number == 0 +} diff --git a/model/Wall.go b/model/Wall.go index 3fed8a7..b8281e8 100644 --- a/model/Wall.go +++ b/model/Wall.go @@ -21,7 +21,7 @@ func NewWall(generator func() []Tile) *Wall { func (w *Wall) FrontDraw() Tile { if w.back < w.front { - panic("front-draw from empty wall") + return Tile{0, 0} } tile := w.tiles[w.front] w.front++ @@ -30,7 +30,7 @@ func (w *Wall) FrontDraw() Tile { func (w *Wall) BackDraw() Tile { if w.back < w.front { - panic("back-draw from empty wall") + return Tile{0, 0} } tile := w.tiles[w.back] w.back--