– 危機と殉教の
(それは字幕がクールなので字幕です)
In this king-of-the-hill challenge in python (yup; you
need go no farther to know you may not submit in java), you need to
create a bot that plays a game very similar to welcome to the dungeon
ゲームのルール
(これはオリジナルゲームではないことに注意してください)
デッキ、アイテムセット、いくつかの報酬カードと死カードがあります。ベースHPは3です。 デッキは、強さを示すために
1,1,2,2,3,3,4,4,5,5,6,7,9
という番号の13枚のモンスターカードで構成されています。
アイテムリスト
-
悪魔条約:悪魔(強さ7モンスター)を倒し、その下のモンスターをダンジョンパイルに倒す。
– (悪魔がダンジョンの最後であった場合、悪魔を倒す) -
健康状態:0 HPに落ちたとき、モンスターを倒して3 HPに戻す。
-
聖杯:偶数の強さのモンスターを倒します(ゲームでは、これらはアンデッドです)。デーモン協定が使用された後に偶数番号のモンスターが発生した場合、それが最初に動作し、このモンスターの後で特別な殺害を受けることはありません。
-
フォアダガー:ダンジョンに入る前にモンスター1つを選択します。このタイプのモンスターは倒される。デーモン協定が使用された後にターゲットモンスターが発生した場合、それが最初に動作し、このモンスターの後で特別な殺害は行われません。
-
シールド:spelunkingする前にHP全体に3を加える。これは、健康状態を3に戻す健康薬の使用には影響しません。
-
鎧:spelunkingする前にHP全体に5を加えます。これは、健康状態を3に戻す健康薬の使用には影響しません。
報酬カードは、ダンジョンに成功した人を追跡するために使用されます。死カードは、ダンジョンで誰が失敗したかを追跡します。
描画フェーズ
すべてのモンスターカードがデッキに戻ってきたら、両プレイヤーは3
HPに回復し、すべての捨てられたアイテムはそれぞれ1つずつ復元されます。
最初のプレイヤーは、デッキからカードを引くか、他のプレイヤーからカードを隠すかを決定します。そうであれば、彼らはダンジョンパイルの上に置くか、選択したアイテムと共にそれを捨てるかを選択する必要があります。捨てられたアイテムとカードは、次のラウンドまでどちらのプレイヤーにも使用できなくなります。
プレイヤー1が自分の番を奪った後、プレイヤー2は同じことをする。プレイヤーは抽選するかどうかと、抽選したカードで何をするかを交互に決めます。誰かが抽選しないか、プレイヤーがデッキから最後のカードを受け取るまで決定します。
プレイヤーがドローをしない、または最後のカードをドローすると決定すると、ドローイングフェーズが終了し、もう一方のプレイヤーはダンジョンに入り、spelunkingを開始する必要があります。
Spelunking Phase
Vorpalダガーが捨てられていない場合、それを適用するカードを決定する必要があります。この段階の残りの段階では、積極的に決定することはありません。
最初のプレイヤーは一番上のカードを受け取ります。ダンジョンに置かれた最後のカードであり、その強さの数字が表示されます。前のターンからデーモン協定が有効であれば、引き出されたカードは捨てられる。さもなければ、プレイヤーのアイテムは「悪魔協定」、「聖杯」、「Vorpal
dagger」の順番でチェックされます。描かれたカードを倒すことができる最初の破棄されていないアイテムが使用され、カードは破棄されます。デーモン協定が使用されている場合、それは次のカードのためにアクティブになります。使用されたアイテムは破棄されません。
適用可能なアイテムがない場合、カードの強さはプレイヤーの健康状態から差し引かれます。彼らの健康状態がもはや肯定的でなければ、3
HPに回復し、可能であれば、その魔法瓶を捨てる。さもなければ、ダンジョンクロールを終了し、死カードを奪う。
プレイヤーが倒されずにダンジョンにカードが残っている間、トップカードを引き出すこのプロセスが繰り返されます。ダンジョン内のすべてのカードを首尾よく倒すと、ダンジョンのクロールが終了し、狙撃プレイヤーは報酬カードを徴収する。
完全なゲームの説明
ゲームは一連のラウンドで構成され、各ラウンドには抽選フェイズがあり、その後には突発フェイズがあります。各ラウンドの終わりに、1人のプレイヤーが死亡カードまたは報酬カードのいずれかを集めている。プレーヤーがいずれかのタイプの5つを累積すると、ゲームは終了する。彼らに5枚の死カードがある場合、彼らはゲームを失う。彼らに5枚の報酬カードがあれば、勝ちます。いずれにせよ、他のプレイヤーは反対の結果を受け取ります。いずれのプレイヤーも1つのタイプのカードが5枚もない場合は、次のラウンドに進み、前回ラウンドに2回目のプレイヤーが先に進み、その逆になります。
KOTH詳細
各ボットは上記の規則に従って1つおきのボットに対して400試合をプレイします。どのボットがプレイヤー1であるか(そして第1ラウンドで最初になる)、各ゲームが交互になり、すべての状態がゲーム間でリセットされます。
ここに再びアイテムがあります:
-
悪魔条約:悪魔(強さ7モンスター)を倒し、その下のモンスターをダンジョンパイルに倒す。
– (悪魔がダンジョンの最後であった場合、悪魔を倒す) -
健康状態:0 HPに落ちたとき、モンスターを倒して3 HPに戻す。
-
聖杯:偶数の強さのモンスターを倒します(ゲームでは、これらはアンデッドです)。デーモン協定が使用された後に偶数番号のモンスターが発生した場合、それが最初に動作し、このモンスターの後で特別な殺害を受けることはありません。
-
フォアダガー:ダンジョンに入る前にモンスター1つを選択します。このタイプのモンスターは倒される。デーモン協定が使用された後にターゲットモンスターが発生した場合、それが最初に動作し、このモンスターの後で特別な殺害は行われません。
-
シールド:spelunkingする前にHP全体に3を加える。これは、健康状態を3に戻す健康薬の使用には影響しません。
-
鎧:spelunkingする前にHP全体に5を加えます。これは、健康状態を3に戻す健康薬の使用には影響しません。
デッキは 1,1,2,2,3,3,4,4,5,5,6,7,9
です。
次の基本クラスから派生したクラス変数を使用しないボットクラスを実装する必要があります。
class BasePlayer:
def start_turn(self, last_turn):
raise NotImplementedError
def play(self, card):
raise NotImplementedError
def vorpal_choice(self, last_turn):
raise NotImplementedError
def result(self, bot, result, dungeon, vorped):
raise NotImplementedError
この基本クラスは、クラスが実装する必要があるメソッドと、それぞれが取る引数の数を示します。
メソッド引数の説明
-
last_turn
は整数またはNone値です。
0〜5の値は、敵がその値で示されたアイテムとともに引かれたカードを捨てたことを示します(上記の項目のリストを参照)。値6は、敵がカードをダンジョンに置いたことを示します。
None値は、ボットがこのラウンドで最初にプレイしていることを示します(vorpal_choice
では不可能)。vorpal_choice
のlast_turnは7になり、そのターンを過ぎたことを示します。 7ではない唯一の状況は、敵が最後のカードを引いたときです。 -
card
は、上に列挙したデッキからのカードの1つの強さを表す数字です。
vorpal_choice
および start_turn
の
さて、 result
の引数はもう少し複雑です:
-
bot
は、ダンジョンに入ったボットを示します。
0はダンジョンに入ることを示し、1は敵がダンジョンに入ったことを示します。 -
result
は旅行の成功を示します。
FalseはSpellunkingボットが成功したことを示し、Trueは失敗したことを示します。 -
dungeon
は、ダンジョン内にあったカードを表すカード/
intのリストです。ダンジョンは発注によって発注されます。ダンジョンに置かれた最初のカードが最初にリストにあり、最後に置かれたカードが最後にあります。あなたは破棄されたカードに関する情報を受け取ることはありません。彼らは他のボットから秘密です。 -
vorped
は、spelunkingボットによって作られた
vorpal_choice
を表す整数です。bot == 0
の場合、これはすでに分かっていますが、bot == 1
私は正直に言うと、なぜ私が勝利結果をFalseにしたのかを完全には思い出さないが、当時は良いアイデアだと思う。
戻り値
-
start_turn
:カードを引き出すには1を返し、play
:対応するアイテムとカードを捨てる場合は0から5を返し、カードをダンジョンに置く場合は6を返します(last_turn入力と一致します。
start_turn中に実行されます)。 -
result
:ボットのデータを更新するための通知機能であるため、
vorpal_choice
:Vorpalダガーで削除したいカードの番号を返します(1を削除する場合は1、5を削除する場合は5)。存在しないカードを選ぶとあなたが殺されます(8は違法、10は違法、0は違法です)。
ここでコントローラをチェックアウトすることができます
追加の説明、または過去にスキップしたかもしれない小さな詳細を繰り返すだけで、すぐに知りたいことがあります:
ボットはお互いに400のゲームをする。
クラス変数なし
特定の他のボットをターゲティングしていません
他のボットを上回ることはありません
ランダムモジュールや他のボットを修正するようなものはありません。
すべてのボットがKOTHに含まれる価値があることが明らかな場合を除き、6ボット最大(1人あたり)です(ただし、ボットをたくさん作ってはいけません)
それは価値があるもののための賞金の終わりを除いて、このKOTHのための特定の終了時間はありません。毎回勝つようにしてください。
結果はこれまでのところ(これらの人たちとはかなり怠け者であることをお詫びしています:P)
1 GrailThief 2732 0.98
2 Steve 2399 0.86
3 DevilWorshipper 1854 0.66
4 RunAway 1336 0.48
5 BoringPlayer 1190 0.42
6 SlapAndFlap 783 0.28
7 DareDevilDumDum 750 0.27
8 RandomMandom 156 0.06
Grailthiefは賞金を「盗む」。それはそれを獲得したためではありません。良い仕事、スラファール!
GrailThief
古い経験豊富なダンジョンクローラー。彼は、他のほとんどの人が望んでいること、聖杯がそれらを救うことを知っているので、彼はそれが消えていることを確かめます。
from base import BasePlayer
import copy
class GrailThief(BasePlayer):
class Stats:
def __init__(self):
self.deck = [1, 2, 3, 4, 5] * 2 + [6, 7, 9]
self.items = {0, 1, 2, 3, 4, 5}
self.dungeon_known = []
self.dungeon_unknown = 0
self.monsters_safe = {2, 4, 6, 7}
self.update()
def update(self):
self.dungeon_total = len(self.dungeon_known) + self.dungeon_unknown
deck_factor = float(self.dungeon_unknown)/len(self.deck) if len(self.deck) > 0 else 1.0
self.dungeon_weighted = [(i, 0.0 if i in self.monsters_safe else 1.0) for i in self.dungeon_known] + [(i, 0.0 if i in self.monsters_safe else deck_factor) for i in self.deck]
dungeon_weighted_sums = dict.fromkeys(self.dungeon_known + self.deck, 0.0)
for i in self.dungeon_weighted:
dungeon_weighted_sums[i[0]] += i[0] * i[1]
self.vorpal = max(dungeon_weighted_sums, key = dungeon_weighted_sums.get)
if 3 in self.items:
self.dungeon_weighted = [(i[0], 0.0 if i[0] == self.vorpal else i[1]) for i in self.dungeon_weighted]
def discard_item(self, item, card):
new = copy.copy(self)
new.items = {i for i in new.items if i != item}
if item == 0:
new.monsters_safe = {i for i in new.monsters_safe if i != 7}
elif item == 2:
new.monsters_safe = {i for i in new.monsters_safe if i not in {2, 4, 6}}
if card is not None:
new.deck = list(new.deck)
new.deck.remove(card)
new.update()
return new
def to_dungeon(self, card):
new = copy.copy(self)
if card is None:
new.dungeon_unknown += 1
else:
new.deck = list(new.deck)
new.deck.remove(card)
new.dungeon_known = list(new.dungeon_known)
new.dungeon_known.append(card)
new.update()
return new
def effective_hp(self):
hp = 3.0
if 1 in self.items:
hp += 3.0
if self.dungeon_total > 0:
hp += sum([(i[0] - 1) * i[1] for i in self.dungeon_weighted])/self.dungeon_total
if 4 in self.items:
hp += 3.0
if 5 in self.items:
hp += 5.0
return hp
def effective_damage(self):
damage = sum([i[0] * i[1] for i in self.dungeon_weighted])
if 0 in self.items:
if self.dungeon_total > 1:
damage -= damage/(self.dungeon_total - 1)
return damage
def __init__(self):
self.stats = self.Stats()
def process_last_turn(self, last_turn):
if last_turn in [0, 1, 2, 3, 4, 5]:
self.stats = self.stats.discard_item(last_turn, None)
elif last_turn == 6:
self.stats = self.stats.to_dungeon(None)
def start_turn(self, last_turn):
self.process_last_turn(last_turn)
if self.stats.effective_hp() > self.stats.effective_damage() + 1.5:
return 1
else:
return 0
def play(self, card):
if 2 in self.stats.items:
self.stats = self.stats.discard_item(2, card)
return 2
else:
self.stats = self.stats.to_dungeon(card)
return 6
def vorpal_choice(self, last_turn):
self.process_last_turn(last_turn)
return self.stats.vorpal
def result(self, bot, result, dungeon, vorped):
self.stats = self.Stats()