介绍
这将是一个完整的,完全践行 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
牌(Tiles)抽象
定义 Tile struct
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
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
,我们编写它的单元测试函数。
internal/game/tile_test.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) } }) } }
执行:
cd internal/game/mahjong go test -v tile_test.go tile.go mahjong.go