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