雲原生專案實踐DevOps(GitOps)+K8S+BPF+SRE,從0到1使用Golang開發生產級麻將遊戲伺服器—第8篇
阿新 • • 發佈:2021-03-08
![](https://img2020.cnblogs.com/blog/436453/202103/436453-20210308092102424-64826476.png)
## 麻將牌 (Mahjong tiles) 抽象和編碼實戰
一句話描述麻將遊戲業務:
* 三人模式<`三人兩房`>只用 `條` 子和 `筒` 子兩種花色共 `72` 張牌。
* 四人模式<`血戰到底`>使用 `筒`、`條`、`萬` 三種花色共 `108` 張牌。
### 系列文章
1. [Golang開發生產級麻將遊戲伺服器—第1篇](https://mp.weixin.qq.com/s/Jyq_A1vehrnMwv6AdOtQ1w)
2. [Golang開發生產級麻將遊戲伺服器—第2篇](https://mp.weixin.qq.com/s/jnQaz08fAzQ3J7tZBdil4Q)
3. [Golang開發生產級麻將遊戲伺服器—第3篇](https://mp.weixin.qq.com/s/ktGxVD5VBoSzbBb-vwxxOg)
4. [Golang開發生產級麻將遊戲伺服器—第4篇](https://mp.weixin.qq.com/s/t1E8YleIbgrzkynbBplH3w)
5. [Golang開發生產級麻將遊戲伺服器—第5篇](https://mp.weixin.qq.com/s/FF7Gkoh7EOJBHEQkTp96dQ)
6. [Golang開發生產級麻將遊戲伺服器—第6篇](https://mp.weixin.qq.com/s/mZkzSomUKiOAuqfIeqj5bA)
7. [Golang開發生產級麻將遊戲伺服器—第7篇](https://mp.weixin.qq.com/s/4on-Us-qhLTwIyPizNhWpw)
### 介紹
這將是一個完整的,完全踐行 `DevOps/GitOps` 與 `Kubernetes` 上雲流程的 Golang 遊戲伺服器開發的系列教程。
這個系列教程是對開源專案 `Nanoserver` 的完整拆解,旨在幫助大家快速上手 Golang(遊戲)伺服器後端開發。通過實踐去理解 Golang 開發的精髓 —— `Share memory by communication(通過通訊共享記憶體)`。
同時這個專案可能還會涉及到 `Linux` 效能調優(`BPF` 相關的工具)和系統保障(`SRE`)的相關的工作。
### Step-By-Step 開發 Mahjong Server
* `單體架構`理解 `Mahjong Server` 業務 -> `Nano Distributed Game Server(分散式)` + `微服務` 改造。
* Demo:[go-mahjong-server](https://github.com/Hacker-Linner/go-mahjong-server)
## 牌(Tiles)抽象
### 定義 Tile struct
![](https://img2020.cnblogs.com/blog/436453/202103/436453-20210308091945961-603250029.png)
```go
type Tile struct {
Id int
Suit int
Rank int
Index int
}
```
* `Id`:`108` 張牌,用 `0~107` 標識每一張牌。
* `Suit`:三種花色,用 `0~2` 標識每一種花色(0:`條`,1:`筒`,2:`萬`)。
* `Rank`:`9` 種點數,用 `1~9` 標識(如:1條,9條,1筒,9筒,1萬,9萬等…)。
* `Index`:索引(條:`1~9`,筒:`11~19`,萬:`21~29`)。
### 通過一張表來理解
三種花色,每種型別牌的索引(`Index`):
| 條(1 ~ 9) | 筒(11 ~ 19) | 萬(21 ~ 29) |
| ---- | ---- | ---- |
1 1條 | 11 1筒 | 21 1萬 |
2 2條 | 12 2筒 | 22 2萬 |
3 3條 | 13 3筒 | 23 3萬 |
4 4條 | 14 4筒 | 24 4萬 |
5 5條 | 15 5筒 | 25 5萬 |
6 6條 | 16 6筒 | 26 6萬 |
7 7條 | 17 7筒 | 27 7萬 |
8 8條 | 18 8筒 | 28 8萬 |
9 9條 | 19 9筒 | 29 9萬 |
所有牌(這裡是 `108` 張)的 `ID` 編號:
| 條(0 ~ 35) | 筒(36 ~ 71) | 萬(72 ~ 107) |
| ---- | ---- | ---- |
0 1條 | 36 1筒 | 72 1萬 |
1 1條 | 37 1筒 | 73 1萬 |
2 1條 | 38 1筒 | 74 1萬 |
3 1條 | 39 1筒 | 75 1萬 |
4 2條 | 40 2筒 | 76 2萬 |
5 2條 | 41 2筒 | 77 2萬 |
6 2條 | 42 2筒 | 78 2萬 |
7 2條 | 43 2筒 | 79 2萬 |
8 3條 | 44 3筒 | 80 3萬 |
9 3條 | 45 3筒 | 81 3萬 |
10 3條 | 46 3筒 | 82 3萬 |
11 3條 | 47 3筒 | 83 3萬 |
12 4條 | 48 4筒 | 84 4萬 |
13 4條 | 49 4筒 | 85 4萬 |
14 4條 | 50 4筒 | 86 4萬 |
15 4條 | 51 4筒 | 87 4萬 |
16 5條 | 52 5筒 | 88 5萬 |
17 5條 | 53 5筒 | 89 5萬 |
18 5條 | 54 5筒 | 90 5萬 |
19 5條 | 55 5筒 | 91 5萬 |
20 6條 | 56 6筒 | 92 6萬 |
21 6條 | 57 6筒 | 93 6萬 |
22 6條 | 58 6筒 | 94 6萬 |
23 6條 | 59 6筒 | 95 6萬 |
24 7條 | 60 7筒 | 96 7萬 |
25 7條 | 61 7筒 | 97 7萬 |
26 7條 | 62 7筒 | 98 7萬 |
27 7條 | 63 7筒 | 99 7萬 |
28 8條 | 64 8筒 | 100 8萬 |
29 8條 | 65 8筒 | 101 8萬 |
30 8條 | 66 8筒 | 102 8萬 |
31 8條 | 67 8筒 | 103 8萬 |
32 9條 | 68 9筒 | 104 9萬 |
33 9條 | 69 9筒 | 105 9萬 |
34 9條 | 70 9筒 | 106 9萬 |
35 9條 | 71 9筒 | 107 9萬 |
## 編碼實戰
### 通過 ID 獲取 Tile
一個算術問題,沒啥好說的。
* 三種花色,每種有 `9` 類不同的牌,每類又有 `4` 張相同的牌。
`internal/game/tile.go`
```go
func TileFromID(id int) *Tile {
if id < 0 {
panic("illegal tile id")
}
var (
tmp = id / 4
h = tmp / 9
v = tmp%9 + 1
i = h*10 + v
)
return &Tile{Suit: h, Rank: v, Index: i, Id: id}
}
```
### 編寫單元測試函式
`TileFromID` 函式上右擊選擇 `Generate Unit Tests For Function`,我們編寫它的單元測試函式。
![](https://img2020.cnblogs.com/blog/436453/202103/436453-20210308092003232-1109270936.png)
`internal/game/tile_test.go`
```go
func TestTileFromID(t *testing.T) {
type args struct {
id int
}
tests := []struct {
name string
args args
want *Tile
}{
// 定義一堆用例
{"1條", args{id: 0}, &Tile{Suit: 0, Rank: 1, Index: 1, Id: 0}},
{"1條", args{id: 1}, &Tile{Suit: 0, Rank: 1, Index: 1, Id: 1}},
{"1條", args{id: 2}, &Tile{Suit: 0, Rank: 1, Index: 1, Id: 2}},
{"1條", args{id: 3}, &Tile{Suit: 0, Rank: 1, Index: 1, Id: 3}},
{"9條", args{id: 35}, &Tile{Suit: 0, Rank: 9, Index: 9, Id: 35}},
{"1筒", args{id: 36}, &Tile{Suit: 1, Rank: 1, Index: 11, Id: 36}},
{"1筒", args{id: 37}, &Tile{Suit: 1, Rank: 1, Index: 11, Id: 37}},
{"1筒", args{id: 38}, &Tile{Suit: 1, Rank: 1, Index: 11, Id: 38}},
{"1筒", args{id: 39}, &Tile{Suit: 1, Rank: 1, Index: 11, Id: 39}},
{"9筒", args{id: 71}, &Tile{Suit: 1, Rank: 9, Index: 19, Id: 71}},
{"1萬", args{id: 72}, &Tile{Suit: 2, Rank: 1, Index: 21, Id: 72}},
{"1萬", args{id: 73}, &Tile{Suit: 2, Rank: 1, Index: 21, Id: 73}},
{"1萬", args{id: 74}, &Tile{Suit: 2, Rank: 1, Index: 21, Id: 74}},
{"1萬", args{id: 75}, &Tile{Suit: 2, Rank: 1, Index: 21, Id: 75}},
{"9萬", args{id: 107}, &Tile{Suit: 2, Rank: 9, Index: 29, Id: 107}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := TileFromID(tt.args.id); !reflect.DeepEqual(got, tt.want) {
t.Errorf("TileFromID() = %v, want %v", got, tt.want)
}
})
}
}
```
執行:
```sh
cd internal/game/mahjong
go test -v tile_test.go tile.go mahjong.go
```
![](https://img2020.cnblogs.com/blog/436453/202103/436453-20210308092019855-272892400.png)
```sh
我是為少
微信:uuhells123
公眾號:黑客下午茶
加我微信(互相學習交流),關注公眾號(獲取更多學習資料~