可打牌,可聊天;出牌只能出对子和单张:)
1,server-服务器端
import socket
import numpy as np
from threading import Thread, Lock
import random
import json
import pickle
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind((\'10.181.22.132\', 6000))
\'\'\'
=================================================
0,数据库
=================================================
\'\'\'
\'\'\'记录有多少人登录\'\'\'
clientDict = {} #ipTuple: strName
\'\'\'记录一个桌子有几个人,凑够三个人开始玩\'\'\'
table = [] #[player, player, player]
\'\'\'玩家类\'\'\'
class player():
def __init__(self, name, card, landloard=False):
self.name = name #ipTuple
self.card = card
self.landloard = landloard
\'\'\'记录上一次出的牌\'\'\'
lastCard = -1
\'\'\'所有的牌面\'\'\'
totalCard = [f\'{i}\' for i in list(range(1, 11))+[\'J\', \'Q\', \'K\'] for j in range(4)]
totalCard += [\'小王\', \'大王\']
\'\'\'牌的大小\'\'\'
cardValue = {key: value for key, value in zip([f\'{i}\' for i in range(1, 11)], range(1, 11))}
cardValue[\'J\'] = 11
cardValue[\'Q\'] = 12
cardValue[\'K\'] = 13
cardValue[\'小王\'] = 14
cardValue[\'大王\'] = 15
\'\'\'
=================================================
1,人齐以后开始游戏
=================================================
\'\'\'
def playGame():
global table
global lastCard
\'\'\'
---------------------------
1-0,游戏开始
---------------------------
\'\'\'
for client in clientDict:
sk.sendto(f\'\033[0;34m人数以齐,游戏开始!\033[0m\'.encode(\'utf-8\'), client)
\'\'\'
---------------------------
1-1,分配地主
---------------------------
\'\'\'
landlordIndex = np.random.randint(0, 3, 1)
print(landlordIndex)
print(table[int(landlordIndex)])
for client in clientDict:
sk.sendto(f\'\033[0;34m{clientDict[table[int(landlordIndex)].name]}是地主\033[0m\'.encode(\'utf-8\'), client)
table[int(landlordIndex)].landloard = True
\'\'\'
---------------------------
1-2,发牌
---------------------------
\'\'\'
#将牌分为三份
middleMemoryCard = totalCard
card1 = sorted([middleMemoryCard[i] for i in np.random.choice(range(54), 17, replace=False)], key=lambda x: cardValue[x])
for card in card1:
middleMemoryCard.remove(card)
card2 = sorted([middleMemoryCard[i] for i in np.random.choice(range(37), 17, replace=False)], key=lambda x: cardValue[x])
farmersCard = [card1, card2]
for card in card2:
middleMemoryCard.remove(card)
card3 = sorted(middleMemoryCard, key=lambda x: cardValue[x])
# 发牌并显示牌
for i in range(3):
if table[i].landloard == True:
table[i].card = card3
sk.sendto(f\'\033[0;35m你的牌是{str(card3)}\033[0m\'.encode(\'utf-8\'), table[i].name)
else:
table[i].card = farmersCard[-1]
sk.sendto(f\'\033[0;35m你的牌是{str(farmersCard[-1])}\033[0m\'.encode(\'utf-8\'), table[i].name)
farmersCard.pop()
\'\'\'
---------------------------
1-3,出牌/说话
---------------------------
\'\'\'
overOrNot = False #游戏结束标志
JudgmentBit = False
farmersOrder = list(range(3))
farmersOrder.remove(landlordIndex)
playerCardOrder = [int(landlordIndex)] + farmersOrder #总的出牌顺序
passNum = 0 #pass个数
while True:
\'\'\'1-3-1,一直循环,只到有人出完牌\'\'\'
for i in playerCardOrder:
passOrNot = False # 出牌位,换人时一旦出牌passNum就要归零
\'\'\'1-3-2,顺序出牌\'\'\'
while True:
for client in clientDict:
sk.sendto(f\'\033[0;34m轮到{clientDict[table[i].name]}出牌,出牌时请以英文“,”隔开,无牌可出请输入pass\033[0m\'.encode(\'utf-8\'), client)
cardMsg = sk.recvfrom(1024)
middleMsg = pickle.loads(cardMsg[0])
\'\'\'1-3-2-1,非出牌人说话\'\'\'
if cardMsg[1] != table[i].name:
for client in clientDict:
if client != cardMsg[1]:
sk.sendto(f\'{clientDict[cardMsg[1]]}说: {middleMsg}\'.encode(\'utf-8\'), client)
\'\'\'1-3-2-2,出牌人无牌可出\出牌错误\所出的牌没有\压不上\出牌成功\'\'\'
if cardMsg[1] == table[i].name:
\'\'\'1-3-2-2-1,出牌人无牌可出\'\'\'
if middleMsg[0] == \'pass\':
passOrNot = True
passNum += 1
for client in clientDict:
sk.sendto(f\'\033[0;36m{clientDict[cardMsg[1]]}竟然跳过了,实在太菜了!!!\033[0m\'.encode(\'utf-8\'), client)
break
elif len(middleMsg) > 2:
\'\'\'1-3-2-2-1.1,出牌错误,出的超过两张不允许\'\'\'
for client in clientDict:
if client != cardMsg[1]:
sk.sendto(f\'{clientDict[cardMsg[1]]}说: {middleMsg}\'.encode(\'utf-8\'), client)
else:
sk.sendto(f\'\033[0;36m只允许出单张或者对子\033[0m\'.encode(\'utf-8\'), client)
elif (lastCard != -1) and (len(lastCard) != len(middleMsg)):
\'\'\'1-3-2-2-1.2,出牌错误,出牌与上一玩家的数目不一致\'\'\'
for client in clientDict:
if client != cardMsg[1]:
sk.sendto(f\'{clientDict[cardMsg[1]]}说: {middleMsg}\'.encode(\'utf-8\'), client)
else:
sk.sendto(f\'\033[0;36m出牌需与上一玩家的数目保持一致!!!\033[0m\'.encode(\'utf-8\'), client)
else:
\'\'\'1-3-2-2-2,所出的牌没有:检查所出的牌是否都有,如果没有则出牌错误,认为是在说话\'\'\'
for card in middleMsg:
if card not in table[i].card:
JudgmentBit = True
for client in clientDict:
if client != cardMsg[1]:
sk.sendto(f\'{clientDict[cardMsg[1]]}说: {middleMsg}\'.encode(\'utf-8\'), client)
else:
sk.sendto(f\'\033[0;36m不要出自己没有的牌!!!\033[0m\'.encode(\'utf-8\'), client)
break
if JudgmentBit:
JudgmentBit = False
continue
if len(middleMsg) == 2:
\'\'\'1-3-2-2-1.1,出牌错误,出的两张不同不允许\'\'\'
if middleMsg[0] != middleMsg[1]:
for client in clientDict:
if client != cardMsg[1]:
sk.sendto(f\'{clientDict[cardMsg[1]]}说: {middleMsg}\'.encode(\'utf-8\'), client)
else:
sk.sendto(f\'\033[0;36m对子必须是相同的牌!!!\033[0m\'.encode(\'utf-8\'), client)
continue
\'\'\'1-3-2-2-3,所出的牌都有,判断是否可以压上\'\'\'
if lastCard == -1:
\'\'\'1-3-2-2-3.1,出牌成功,第一个出牌,总是能压上\'\'\'
lastCard = middleMsg
for card in middleMsg:
\'\'\'移除牌\'\'\'
table[i].card.remove(card)
for client in clientDict:
if client != cardMsg[1]:
sk.sendto(f\'\033[0;31m{clientDict[cardMsg[1]]}出牌: {middleMsg}\033[0m\'.encode(\'utf-8\'), client)
else:
sk.sendto(f\'出牌成功!现在的牌是\033[0;35m{table[i].card}\033[0m\'.encode(\'utf-8\'), client)
break
elif lastCard[0] >= middleMsg[0]:
\'\'\'1-3-2-2-3.2,出的牌压不上,重新出牌\'\'\'
for client in clientDict:
if client != cardMsg[1]:
sk.sendto(f\'{clientDict[cardMsg[1]]}说: {middleMsg}\'.encode(\'utf-8\'), client)
else:
sk.sendto(f\'\033[0;36m出的牌太小了!!!\033[0m\'.encode(\'utf-8\'), client)
continue
else:
\'\'\'1-3-2-2-3.2,出牌成功,出的牌可以压上\'\'\'
lastCard = middleMsg
for card in middleMsg:
\'\'\'移除牌\'\'\'
table[i].card.remove(card)
for client in clientDict:
if client != cardMsg[1]:
sk.sendto(f\'\033[0;31m{clientDict[cardMsg[1]]}出牌: {middleMsg}\033[0m\'.encode(\'utf-8\'), client)
else:
sk.sendto(f\'出牌成功!现在的牌是\033[0;35m{table[i].card}\033[0m\'.encode(\'utf-8\'), client)
break
\'\'\'一旦有人出牌,passNum置零\'\'\'
if not passOrNot:
passNum = 0
\'\'\'如果连续两个人跳过,重置lastCard\'\'\'
if passNum == 2:
lastCard = -1
\'\'\'1-3-3,如果有人出完了,游戏结束\'\'\'
if len(card3) == 0:
for client in clientDict:
sk.sendto(f\'\033[0;34m**********************************地主获胜**********************************\033[0m\'.encode(\'utf-8\'), client)
overOrNot = True
break
elif len(card1) == 0 or len(card2) == 0:
for client in clientDict:
sk.sendto(f\'\033[0;34m**********************************农民获胜**********************************\033[0m\'.encode(\'utf-8\'), client)
overOrNot = True
break
if overOrNot:
break
\'\'\'
---------------------------
1-4,初始化
---------------------------
\'\'\'
table = []
\'\'\'主程序\'\'\'
if __name__ == \'__main__\':
while True:
msg = sk.recvfrom(1024)
\'\'\'
=================================================
2,玩家登录、发送消息、申请玩游戏
=================================================
\'\'\'
if msg[1] not in clientDict:
\'\'\'2-1-1:登录\'\'\'
print(msg[1], pickle.loads(msg[0]))
clientDict[msg[1]] = pickle.loads(msg[0])
print(clientDict)
for client in clientDict:
sk.sendto(f\'\033[0;31m欢迎{clientDict[msg[1]]}接入棋牌聊天室,当前版本1.1,只允许出单张和对子,想要玩牌请输入p/P,退出请输入QUTI\033[0m\'.encode(\'utf-8\'), client)
else:
\'\'\'2-1-2:退出\'\'\'
msgRec = pickle.loads(msg[0])
if msgRec[0].upper() == \'QUTI\':
print(f\'\033[0;32m{msg[1]}退出棋牌聊天室\033[0m\')
quitter = clientDict[msg[1]]
clientDict.pop(msg[1])
print(clientDict)
for client in clientDict:
sk.sendto(f\'\033[0;32m{quitter}退出棋牌聊天室\033[0m\'.encode(\'utf-8\'), client)
elif msgRec[0].upper() == \'P\':
\'\'\'2-1-3:申请游戏,初始化玩家\'\'\'
if len(table) < 3:
print(f\'\033[0;33m{msg[1]}申请参战\033[0m\')
table.append(player(msg[1], []))
print(f\'-->{table[-1].name}\')
for client in clientDict:
sk.sendto(f\'\033[0;33m{clientDict[msg[1]]}申请参战,还差{3-len(table)}人\033[0m\'.encode(\'utf-8\'), client)
else:
for client in clientDict:
sk.sendto(f\'\033[0;33m{clientDict[msg[1]]}申请参战,但很可惜人数满了。。。\033[0m\'.encode(\'utf-8\'), client)
else:
\'\'\'2-1-4:发送消息\'\'\'
for client in clientDict:
if client != msg[1]:
sk.sendto(f\'{clientDict[msg[1]]}说: {pickle.loads(msg[0])}\'.encode(\'utf-8\'), client)
\'\'\'
---------------------------
2-2,开始游戏
---------------------------
\'\'\'
if len(table) == 3:
playGame()
2,client-客户端
\'\'\'client\'\'\'
import socket
from threading import Thread
import pickle
from colorama import init
init(autoreset=True)
sk = socket.socket(type=socket.SOCK_DGRAM)
server = (\'10.181.22.132\', 6000)
def receiveMessage(sk):
\'\'\'接收消息\'\'\'
while True:
msg = sk.recvfrom(1024)
print(msg[0].decode(\'utf-8\'))
def sendMessage(sk):
\'\'\'发消息,轮到出牌的时候出牌\'\'\'
while True:
msg = list(input(\'>>>\').split(\',\'))
sk.sendto(pickle.dumps(msg), server)
if msg[0].upper() == \'P\':
print(\'申请参战!\')
if msg[0].upper() == \'QUTI\':
print(\'退出棋牌室,再见!\')
break
if __name__ == \'__main__\':
name = input(\'请输入您的名字:\')
sk.sendto(pickle.dumps(name), server)
th1 = Thread(target=receiveMessage, args=(sk, ))
th2 = Thread(target=sendMessage, args=(sk,))
th1.start()
th2.start()