云原生项目实践DevOps(GitOps)+K8S+BPF+SRE,从0到1使用Golang开发生产级麻将游戏服务器—第8篇

麻将牌 (Mahjong tiles) 抽象和编码实战

一句话描述麻将游戏业务:

  • 三人模式<三人两房>只用 子和 子两种花色共 72 张牌。
  • 四人模式<血战到底>使用 三种花色共 108 张牌。

系列文章

  1. Golang开发生产级麻将游戏服务器—第1篇
  2. Golang开发生产级麻将游戏服务器—第2篇
  3. Golang开发生产级麻将游戏服务器—第3篇
  4. Golang开发生产级麻将游戏服务器—第4篇
  5. Golang开发生产级麻将游戏服务器—第5篇
  6. Golang开发生产级麻将游戏服务器—第6篇
  7. Golang开发生产级麻将游戏服务器—第7篇

介绍

这将是一个完整的,完全践行 DevOps/GitOpsKubernetes 上云流程的 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
}
  • Id108 张牌,用 0~107 标识每一张牌。
  • Suit:三种花色,用 0~2 标识每一种花色(0:,1:,2:)。
  • Rank9 种点数,用 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

我是为少
微信:uuhells123
公众号:黑客下午茶
加我微信(互相学习交流),关注公众号(获取更多学习资料~)
posted @ 2021-03-08 09:21  为少  阅读(433)  评论(0编辑  收藏  举报