LoginSignup
3
2

More than 3 years have passed since last update.

XENOをpythonで実装

Last updated at Posted at 2020-04-04

XENOの動画、めっちゃくちゃ面白いですよね。
普段はrailsを書いてるのですが、たまにはpythonの練習を兼ねて今話題のXENOをpythonで実装してみました。

そのうち機械学習のネタに使ってみたりyoutube投稿してみたい。

mannual_flagをTrueにすればテキトーロジックのCPU戦が遊べます。

Xeno.py
import random

class Xeno():
    def __init__(self):
        self.winner = "none"

    class Player():
        def __init__(self,teban):
            self.hand = []
            self.field = []
            self.predict_flag = False
            self.defence_flag = False
            self.mannual_flag = False
            if teban == 0:
                self.teban="sente"
            elif teban ==1:
                self.teban="gote"

    def set_deck(self):
        card_list=[1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,10]
        random.shuffle(card_list)
        self.deck = card_list
        #転生札処理
        self.reincarnation_card = self.deck.pop(-1)

    #山札から1枚ドロー
    def draw_top_card(self):
        if len(self.deck) > 0:
            self.drawed_card=self.deck.pop(0)
            return self.drawed_card

    #賢者実行 デッキから3枚見て1枚をドローカードにしデッキをシャッフル
    def do_predict(self):
        if len(self.deck) > 2:
            options = self.deck[0:3]
            if self.player.mannual_flag ==True:
                print("賢者の効果発動")
                print(options)
                print("選択するカードを入力してください")
                ind = options.index(self.inputnumber())
            else:
                ind = options.index(options[1])
            selected_card = self.deck.pop(ind)
            random.shuffle(self.deck)
            self.drawed_card = selected_card
            return self.drawed_card

    #マッチセットアップ
    def match_initialize(self):
        self.sente = self.Player(0)
        self.gote = self.Player(1)

        #山札、転生札を作成し、各プレイヤー1枚ずつドロー
        self.set_deck()
        self.sente.hand.append(self.draw_top_card())
        self.gote.hand.append(self.draw_top_card())

    #ドローからターンエンドまでのシークエンス
    def play_turn(self,_player):
        if _player == self.sente:
            self.player = self.sente
            self.o_player = self.gote
        else:
            self.player = self.gote
            self.o_player = self.sente

        if self.player.predict_flag == True and len(self.deck) > 2:
            self.drawed_card = self.do_predict()
            self.player.predict_flag = False
        else:
            self.drawed_card = self.draw_top_card()


        #ドローカードを手札に追加
        self.player.hand.append(self.drawed_card)

        if self.player.mannual_flag ==True:
            print("drawed card:",self.drawed_card)
            print(self.player.teban, self.player.hand)

        #手札からカードを1枚場に出す
        self.play_card = self.decide_play_card()

        #手札から出したカードを削除
        self.player.hand.remove(self.play_card)
        #場に追加
        self.player.field.append(self.play_card)
        # print("player hand:", self.player.hand)

        #出したカードの効果をプレイ 
        if self.o_player.defence_flag != True or self.play_card == 7 or self.play_card == 4:
            self.play_effect()
        #相手が守護を出していた場合、フラグリセットのみ
        else:
            self.o_player.defence_flag = False

        print("player field:", self.player.field)
        print("o_player field:", self.o_player.field)

        #ターン終了時、デッキがなくなっていた場合、手札バトル
        print("deck maisuu:", len(self.deck))
        if len(self.deck) == 0:
            self.battle()

    #最終決戦
    def battle(self):
        print("battle!!!!!!!!!!!!!")
        print("sente:", self.sente.hand[0])
        print("gote:", self.gote.hand[0])
        if self.sente.hand[0] > self.gote.hand[0]:
            self.winner = self.sente.teban
        elif self.gote.hand[0]>self.sente.hand[0]:
            self.winner = self.gote.teban
        else:
            self.winner = "DRAW"

    def decide_play_card(self):
        if self.player.mannual_flag== True:
            print("プレイするカード番号を入力してください")
            return self.inputnumber()
        else:
            if self.player.hand.count(10) != 1:
                # random.shuffle(self.player.hand)
                self.player.hand.sort()
                return self.player.hand[0]
            else:
                self.player.hand.sort()
                return self.player.hand[0]

    def play_effect(self):
        pl = self.play_card
        if pl == 1:
            print("play:", pl)
            self.revolution()
        elif pl ==2:
            print("play:", pl)
            self.detect_number()
        elif pl == 3:
            print("play:", pl)
            self.publicate()
        elif pl ==4:
            print("play:", pl)
            self.skip_effect()
        elif pl ==5:
            print("play:", pl)
            self.hide_draw_and_drop()
        elif pl == 6:
            print("play:", pl)
            self.battle_novice()
        elif pl == 7:
            print("play:", pl)
            self.predict()
        elif pl == 8:
            print("play:", pl)
            self.exchange()
        elif pl == 9:
            print("play:", pl)
            self.public_draw_and_drop()

    def inputnumber(self):
        if self.player.mannual_flag==True:
            s = int(input())
            return s
        else:
            return 1

    #1 少年
    def revolution(self):
        all_field = self.sente.field + self.gote.field
        #フィールド上にすでに1が出ていた場合のみ公開処刑
        print(all_field)
        if all_field.count(1) > 1:
            self.public_draw_and_drop()

    #2 兵士
    def detect_number(self):
        detection_number = 3
        if self.player.mannual_flag == True:
            print("兵士の効果発動")
            print("相手の手札予想を入力してください")
            detection_number = self.inputnumber()
        else:
            detection_number = 5

        if self.o_player.hand[0] == detection_number:
            self.winner = self.player.teban

        #3 占い師
    def publicate(self):
        print(self.o_player.hand)

    #4 守護
    def skip_effect(self):
        self.player.defence_flag = True

    #5 死神
    def hide_draw_and_drop(self):
        if len(self.deck)>0:
            #相手は1枚ドローし手札シャッフル
            self.draw_card = self.draw_top_card()
            self.o_player.hand.append(self.draw_card)
            random.shuffle(self.o_player.hand)
            if self.player.mannual_flag == True:
                print("捨てさせる手札の位置を選んでください 0:左 1:右")
                inp = self.inputnumber()
            else:
                inp = 0

            #0番目カードをドロップ
            drop_target_card = self.o_player.hand.pop(inp)
            self.o_player.field.append(drop_target_card)

            #targetが10だった場合、転生処理
            if drop_target_card == 10:
                self.reincarnate()

    #6 貴族
    def battle_novice(self):
        self.battle()

    #7 賢者
    def predict(self):
        self.player.predict_flag = True

    #8 聖霊
    def exchange(self):
        tmp = self.player.hand[0]
        self.player.hand[0] = self.o_player.hand[0]
        self.o_player.hand[0] = tmp

    #9 皇帝
    def public_draw_and_drop(self):
        if len(self.deck) > 0:
            self.o_player.hand.append(self.draw_top_card())
            #手札公開
            if self.player.mannual_flag ==True:
                print("相手の手札はこちら")
                print(self.o_player.hand)
                #ターゲット選択
                print("select target number:")
                drop_target = self.inputnumber()
                ind = self.o_player.hand.index(drop_target)
            else:
                ind = 0

            drop_target_card = self.o_player.hand.pop(ind)
            self.o_player.field.append(drop_target_card)

            #皇帝のカード(9)がプレイされたかつターゲットカードが英雄(10)だった場合はplayer勝利
            if drop_target_card == 10:
                if self.play_card == 9:
                    self.winner = self.player.teban
                elif self.play_card == 1:
                    self.reincarnate()

    #10 英雄
    def reincarnate(self):
        #手札を捨てる 
        self.o_player.field.append(self.o_player.hand.pop(0))
        #転生札をドロー
        self.o_player.hand.append(self.reincarnation_card)


def main():
    winner_list = []
    win_process =[]
    for i in range(1,1000):
        xeno = Xeno()
        xeno.match_initialize()
        xeno.sente.mannual_flag = False
        xeno.gote.mannual_flag = False

        while True:
            print("=======================")
            if xeno.winner == "none":
                xeno.play_turn(xeno.sente)
            else:
                break
            print("=======================")
            if xeno.winner == "none":
                xeno.play_turn(xeno.gote)
            else:
                break

        print("winner :", xeno.winner)
        winner_list.append(xeno.winner)


    print("gote",winner_list.count("gote"))
    print("sente",winner_list.count("sente"))
    print("Draw",winner_list.count("DRAW"))

if __name__ == '__main__':
    main()

ちなみにロジックテキトーですが、10000試合の結果
gote 4543
sente 4967
Draw 489

6,10の組み合わせの初手勝ちがあり得る分、やはり先手のほうが有利ですね。
後、守護のカードは実質「相手に手札を選んで捨てさせる + 相手のターンスキップ」と同義なのでかなり強いアタッカーになってる気がします。

3
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2