diff --git a/card.py b/card.py new file mode 100644 index 0000000..c633cdf --- /dev/null +++ b/card.py @@ -0,0 +1,238 @@ +import random +import game + +cards = dict() +card_name = ["1.攻擊","2.防禦","3.治癒","4.補給","5.強奪","6.奇襲","7.交易","8.洞悉","9.妙策","10.掃射","11.加護","12.劇毒","13.詛咒","14.反制","15.狂亂","16.逆轉"] +unattackable = ['2','8','14','17','18'] +unrobable = ['8','17','18'] +for i in range(len(card_name)): + cards[str(i+1)] = card_name[i] # initialize cards +# create default deck +# 攻擊*15 防禦*15 治癒*15 補給*10 強奪*10 奇襲*10 交易*10 洞悉*5 妙策*5 掃射*5 加護*5 劇毒*2 詛咒*2 反制*2 狂亂*2 逆轉*2 +default_deck = ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', '8', '8', '8', '8', '8', '9', '9', '9', '9', '9', '10', '10', '10', '10', '10', '11', '11', '11', '11', '11', '12', '12', '13', '13', '14', '14', '15', '15', '16', '16'] +random.shuffle(default_deck) # wash + +# card functions +# cur:current player +# ene:enemy +def attack(cur,ene): + cur.attacking = True + cur.damage = 2 # 給反制判斷的 + print("{} 攻擊 {}".format(cur.name,ene.name)) + if ene.defence(): + game.display(ene) # 顯示手牌 + while True: + choice = input("請問要防禦嗎? 不使用請輸入0 ") + if choice in ene.hand: + if choice in unattackable: + skills[choice](cur,ene) + ene.remove_card(choice) + break + elif choice == "0": + print("{} 受到{}點傷害".format(ene.name,cur.damage)) + ene.life -= cur.damage + break + else: + print("{} 受到{}點傷害".format(ene.name,cur.damage)) + ene.life -= cur.damage + cur.attacking = False + cur.damage = 0 # reset + +def defend(cur,ene): + if cur.attacking or cur.surprise: + print("{} 防禦成功".format(ene.name)) + else: + print("{} 沒什麼可以防禦的,回復一點生命".format(cur.name)) + cur.life += 1 + +def heal(cur,ene): + print("{} 回復兩點生命".format(cur.name)) + cur.life += 2 + +def supply(cur,ene): + print("{} 增加兩張手牌".format(cur.name)) + for _ in range(2): + game.draw(cur) + +def rob(cur,ene): + cur.robbing = True + print("{} 正在對 {} 行搶".format(cur.name,ene.name)) + if ene.keep(): + game.display(ene) # 顯示手牌 + while True: + choice = input("請問要防禦嗎? 不使用請輸入0 ") + if choice in ene.hand: + if choice in unrobable: + skills[choice](cur,ene) + ene.remove_card(choice) + break + elif choice == "0": + break + else: + if len(ene.hand) == 0: + print("可惜,{} 有夠窮,沒東西能搶".format(ene.name)) + else: + game.display(ene) + while True: + swag = input("{} 要搶哪張? ".format(cur.name)) + if swag in ene.hand: + ene.robbed(swag) + cur.add_card(swag) + break + cur.robbing = False + +def surprise(cur,ene): + cur.surprise = True + cur.damage = 1 # 給反制判斷 + print("{} 發動奇襲".format(cur.name)) + if ene.defence(): + game.display(ene) # 顯示手牌 + while True: + choice = input("請問要防禦嗎? 不使用請輸入0 ") + if choice in ene.hand: + if choice in unattackable: + skills[choice](cur,ene) + ene.remove_card(choice) + break + elif choice == "0": + print("{} 受到{}點傷害,而且掉了一張手牌".format(ene.name,cur.damage)) + ene.life -= cur.damage + drop = random.choice(ene.hand) + ene.remove_card(drop) + break + else: + print("{} 受到{}點傷害,而且掉了一張手牌".format(ene.name,cur.damage)) + ene.life -= cur.damage + drop = random.choice(ene.hand) + ene.remove_card(drop) + cur.surprise = False + cur.damage = 0 # reset + +def trade(cur,ene): + print("{} 想與 {} 進行交易".format(cur.name,ene.name)) + cur.remove_card("7") # you can't trade the using card "trade" + game.display(cur) # 顯示手牌 + while True: + choice = input("選擇一張手牌以交換 ") + if choice in cur.hand: + cur_item = choice + print("{} 選擇了 {}".format(cur.name,cards[choice])) + break + game.display(ene) # 顯示手牌 + while True: + choice = input("選擇一張手牌以交換 ") + if choice in ene.hand: + ene_item = choice + print(ene.name,"choose",cards[choice]) + break + # current player part + cur.hand.remove(cur_item) + cur.display.remove(cards[cur_item]) + cur.hand.append(ene_item) + cur.display.append(cards[ene_item]) + # enemy part + ene.hand.remove(ene_item) + ene.display.remove(cards[ene_item]) + ene.hand.append(cur_item) + ene.display.append(cards[cur_item]) + + cur.add_card("7") # add back the card. game system will remove this card right away + +def aware(cur,ene): + if cur.attacking: + print("{} 洞悉了 {} 的攻擊,並抽取了一張手牌".format(ene.name,cur.name)) + game.draw(ene) + elif cur.robbing: + print("{} 洞悉了 {} 的強奪,並抽取了一張手牌".format(ene.name,cur.name)) + game.draw(ene) + elif cur.surprise: + print("{} 洞悉了 {} 的奇襲,並抽取了一張手牌".format(ene.name,cur.name)) + game.draw(ene) + else: + for _ in range(3): + print("{} 增加三張手牌".format(cur.name)) + game.draw(cur) + +def plan(cur,ene): + print("{} 有個妙策".format(cur.name)) + options = random.sample(cur.deck,3) + o_name = [] # names of cards in options + for id in options: + o_name.append(cards[id]) + print(o_name) + while True: + choice = input("選擇一張卡加入手牌 ") + if choice in options: + cur.add_card(choice) + break + +def sweep(cur,ene): + cur.attacking = True + cur.damage = random.randint(0,5) + print("{} 對 {} 進行掃射,威力是 {}".format(cur.name,ene.name,cur.damage)) + if ene.defence(): + game.display(ene) # 顯示手牌 + while True: + choice = input("請問要防禦嗎? 不使用請輸入0 ") + if choice in ene.hand: + if choice in unattackable: + skills[choice](cur,ene) + ene.remove_card(choice) + break + elif choice == "0": + print("{} 受到{}點傷害".format(ene.name,cur.damage)) + ene.life -= cur.damage + break + else: + print("{} 受到{}點傷害".format(ene.name,cur.damage)) + ene.life -= cur.damage + cur.attacking = False + cur.damage = 0 # reset + +def bless(cur,ene): + print("{} 獲得加護,身上的毒素一掃而空,並回復三點生命,還抽取了兩張手牌".format(cur.name)) + cur.poison = 0 # 解毒 + cur.life += 3 + for _ in range(2): + game.draw(cur) + +def poison(cur,ene): + if ene.poison != 0: + s = "又" + else: + s = "" + print("{} 在食物下毒,{} {}中毒了".format(cur.name,ene.name, s)) + ene.poison += 1 + +def curse(cur,ene): + print("{} 詛咒了 {},使其損失四點生命,並掉了一張手牌".format(cur.name,ene.name)) + ene.life -= 4 + drop = random.choice(ene.hand) + ene.remove_card(drop) + +def counter(cur,ene): + if cur.attacking: + print("{} 反制了 {} 的攻擊,反彈了{}點傷害".format(ene.name,cur.name,cur.damage)) + cur.life -= cur.damage + elif cur.surprise: + print("{} 反制了 {} 的奇襲,反彈了{}點傷害,並使其掉了一張手牌".format(ene.name,cur.name,cur.damage)) + cur -= cur.damage + drop = random.choice(cur.hand) + cur.remove_card(drop) + else: + print("{} 反制了敵手,使 {} 生命值減半了!".format(cur.name,ene.name)) + ene.life = ene.life//2 + +def chaos(cur,ene): + print("{} 進入狂亂模式,回復三點生命,並對 {} 造成三點傷害".format(cur.name,ene.name)) + cur.life += 3 + ene.life -= 3 + +def reverse(cur,ene): + print("{} 一口氣逆轉了情勢".format(cur.name)) + cur.life,ene.life = ene.life,cur.life + +skills = dict() +skill_name = [attack,defend,heal,supply,rob,surprise,trade,aware,plan,sweep,bless,poison,curse,counter,chaos,reverse] +for i in range(len(skill_name)): + skills[str(i+1)] = skill_name[i] diff --git a/game.py b/game.py new file mode 100644 index 0000000..2b2ab15 --- /dev/null +++ b/game.py @@ -0,0 +1,107 @@ +import random +import card + +class Player: + def __init__(self,name,deck): + self.name = name + self.deck = deck[:] # to pass by value instead of by reference + self.hand = [] + self.display = [] # names of cards in hand + self.life = 20 + self.poison = 0 + self.damage = 0 # 因為反制要拿來判斷掃射 + self.playing = False + self.attacking = False + self.robbing = False + self.surprise = False # 又是因為反制要判斷奇襲 + self.turn = 0 + + def poison_check(self): + if self.poison != 0: + self.life -= self.poison + return True + else: + return False + + def add_card(self,id): + self.hand.append(id) + self.display.append(card.cards[id]) + self.deck.remove(id) + + def remove_card(self,id): + self.hand.remove(id) + self.display.remove(card.cards[id]) + self.deck.append(id) + + def robbed(self,id): # be robbed + self.hand.remove(id) + self.display.remove(card.cards[id]) + + def defence(self): # to decide if player is able to defend or not + for c in self.hand: + if c in card.unattackable: + return True + return False + + def keep(self): # to decide if player is able to be robbed or not + for c in self.hand: + if c in card.unrobable: + return True + return False + def surrender(self): + self.life = 0 + +# game functions +def health(p1,p2): + print("{} 的生命: {}".format(p1.name,p1.life)) + print("{} 的生命: {}".format(p2.name,p2.life)) + +def display(player): + print("這是 {} 的手牌".format(player.name)) + print(player.display) + +def draw(player): # 抽卡 + if len(player.deck) == 0: + player.life = -99999999 # 牌抽乾了就讓他死 + print("你抽到了死神") + return None + new = random.choice(player.deck) + print("{} 抽到了 {}".format(player.name,card.cards[new])) + player.add_card(new) + print("牌組剩餘: {} 張".format(len(player.deck))) + +# turn control +# cur:current player +# ene:enemy +def turn(p1,p2): + if p1.playing == True: + cur = p1 + ene = p2 + elif p2.playing == True: + cur = p2 + ene = p1 + cur.turn += 1 + print("") # change line + print("{} 的第{}回合".format(cur.name,cur.turn)) + if cur.poison_check(): + print("{} 受到了劇毒的侵蝕".format(cur.name)) + print("{} 損失{}點生命".format(cur.name,cur.poison)) + if cur.life <= 0: + return + health(p1,p2) + draw(cur) # 抽卡 + display(cur) # 顯示手牌 + while True: + choice = input("請問要使用手牌嗎? 若不使用請輸入0 ") + if choice in cur.hand: + card.skills[choice](cur,ene) + cur.remove_card(choice) + break + elif choice == "0": + break + elif choice == "-1": + cur.surrender() + print("{}投降".format(cur.name)) + break + del choice # prevent reading old data + p1.playing,p2.playing = p2.playing,p1.playing # switch! diff --git a/pyws.py b/pyws.py new file mode 100644 index 0000000..a163f59 --- /dev/null +++ b/pyws.py @@ -0,0 +1,86 @@ +import card +import game +from room import Room, sendTo + +import asyncio +import datetime +import random +import websockets + + +connected = {-1: []} +character = dict() +name=["安","圭月","梅","小兔","銀","正作","W","桑德","海爾","雪村"] + +for i in range(len(name)): + character[str(i+1)] = name[i] + +async def handler(websocket, path): + global connected + # Register. + connected[-1].append(websocket) + websocket.status = Room.CONNECTED + await websocket.send("CHOOSE CHARACTER") + try: + # Implement logic here. + while 1: + message = await websocket.recv() + if websocket.status == Room.CONNECTED: # choose character + choice = message + while choice not in map(lambda x : str(x+1),list(range(len(name)))): + await websocket.send("CHOOSE") + await websocket.send("CHOOSE: "+ str(choice) + "\n" + str(list(range(len(name))))) + choice = await websocket.recv() + p_name = character[choice] + await websocket.send("PLAYER "+p_name) + websocket.player = game.Player(p_name,card.default_deck) + + websocket.status = Room.MATCHING + + elif websocket.status == Room.MATCHING: + try: + room_id = int(message) + connected[room_id] = connected.get(room_id, Room(room_id)) + + count = connected[room_id].count() + + if count <= 1: # Enter the room + connected[room_id].player_add(websocket) + connected[-1].remove(websocket) + await websocket.send("You have entered room "+ str(connected[room_id])) + websocket.room = room_id + + if count+1 == 1: # 該玩家已加入房間 + await websocket.send("Waiting for another player...") + else: + for ws in connected[room_id]: + ws.status = Room.PLAYING + await ws.send("The game will start soon.....") + # await connected[room_id].start() + # Testing + + else: # Can't enter the room + await websocket.send("SAD, This room is full. Please enter another room.") + except Exception as e: + print(e) + print("STATUS = MATCHING") + elif websocket.status == Room.PLAYING: + print("STATUS = PLAYING, message got") + for ws in connected[websocket.room]: + await ws.send("STARTING... But unfortunately, we haven't completed this part of code.") + print("STATUS = PLAYING, message sent") + + finally: + # Unregister. + connected[websocket.room].player_delete(websocket) + print(connected) + + + +"""cert = ssl.SSLContext() +cert.load_cert_chain("/etc/letsencrypt/live/stoneapp.tech/fullchain.pem","/etc/letsencrypt/live/stoneapp.tech/privkey.pem") +start_server = websockets.serve(handler, '10.128.0.2', 8787,ssl=cert)""" + +start_server = websockets.serve(handler, '127.0.0.1', 9000) +asyncio.get_event_loop().run_until_complete(start_server) +asyncio.get_event_loop().run_forever() diff --git a/room.py b/room.py new file mode 100644 index 0000000..d1a6f6b --- /dev/null +++ b/room.py @@ -0,0 +1,55 @@ +import game +import random + +class Room: + CONNECTED = 0 + MATCHING = 1 + PLAYING = 2 + WAITING = -1 + def __init__(self, room, players=[]): + self.room = room + self.players = players + + def __repr__(self): + return "ROOM {}, {} player(s)".format(str(self.room), len(self.players)) + + def __iter__(self): + return iter(self.players) + + def player_add(self, player): + if self.count() >= 2: + return + self.players.append(player) + + def player_delete(self, player): + try: + self.players.remove(player) + except: + pass + + def count(self): + return len(self.players) + + async def start(self): + p1, p2 = self.players[0].player, self.players[1].player + first = random.choice([p1, p2]) + print(first, p1, p2) + first.playing = True # so the first one will be random + await sendTo(first.name + "先攻", *self.players) + print(first.name,"先攻") + print() # change line + for _ in range(3): # 初始手牌*3 + game.draw(p1) + game.draw(p2) + + while p1.life > 0 and p2.life > 0: + await game.turn(self.players[0], self.players[1]) + + if p1.life <= 0: + print("{} 獲勝".format(p2.name)) + elif p2.life <= 0: + print("{} 獲勝".format(p1.name)) + +async def sendTo(message, *ws_list): + for ws in ws_list: + await ws.send(message)