3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?