雲原生項目實踐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
公眾號:黑客下午茶
加我微信(互相學習交流),關注公眾號(獲取更多學習資料~)