Browse Source

betting logic

master
tangmingyou 4 years ago
parent
commit
e9891d0f51
  1. 115
      api/poker.pb.go
  2. 2
      api/poker.proto
  3. 282
      api/proto.js
  4. 2
      internal/game/player.go
  5. 139
      internal/game/table.go
  6. 60
      internal/service/table.go

115
api/poker.pb.go

@ -1150,7 +1150,6 @@ type ResGameFullStatus struct {
TableNo int32 `protobuf:"varint,2,opt,name=tableNo,proto3" json:"tableNo,omitempty"` // 所在桌面编号
GameStage int32 `protobuf:"varint,3,opt,name=gameStage,proto3" json:"gameStage,omitempty"` // 游戏阶段?
Chip int32 `protobuf:"varint,4,opt,name=chip,proto3" json:"chip,omitempty"` // 牌桌筹码
RoundTimes int32 `protobuf:"varint,5,opt,name=roundTimes,proto3" json:"roundTimes,omitempty"` // 回合次数
PlayerId int64 `protobuf:"varint,6,opt,name=playerId,proto3" json:"playerId,omitempty"` // 当前玩家id
BigBlindPos int32 `protobuf:"varint,7,opt,name=bigBlindPos,proto3" json:"bigBlindPos,omitempty"` // 大盲注位
SmallBlindPos int32 `protobuf:"varint,8,opt,name=smallBlindPos,proto3" json:"smallBlindPos,omitempty"` // 小盲注位
@ -1218,13 +1217,6 @@ func (x *ResGameFullStatus) GetChip() int32 {
return 0
}
func (x *ResGameFullStatus) GetRoundTimes() int32 {
if x != nil {
return x.RoundTimes
}
return 0
}
func (x *ResGameFullStatus) GetPlayerId() int64 {
if x != nil {
return x.PlayerId
@ -1811,7 +1803,7 @@ type ResCalcWinnerChip struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PlayersWinChip map[int64]int32 `protobuf:"bytes,9,rep,name=playersWinChip,proto3" json:"playersWinChip,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
WinsChip map[int64]int32 `protobuf:"bytes,9,rep,name=winsChip,proto3" json:"winsChip,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
}
func (x *ResCalcWinnerChip) Reset() {
@ -1846,13 +1838,61 @@ func (*ResCalcWinnerChip) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{32}
}
func (x *ResCalcWinnerChip) GetPlayersWinChip() map[int64]int32 {
func (x *ResCalcWinnerChip) GetWinsChip() map[int64]int32 {
if x != nil {
return x.PlayersWinChip
return x.WinsChip
}
return nil
}
// 回合数变化时响应消息,前端等发牌动画结束后放开操作
type ResGameNextRound struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Round int32 `protobuf:"varint,1,opt,name=round,proto3" json:"round,omitempty"`
}
func (x *ResGameNextRound) Reset() {
*x = ResGameNextRound{}
if protoimpl.UnsafeEnabled {
mi := &file_poker_proto_msgTypes[33]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ResGameNextRound) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResGameNextRound) ProtoMessage() {}
func (x *ResGameNextRound) ProtoReflect() protoreflect.Message {
mi := &file_poker_proto_msgTypes[33]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ResGameNextRound.ProtoReflect.Descriptor instead.
func (*ResGameNextRound) Descriptor() ([]byte, []int) {
return file_poker_proto_rawDescGZIP(), []int{33}
}
func (x *ResGameNextRound) GetRound() int32 {
if x != nil {
return x.Round
}
return 0
}
var File_poker_proto protoreflect.FileDescriptor
var file_poker_proto_rawDesc = []byte{
@ -1927,7 +1967,7 @@ var file_poker_proto_rawDesc = []byte{
0x12, 0x12, 0x0a, 0x04, 0x63, 0x68, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04,
0x63, 0x68, 0x69, 0x70, 0x22, 0x0f, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x47, 0x61, 0x6d, 0x65, 0x41,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x13, 0x0a, 0x11, 0x52, 0x65, 0x71, 0x47, 0x61, 0x6d, 0x65,
0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xd2, 0x02, 0x0a, 0x11, 0x52,
0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xb2, 0x02, 0x0a, 0x11, 0x52,
0x65, 0x73, 0x47, 0x61, 0x6d, 0x65, 0x46, 0x75, 0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x12, 0x16, 0x0a, 0x06, 0x69, 0x6e, 0x47, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
0x52, 0x06, 0x69, 0x6e, 0x47, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x62, 0x6c,
@ -1935,9 +1975,7 @@ var file_poker_proto_rawDesc = []byte{
0x4e, 0x6f, 0x12, 0x1c, 0x0a, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x67, 0x65, 0x18,
0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x67, 0x61, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x67, 0x65,
0x12, 0x12, 0x0a, 0x04, 0x63, 0x68, 0x69, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04,
0x63, 0x68, 0x69, 0x70, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x54, 0x69, 0x6d,
0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x54,
0x69, 0x6d, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64,
0x63, 0x68, 0x69, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64,
0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x64,
0x12, 0x20, 0x0a, 0x0b, 0x62, 0x69, 0x67, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x50, 0x6f, 0x73, 0x18,
0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x62, 0x69, 0x67, 0x42, 0x6c, 0x69, 0x6e, 0x64, 0x50,
@ -1998,19 +2036,21 @@ var file_poker_proto_rawDesc = []byte{
0x0a, 0x10, 0x52, 0x65, 0x73, 0x47, 0x61, 0x6d, 0x65, 0x45, 0x6e, 0x64, 0x53, 0x65, 0x74, 0x74,
0x6c, 0x65, 0x12, 0x2a, 0x0a, 0x04, 0x67, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x16, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x47, 0x61, 0x6d, 0x65, 0x46, 0x75,
0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x04, 0x67, 0x61, 0x6d, 0x65, 0x22, 0xaa,
0x6c, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x04, 0x67, 0x61, 0x6d, 0x65, 0x22, 0x92,
0x01, 0x0a, 0x11, 0x52, 0x65, 0x73, 0x43, 0x61, 0x6c, 0x63, 0x57, 0x69, 0x6e, 0x6e, 0x65, 0x72,
0x43, 0x68, 0x69, 0x70, 0x12, 0x52, 0x0a, 0x0e, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x57,
0x69, 0x6e, 0x43, 0x68, 0x69, 0x70, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x43, 0x61, 0x6c, 0x63, 0x57, 0x69, 0x6e, 0x6e, 0x65, 0x72,
0x43, 0x68, 0x69, 0x70, 0x2e, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x73, 0x57, 0x69, 0x6e, 0x43,
0x68, 0x69, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x70, 0x6c, 0x61, 0x79, 0x65, 0x72,
0x73, 0x57, 0x69, 0x6e, 0x43, 0x68, 0x69, 0x70, 0x1a, 0x41, 0x0a, 0x13, 0x50, 0x6c, 0x61, 0x79,
0x65, 0x72, 0x73, 0x57, 0x69, 0x6e, 0x43, 0x68, 0x69, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0b, 0x5a, 0x09, 0x2e,
0x2f, 0x61, 0x70, 0x69, 0x3b, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x43, 0x68, 0x69, 0x70, 0x12, 0x40, 0x0a, 0x08, 0x77, 0x69, 0x6e, 0x73, 0x43, 0x68, 0x69, 0x70,
0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73,
0x43, 0x61, 0x6c, 0x63, 0x57, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x43, 0x68, 0x69, 0x70, 0x2e, 0x57,
0x69, 0x6e, 0x73, 0x43, 0x68, 0x69, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x77, 0x69,
0x6e, 0x73, 0x43, 0x68, 0x69, 0x70, 0x1a, 0x3b, 0x0a, 0x0d, 0x57, 0x69, 0x6e, 0x73, 0x43, 0x68,
0x69, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
0x02, 0x38, 0x01, 0x22, 0x28, 0x0a, 0x10, 0x52, 0x65, 0x73, 0x47, 0x61, 0x6d, 0x65, 0x4e, 0x65,
0x78, 0x74, 0x52, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x42, 0x0b, 0x5a,
0x09, 0x2e, 0x2f, 0x61, 0x70, 0x69, 0x3b, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
@ -2025,7 +2065,7 @@ func file_poker_proto_rawDescGZIP() []byte {
return file_poker_proto_rawDescData
}
var file_poker_proto_msgTypes = make([]protoimpl.MessageInfo, 34)
var file_poker_proto_msgTypes = make([]protoimpl.MessageInfo, 35)
var file_poker_proto_goTypes = []interface{}{
(*ProtoWrap)(nil), // 0: api.ProtoWrap
(*Ping)(nil), // 1: api.Ping
@ -2060,7 +2100,8 @@ var file_poker_proto_goTypes = []interface{}{
(*ResNoticePlayerLine)(nil), // 30: api.ResNoticePlayerLine
(*ResGameEndSettle)(nil), // 31: api.ResGameEndSettle
(*ResCalcWinnerChip)(nil), // 32: api.ResCalcWinnerChip
nil, // 33: api.ResCalcWinnerChip.PlayersWinChipEntry
(*ResGameNextRound)(nil), // 33: api.ResGameNextRound
nil, // 34: api.ResCalcWinnerChip.WinsChipEntry
}
var file_poker_proto_depIdxs = []int32{
9, // 0: api.ResLobbyView.tables:type_name -> api.LobbyTable
@ -2070,7 +2111,7 @@ var file_poker_proto_depIdxs = []int32{
25, // 4: api.TablePlayer.betRole:type_name -> api.BetRole
24, // 5: api.TablePlayer.handCard:type_name -> api.Card
22, // 6: api.ResGameEndSettle.game:type_name -> api.ResGameFullStatus
33, // 7: api.ResCalcWinnerChip.playersWinChip:type_name -> api.ResCalcWinnerChip.PlayersWinChipEntry
34, // 7: api.ResCalcWinnerChip.winsChip:type_name -> api.ResCalcWinnerChip.WinsChipEntry
8, // [8:8] is the sub-list for method output_type
8, // [8:8] is the sub-list for method input_type
8, // [8:8] is the sub-list for extension type_name
@ -2480,6 +2521,18 @@ func file_poker_proto_init() {
return nil
}
}
file_poker_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ResGameNextRound); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
@ -2487,7 +2540,7 @@ func file_poker_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_poker_proto_rawDesc,
NumEnums: 0,
NumMessages: 34,
NumMessages: 35,
NumExtensions: 0,
NumServices: 0,
},

2
api/poker.proto

@ -201,7 +201,7 @@ message ResGameEndSettle {
//
message ResCalcWinnerChip {
map<int64, int32> playersWinChip = 9;
map<int64, int32> winsChip = 9;
}
//

282
api/proto.js

@ -4816,7 +4816,6 @@ export const api = $root.api = (() => {
* @property {number|null} [tableNo] ResGameFullStatus tableNo
* @property {number|null} [gameStage] ResGameFullStatus gameStage
* @property {number|null} [chip] ResGameFullStatus chip
* @property {number|null} [roundTimes] ResGameFullStatus roundTimes
* @property {number|Long|null} [playerId] ResGameFullStatus playerId
* @property {number|null} [bigBlindPos] ResGameFullStatus bigBlindPos
* @property {number|null} [smallBlindPos] ResGameFullStatus smallBlindPos
@ -4873,14 +4872,6 @@ export const api = $root.api = (() => {
*/
ResGameFullStatus.prototype.chip = 0;
/**
* ResGameFullStatus roundTimes.
* @member {number} roundTimes
* @memberof api.ResGameFullStatus
* @instance
*/
ResGameFullStatus.prototype.roundTimes = 0;
/**
* ResGameFullStatus playerId.
* @member {number|Long} playerId
@ -4953,8 +4944,6 @@ export const api = $root.api = (() => {
writer.uint32(/* id 3, wireType 0 =*/24).int32(message.gameStage);
if (message.chip != null && Object.hasOwnProperty.call(message, "chip"))
writer.uint32(/* id 4, wireType 0 =*/32).int32(message.chip);
if (message.roundTimes != null && Object.hasOwnProperty.call(message, "roundTimes"))
writer.uint32(/* id 5, wireType 0 =*/40).int32(message.roundTimes);
if (message.playerId != null && Object.hasOwnProperty.call(message, "playerId"))
writer.uint32(/* id 6, wireType 0 =*/48).int64(message.playerId);
if (message.bigBlindPos != null && Object.hasOwnProperty.call(message, "bigBlindPos"))
@ -5017,10 +5006,6 @@ export const api = $root.api = (() => {
message.chip = reader.int32();
break;
}
case 5: {
message.roundTimes = reader.int32();
break;
}
case 6: {
message.playerId = reader.int64();
break;
@ -5092,9 +5077,6 @@ export const api = $root.api = (() => {
if (message.chip != null && message.hasOwnProperty("chip"))
if (!$util.isInteger(message.chip))
return "chip: integer expected";
if (message.roundTimes != null && message.hasOwnProperty("roundTimes"))
if (!$util.isInteger(message.roundTimes))
return "roundTimes: integer expected";
if (message.playerId != null && message.hasOwnProperty("playerId"))
if (!$util.isInteger(message.playerId) && !(message.playerId && $util.isInteger(message.playerId.low) && $util.isInteger(message.playerId.high)))
return "playerId: integer|Long expected";
@ -5145,8 +5127,6 @@ export const api = $root.api = (() => {
message.gameStage = object.gameStage | 0;
if (object.chip != null)
message.chip = object.chip | 0;
if (object.roundTimes != null)
message.roundTimes = object.roundTimes | 0;
if (object.playerId != null)
if ($util.Long)
(message.playerId = $util.Long.fromValue(object.playerId)).unsigned = false;
@ -5205,7 +5185,6 @@ export const api = $root.api = (() => {
object.tableNo = 0;
object.gameStage = 0;
object.chip = 0;
object.roundTimes = 0;
if ($util.Long) {
let long = new $util.Long(0, 0, false);
object.playerId = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long;
@ -5222,8 +5201,6 @@ export const api = $root.api = (() => {
object.gameStage = message.gameStage;
if (message.chip != null && message.hasOwnProperty("chip"))
object.chip = message.chip;
if (message.roundTimes != null && message.hasOwnProperty("roundTimes"))
object.roundTimes = message.roundTimes;
if (message.playerId != null && message.hasOwnProperty("playerId"))
if (typeof message.playerId === "number")
object.playerId = options.longs === String ? String(message.playerId) : message.playerId;
@ -7528,7 +7505,7 @@ export const api = $root.api = (() => {
* Properties of a ResCalcWinnerChip.
* @memberof api
* @interface IResCalcWinnerChip
* @property {Object.<string,number>|null} [playersWinChip] ResCalcWinnerChip playersWinChip
* @property {Object.<string,number>|null} [winsChip] ResCalcWinnerChip winsChip
*/
/**
@ -7540,7 +7517,7 @@ export const api = $root.api = (() => {
* @param {api.IResCalcWinnerChip=} [properties] Properties to set
*/
function ResCalcWinnerChip(properties) {
this.playersWinChip = {};
this.winsChip = {};
if (properties)
for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null)
@ -7548,12 +7525,12 @@ export const api = $root.api = (() => {
}
/**
* ResCalcWinnerChip playersWinChip.
* @member {Object.<string,number>} playersWinChip
* ResCalcWinnerChip winsChip.
* @member {Object.<string,number>} winsChip
* @memberof api.ResCalcWinnerChip
* @instance
*/
ResCalcWinnerChip.prototype.playersWinChip = $util.emptyObject;
ResCalcWinnerChip.prototype.winsChip = $util.emptyObject;
/**
* Creates a new ResCalcWinnerChip instance using the specified properties.
@ -7579,9 +7556,9 @@ export const api = $root.api = (() => {
ResCalcWinnerChip.encode = function encode(message, writer) {
if (!writer)
writer = $Writer.create();
if (message.playersWinChip != null && Object.hasOwnProperty.call(message, "playersWinChip"))
for (let keys = Object.keys(message.playersWinChip), i = 0; i < keys.length; ++i)
writer.uint32(/* id 9, wireType 2 =*/74).fork().uint32(/* id 1, wireType 0 =*/8).int64(keys[i]).uint32(/* id 2, wireType 0 =*/16).int32(message.playersWinChip[keys[i]]).ldelim();
if (message.winsChip != null && Object.hasOwnProperty.call(message, "winsChip"))
for (let keys = Object.keys(message.winsChip), i = 0; i < keys.length; ++i)
writer.uint32(/* id 9, wireType 2 =*/74).fork().uint32(/* id 1, wireType 0 =*/8).int64(keys[i]).uint32(/* id 2, wireType 0 =*/16).int32(message.winsChip[keys[i]]).ldelim();
return writer;
};
@ -7617,8 +7594,8 @@ export const api = $root.api = (() => {
let tag = reader.uint32();
switch (tag >>> 3) {
case 9: {
if (message.playersWinChip === $util.emptyObject)
message.playersWinChip = {};
if (message.winsChip === $util.emptyObject)
message.winsChip = {};
let end2 = reader.uint32() + reader.pos;
key = 0;
value = 0;
@ -7636,7 +7613,7 @@ export const api = $root.api = (() => {
break;
}
}
message.playersWinChip[typeof key === "object" ? $util.longToHash(key) : key] = value;
message.winsChip[typeof key === "object" ? $util.longToHash(key) : key] = value;
break;
}
default:
@ -7674,15 +7651,15 @@ export const api = $root.api = (() => {
ResCalcWinnerChip.verify = function verify(message) {
if (typeof message !== "object" || message === null)
return "object expected";
if (message.playersWinChip != null && message.hasOwnProperty("playersWinChip")) {
if (!$util.isObject(message.playersWinChip))
return "playersWinChip: object expected";
let key = Object.keys(message.playersWinChip);
if (message.winsChip != null && message.hasOwnProperty("winsChip")) {
if (!$util.isObject(message.winsChip))
return "winsChip: object expected";
let key = Object.keys(message.winsChip);
for (let i = 0; i < key.length; ++i) {
if (!$util.key64Re.test(key[i]))
return "playersWinChip: integer|Long key{k:int64} expected";
if (!$util.isInteger(message.playersWinChip[key[i]]))
return "playersWinChip: integer{k:int64} expected";
return "winsChip: integer|Long key{k:int64} expected";
if (!$util.isInteger(message.winsChip[key[i]]))
return "winsChip: integer{k:int64} expected";
}
}
return null;
@ -7700,12 +7677,12 @@ export const api = $root.api = (() => {
if (object instanceof $root.api.ResCalcWinnerChip)
return object;
let message = new $root.api.ResCalcWinnerChip();
if (object.playersWinChip) {
if (typeof object.playersWinChip !== "object")
throw TypeError(".api.ResCalcWinnerChip.playersWinChip: object expected");
message.playersWinChip = {};
for (let keys = Object.keys(object.playersWinChip), i = 0; i < keys.length; ++i)
message.playersWinChip[keys[i]] = object.playersWinChip[keys[i]] | 0;
if (object.winsChip) {
if (typeof object.winsChip !== "object")
throw TypeError(".api.ResCalcWinnerChip.winsChip: object expected");
message.winsChip = {};
for (let keys = Object.keys(object.winsChip), i = 0; i < keys.length; ++i)
message.winsChip[keys[i]] = object.winsChip[keys[i]] | 0;
}
return message;
};
@ -7724,12 +7701,12 @@ export const api = $root.api = (() => {
options = {};
let object = {};
if (options.objects || options.defaults)
object.playersWinChip = {};
object.winsChip = {};
let keys2;
if (message.playersWinChip && (keys2 = Object.keys(message.playersWinChip)).length) {
object.playersWinChip = {};
if (message.winsChip && (keys2 = Object.keys(message.winsChip)).length) {
object.winsChip = {};
for (let j = 0; j < keys2.length; ++j)
object.playersWinChip[keys2[j]] = message.playersWinChip[keys2[j]];
object.winsChip[keys2[j]] = message.winsChip[keys2[j]];
}
return object;
};
@ -7763,6 +7740,209 @@ export const api = $root.api = (() => {
return ResCalcWinnerChip;
})();
api.ResGameNextRound = (function() {
/**
* Properties of a ResGameNextRound.
* @memberof api
* @interface IResGameNextRound
* @property {number|null} [round] ResGameNextRound round
*/
/**
* Constructs a new ResGameNextRound.
* @memberof api
* @classdesc Represents a ResGameNextRound.
* @implements IResGameNextRound
* @constructor
* @param {api.IResGameNextRound=} [properties] Properties to set
*/
function ResGameNextRound(properties) {
if (properties)
for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null)
this[keys[i]] = properties[keys[i]];
}
/**
* ResGameNextRound round.
* @member {number} round
* @memberof api.ResGameNextRound
* @instance
*/
ResGameNextRound.prototype.round = 0;
/**
* Creates a new ResGameNextRound instance using the specified properties.
* @function create
* @memberof api.ResGameNextRound
* @static
* @param {api.IResGameNextRound=} [properties] Properties to set
* @returns {api.ResGameNextRound} ResGameNextRound instance
*/
ResGameNextRound.create = function create(properties) {
return new ResGameNextRound(properties);
};
/**
* Encodes the specified ResGameNextRound message. Does not implicitly {@link api.ResGameNextRound.verify|verify} messages.
* @function encode
* @memberof api.ResGameNextRound
* @static
* @param {api.IResGameNextRound} message ResGameNextRound message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
ResGameNextRound.encode = function encode(message, writer) {
if (!writer)
writer = $Writer.create();
if (message.round != null && Object.hasOwnProperty.call(message, "round"))
writer.uint32(/* id 1, wireType 0 =*/8).int32(message.round);
return writer;
};
/**
* Encodes the specified ResGameNextRound message, length delimited. Does not implicitly {@link api.ResGameNextRound.verify|verify} messages.
* @function encodeDelimited
* @memberof api.ResGameNextRound
* @static
* @param {api.IResGameNextRound} message ResGameNextRound message or plain object to encode
* @param {$protobuf.Writer} [writer] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
ResGameNextRound.encodeDelimited = function encodeDelimited(message, writer) {
return this.encode(message, writer).ldelim();
};
/**
* Decodes a ResGameNextRound message from the specified reader or buffer.
* @function decode
* @memberof api.ResGameNextRound
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @param {number} [length] Message length if known beforehand
* @returns {api.ResGameNextRound} ResGameNextRound
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
ResGameNextRound.decode = function decode(reader, length) {
if (!(reader instanceof $Reader))
reader = $Reader.create(reader);
let end = length === undefined ? reader.len : reader.pos + length, message = new $root.api.ResGameNextRound();
while (reader.pos < end) {
let tag = reader.uint32();
switch (tag >>> 3) {
case 1: {
message.round = reader.int32();
break;
}
default:
reader.skipType(tag & 7);
break;
}
}
return message;
};
/**
* Decodes a ResGameNextRound message from the specified reader or buffer, length delimited.
* @function decodeDelimited
* @memberof api.ResGameNextRound
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @returns {api.ResGameNextRound} ResGameNextRound
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
ResGameNextRound.decodeDelimited = function decodeDelimited(reader) {
if (!(reader instanceof $Reader))
reader = new $Reader(reader);
return this.decode(reader, reader.uint32());
};
/**
* Verifies a ResGameNextRound message.
* @function verify
* @memberof api.ResGameNextRound
* @static
* @param {Object.<string,*>} message Plain object to verify
* @returns {string|null} `null` if valid, otherwise the reason why it is not
*/
ResGameNextRound.verify = function verify(message) {
if (typeof message !== "object" || message === null)
return "object expected";
if (message.round != null && message.hasOwnProperty("round"))
if (!$util.isInteger(message.round))
return "round: integer expected";
return null;
};
/**
* Creates a ResGameNextRound message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof api.ResGameNextRound
* @static
* @param {Object.<string,*>} object Plain object
* @returns {api.ResGameNextRound} ResGameNextRound
*/
ResGameNextRound.fromObject = function fromObject(object) {
if (object instanceof $root.api.ResGameNextRound)
return object;
let message = new $root.api.ResGameNextRound();
if (object.round != null)
message.round = object.round | 0;
return message;
};
/**
* Creates a plain object from a ResGameNextRound message. Also converts values to other types if specified.
* @function toObject
* @memberof api.ResGameNextRound
* @static
* @param {api.ResGameNextRound} message ResGameNextRound
* @param {$protobuf.IConversionOptions} [options] Conversion options
* @returns {Object.<string,*>} Plain object
*/
ResGameNextRound.toObject = function toObject(message, options) {
if (!options)
options = {};
let object = {};
if (options.defaults)
object.round = 0;
if (message.round != null && message.hasOwnProperty("round"))
object.round = message.round;
return object;
};
/**
* Converts this ResGameNextRound to JSON.
* @function toJSON
* @memberof api.ResGameNextRound
* @instance
* @returns {Object.<string,*>} JSON object
*/
ResGameNextRound.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
/**
* Gets the default type url for ResGameNextRound
* @function getTypeUrl
* @memberof api.ResGameNextRound
* @static
* @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
* @returns {string} The default type url
*/
ResGameNextRound.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
if (typeUrlPrefix === undefined) {
typeUrlPrefix = "type.googleapis.com";
}
return typeUrlPrefix + "/api.ResGameNextRound";
};
return ResGameNextRound;
})();
return api;
})();

2
internal/game/player.go

@ -19,7 +19,7 @@ type Player struct {
Cards [2]*Card // 手牌
Chip int32 // 玩家筹码
TotalBetChip int32 // 本次游戏已下注筹码
Status int32 // 状态: 1待准备开始,2已准备开始,3等待其他玩家动作,[4第一回合小盲注跟注,5待大盲注,5待小盲注,] 6待跟注,7已弃牌
Status int32 // 状态: 1待准备开始,2已准备开始,3等待其他玩家动作,[4第一回合小盲注跟注,5待大盲注,5待小盲注,] 6待跟注,7已弃牌,8结算中
LastStatus int32 // 变化前一个状态
BetOpts []int32 // status=[4,6]时下注可操作按钮: 1跟注,2加注(-[0]+),3All-In,4弃牌,5过牌
BetMin int32 // 最低下注额

139
internal/game/table.go

@ -30,6 +30,7 @@ type Table struct {
TexasType int32 // 德州扑克类型: (1限注德州扑克:你只能增加与大盲注相同的投注额; 2底池限制德州扑克:你只能增加当时台面最大额的投注额(已经完成所有投注); 3无限制德州扑克:你可在手持额度下,增加任何额度的投注额,如果你投入所有筹码,就是“全押”)
LimitInAmount int32 // 最低入场金额
LastPosBetType int32 // 上家下注类型(弃牌不记录跳过) -> player.BetOpts
LastPosBetChip int32 // 上家下注金额
RoundRaiseTimes int32 // 该轮押注圈加注次数
@ -130,7 +131,7 @@ func (t *Table) JoinPlayer(player *Player) (int, error) {
// BuildResGameFullStatus 构建牌桌当前游戏状态消息
func (t *Table) BuildResGameFullStatus() *api.ResGameFullStatus {
resGame := &api.ResGameFullStatus{
InGame: collect.In(t.Stage, 2, 3, 4, 5, 6, 7),
InGame: collect.In(t.Stage, 2, 3, 4, 5, 7),
TableNo: t.TableNo,
GameStage: t.Stage,
Chip: t.Chip,
@ -172,15 +173,13 @@ func (t *Table) BuildResGameFullStatus() *api.ResGameFullStatus {
BetOpts: p.BetOpts,
},
}
// 未到结算时不展示其他玩家手牌
if !collect.In(t.Stage, 7, 9) {
for j, card := range p.Cards {
if card == nil {
player.HandCard[j] = nil
continue
}
player.HandCard[j] = &api.Card{Dot: int32(card.Dot), Suit: CardColors[card.Suit]}
// 玩家手牌
for j, card := range p.Cards {
if card == nil {
player.HandCard[j] = nil
continue
}
player.HandCard[j] = &api.Card{Dot: int32(card.Dot), Suit: CardColors[card.Suit]}
}
resGame.Players[i] = player
}
@ -189,15 +188,20 @@ func (t *Table) BuildResGameFullStatus() *api.ResGameFullStatus {
func (t *Table) NoticeGameFullStatus() {
// 发送当前游戏状态消息到牌桌所有用户
resGame := t.BuildResGameFullStatus()
gameEnd := collect.In(t.Stage, 1, 7, 9)
for _, player := range t.Players {
if player != nil && player.ProtoWriter != nil {
resGame := t.BuildResGameFullStatus()
resGame.PlayerId = player.Id
// 只返回自己的手牌 TODO 结算时全部返回
for _, p := range resGame.Players {
if p != nil && p.Id != player.Id {
p.HandCard[0] = nil
p.HandCard[1] = nil
// 除结算时,只返回自己的手牌
if !gameEnd {
resGame = t.BuildResGameFullStatus()
resGame.PlayerId = player.Id
for _, p := range resGame.Players {
if p != nil && p.Id != player.Id {
p.HandCard[0] = nil
p.HandCard[1] = nil
}
}
}
player.ProtoWriter.Write(resGame)
@ -244,32 +248,21 @@ func (t *Table) RoundOver() error {
}
// 重置一些状态
t.LastPosBetChip = 0
t.RoundRaiseTimes = 0
for _, p := range t.Players {
if p != nil {
p.RoundBetTimes = 0
p.WaitBet()
}
}
// 由小盲注或小盲注后第一个未弃牌玩家开始
nextPos := t.SmallBlindPos
if t.Players[t.SmallBlindPos].Status == 7 {
nextPos = t.NextHoldingCardPlayerPos(nextPos)
}
nextPlayer := t.Players[nextPos]
nextPlayer.SetStatus(6)
nextPlayer.BetOpts = []int32{1, 2, 4, 5}
// 由小盲注或小盲注后第一个未弃牌玩家开始
t.SetNextPlayerWithRoundStart()
return nil
}
// SetNextPlayerWithRoundStart 回合开始, 设置下一个下注玩家
func (t *Table) SetNextPlayerWithRoundStart() {
nextPos := t.SmallBlindPos
if t.Stage == 2 { // TODO 第一回合第一轮由大盲注后一个玩家下注
if t.Stage == 2 { // 第一回合第一轮由大盲注后一个玩家下注
nextPos = t.NextPlayerPos(t.BigBlindPos)
}
if t.Players[nextPos].Status == 7 {
if t.Players[nextPos].Status == 7 { // 其他回合由小盲注或其后第一个未弃牌玩家开始下注
nextPos = t.NextHoldingCardPlayerPos(nextPos)
}
// 重置其他玩家状态为等待
@ -287,6 +280,11 @@ func (t *Table) SetNextPlayerWithRoundStart() {
nextP.BetOpts = []int32{2, 4}
nextP.BetMin = t.BigBlindChip
// 回合第一个玩家可过牌
if t.Stage != 2 {
nextP.BetOpts = append(nextP.BetOpts, 5)
}
switch t.TexasType {
case 2: // 底池限注
nextP.BetMax = t.Chip + t.LastPosBetChip*2
@ -318,7 +316,7 @@ func (t *Table) SetNextPlayerWithRoundStart() {
}
}
// SetNextPlayer 查找下一个下注玩家, TODO 并计算最大最小下注额
// SetNextPlayer 查找下一个下注玩家, 并计算最大最小下注额
func (t *Table) SetNextPlayer(current int) {
// 找下一个拿牌玩家
var nextPos = t.NextHoldingCardPlayerPos(current)
@ -332,10 +330,56 @@ func (t *Table) SetNextPlayer(current int) {
}
}
nextP := t.Players[nextPos]
// 判断该轮下一玩家可下注情况 : 下一玩家是否已下注,当前玩家是否跟注,
nextP.SetStatus(6)
// 最大最小下注额
nextP.BetMin = t.LastPosBetChip
nextP.BetOpts = []int32{1, 4}
// 可过牌
if t.LastPosBetType == 5 {
nextP.BetOpts = append(nextP.BetOpts, 5)
}
// 下一玩家需跟注
// 游戏类型处理最大下注额
switch t.TexasType {
case 2: // 底池限注
nextP.BetOpts = append(nextP.BetOpts, 2)
nextP.BetMax = t.Chip + t.LastPosBetChip*2
case 3: // 无限注
nextP.BetOpts = append(nextP.BetOpts, 2, 3) // 可 all in
nextP.BetMax = -1
case 1: // 限注
fallthrough
default:
// 限注比赛只允许一次下注与三次加注
if t.RoundRaiseTimes < 3 {
nextP.BetOpts = append(nextP.BetOpts, 2)
// 第1,2回合跟注加注需和大盲注相同, 3,4回合两倍
nextP.BetMax = t.BigBlindChip * (t.Stage/2 + 1)
} else {
// 只能跟注
nextP.BetMax = t.LastPosBetChip
}
}
// 如果下一玩家是大小盲注第一次下注
if t.Stage == 2 && nextP.RoundBetTimes == 0 {
switch nextP.PosIndex {
case t.SmallBlindPos:
nextP.BetMin -= t.SmallBlindChip
if t.TexasType != 3 {
nextP.BetMax -= t.SmallBlindChip
}
case t.BigBlindPos:
nextP.BetMin -= t.BigBlindChip
nextP.BetOpts = append(nextP.BetOpts, 5)
if t.TexasType != 3 {
nextP.BetMax -= t.BigBlindChip
}
}
}
}
// cardFightAndSettle 斗牌并结算
@ -355,7 +399,7 @@ func (t *Table) cardFightAndSettle() error {
} else {
// 剩余玩家大于1: 比牌
for _, p := range t.Players {
if p == nil {
if p == nil || p.Status == 7 {
continue
}
hand, err := AnalyzeMaxHand(p.Cards, t.PublicCards)
@ -375,12 +419,21 @@ func (t *Table) cardFightAndSettle() error {
}
}
}
// 向所有玩家输赢消息 ResCalcWinnerChip
winnerCount := int32(len(winners))
// TODO 所有玩家输赢消息 ResCalcWinnerChip
resWin := &api.ResCalcWinnerChip{}
resWin.WinsChip = make(map[int64]int32, 11)
for _, p := range t.Players {
if p != nil {
resWin.WinsChip[p.Id] = -p.TotalBetChip
}
}
if winnerCount == 1 {
// 只有一个玩家获胜
winner := winners[0]
winner.Chip += t.Chip
resWin.WinsChip[winner.Id] += t.Chip
t.Chip = 0
} else {
// 平分奖池
@ -389,6 +442,8 @@ func (t *Table) cardFightAndSettle() error {
lessNear := lessPos - t.SmallBlindPos
for _, p := range winners {
p.Chip += once
resWin.WinsChip[p.Id] += once
// 计算最靠近发牌者的赢家
pNear := p.PosIndex - t.SmallBlindPos
if pNear*lessPos < 0 { // 一正一负, 正的近
@ -403,14 +458,21 @@ func (t *Table) cardFightAndSettle() error {
less := t.Chip - once*winnerCount
if less > 0 {
t.Players[lessPos].Chip += less
resWin.WinsChip[t.Players[lessPos].Id] += less
}
t.Chip = 0
}
// TODO 通知输赢金额
// 玩家置为待操作状态
// 手牌: stage(1,2) other
// 1.展示其他玩家手牌(组合牌型)
// 2.展示玩家输赢金额(动画) ResCalcWinnerChip
t.NoticeAllPlayer(resWin)
// 3.主动准备 (重置) ready card[2]hold, pub[5]hold, self not show
// TODO 初始化牌桌及状态
t.InitGameAndPlayerStatus()
// t.InitGameAndPlayerStatus()
go func() {
// TODO 等前端展示3秒钟后,牌桌回到初始状态,剔除掉线玩家
@ -418,11 +480,6 @@ func (t *Table) cardFightAndSettle() error {
return nil
}
// DiscardAllPlayerWin 其他玩家弃牌,玩家赢
func (t *Table) DiscardAllPlayerWin(player *Player) {
}
// NoticeGamePlayerCall TODO 发送(下注信息、下注人、下一位下注人)到牌桌所有用户
//func (t *Table) NoticeGamePlayerCall() {
//

60
internal/service/table.go

@ -346,6 +346,9 @@ func HandleReqGameStart(player *game.Player, msg *api.ReqGameStart) (proto.Messa
}
}
// 初始化桌面和玩家状态
table.InitGameAndPlayerStatus()
// 游戏状态开始
table.Stage = 2
// 小盲注位
@ -402,10 +405,7 @@ func HandleReqGameStart(player *game.Player, msg *api.ReqGameStart) (proto.Messa
}
// 待大盲注位下一位玩家下注
optPos := table.NextPlayerPos(table.BigBlindPos)
optPlayer := table.Players[optPos]
optPlayer.SetStatus(3)
optPlayer.BetOpts = []int32{2, 4}
table.SetNextPlayerWithRoundStart()
// 广播牌桌状态
table.NoticeGameFullStatus()
@ -479,9 +479,12 @@ func HandleReqBetting(player *game.Player, msg *api.ReqBetting) (proto.Message,
raise = msg.BetChip > player.BetMin
if raise {
table.RoundRaiseTimes++
table.LastPosBetType = 2
} else {
table.LastPosBetType = 1
}
player.RoundBetTimes++
table.LastPosBetChip = msg.BetChip
table.LastPosBetChip = playerBettingChip
table.Chip += msg.BetChip
player.Chip -= msg.BetChip
player.TotalBetChip += msg.BetChip
@ -497,6 +500,7 @@ func HandleReqBetting(player *game.Player, msg *api.ReqBetting) (proto.Message,
}
case 3: // All-In TODO 边池
table.LastPosBetType = 3
player.RoundBetTimes++
table.LastPosBetChip = player.Chip
table.Chip += player.Chip
@ -520,6 +524,7 @@ func HandleReqBetting(player *game.Player, msg *api.ReqBetting) (proto.Message,
return &api.ResSuccess{}, nil
}
case 5: // 过牌
table.LastPosBetType = 5
player.RoundBetTimes++
betNotice.Line2 = "过牌"
@ -532,12 +537,7 @@ func HandleReqBetting(player *game.Player, msg *api.ReqBetting) (proto.Message,
player.GameTable.NoticeAllPlayer(betNotice)
}
if player.Status != 7 {
player.SetStatus(3)
}
// 下注完成:若还有玩家未下注、加注,下一玩家继续下注;若该轮下注完成,发牌开启下一轮下注
// 下一位玩家:跟注
nextPlayerPos := table.NextHoldingCardPlayerPos(player.PosIndex)
nextPlayer := table.Players[nextPlayerPos]
//if nextPlayer.Id == player.Id {
@ -561,45 +561,9 @@ func HandleReqBetting(player *game.Player, msg *api.ReqBetting) (proto.Message,
}
}
// 判断该轮下一玩家可下注情况 : 下一玩家是否已下注,当前玩家是否跟注,
nextPlayer.SetStatus(6)
nextPlayer.BetMin = playerBettingChip
nextPlayer.BetOpts = []int32{1, 4}
// 下一玩家需跟注
// 游戏类型处理最大下注额
switch table.TexasType {
case 2: // 底池限注
nextPlayer.BetOpts = append(nextPlayer.BetOpts, 3)
nextPlayer.BetMax = table.Chip + table.LastPosBetChip*2
case 3: // 无限注
nextPlayer.BetOpts = append(nextPlayer.BetOpts, 2, 3) // 可 all in
nextPlayer.BetMax = -1
case 1: // 限注
fallthrough
default:
// 限注比赛只允许一次下注与三次加注
if table.RoundRaiseTimes < 3 {
nextPlayer.BetOpts = append(nextPlayer.BetOpts, 3)
// 第1,2回合跟注加注需和大盲注相同, 3,4回合两倍
nextPlayer.BetMax = table.BigBlindChip * (table.Stage/2 + 1)
} else {
// 只能跟注
nextPlayer.BetMax = playerBettingChip
}
}
// 查找下一位下注玩家
table.SetNextPlayer(player.PosIndex)
// 如果下一玩家是大小盲注第一次下注
if table.Stage == 2 && nextPlayer.RoundBetTimes == 0 {
switch nextPlayer.PosIndex {
case table.SmallBlindPos:
nextPlayer.BetMin -= table.SmallBlindChip
nextPlayer.BetMax -= table.SmallBlindChip
case table.BigBlindPos:
nextPlayer.BetMin -= table.BigBlindChip
nextPlayer.BetMax -= table.BigBlindChip
}
}
// 依赌场规则而异,
// 若所余筹码All-in后仍低于最低加注金额,则此注仅视为跟注(call)而不能被当成加注(raise),亦及该圈若未有其他人再加注,则原加注者(此例中的第一位牌手)仅可跟注补齐或盖牌,于此圈不可再行加注
// 亦有少部分赌场规定All-in后大于最低加注额的一半以上,原加注者即可重新加注。

Loading…
Cancel
Save