ホワイトエレファントエクスチェンジ


11

7月のクリスマスです。だから、仮想の白い象のギフト交換よりも良いお祝いの方法です。

このキングオブザヒルチャレンジでは、ホワイトエレファントエクスチェンジシミュレーションで遊ぶボットを作成し、可能な限り最高のプレゼントを獲得する必要があります。

ゲームのルール

  • ゲームは多くのラウンドでプレイされ、各ラウンドは可変数のターンで構成されます。
  • ラウンド設定:ゲーム内のプレイヤーと同じ数のプレゼントがあり、それぞれが範囲[0 ... 1)でランダムに均一に評価されます。この値は、プレゼントが「開かれる」まで不明です。プレイヤーはランダムな順番でキューに入れられます。最初のプレーヤーがキューの先頭からポップされます。
  • プレイヤーのターンのとき、彼らはプレゼントを開くか、他のプレイヤーのプレゼントを盗んで、プレゼントが盗まれたプレイヤーにターンを渡すことができます。
    • 各プレゼントは最大3回盗まれます。
    • 盗まれたプレイヤーから盗むことはできません。
    • 各プレーヤーは、一度に1つのプレゼンスしか持てません。
  • プレゼントが開かれた後、プレイはキューの先頭からポップされた次のプレイヤーに進みます。これは、まだ順番が来ていない次の順番​​のプレイヤーになります。
  • ラウンド終了:すべてのプレゼントが開かれると、ラウンドが終了し、各プレイヤーが保持しているプレゼントの値がそのプレイヤーのスコアに加算されます。新しいラウンドが始まり、各プレイヤーは現在何も持っておらず、プレイヤーの順番はシャッフルされます。
  • ゲームの終了:少なくとも1人のプレイヤーが100 500ポイントを獲得すると、ゲームは終了し、プレゼントの合計値が最も高いプレイヤーに勝利が与えられます。

コーディング

すべての提出物はPython 3.7と互換性がある必要があります。から直接継承するクラスを作成する必要がありますWhiteElephantBot。例えば:

class FooBot(WhiteElephantBot):
    # Your implementation here

ボットクラスで__init__メソッド(引数を1つ取るname)を提供できます。このメソッドはを呼び出す必要がありますsuper().__init__(name)。クラスにはtake_turn、この順序で次の引数を受け取るメソッドが必要です。

  • players:まだプレゼントを持っていないすべてのプレイヤーの順番でのプレイヤー名のリスト。
  • presents:プレーヤー名を2タプルにマップする辞書。このタプルには、そのプレーヤーが保持している現在の値と、現在の盗まれた回数が含まれています。これには、現在プレゼントを持っている他のプレイヤーのみが含まれます。
  • just_stole:最後に行われたアクションがスチールであった場合、これは盗んだプレーヤーの名前になります。そうでない場合は、になりますNone

各引数は不変または新しいオブジェクトであるため、それらのいずれかを変更してもゲームに影響はありません。必要に応じて、任意の引数のコピーを保持できます。

以下の値の例presents

{
    'Alice':   (0.35, 0),
    'Bob':     (0.81, 2),
    'Charlie': (0.57, 1)
}

あなたのtake_turn方法はあなたから盗むしたり、希望するプレイヤーの名前を返す必要がありますNone存在を開くことを。例外を発生させstrたりNone、または以外の何かを返したり、盗むことができないプレーヤーの名前を返したりした場合、デフォルトでプレゼントを開きます。

コンストラクタは各ラウンドの開始時に呼び出されるため、ラウンドごとに状態を覚えることはできません。

から継承することにより、WhiteElephantBot現在のsteal_targets辞書を取得し、just_stole盗むことができるプレイヤーの名前のリストを返すメソッドにアクセスできます。

スクリプトに必要なモジュールは、エントリの一番上にインポートする必要があります。

テストドライバー

テストドライバーはこちらにありますfrom white_elephant import WhiteElephantBot投稿された回答に含める必要はありませんが、ローカルモジュールで行う必要があります。

ベースラインの競合他社

  • ランダム:新しいプレゼントを開くか、スチールするかをランダムに選択します。スチールターゲットは一様にランダムに選択されます。
  • 貪欲:盗まれ得る最も価値のあるプレゼントを盗みます。プレゼントを盗まれない場合は、プレゼントを開きます。
  • Nice:常に新しいプレゼントを開きます。盗むな。

追加の規則

  • すべての例外をキャッチするのはあなたの責任です。クラスが例外のキャッチに失敗した場合、失格になります。また、KeyboardInterruptsをキャッチしないでください。
  • ファイルや他の方法を使用して、ゲーム間で状態を保存できないことを回避しないでください。たとえば、途中でニューラルネットワークの状態をファイルに保存することはできません。
  • ボットは、クラスコードおよび関連する定数内に自己完結している必要があります。
  • 標準ライブラリのインポートのみを使用できます。
  • 厳密なパフォーマンス要件はありません。合理的かつ慎重になります。パフォーマンスが問題になる場合、時間制限を追加する権利を留保します。
  • 1人につき1つのエントリ。複数のエントリを送信すると、ボットが連携して動作しない場合があります。現時点では、1人につき複数のエントリを許可しますが、問題が生じた場合は後で禁止する場合があります。
  • これは明確な終了日がないオープンな競争です。大幅な変更があった場合は、いつでも再実行できます。

EDIT1:ランキングがより一貫するように、勝利スコアを100から500に変更しました。テストドライバーには新しいバグ修正があり、勝利スコアの変更も反映されます。

EDIT2:必要なインポートに関するメモを明確化。


リーダーボード(2018年8月8日現在)

  1. SampleBot(500.093)
  2. LastMinuteBot(486.163)
  3. ロビンフッド(463.160)
  4. オッドトッド(448.825)
  5. GreedyBot(438.520)
  6. SecondPlaceBot(430.598)
  7. ThresholdBot(390.480)
  8. ギャンブラー(313.362)
  9. NiceBot(275.536)
  10. RandomBot(256.172)
  11. グッドサマリタン(136.298)

盗むことは何回でもできますか?私がプレイしたとき、通常、連続して2スチールか何かの制限があり、3人目は1つを開く必要があります。これにより、同じギフトが1ターンに複数回盗まれるのを防ぎます。
mbomb007

@ mbomb007はい。特定のプレゼントが盗まれないようにする他のルールによる場合を除き、チェーン盗みは無制限です。各プレゼントは3回だけ盗まれ、盗まれたプレイヤーから盗むことはできません。
ビーフスター

プレゼントを盗んでから、元のプレゼントを盗むことはできますか?
エリックアウトゴルファー

@EriktheOutgolfer:はい、その間に別の順番がある限り。プレゼントが盗まれた直後に盗むことはできません。
ビーフスター

1
ヤンキースワップ!?次に、誕生日パーティーを共有しますか?
ngm

回答:


3

LastMinuteBot

(私はPythonをほとんど知らないので、コードの骨組みを@Mnemonicに大いに感謝します。)

class LastMinuteBot(WhiteElephantBot):
    def take_turn(self, players, presents, just_stole):
        targets = self.steal_targets(presents, just_stole)
        if len(targets) <= 1:
            return None

        target = None

        # If most of the presents are already distributed, try to steal an 
        #  un-restealable gift of high value
        if len(presents) > (len(players) + len(presents)) * 0.75:
            at_threshold = [t for t in targets if presents[t][1]==2 and presents[t][0]>=0.8]
            if at_threshold:
                target = max(at_threshold, key=lambda x: presents[x][0])

        # Otherwise, take the best available
        if not target:
            target = max(targets, key=lambda x: presents[x][0])

        return target if presents[target][0] > 0.5 else None

ギフトは3回以上盗まれないという事実を活用し、価値の高いギフトを見つけてほとんどのプレゼントが開かれている場合は、3回目の盗みをします。


シンプルでありながら美しい
r_j

2

オッド・トッド

class OddTodd(WhiteElephantBot):
    def take_turn(self, players, presents, just_stole):

        targets = self.steal_targets(presents, just_stole)

        # if none to steal, pick present
        if len(targets) <= 1:
            return None

        # steals the best gift that he can, as long as he's the 1st/3rd steal
        targets = [t for t in targets if presents[t][1] % 2 == 0]
        if targets:
            return max(targets, key=lambda x:presents[x][0])

        else:
            return None

彼ができる最高の贈り物を盗みますが、もし彼から盗まれた場合、彼はそれを取り戻すことができないので、贈り物を盗む二人目になりたくありません。


11行目の構文エラー。リストの内包表記の==代わりにが必要=です。
ビーフスター

修正、ありがとう!Pythonをあまり使用しないでください。
brian_t

1

SecondPlaceBot

class SecondPlaceBot(WhiteElephantBot):
    def take_turn(self, players, presents, just_stole):
        targets = self.steal_targets(presents, just_stole)
        if len(targets) <= 1:
            return None

        # If most of the presents are already distributed, take the second best.
        if len(presents) > (len(players) + len(presents)) * 0.8:
            target = sorted(targets, key=lambda x: presents[x][0])[-2]
        # Otherwise, take the best and hope someone steals it later.
        else:
            target = max(targets, key=lambda x: presents[x][0])

        return target if presents[target][0] > 0.5 else None

誰もが最も貴重な贈り物を求めて戦っています。次善の贈り物はほとんど同じですが、盗まれる可能性ははるかに低いです。


1

ThresholdBot

import random

class ThresholdBot(WhiteElephantBot):
    def __init__(self, name):
        self.name = name
        # Choose a minimum value to be happy.
        self.goal = 1 - random.random() ** 2

    def take_turn(self, players, presents, just_stole):
        # Find who has a gift that's sufficiently valuable.
        targets = self.steal_targets(presents, just_stole)
        targets = [x for x in targets if presents[x][0] >= self.goal]
        targets = sorted(targets, key=lambda x: presents[x][0])

        if not targets:
            return None

        # Choose a target (biased toward the best gifts).
        weighted = []
        for i, target in enumerate(targets, 1):
            weighted += [target] * i ** 2
        return random.choice(weighted)

私たちは本当になって気にしない最高の贈り物、ちょうど何か良いの十分。盗む価値のあるものがあれば、それを行います。


1

SampleBot

import random

class SampleBot(WhiteElephantBot):
    def rollout(self, values, counts, just_stole, next_move):
        targets = set()
        move_chosen = False
        for i, (v, n) in enumerate(zip(values, counts)):
            if v and n < 3 and i != just_stole and i != 0:
                targets.add(i)
        for i in range(len(values)):
            if values[i]:
                break
            while True:
                if not targets:
                    break
                if move_chosen:
                    j = max(targets, key=lambda i: values[i])
                    if values[j] < 0.5:
                        break
                else:
                    move_chosen = True
                    if next_move is None:
                        break
                    j = next_move
                values[i] = values[j]
                counts[i] = counts[j] + 1
                values[j] = 0
                counts[j] = 0
                if just_stole is not None and counts[just_stole] < 3:
                    targets.add(just_stole)
                if j in targets:
                    targets.remove(j)
                just_stole = i
                i = j
            values[i] = random.random()
            for player in (just_stole, i):
                if player is not None and values[player] and counts[player] < 3:
                    targets.add(player)
        return values[0]
    def take_turn(self, players, presents, just_stole, n_rollouts=2000):
        names = [self.name] + players + list(presents.keys())
        values = [presents[name][0] if name in presents else None for name in names]
        counts = [presents[name][1] if name in presents else 0 for name in names]
        if just_stole is not None:
            just_stole = names.index(just_stole)
        targets = [None]
        for i, (v, n) in enumerate(zip(values, counts)):
            if v and n < 3 and i != just_stole and i != 0:
                targets.append(i)
        if len(targets) == 1:
            return targets[0]
        scores = [0. for _ in targets]
        n = n_rollouts // len(targets)
        for i, target in enumerate(targets):
            for _ in range(n):
                scores[i] += self.rollout(list(values), list(counts), just_stole, target) / float(n)
        target_index = targets[scores.index(max(scores))]
        if target_index is None:
            return None
        return names[target_index]

各プレイヤーが貪欲に行動して2000のシミュレーションを実行し、最適なアクションを選択します。


このボットは正確に何をしますか?
ビーフスター

@Beefsterは、各プレイヤーが貪欲に行動する2000のランダムゲームを実行し、平均スコアが最も高い動きを選択します。
user1502040

名前エラー。ランダムにインポートする必要があります。
ビーフスター

1

ロビンフッド

class RobinHood(WhiteElephantBot):       
    def take_turn(self, players, presents, just_stole):
        #get the possible steal targets
        targets = self.steal_targets(presents, just_stole)
        #who stole his gift?
        targets = [x for x in targets if presents[x][1] > 0]
        #sort by value
        targets = sorted(targets, key=lambda x: presents[x][0])        
        #only steal back if it's worth it        
        targets = [x for x in targets if presents[x][0] > 0.5]

        if len(targets)>0:
           return targets.pop()

プレゼントをもらえなかった金持ちから盗む


インデントエラーがあります。
ビーフスター

0

善きサマリア人

class GoodSamaritan(WhiteElephantBot):     
    def take_turn(self, players, presents, just_stole):  
        targets = self.steal_targets(presents, just_stole)

         #if only one player has a gift, don't steal it!
        if len(presents)<=1 or len(targets)==0:
             return None
        else:       
             #Steal the worst present  
             return min(targets, key=lambda x: presents[x][0])

不運な人に幸運を与える別のチャンスを与える


0

ギャンブラー

class Gambler(WhiteElephantBot):
    def take_turn(self, players, presents, just_stole):        
        #get the possible steal targets
        targets = self.steal_targets(presents, just_stole)        

        #last player 
        if len(players)==0:
            #lets gamble! Try and get the highest score
            return None

        #If you are not last, steal the best gift that can be restolen so maybe you can become the last player
        targets = [t for t in targets if presents[t][1]<2 ]
        if targets:
            return max(targets, key=lambda x: presents[x][0])   

ギャンブラーは病みつきになり、最後のプレーヤーになろうと試み、その後、他のすべてのプレーヤーに勝つために新しいプレゼントに賭けます。


0

Top3Bot

class Top3Bot(WhiteElephantBot):
    def __init__(self, name):
        super().__init__(name)
        self.firstturn = True

    def take_turn(self, players, presents, just_stole):
        if self.firstturn:
            num_presents = len(players) + len(presents) + 1
            self.value_limit = (num_presents - 3) / num_presents
            self.firstturn = False

        targets = self.steal_targets(presents, just_stole)

        if players:
            targets += None

        return max(
            targets,
            key=lambda name: self.steal_ranking(name, presents, len(players))
        )


    def steal_ranking(self, name, presents, presents_remaining):
        if name is None:
            return (0, 0)

        present_value = presents[name][0]
        num_steals = presents[name][1]
        if present_value >= self.value_limit:
            if num_steals == 2:
                return (5, present_value)
            elif  num_steals == 0:
                return (4, -presemt_value)
            elif num_steals == 1 and presents_remaining == 0:
                return (3, -present_value)
            else:
                return (-1, present_value)
        else:
            if num_steals < 2:
                return (2, present_value)
            else:
                return (-2, present_value)

このボットは、可能な限り最高のプレゼントを取得しようとはしませんが、> =(n-3)/ n(nはプレゼントの数)の値を持つプレゼントを取得しようとします。ほとんどの場合、それほど価値のあるプレゼントがあり、Top3Botはこれらの1つを手に入れようとしますが、どれを手に入れるかは気にしません。


あなたの議論__init__が欠けてselfいる
-Beefster
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.