From 0181303f577404ea730063f9ef974f083683f49a Mon Sep 17 00:00:00 2001 From: tangmingyou <234767776@qq.com> Date: Tue, 7 Feb 2023 17:55:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8B=E6=B3=A8=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 + api/operation.go | 4 + api/poker.pb.go | 188 ++++++++++++- api/poker.proto | 25 +- api/proto.js | 553 ++++++++++++++++++++++++++++++++++++++ internal/game/player.go | 8 +- internal/game/table.go | 6 +- internal/service/table.go | 77 ++++++ 8 files changed, 858 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index fd35c6a..3b05201 100644 --- a/README.md +++ b/README.md @@ -19,3 +19,13 @@ pbjs -t json api/*.proto > jsproto.json 2. player ready 3. table begin 发牌 4. 开始流程,大盲注 小盲注 + + +[网易德州扑克规则](http://sports.163.com/special/poker_rule/?ivk_sa=1025883k) + +跟注规则: +小盲注:房主下一个 +大盲注:房主下下一个 +跟注/加注:大盲注下一个 + +只有两人:第一轮小盲注先,后续大盲注先下注 diff --git a/api/operation.go b/api/operation.go index 88d95a3..878b6a5 100644 --- a/api/operation.go +++ b/api/operation.go @@ -49,6 +49,10 @@ var protoInstances = []proto.Message{ &ResBigBlindChip{}, &ResSmallBlindChip{}, + + &ReqPlaceBetChip{}, + &ReqBetWeakHand{}, + &ReqBetDiscard{}, } var ( diff --git a/api/poker.pb.go b/api/poker.pb.go index 26a20f9..fe06a9f 100644 --- a/api/poker.pb.go +++ b/api/poker.pb.go @@ -1253,11 +1253,11 @@ type TablePlayer struct { Id int64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` Username string `protobuf:"bytes,3,opt,name=username,proto3" json:"username,omitempty"` Avatar string `protobuf:"bytes,4,opt,name=avatar,proto3" json:"avatar,omitempty"` - Chip int32 `protobuf:"varint,5,opt,name=chip,proto3" json:"chip,omitempty"` // 筹码 - Status int32 `protobuf:"varint,6,opt,name=status,proto3" json:"status,omitempty"` // 玩家状态: 1待准备开始,2已准备开始,已开始(3等待其他玩家动作,4待大盲注,5待小盲注,6待跟注,7已弃) - LastStatus int32 `protobuf:"varint,7,opt,name=lastStatus,proto3" json:"lastStatus,omitempty"` - Master bool `protobuf:"varint,8,opt,name=master,proto3" json:"master,omitempty"` // 是否房主` - HandCard []*Card `protobuf:"bytes,15,rep,name=handCard,proto3" json:"handCard,omitempty"` // 手牌 + Chip int32 `protobuf:"varint,5,opt,name=chip,proto3" json:"chip,omitempty"` // 筹码 + Status int32 `protobuf:"varint,6,opt,name=status,proto3" json:"status,omitempty"` // 玩家状态: 1待准备开始,2已准备开始,已开始(3等待其他玩家动作,4待大盲注,5待小盲注,6待跟注,7已弃) + LastStatus int32 `protobuf:"varint,7,opt,name=lastStatus,proto3" json:"lastStatus,omitempty"` // TODO 删, 前端通过消息监听获取下注金额信息 + Master bool `protobuf:"varint,8,opt,name=master,proto3" json:"master,omitempty"` // 是否房主` + HandCard []*Card `protobuf:"bytes,15,rep,name=handCard,proto3" json:"handCard,omitempty"` // 手牌 } func (x *TablePlayer) Reset() { @@ -1622,6 +1622,132 @@ func (*ResDismissGameTable) Descriptor() ([]byte, []int) { return file_poker_proto_rawDescGZIP(), []int{29} } +// 下注 +type ReqPlaceBetChip struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Chip int32 `protobuf:"varint,1,opt,name=chip,proto3" json:"chip,omitempty"` +} + +func (x *ReqPlaceBetChip) Reset() { + *x = ReqPlaceBetChip{} + if protoimpl.UnsafeEnabled { + mi := &file_poker_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReqPlaceBetChip) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReqPlaceBetChip) ProtoMessage() {} + +func (x *ReqPlaceBetChip) ProtoReflect() protoreflect.Message { + mi := &file_poker_proto_msgTypes[30] + 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 ReqPlaceBetChip.ProtoReflect.Descriptor instead. +func (*ReqPlaceBetChip) Descriptor() ([]byte, []int) { + return file_poker_proto_rawDescGZIP(), []int{30} +} + +func (x *ReqPlaceBetChip) GetChip() int32 { + if x != nil { + return x.Chip + } + return 0 +} + +// 让牌 +type ReqBetWeakHand struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ReqBetWeakHand) Reset() { + *x = ReqBetWeakHand{} + if protoimpl.UnsafeEnabled { + mi := &file_poker_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReqBetWeakHand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReqBetWeakHand) ProtoMessage() {} + +func (x *ReqBetWeakHand) ProtoReflect() protoreflect.Message { + mi := &file_poker_proto_msgTypes[31] + 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 ReqBetWeakHand.ProtoReflect.Descriptor instead. +func (*ReqBetWeakHand) Descriptor() ([]byte, []int) { + return file_poker_proto_rawDescGZIP(), []int{31} +} + +// 弃牌 +type ReqBetDiscard struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ReqBetDiscard) Reset() { + *x = ReqBetDiscard{} + if protoimpl.UnsafeEnabled { + mi := &file_poker_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ReqBetDiscard) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ReqBetDiscard) ProtoMessage() {} + +func (x *ReqBetDiscard) ProtoReflect() protoreflect.Message { + mi := &file_poker_proto_msgTypes[32] + 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 ReqBetDiscard.ProtoReflect.Descriptor instead. +func (*ReqBetDiscard) Descriptor() ([]byte, []int) { + return file_poker_proto_rawDescGZIP(), []int{32} +} + var File_poker_proto protoreflect.FileDescriptor var file_poker_proto_rawDesc = []byte{ @@ -1741,8 +1867,13 @@ var file_poker_proto_rawDesc = []byte{ 0x28, 0x05, 0x52, 0x04, 0x63, 0x68, 0x69, 0x70, 0x22, 0x15, 0x0a, 0x13, 0x52, 0x65, 0x71, 0x44, 0x69, 0x73, 0x6d, 0x69, 0x73, 0x73, 0x47, 0x61, 0x6d, 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x15, 0x0a, 0x13, 0x52, 0x65, 0x73, 0x44, 0x69, 0x73, 0x6d, 0x69, 0x73, 0x73, 0x47, 0x61, 0x6d, - 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x61, 0x70, 0x69, 0x3b, - 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x25, 0x0a, 0x0f, 0x52, 0x65, 0x71, 0x50, 0x6c, 0x61, + 0x63, 0x65, 0x42, 0x65, 0x74, 0x43, 0x68, 0x69, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x68, 0x69, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x68, 0x69, 0x70, 0x22, 0x10, 0x0a, + 0x0e, 0x52, 0x65, 0x71, 0x42, 0x65, 0x74, 0x57, 0x65, 0x61, 0x6b, 0x48, 0x61, 0x6e, 0x64, 0x22, + 0x0f, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x42, 0x65, 0x74, 0x44, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, + 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x61, 0x70, 0x69, 0x3b, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1757,7 +1888,7 @@ func file_poker_proto_rawDescGZIP() []byte { return file_poker_proto_rawDescData } -var file_poker_proto_msgTypes = make([]protoimpl.MessageInfo, 30) +var file_poker_proto_msgTypes = make([]protoimpl.MessageInfo, 33) var file_poker_proto_goTypes = []interface{}{ (*ProtoWrap)(nil), // 0: api.ProtoWrap (*Ping)(nil), // 1: api.Ping @@ -1789,6 +1920,9 @@ var file_poker_proto_goTypes = []interface{}{ (*ResSmallBlindChip)(nil), // 27: api.ResSmallBlindChip (*ReqDismissGameTable)(nil), // 28: api.ReqDismissGameTable (*ResDismissGameTable)(nil), // 29: api.ResDismissGameTable + (*ReqPlaceBetChip)(nil), // 30: api.ReqPlaceBetChip + (*ReqBetWeakHand)(nil), // 31: api.ReqBetWeakHand + (*ReqBetDiscard)(nil), // 32: api.ReqBetDiscard } var file_poker_proto_depIdxs = []int32{ 9, // 0: api.ResLobbyView.tables:type_name -> api.LobbyTable @@ -2169,6 +2303,42 @@ func file_poker_proto_init() { return nil } } + file_poker_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReqPlaceBetChip); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_poker_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReqBetWeakHand); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_poker_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ReqBetDiscard); 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{ @@ -2176,7 +2346,7 @@ func file_poker_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_poker_proto_rawDesc, NumEnums: 0, - NumMessages: 30, + NumMessages: 33, NumExtensions: 0, NumServices: 0, }, diff --git a/api/poker.proto b/api/poker.proto index 3aa8f55..758d307 100644 --- a/api/poker.proto +++ b/api/poker.proto @@ -147,6 +147,7 @@ message TablePlayer { int32 status = 6; // 玩家状态: 1待准备开始,2已准备开始,已开始(3等待其他玩家动作,4待大盲注,5待小盲注,6待跟注,7已弃) int32 lastStatus = 7; // TODO 删, 前端通过消息监听获取下注金额信息 bool master = 8; // 是否房主` + BetRole betRole = 14; // 下注时规则限制 repeated Card handCard = 15; // 手牌 } @@ -155,6 +156,12 @@ message Card { string suit = 2; // 花色, protobuf默认值0, string类型区分空白牌 } +// player status in (4,6) 跟注时规则 +message BetRole { + int32 minChip = 1; // 最低下注额:小盲注加注(按惯例至少2倍与大盲注) + int32 maxChip = 2; // 最高下注额: +} + // 加入游戏 ============= end // 开始游戏 @@ -176,4 +183,20 @@ message ResSmallBlindChip { message ReqDismissGameTable { } message ResDismissGameTable { -} \ No newline at end of file +} + +// 下注 +message ReqPlaceBetChip { + int32 betChip = 1; // 跟注/加注金额 + bool allIn = 2; // 是否 allIn +} + +// 让牌 +message ReqBetWeakHand { + +} + +// 弃牌 +message ReqBetDiscard { + +} diff --git a/api/proto.js b/api/proto.js index 2388094..dddef70 100644 --- a/api/proto.js +++ b/api/proto.js @@ -6811,6 +6811,559 @@ export const api = $root.api = (() => { return ResDismissGameTable; })(); + api.ReqPlaceBetChip = (function() { + + /** + * Properties of a ReqPlaceBetChip. + * @memberof api + * @interface IReqPlaceBetChip + * @property {number|null} [chip] ReqPlaceBetChip chip + */ + + /** + * Constructs a new ReqPlaceBetChip. + * @memberof api + * @classdesc Represents a ReqPlaceBetChip. + * @implements IReqPlaceBetChip + * @constructor + * @param {api.IReqPlaceBetChip=} [properties] Properties to set + */ + function ReqPlaceBetChip(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]]; + } + + /** + * ReqPlaceBetChip chip. + * @member {number} chip + * @memberof api.ReqPlaceBetChip + * @instance + */ + ReqPlaceBetChip.prototype.chip = 0; + + /** + * Creates a new ReqPlaceBetChip instance using the specified properties. + * @function create + * @memberof api.ReqPlaceBetChip + * @static + * @param {api.IReqPlaceBetChip=} [properties] Properties to set + * @returns {api.ReqPlaceBetChip} ReqPlaceBetChip instance + */ + ReqPlaceBetChip.create = function create(properties) { + return new ReqPlaceBetChip(properties); + }; + + /** + * Encodes the specified ReqPlaceBetChip message. Does not implicitly {@link api.ReqPlaceBetChip.verify|verify} messages. + * @function encode + * @memberof api.ReqPlaceBetChip + * @static + * @param {api.IReqPlaceBetChip} message ReqPlaceBetChip message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ReqPlaceBetChip.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.chip != null && Object.hasOwnProperty.call(message, "chip")) + writer.uint32(/* id 1, wireType 0 =*/8).int32(message.chip); + return writer; + }; + + /** + * Encodes the specified ReqPlaceBetChip message, length delimited. Does not implicitly {@link api.ReqPlaceBetChip.verify|verify} messages. + * @function encodeDelimited + * @memberof api.ReqPlaceBetChip + * @static + * @param {api.IReqPlaceBetChip} message ReqPlaceBetChip message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ReqPlaceBetChip.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a ReqPlaceBetChip message from the specified reader or buffer. + * @function decode + * @memberof api.ReqPlaceBetChip + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {api.ReqPlaceBetChip} ReqPlaceBetChip + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ReqPlaceBetChip.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.ReqPlaceBetChip(); + while (reader.pos < end) { + let tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + message.chip = reader.int32(); + break; + } + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a ReqPlaceBetChip message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof api.ReqPlaceBetChip + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {api.ReqPlaceBetChip} ReqPlaceBetChip + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ReqPlaceBetChip.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a ReqPlaceBetChip message. + * @function verify + * @memberof api.ReqPlaceBetChip + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + ReqPlaceBetChip.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.chip != null && message.hasOwnProperty("chip")) + if (!$util.isInteger(message.chip)) + return "chip: integer expected"; + return null; + }; + + /** + * Creates a ReqPlaceBetChip message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof api.ReqPlaceBetChip + * @static + * @param {Object.} object Plain object + * @returns {api.ReqPlaceBetChip} ReqPlaceBetChip + */ + ReqPlaceBetChip.fromObject = function fromObject(object) { + if (object instanceof $root.api.ReqPlaceBetChip) + return object; + let message = new $root.api.ReqPlaceBetChip(); + if (object.chip != null) + message.chip = object.chip | 0; + return message; + }; + + /** + * Creates a plain object from a ReqPlaceBetChip message. Also converts values to other types if specified. + * @function toObject + * @memberof api.ReqPlaceBetChip + * @static + * @param {api.ReqPlaceBetChip} message ReqPlaceBetChip + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + ReqPlaceBetChip.toObject = function toObject(message, options) { + if (!options) + options = {}; + let object = {}; + if (options.defaults) + object.chip = 0; + if (message.chip != null && message.hasOwnProperty("chip")) + object.chip = message.chip; + return object; + }; + + /** + * Converts this ReqPlaceBetChip to JSON. + * @function toJSON + * @memberof api.ReqPlaceBetChip + * @instance + * @returns {Object.} JSON object + */ + ReqPlaceBetChip.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for ReqPlaceBetChip + * @function getTypeUrl + * @memberof api.ReqPlaceBetChip + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + ReqPlaceBetChip.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/api.ReqPlaceBetChip"; + }; + + return ReqPlaceBetChip; + })(); + + api.ReqBetWeakHand = (function() { + + /** + * Properties of a ReqBetWeakHand. + * @memberof api + * @interface IReqBetWeakHand + */ + + /** + * Constructs a new ReqBetWeakHand. + * @memberof api + * @classdesc Represents a ReqBetWeakHand. + * @implements IReqBetWeakHand + * @constructor + * @param {api.IReqBetWeakHand=} [properties] Properties to set + */ + function ReqBetWeakHand(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]]; + } + + /** + * Creates a new ReqBetWeakHand instance using the specified properties. + * @function create + * @memberof api.ReqBetWeakHand + * @static + * @param {api.IReqBetWeakHand=} [properties] Properties to set + * @returns {api.ReqBetWeakHand} ReqBetWeakHand instance + */ + ReqBetWeakHand.create = function create(properties) { + return new ReqBetWeakHand(properties); + }; + + /** + * Encodes the specified ReqBetWeakHand message. Does not implicitly {@link api.ReqBetWeakHand.verify|verify} messages. + * @function encode + * @memberof api.ReqBetWeakHand + * @static + * @param {api.IReqBetWeakHand} message ReqBetWeakHand message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ReqBetWeakHand.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + return writer; + }; + + /** + * Encodes the specified ReqBetWeakHand message, length delimited. Does not implicitly {@link api.ReqBetWeakHand.verify|verify} messages. + * @function encodeDelimited + * @memberof api.ReqBetWeakHand + * @static + * @param {api.IReqBetWeakHand} message ReqBetWeakHand message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ReqBetWeakHand.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a ReqBetWeakHand message from the specified reader or buffer. + * @function decode + * @memberof api.ReqBetWeakHand + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {api.ReqBetWeakHand} ReqBetWeakHand + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ReqBetWeakHand.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.ReqBetWeakHand(); + while (reader.pos < end) { + let tag = reader.uint32(); + switch (tag >>> 3) { + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a ReqBetWeakHand message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof api.ReqBetWeakHand + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {api.ReqBetWeakHand} ReqBetWeakHand + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ReqBetWeakHand.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a ReqBetWeakHand message. + * @function verify + * @memberof api.ReqBetWeakHand + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + ReqBetWeakHand.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + return null; + }; + + /** + * Creates a ReqBetWeakHand message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof api.ReqBetWeakHand + * @static + * @param {Object.} object Plain object + * @returns {api.ReqBetWeakHand} ReqBetWeakHand + */ + ReqBetWeakHand.fromObject = function fromObject(object) { + if (object instanceof $root.api.ReqBetWeakHand) + return object; + return new $root.api.ReqBetWeakHand(); + }; + + /** + * Creates a plain object from a ReqBetWeakHand message. Also converts values to other types if specified. + * @function toObject + * @memberof api.ReqBetWeakHand + * @static + * @param {api.ReqBetWeakHand} message ReqBetWeakHand + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + ReqBetWeakHand.toObject = function toObject() { + return {}; + }; + + /** + * Converts this ReqBetWeakHand to JSON. + * @function toJSON + * @memberof api.ReqBetWeakHand + * @instance + * @returns {Object.} JSON object + */ + ReqBetWeakHand.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for ReqBetWeakHand + * @function getTypeUrl + * @memberof api.ReqBetWeakHand + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + ReqBetWeakHand.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/api.ReqBetWeakHand"; + }; + + return ReqBetWeakHand; + })(); + + api.ReqBetDiscard = (function() { + + /** + * Properties of a ReqBetDiscard. + * @memberof api + * @interface IReqBetDiscard + */ + + /** + * Constructs a new ReqBetDiscard. + * @memberof api + * @classdesc Represents a ReqBetDiscard. + * @implements IReqBetDiscard + * @constructor + * @param {api.IReqBetDiscard=} [properties] Properties to set + */ + function ReqBetDiscard(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]]; + } + + /** + * Creates a new ReqBetDiscard instance using the specified properties. + * @function create + * @memberof api.ReqBetDiscard + * @static + * @param {api.IReqBetDiscard=} [properties] Properties to set + * @returns {api.ReqBetDiscard} ReqBetDiscard instance + */ + ReqBetDiscard.create = function create(properties) { + return new ReqBetDiscard(properties); + }; + + /** + * Encodes the specified ReqBetDiscard message. Does not implicitly {@link api.ReqBetDiscard.verify|verify} messages. + * @function encode + * @memberof api.ReqBetDiscard + * @static + * @param {api.IReqBetDiscard} message ReqBetDiscard message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ReqBetDiscard.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + return writer; + }; + + /** + * Encodes the specified ReqBetDiscard message, length delimited. Does not implicitly {@link api.ReqBetDiscard.verify|verify} messages. + * @function encodeDelimited + * @memberof api.ReqBetDiscard + * @static + * @param {api.IReqBetDiscard} message ReqBetDiscard message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + ReqBetDiscard.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a ReqBetDiscard message from the specified reader or buffer. + * @function decode + * @memberof api.ReqBetDiscard + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {api.ReqBetDiscard} ReqBetDiscard + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ReqBetDiscard.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.ReqBetDiscard(); + while (reader.pos < end) { + let tag = reader.uint32(); + switch (tag >>> 3) { + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a ReqBetDiscard message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof api.ReqBetDiscard + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {api.ReqBetDiscard} ReqBetDiscard + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + ReqBetDiscard.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a ReqBetDiscard message. + * @function verify + * @memberof api.ReqBetDiscard + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + ReqBetDiscard.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + return null; + }; + + /** + * Creates a ReqBetDiscard message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof api.ReqBetDiscard + * @static + * @param {Object.} object Plain object + * @returns {api.ReqBetDiscard} ReqBetDiscard + */ + ReqBetDiscard.fromObject = function fromObject(object) { + if (object instanceof $root.api.ReqBetDiscard) + return object; + return new $root.api.ReqBetDiscard(); + }; + + /** + * Creates a plain object from a ReqBetDiscard message. Also converts values to other types if specified. + * @function toObject + * @memberof api.ReqBetDiscard + * @static + * @param {api.ReqBetDiscard} message ReqBetDiscard + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + ReqBetDiscard.toObject = function toObject() { + return {}; + }; + + /** + * Converts this ReqBetDiscard to JSON. + * @function toJSON + * @memberof api.ReqBetDiscard + * @instance + * @returns {Object.} JSON object + */ + ReqBetDiscard.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + /** + * Gets the default type url for ReqBetDiscard + * @function getTypeUrl + * @memberof api.ReqBetDiscard + * @static + * @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com") + * @returns {string} The default type url + */ + ReqBetDiscard.getTypeUrl = function getTypeUrl(typeUrlPrefix) { + if (typeUrlPrefix === undefined) { + typeUrlPrefix = "type.googleapis.com"; + } + return typeUrlPrefix + "/api.ReqBetDiscard"; + }; + + return ReqBetDiscard; + })(); + return api; })(); diff --git a/internal/game/player.go b/internal/game/player.go index d901836..d27a223 100644 --- a/internal/game/player.go +++ b/internal/game/player.go @@ -12,7 +12,8 @@ type Player struct { Avatar string Cards [2]*Card // 手牌 Chip int32 // 玩家筹码 - Status int32 // 状态: 1待准备开始,2已准备开始,3等待其他玩家动作,4小盲注跟注, [5待大盲注,5待小盲注,] 6待跟注,7已弃牌 + RoundChip int32 // 该回合已下注筹码 + Status int32 // 状态: 1待准备开始,2已准备开始,3等待其他玩家动作,4第一回合小盲注跟注, [5待大盲注,5待小盲注,] 6待跟注,7已弃牌 LastStatus int32 // 变化前一个状态 GameTable *Table // 当前牌桌 @@ -26,6 +27,11 @@ func (p *Player) Init() { p.StatusLock = new(sync.Mutex) } +// RoundInit 下一回合初始化 +func (p *Player) RoundInit() { + p.RoundChip = 0 +} + func (p *Player) SetStatus(status int32) { p.StatusLock.Lock() defer p.StatusLock.Unlock() diff --git a/internal/game/table.go b/internal/game/table.go index 0837b9b..98b8a0d 100644 --- a/internal/game/table.go +++ b/internal/game/table.go @@ -22,8 +22,10 @@ type Table struct { RobotNum int32 // 机器人数 Players []*Player // 玩家 Robots []*Robot - BigBlindPos int // 大盲注位 - SmallBlindPos int // 小盲注位 + BigBlindPos int // 大盲注位 + SmallBlindPos int // 小盲注位 + BigBlindChip int32 // 大盲注金额 + TexasType int32 // 德州扑克类型: (1限注德州扑克:你只能增加与大盲注相同的投注额; 2底池限制德州扑克:你只能增加当时台面最大额的投注额(已经完成所有投注); 3无限制德州扑克:你可在手持额度下,增加任何额度的投注额,如果你投入所有筹码,就是“全押”) PlayersLock *sync.Mutex ChipLock *sync.Mutex // 桌面筹码更新锁 diff --git a/internal/service/table.go b/internal/service/table.go index 3ed7633..55e46df 100644 --- a/internal/service/table.go +++ b/internal/service/table.go @@ -373,3 +373,80 @@ func HandleReqGameStart(player *game.Player, msg *api.ReqGameStart) (proto.Messa table.NoticeGameFullStatus() return &api.ResSuccess{}, nil } + +// HandleReqPlaceBetChip 下注 +// 网易德州扑克:http://sports.163.com/special/poker_rule/?ivk_sa=1025883k +// 天天德州: http://game.people.com.cn/n/2014/0220/c40130-24413078.html +// wiki: https://zh.wikipedia.org/wiki/%E5%BE%B7%E5%B7%9E%E6%92%B2%E5%85%8B +// 加注:增加下注额。 2、一人结束行动后按顺时针方向下一玩家获得行动权,直到不再有人弃牌,且每人已向奖池投入相同注额。 +// 德州扑克多名玩家ALL IN之后的筹码 如何分配?https://www.zhihu.com/question/32187371 +// All-in技巧:https://bac88.net/%E5%BE%B7%E5%B7%9E%E6%92%B2%E5%85%8B%E6%8A%80%E5%B7%A7-all-in%E7%9A%84%E6%8A%80%E5%B7%A7/ +// 起手牌组合概率:https://www.moshike.com/a/1011.html +func HandleReqPlaceBetChip(player *game.Player, msg *api.ReqPlaceBetChip) (proto.Message, error) { + player.Lock.Lock() + defer player.Lock.Unlock() + player.GameTable.ChipLock.Lock() + defer player.GameTable.ChipLock.Unlock() + + if !collect.In(player.Status, 4, 6) { + return &api.ResFail{Msg: "当前未轮到您下注"}, nil + } + switch player.Status { + case 4: // 小盲注下注,下注金额最小大盲注1半, + if msg.Chip < player.GameTable.BigBlindChip/2 { + return &api.ResFail{Msg: fmt.Sprintf("您当前最小下注金额%d", player.GameTable.BigBlindChip/2)}, nil + } + case 6: // 轮流下注,下注金额最小大盲注 + if msg.Chip < player.GameTable.BigBlindChip { + return &api.ResFail{Msg: fmt.Sprintf("您当前最小下注金额%d", player.GameTable.BigBlindChip)}, nil + } + default: + return &api.ResFail{Msg: "当前未轮到您下注"}, nil + } + // 检查最大下注金额 + var maxBetChip int32 = 0 + // 依赌场规则而异, + // 若所余筹码All-in后仍低于最低加注金额,则此注仅视为跟注(call)而不能被当成加注(raise),亦及该圈若未有其他人再加注,则原加注者(此例中的第一位牌手)仅可跟注补齐或盖牌,于此圈不可再行加注 + // 亦有少部分赌场规定All-in后大于最低加注额的一半以上,原加注者即可重新加注。 + + allIn := false + fmt.Println(allIn) + switch player.GameTable.TexasType { + case 1: // 大盲注 + maxBetChip = player.GameTable.BigBlindChip + case 2: // 台面最大额 + maxBetChip = player.GameTable.Chip + case 3: // 最大All In + maxBetChip = player.Chip + default: + return &api.ResFail{Msg: "牌桌"}, nil + } + + if player.GameTable.TexasType == 3 { + // 无限制可All In + allIn = msg.Chip == maxBetChip + + } else if player.Status == 4 { + // 最大金额减去小盲注金额 + maxBetChip -= player.GameTable.BigBlindChip / 2 + } + if msg.Chip > maxBetChip { + return &api.ResFail{Msg: fmt.Sprintf("您当前最大下注金额%d", maxBetChip)}, nil + } + + player.Chip -= msg.Chip + + return nil, nil +} + +// HandleReqBetWeakHand 让牌 +func HandleReqBetWeakHand(player *game.Player, msg *api.ReqBetWeakHand) (proto.Message, error) { + + return nil, nil +} + +// HandleReqBetDiscard 弃牌 +func HandleReqBetDiscard(player *game.Player, msg *api.ReqBetDiscard) (proto.Message, error) { + + return nil, nil +}